1 /*******************************************************************************
2 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
16 import java
.io
.IOException
;
17 import java
.nio
.MappedByteBuffer
;
18 import java
.nio
.channels
.FileChannel
;
19 import java
.nio
.channels
.FileChannel
.MapMode
;
20 import java
.util
.UUID
;
22 import org
.eclipse
.linuxtools
.ctf
.core
.event
.io
.BitBuffer
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.ArrayDefinition
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinitionScope
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
30 * <b><u>StreamInput</u></b>
32 * Represents a trace file that belongs to a certain stream.
34 public class StreamInput
implements IDefinitionScope
{
36 // ------------------------------------------------------------------------
38 // ------------------------------------------------------------------------
41 * The associated Stream
43 private final Stream stream
;
46 * FileChannel to the trace file
48 private final FileChannel fileChannel
;
51 * Information on the file (used for debugging)
53 public final File file
;
56 * The packet index of this input
58 private final StreamInputPacketIndex index
= new StreamInputPacketIndex();
60 private long timestampEnd
;
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
67 * Constructs a StreamInput.
70 * The stream to which this StreamInput belongs to.
72 * The FileChannel to the trace file.
74 * Information about the trace file (for debugging purposes).
76 public StreamInput(Stream stream
, FileChannel fileChannel
, File file
) {
78 this.fileChannel
= fileChannel
;
82 // ------------------------------------------------------------------------
83 // Getters/Setters/Predicates
84 // ------------------------------------------------------------------------
86 public Stream
getStream() {
90 public StreamInputPacketIndex
getIndex() {
94 public FileChannel
getFileChannel() {
98 public String
getFilename() {
99 return file
.getName();
102 public long getTimestampEnd() {
106 public void setTimestampEnd(long timestampEnd
) {
107 this.timestampEnd
= timestampEnd
;
111 public String
getPath() {
112 return ""; //$NON-NLS-1$
115 // ------------------------------------------------------------------------
117 // ------------------------------------------------------------------------
120 public Definition
lookupDefinition(String lookupPath
) {
121 /* TODO: lookup in different dynamic scopes is not supported yet. */
126 * Create the index for this trace file.
128 * @throws CTFReaderException
130 public void createIndex() throws CTFReaderException
{
132 * The size of the file in bytes
134 long fileSizeBytes
= 0;
136 fileSizeBytes
= fileChannel
.size();
137 } catch (IOException e
) {
138 throw new CTFReaderException(e
);
142 * Offset of the current packet in bytes
144 long packetOffsetBytes
= 0;
147 * Initial size, it should map at least the packet header + context
150 * TODO: use a less arbitrary size.
155 * Definition of trace packet header
157 StructDefinition tracePacketHeaderDef
= null;
160 * Definition of trace stream packet context
162 StructDefinition streamPacketContextDef
= null;
165 * The BitBuffer to extract data from the StreamInput
167 BitBuffer bitBuffer
= new BitBuffer();
168 bitBuffer
.order(this.getStream().getTrace().getByteOrder());
171 * Create the definitions we need to read the packet headers + contexts
173 if (getStream().getTrace().getPacketHeader() != null) {
174 tracePacketHeaderDef
= getStream().getTrace().getPacketHeader().createDefinition(
175 this, "trace.packet.header"); //$NON-NLS-1$
178 if (getStream().getPacketContextDecl() != null) {
179 streamPacketContextDef
= getStream().getPacketContextDecl().createDefinition(
180 this, "stream.packet.context"); //$NON-NLS-1$
184 * Scan through the packets of the file.
186 while (packetOffsetBytes
< fileSizeBytes
) {
188 * If there is less data remaining than what we want to map, reduce
191 if ((fileSizeBytes
- packetOffsetBytes
) < mapSize
) {
192 mapSize
= fileSizeBytes
- packetOffsetBytes
;
200 bb
= fileChannel
.map(MapMode
.READ_ONLY
, packetOffsetBytes
,
202 } catch (IOException e
) {
203 throw new CTFReaderException(e
);
205 bitBuffer
.setByteBuffer(bb
);
208 * Create the index entry
210 StreamInputPacketIndexEntry packetIndex
= new StreamInputPacketIndexEntry(
214 * Read the trace packet header if it exists.
216 if (tracePacketHeaderDef
!= null) {
217 tracePacketHeaderDef
.read(bitBuffer
);
220 * Check the CTF magic number
222 IntegerDefinition magicDef
= (IntegerDefinition
) tracePacketHeaderDef
.lookupDefinition("magic"); //$NON-NLS-1$
223 if (magicDef
!= null) {
224 int magic
= (int) magicDef
.getValue();
225 if (magic
!= Utils
.CTF_MAGIC
) {
226 throw new CTFReaderException(
227 "CTF magic mismatch " + Integer
.toHexString(magic
) + " vs " + Integer
.toHexString(Utils
.CTF_MAGIC
)); //$NON-NLS-1$//$NON-NLS-2$
233 * Check the trace UUID
235 ArrayDefinition uuidDef
= (ArrayDefinition
) tracePacketHeaderDef
.lookupDefinition("uuid"); //$NON-NLS-1$
236 if (uuidDef
!= null) {
237 byte[] uuidArray
= new byte[16];
239 for (int i
= 0; i
< 16; i
++) {
240 IntegerDefinition uuidByteDef
= (IntegerDefinition
) uuidDef
.getElem(i
);
241 uuidArray
[i
] = (byte) uuidByteDef
.getValue();
244 UUID uuid
= Utils
.makeUUID(uuidArray
);
246 if (!getStream().getTrace().getUUID().equals(uuid
)) {
247 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
252 * Check that the stream id did not change
254 IntegerDefinition streamIDDef
= (IntegerDefinition
) tracePacketHeaderDef
.lookupDefinition("stream_id"); //$NON-NLS-1$
255 if (streamIDDef
!= null) {
256 long streamID
= streamIDDef
.getValue();
258 if (streamID
!= getStream().getId()) {
259 throw new CTFReaderException(
260 "Stream ID changing within a StreamInput"); //$NON-NLS-1$
266 * Read the stream packet context if it exists.
268 if (streamPacketContextDef
!= null) {
269 streamPacketContextDef
.read(bitBuffer
);
272 * Read the content size in bits
274 IntegerDefinition contentSizeDef
= (IntegerDefinition
) streamPacketContextDef
.lookupDefinition("content_size"); //$NON-NLS-1$
275 if (contentSizeDef
!= null) {
276 packetIndex
.contentSizeBits
= (int) contentSizeDef
.getValue();
278 packetIndex
.contentSizeBits
= (int) (fileSizeBytes
* 8);
282 * Read the packet size in bits
284 IntegerDefinition packetSizeDef
= (IntegerDefinition
) streamPacketContextDef
.lookupDefinition("packet_size"); //$NON-NLS-1$
285 if (packetSizeDef
!= null) {
286 packetIndex
.packetSizeBits
= (int) packetSizeDef
.getValue();
288 if (packetIndex
.contentSizeBits
!= 0) {
289 packetIndex
.packetSizeBits
= packetIndex
.contentSizeBits
;
291 packetIndex
.packetSizeBits
= (int) (fileSizeBytes
* 8);
296 * Read the begin timestamp
298 IntegerDefinition timestampBeginDef
= (IntegerDefinition
) streamPacketContextDef
.lookupDefinition("timestamp_begin"); //$NON-NLS-1$
299 if (timestampBeginDef
!= null) {
300 packetIndex
.timestampBegin
= timestampBeginDef
.getValue();
304 * Read the end timestamp
306 IntegerDefinition timestampEndDef
= (IntegerDefinition
) streamPacketContextDef
.lookupDefinition("timestamp_end"); //$NON-NLS-1$
307 if (timestampEndDef
!= null) {
308 setTimestampEnd(packetIndex
.timestampEnd
= timestampEndDef
.getValue());
312 * If there is no packet context, infer the content and packet
313 * size from the file size (assume that there is only one packet
316 packetIndex
.contentSizeBits
= (int) (fileSizeBytes
* 8);
317 packetIndex
.packetSizeBits
= (int) (fileSizeBytes
* 8);
320 /* Basic validation */
321 if (packetIndex
.contentSizeBits
> packetIndex
.packetSizeBits
) {
322 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
325 if (packetIndex
.packetSizeBits
> ((fileSizeBytes
- packetIndex
.offsetBytes
) * 8)) {
326 throw new CTFReaderException(
327 "Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
331 * Offset in the file, in bits
333 packetIndex
.dataOffsetBits
= bitBuffer
.position();
336 * Add the packet index entry to the index
338 index
.addEntry(packetIndex
);
341 * Update the counting packet offset
343 packetOffsetBytes
+= (packetIndex
.packetSizeBits
+ 7) / 8;