23ad52dc43a1df93ae51664f807d7f2d18461bc6
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInput.java
1 /*******************************************************************************
2 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
3 *
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
8 *
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.ctf.core.trace;
14
15 import java.io.File;
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;
21
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;
28
29 /**
30 * <b><u>StreamInput</u></b>
31 * <p>
32 * Represents a trace file that belongs to a certain stream.
33 */
34 public class StreamInput implements IDefinitionScope {
35
36 // ------------------------------------------------------------------------
37 // Attributes
38 // ------------------------------------------------------------------------
39
40 /**
41 * The associated Stream
42 */
43 private final Stream stream;
44
45 /**
46 * FileChannel to the trace file
47 */
48 private final FileChannel fileChannel;
49
50 /**
51 * Information on the file (used for debugging)
52 */
53 public final File file;
54
55 /**
56 * The packet index of this input
57 */
58 private final StreamInputPacketIndex index = new StreamInputPacketIndex();
59
60 private long timestampEnd;
61
62 // ------------------------------------------------------------------------
63 // Constructors
64 // ------------------------------------------------------------------------
65
66 /**
67 * Constructs a StreamInput.
68 *
69 * @param stream
70 * The stream to which this StreamInput belongs to.
71 * @param fileChannel
72 * The FileChannel to the trace file.
73 * @param file
74 * Information about the trace file (for debugging purposes).
75 */
76 public StreamInput(Stream stream, FileChannel fileChannel, File file) {
77 this.stream = stream;
78 this.fileChannel = fileChannel;
79 this.file = file;
80 }
81
82 // ------------------------------------------------------------------------
83 // Getters/Setters/Predicates
84 // ------------------------------------------------------------------------
85
86 public Stream getStream() {
87 return stream;
88 }
89
90 public StreamInputPacketIndex getIndex() {
91 return index;
92 }
93
94 public FileChannel getFileChannel() {
95 return fileChannel;
96 }
97
98 public String getFilename() {
99 return file.getName();
100 }
101
102 public long getTimestampEnd() {
103 return timestampEnd;
104 }
105
106 public void setTimestampEnd(long timestampEnd) {
107 this.timestampEnd = timestampEnd;
108 }
109
110 @Override
111 public String getPath() {
112 return ""; //$NON-NLS-1$
113 }
114
115 // ------------------------------------------------------------------------
116 // Operations
117 // ------------------------------------------------------------------------
118
119 @Override
120 public Definition lookupDefinition(String lookupPath) {
121 /* TODO: lookup in different dynamic scopes is not supported yet. */
122 return null;
123 }
124
125 /**
126 * Create the index for this trace file.
127 *
128 * @throws CTFReaderException
129 */
130 public void createIndex() throws CTFReaderException {
131 /*
132 * The size of the file in bytes
133 */
134 long fileSizeBytes = 0;
135 try {
136 fileSizeBytes = fileChannel.size();
137 } catch (IOException e) {
138 throw new CTFReaderException(e);
139 }
140
141 /*
142 * Offset of the current packet in bytes
143 */
144 long packetOffsetBytes = 0;
145
146 /*
147 * Initial size, it should map at least the packet header + context
148 * size.
149 *
150 * TODO: use a less arbitrary size.
151 */
152 long mapSize = 4096;
153
154 /*
155 * Definition of trace packet header
156 */
157 StructDefinition tracePacketHeaderDef = null;
158
159 /*
160 * Definition of trace stream packet context
161 */
162 StructDefinition streamPacketContextDef = null;
163
164 /*
165 * The BitBuffer to extract data from the StreamInput
166 */
167 BitBuffer bitBuffer = new BitBuffer();
168 bitBuffer.order(this.getStream().getTrace().getByteOrder());
169
170 /*
171 * Create the definitions we need to read the packet headers + contexts
172 */
173 if (getStream().getTrace().getPacketHeader() != null) {
174 tracePacketHeaderDef = getStream().getTrace().getPacketHeader()
175 .createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
176 }
177
178 if (getStream().getPacketContextDecl() != null) {
179 streamPacketContextDef = getStream().getPacketContextDecl()
180 .createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
181 }
182
183 /*
184 * Scan through the packets of the file.
185 */
186 while (packetOffsetBytes < fileSizeBytes) {
187 /*
188 * If there is less data remaining than what we want to map, reduce
189 * the map size.
190 */
191 if ((fileSizeBytes - packetOffsetBytes) < mapSize) {
192 mapSize = fileSizeBytes - packetOffsetBytes;
193 }
194
195 /*
196 * Map the packet.
197 */
198 MappedByteBuffer bb;
199 try {
200 bb = fileChannel.map(MapMode.READ_ONLY, packetOffsetBytes,
201 mapSize);
202 } catch (IOException e) {
203 throw new CTFReaderException(e);
204 }
205 bitBuffer.setByteBuffer(bb);
206
207 /*
208 * Create the index entry
209 */
210 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
211 packetOffsetBytes);
212
213 /*
214 * Read the trace packet header if it exists.
215 */
216 if (tracePacketHeaderDef != null) {
217 tracePacketHeaderDef.read(bitBuffer);
218
219 /*
220 * Check the CTF magic number
221 */
222 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
223 .lookupDefinition("magic"); //$NON-NLS-1$
224 if (magicDef != null) {
225 int magic = (int) magicDef.getValue();
226 if (magic != Utils.CTF_MAGIC) {
227 throw new CTFReaderException(
228 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
229 }
230
231 }
232
233 /*
234 * Check the trace UUID
235 */
236 ArrayDefinition uuidDef = (ArrayDefinition) tracePacketHeaderDef
237 .lookupDefinition("uuid"); //$NON-NLS-1$
238 if (uuidDef != null) {
239 byte[] uuidArray = new byte[16];
240
241 for (int i = 0; i < 16; i++) {
242 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef
243 .getElem(i);
244 uuidArray[i] = (byte) uuidByteDef.getValue();
245 }
246
247 UUID uuid = Utils.makeUUID(uuidArray);
248
249 if (!getStream().getTrace().getUUID().equals(uuid)) {
250 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
251 }
252 }
253
254 /*
255 * Check that the stream id did not change
256 */
257 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
258 .lookupDefinition("stream_id"); //$NON-NLS-1$
259 if (streamIDDef != null) {
260 long streamID = streamIDDef.getValue();
261
262 if (streamID != getStream().getId()) {
263 throw new CTFReaderException(
264 "Stream ID changing within a StreamInput"); //$NON-NLS-1$
265 }
266 }
267 }
268
269 /*
270 * Read the stream packet context if it exists.
271 */
272 if (streamPacketContextDef != null) {
273 streamPacketContextDef.read(bitBuffer);
274
275 /*
276 * Read the content size in bits
277 */
278 IntegerDefinition contentSizeDef = (IntegerDefinition) streamPacketContextDef
279 .lookupDefinition("content_size"); //$NON-NLS-1$
280 if (contentSizeDef != null) {
281 packetIndex.setContentSizeBits((int) contentSizeDef
282 .getValue());
283 } else {
284 packetIndex.setContentSizeBits((int) (fileSizeBytes * 8));
285 }
286
287 /*
288 * Read the packet size in bits
289 */
290 IntegerDefinition packetSizeDef = (IntegerDefinition) streamPacketContextDef
291 .lookupDefinition("packet_size"); //$NON-NLS-1$
292 if (packetSizeDef != null) {
293 packetIndex.setPacketSizeBits((int) packetSizeDef
294 .getValue());
295 } else {
296 if (packetIndex.getContentSizeBits() != 0) {
297 packetIndex.setPacketSizeBits(packetIndex
298 .getContentSizeBits());
299 } else {
300 packetIndex
301 .setPacketSizeBits((int) (fileSizeBytes * 8));
302 }
303 }
304
305 /*
306 * Read the begin timestamp
307 */
308 IntegerDefinition timestampBeginDef = (IntegerDefinition) streamPacketContextDef
309 .lookupDefinition("timestamp_begin"); //$NON-NLS-1$
310 if (timestampBeginDef != null) {
311 packetIndex.setTimestampBegin( timestampBeginDef.getValue());
312 }
313
314 /*
315 * Read the end timestamp
316 */
317 IntegerDefinition timestampEndDef = (IntegerDefinition) streamPacketContextDef
318 .lookupDefinition("timestamp_end"); //$NON-NLS-1$
319 if (timestampEndDef != null) {
320 packetIndex.setTimestampEnd(timestampEndDef
321 .getValue());
322 setTimestampEnd(packetIndex.getTimestampEnd());
323 }
324 } else {
325 /*
326 * If there is no packet context, infer the content and packet
327 * size from the file size (assume that there is only one packet
328 * and no padding)
329 */
330 packetIndex.setContentSizeBits( (int) (fileSizeBytes * 8));
331 packetIndex.setPacketSizeBits( (int) (fileSizeBytes * 8));
332 }
333
334 /* Basic validation */
335 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
336 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
337 }
338
339 if (packetIndex.getPacketSizeBits() > ((fileSizeBytes - packetIndex.getOffsetBytes()) * 8)) {
340 throw new CTFReaderException(
341 "Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
342 }
343
344 /*
345 * Offset in the file, in bits
346 */
347 packetIndex.setDataOffsetBits( bitBuffer.position());
348
349 /*
350 * Add the packet index entry to the index
351 */
352 index.addEntry(packetIndex);
353
354 /*
355 * Update the counting packet offset
356 */
357 packetOffsetBytes += (packetIndex.getPacketSizeBits() + 7) / 8;
358
359 }
360 index.getEntries().get(0).setIndexBegin(0L);
361 }
362
363 }
This page took 0.037354 seconds and 4 git commands to generate.