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
.internal
.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
.types
.ArrayDefinition
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinitionScope
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFReaderException
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.Utils
;
29 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.io
.BitBuffer
;
32 * <b><u>StreamInput</u></b>
34 * Represents a trace file that belongs to a certain stream.
36 public class StreamInput
implements IDefinitionScope
{
38 // ------------------------------------------------------------------------
40 // ------------------------------------------------------------------------
43 * The associated Stream
45 private final Stream stream
;
48 * FileChannel to the trace file
50 private final FileChannel fileChannel
;
53 * Information on the file (used for debugging)
55 public final File file
;
58 * The packet index of this input
60 private final StreamInputPacketIndex index
= new StreamInputPacketIndex();
62 private long timestampEnd
;
64 // ------------------------------------------------------------------------
66 // ------------------------------------------------------------------------
69 * Constructs a StreamInput.
72 * The stream to which this StreamInput belongs to.
74 * The FileChannel to the trace file.
76 * Information about the trace file (for debugging purposes).
78 public StreamInput(Stream stream
, FileChannel fileChannel
, File file
) {
80 this.fileChannel
= fileChannel
;
84 // ------------------------------------------------------------------------
85 // Getters/Setters/Predicates
86 // ------------------------------------------------------------------------
88 public Stream
getStream() {
92 public StreamInputPacketIndex
getIndex() {
96 public FileChannel
getFileChannel() {
100 public String
getFilename() {
101 return file
.getName();
104 public long getTimestampEnd() {
108 public void setTimestampEnd(long timestampEnd
) {
109 this.timestampEnd
= timestampEnd
;
113 public String
getPath() {
114 return ""; //$NON-NLS-1$
117 // ------------------------------------------------------------------------
119 // ------------------------------------------------------------------------
121 @SuppressWarnings("unused")
123 public Definition
lookupDefinition(String lookupPath
) {
124 /* TODO: lookup in different dynamic scopes is not supported yet. */
129 * Create the index for this trace file.
131 * @throws CTFReaderException
133 public void createIndex() throws CTFReaderException
{
135 * The size of the file in bytes
137 long fileSizeBytes
= 0;
139 fileSizeBytes
= fileChannel
.size();
140 } catch (IOException e
) {
141 throw new CTFReaderException(e
);
145 * Offset of the current packet in bytes
147 long packetOffsetBytes
= 0;
150 * Initial size, it should map at least the packet header + context
153 * TODO: use a less arbitrary size.
158 * Definition of trace packet header
160 StructDefinition tracePacketHeaderDef
= null;
163 * Definition of trace stream packet context
165 StructDefinition streamPacketContextDef
= null;
168 * The BitBuffer to extract data from the StreamInput
170 BitBuffer bitBuffer
= new BitBuffer();
171 bitBuffer
.order(this.getStream().getTrace().getByteOrder());
174 * Create the definitions we need to read the packet headers + contexts
176 if (getStream().getTrace().getPacketHeader() != null) {
177 tracePacketHeaderDef
= getStream().getTrace().getPacketHeader()
178 .createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
181 if (getStream().getPacketContextDecl() != null) {
182 streamPacketContextDef
= getStream().getPacketContextDecl()
183 .createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
187 * Scan through the packets of the file.
189 while (packetOffsetBytes
< fileSizeBytes
) {
191 * If there is less data remaining than what we want to map, reduce
194 if ((fileSizeBytes
- packetOffsetBytes
) < mapSize
) {
195 mapSize
= fileSizeBytes
- packetOffsetBytes
;
203 bb
= fileChannel
.map(MapMode
.READ_ONLY
, packetOffsetBytes
,
205 } catch (IOException e
) {
206 throw new CTFReaderException(e
);
208 bitBuffer
.setByteBuffer(bb
);
211 * Create the index entry
213 StreamInputPacketIndexEntry packetIndex
= new StreamInputPacketIndexEntry(
217 * Read the trace packet header if it exists.
219 if (tracePacketHeaderDef
!= null) {
220 tracePacketHeaderDef
.read(bitBuffer
);
223 * Check the CTF magic number
225 IntegerDefinition magicDef
= (IntegerDefinition
) tracePacketHeaderDef
226 .lookupDefinition("magic"); //$NON-NLS-1$
227 if (magicDef
!= null) {
228 int magic
= (int) magicDef
.getValue();
229 if (magic
!= Utils
.CTF_MAGIC
) {
230 throw new CTFReaderException(
231 "CTF magic mismatch " + Integer
.toHexString(magic
) + " vs " + Integer
.toHexString(Utils
.CTF_MAGIC
)); //$NON-NLS-1$//$NON-NLS-2$
237 * Check the trace UUID
239 ArrayDefinition uuidDef
= (ArrayDefinition
) tracePacketHeaderDef
240 .lookupDefinition("uuid"); //$NON-NLS-1$
241 if (uuidDef
!= null) {
242 byte[] uuidArray
= new byte[16];
244 for (int i
= 0; i
< 16; i
++) {
245 IntegerDefinition uuidByteDef
= (IntegerDefinition
) uuidDef
247 uuidArray
[i
] = (byte) uuidByteDef
.getValue();
250 UUID uuid
= Utils
.makeUUID(uuidArray
);
252 if (!getStream().getTrace().getUUID().equals(uuid
)) {
253 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
258 * Check that the stream id did not change
260 IntegerDefinition streamIDDef
= (IntegerDefinition
) tracePacketHeaderDef
261 .lookupDefinition("stream_id"); //$NON-NLS-1$
262 if (streamIDDef
!= null) {
263 long streamID
= streamIDDef
.getValue();
265 if (streamID
!= getStream().getId()) {
266 throw new CTFReaderException(
267 "Stream ID changing within a StreamInput"); //$NON-NLS-1$
273 * Read the stream packet context if it exists.
275 if (streamPacketContextDef
!= null) {
276 streamPacketContextDef
.read(bitBuffer
);
279 * Read the content size in bits
281 IntegerDefinition contentSizeDef
= (IntegerDefinition
) streamPacketContextDef
282 .lookupDefinition("content_size"); //$NON-NLS-1$
283 if (contentSizeDef
!= null) {
284 packetIndex
.setContentSizeBits((int) contentSizeDef
287 packetIndex
.setContentSizeBits((int) (fileSizeBytes
* 8));
291 * Read the packet size in bits
293 IntegerDefinition packetSizeDef
= (IntegerDefinition
) streamPacketContextDef
294 .lookupDefinition("packet_size"); //$NON-NLS-1$
295 if (packetSizeDef
!= null) {
296 packetIndex
.setPacketSizeBits((int) packetSizeDef
299 if (packetIndex
.getContentSizeBits() != 0) {
300 packetIndex
.setPacketSizeBits(packetIndex
301 .getContentSizeBits());
304 .setPacketSizeBits((int) (fileSizeBytes
* 8));
309 * Read the begin timestamp
311 IntegerDefinition timestampBeginDef
= (IntegerDefinition
) streamPacketContextDef
312 .lookupDefinition("timestamp_begin"); //$NON-NLS-1$
313 if (timestampBeginDef
!= null) {
314 packetIndex
.setTimestampBegin( timestampBeginDef
.getValue());
318 * Read the end timestamp
320 IntegerDefinition timestampEndDef
= (IntegerDefinition
) streamPacketContextDef
321 .lookupDefinition("timestamp_end"); //$NON-NLS-1$
322 if (timestampEndDef
!= null) {
323 packetIndex
.setTimestampEnd(timestampEndDef
325 setTimestampEnd(packetIndex
.getTimestampEnd());
329 * If there is no packet context, infer the content and packet
330 * size from the file size (assume that there is only one packet
333 packetIndex
.setContentSizeBits( (int) (fileSizeBytes
* 8));
334 packetIndex
.setPacketSizeBits( (int) (fileSizeBytes
* 8));
337 /* Basic validation */
338 if (packetIndex
.getContentSizeBits() > packetIndex
.getPacketSizeBits()) {
339 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
342 if (packetIndex
.getPacketSizeBits() > ((fileSizeBytes
- packetIndex
.getOffsetBytes()) * 8)) {
343 throw new CTFReaderException(
344 "Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
348 * Offset in the file, in bits
350 packetIndex
.setDataOffsetBits( bitBuffer
.position());
353 * Add the packet index entry to the index
355 index
.addEntry(packetIndex
);
358 * Update the counting packet offset
360 packetOffsetBytes
+= (packetIndex
.getPacketSizeBits() + 7) / 8;
363 index
.getEntries().get(0).setIndexBegin(0L);