Merge branch 'master' into lttng-luna
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / Metadata.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2013 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:
10 * Matthew Khouzam - Initial API and implementation
11 * Simon Marchi - Initial API and implementation
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.ctf.core.trace;
15
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.FileNotFoundException;
19 import java.io.FileReader;
20 import java.io.IOException;
21 import java.io.Reader;
22 import java.io.StringReader;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.nio.channels.FileChannel;
26 import java.util.Arrays;
27 import java.util.UUID;
28
29 import org.antlr.runtime.ANTLRReaderStream;
30 import org.antlr.runtime.CommonTokenStream;
31 import org.antlr.runtime.MismatchedTokenException;
32 import org.antlr.runtime.RecognitionException;
33 import org.antlr.runtime.tree.CommonTree;
34 import org.eclipse.linuxtools.ctf.parser.CTFLexer;
35 import org.eclipse.linuxtools.ctf.parser.CTFParser;
36 import org.eclipse.linuxtools.ctf.parser.CTFParser.parse_return;
37 import org.eclipse.linuxtools.internal.ctf.core.event.metadata.IOStructGen;
38 import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.CtfAntlrException;
39 import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
40
41 /**
42 * The CTF trace metadata file
43 *
44 * @version 1.0
45 * @author Matthew Khouzam
46 * @author Simon Marchi
47 */
48 public class Metadata {
49
50 // ------------------------------------------------------------------------
51 // Constants
52 // ------------------------------------------------------------------------
53
54 /**
55 * Name of the metadata file in the trace directory
56 */
57 private static final String METADATA_FILENAME = "metadata"; //$NON-NLS-1$
58
59 /**
60 * Size of the metadata packet header, in bytes, computed by hand.
61 */
62 private static final int METADATA_PACKET_HEADER_SIZE = 37;
63
64 // ------------------------------------------------------------------------
65 // Attributes
66 // ------------------------------------------------------------------------
67
68 /**
69 * Reference to the metadata file
70 */
71 private File metadataFile = null;
72
73 /**
74 * Byte order as detected when reading the TSDL magic number.
75 */
76 private ByteOrder detectedByteOrder = null;
77
78 /**
79 * The trace file to which belongs this metadata file.
80 */
81 private CTFTrace trace = null;
82
83 // ------------------------------------------------------------------------
84 // Constructors
85 // ------------------------------------------------------------------------
86
87 /**
88 * Constructs a Metadata object.
89 *
90 * @param trace
91 * The trace to which belongs this metadata file.
92 */
93 public Metadata(CTFTrace trace) {
94 this.trace = trace;
95
96 /* Path of metadata file = trace directory path + metadata filename */
97 String metadataPath = trace.getTraceDirectory().getPath()
98 + Utils.SEPARATOR + METADATA_FILENAME;
99
100 /* Create a file reference to the metadata file */
101 metadataFile = new File(metadataPath);
102 }
103
104 // ------------------------------------------------------------------------
105 // Getters/Setters/Predicates
106 // ------------------------------------------------------------------------
107
108 /**
109 * Returns the ByteOrder that was detected while parsing the metadata.
110 *
111 * @return The byte order.
112 */
113 public ByteOrder getDetectedByteOrder() {
114 return detectedByteOrder;
115 }
116
117 // ------------------------------------------------------------------------
118 // Operations
119 // ------------------------------------------------------------------------
120
121 /**
122 * Parse the metadata file.
123 *
124 * @throws CTFReaderException
125 * If there was a problem parsing the metadata
126 */
127 public void parse() throws CTFReaderException {
128 CTFReaderException tempException = null;
129
130 FileInputStream fis = null;
131 FileChannel metadataFileChannel = null;
132
133 /*
134 * Reader. It will contain a StringReader if we are using packet-based
135 * metadata and it will contain a FileReader if we have text-based
136 * metadata.
137 */
138 Reader metadataTextInput = null;
139
140 try {
141 fis = new FileInputStream(metadataFile);
142 metadataFileChannel = fis.getChannel();
143
144 /* Check if metadata is packet-based */
145 if (isPacketBased(metadataFileChannel)) {
146 /* Create StringBuffer to receive metadata text */
147 StringBuffer metadataText = new StringBuffer();
148
149 /*
150 * Read metadata packet one by one, appending the text to the
151 * StringBuffer
152 */
153 MetadataPacketHeader packetHeader = readMetadataPacket(
154 metadataFileChannel, metadataText);
155 while (packetHeader != null) {
156 packetHeader = readMetadataPacket(metadataFileChannel,
157 metadataText);
158 }
159
160 /* Wrap the metadata string with a StringReader */
161 metadataTextInput = new StringReader(metadataText.toString());
162 } else {
163 /* Wrap the metadata file with a FileReader */
164 metadataTextInput = new FileReader(metadataFile);
165 }
166
167 CommonTree tree = createAST(metadataTextInput);
168
169 /* Generate IO structures (declarations) */
170 IOStructGen gen = new IOStructGen(tree, trace);
171 gen.generate();
172
173 } catch (FileNotFoundException e) {
174 tempException = new CTFReaderException("Cannot find metadata file!"); //$NON-NLS-1$
175 } catch (IOException e) {
176 /* This would indicate a problem with the ANTLR library... */
177 tempException = new CTFReaderException(e);
178 } catch (ParseException e) {
179 tempException = new CTFReaderException(e);
180 } catch (MismatchedTokenException e) {
181 tempException = new CtfAntlrException(e);
182 } catch (RecognitionException e) {
183 tempException = new CtfAntlrException(e);
184 }
185
186 /* Ghetto resource management. Java 7 will deliver us from this... */
187 if (metadataTextInput != null) {
188 try {
189 metadataTextInput.close();
190 } catch (IOException e) {
191 // Do nothing
192 }
193 }
194 if (metadataFileChannel != null) {
195 try {
196 metadataFileChannel.close();
197 } catch (IOException e) {
198 // Do nothing
199 }
200 }
201 if (fis != null) {
202 try {
203 fis.close();
204 } catch (IOException e) {
205 // Do nothing
206 }
207 }
208
209 if (tempException != null) {
210 throw tempException;
211 }
212 }
213
214 private static CommonTree createAST(Reader metadataTextInput) throws IOException,
215 RecognitionException {
216 /* Create an ANTLR reader */
217 ANTLRReaderStream antlrStream;
218 antlrStream = new ANTLRReaderStream(metadataTextInput);
219
220 /* Parse the metadata text and get the AST */
221 CTFLexer ctfLexer = new CTFLexer(antlrStream);
222 CommonTokenStream tokens = new CommonTokenStream(ctfLexer);
223 CTFParser ctfParser = new CTFParser(tokens, false);
224
225 parse_return pr = ctfParser.parse();
226 return (CommonTree) pr.getTree();
227 }
228
229 /**
230 * Determines whether the metadata file is packet-based by looking at the
231 * TSDL magic number. If it is packet-based, it also gives information about
232 * the endianness of the trace using the detectedByteOrder attribute.
233 *
234 * @param metadataFileChannel
235 * FileChannel of the metadata file.
236 * @return True if the metadata is packet-based.
237 * @throws CTFReaderException
238 */
239 private boolean isPacketBased(FileChannel metadataFileChannel)
240 throws CTFReaderException {
241 /*
242 * Create a ByteBuffer to read the TSDL magic number (default is big
243 * endian)
244 */
245 ByteBuffer magicByteBuffer = ByteBuffer.allocate(Utils.TSDL_MAGIC_LEN);
246
247 /* Read without changing file position */
248 try {
249 metadataFileChannel.read(magicByteBuffer, 0);
250 } catch (IOException e) {
251 throw new CTFReaderException("Unable to read metadata file channel.", e); //$NON-NLS-1$
252 }
253
254 /* Get the first int from the file */
255 int magic = magicByteBuffer.getInt(0);
256
257 /* Check if it matches */
258 if (Utils.TSDL_MAGIC == magic) {
259 detectedByteOrder = ByteOrder.BIG_ENDIAN;
260 return true;
261 }
262
263 /* Try the same thing, but with little endian */
264 magicByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
265 magic = magicByteBuffer.getInt(0);
266
267 if (Utils.TSDL_MAGIC == magic) {
268 detectedByteOrder = ByteOrder.LITTLE_ENDIAN;
269 return true;
270 }
271
272 return false;
273 }
274
275 /**
276 * Reads a metadata packet from the given metadata FileChannel, do some
277 * basic validation and append the text to the StringBuffer.
278 *
279 * @param metadataFileChannel
280 * Metadata FileChannel
281 * @param metadataText
282 * StringBuffer to which the metadata text will be appended.
283 * @return A structure describing the header of the metadata packet, or null
284 * if the end of the file is reached.
285 * @throws CTFReaderException
286 */
287 private MetadataPacketHeader readMetadataPacket(
288 FileChannel metadataFileChannel, StringBuffer metadataText)
289 throws CTFReaderException {
290 /* Allocate a ByteBuffer for the header */
291 ByteBuffer headerByteBuffer = ByteBuffer.allocate(METADATA_PACKET_HEADER_SIZE);
292
293 /* Read the header */
294 int nbBytesRead;
295 try {
296 nbBytesRead = metadataFileChannel.read(headerByteBuffer);
297 } catch (IOException e) {
298 throw new CTFReaderException("Error reading the metadata header.", e); //$NON-NLS-1$
299 }
300
301 /* Return null if EOF */
302 if (nbBytesRead < 0) {
303 return null;
304 }
305
306 /* Set ByteBuffer's position to 0 */
307 headerByteBuffer.position(0);
308
309 /* Use byte order that was detected with the magic number */
310 headerByteBuffer.order(detectedByteOrder);
311
312 assert (nbBytesRead == METADATA_PACKET_HEADER_SIZE);
313
314 MetadataPacketHeader header = new MetadataPacketHeader();
315
316 /* Read from the ByteBuffer */
317 header.magic = headerByteBuffer.getInt();
318 headerByteBuffer.get(header.uuid);
319 header.checksum = headerByteBuffer.getInt();
320 header.contentSize = headerByteBuffer.getInt();
321 header.packetSize = headerByteBuffer.getInt();
322 header.compressionScheme = headerByteBuffer.get();
323 header.encryptionScheme = headerByteBuffer.get();
324 header.checksumScheme = headerByteBuffer.get();
325 header.ctfMajorVersion = headerByteBuffer.get();
326 header.ctfMinorVersion = headerByteBuffer.get();
327
328 /* Check TSDL magic number */
329 if (header.magic != Utils.TSDL_MAGIC) {
330 throw new CTFReaderException("TSDL magic number does not match"); //$NON-NLS-1$
331 }
332
333 /* Check UUID */
334 UUID uuid = Utils.makeUUID(header.uuid);
335 if (!trace.uuidIsSet()) {
336 trace.setUUID(uuid);
337 } else {
338 if (!trace.getUUID().equals(uuid)) {
339 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
340 }
341 }
342
343 /* Extract the text from the packet */
344 int payloadSize = ((header.contentSize / 8) - METADATA_PACKET_HEADER_SIZE);
345 if (payloadSize < 0) {
346 throw new CTFReaderException("Invalid metadata packet payload size."); //$NON-NLS-1$
347 }
348 int skipSize = (header.packetSize - header.contentSize) / 8;
349
350 /* Read the payload + the padding in a ByteBuffer */
351 ByteBuffer payloadByteBuffer = ByteBuffer.allocateDirect(payloadSize
352 + skipSize);
353 try {
354 metadataFileChannel.read(payloadByteBuffer);
355 } catch (IOException e) {
356 throw new CTFReaderException("Error reading metadata packet payload.", e); //$NON-NLS-1$
357 }
358 payloadByteBuffer.rewind();
359
360 /* Read only the payload from the ByteBuffer into a byte array */
361 byte payloadByteArray[] = new byte[payloadByteBuffer.remaining()];
362 payloadByteBuffer.get(payloadByteArray, 0, payloadSize);
363
364 /* Convert the byte array to a String */
365 String str = new String(payloadByteArray, 0, payloadSize);
366
367 /* Append it to the existing metadata */
368 metadataText.append(str);
369
370 return header;
371 }
372
373 private static class MetadataPacketHeader {
374
375 public int magic;
376 public byte uuid[] = new byte[16];
377 public int checksum;
378 public int contentSize;
379 public int packetSize;
380 public byte compressionScheme;
381 public byte encryptionScheme;
382 public byte checksumScheme;
383 public byte ctfMajorVersion;
384 public byte ctfMinorVersion;
385
386 @Override
387 public String toString() {
388 /* Only for debugging, shouldn't be externalized */
389 /* Therefore it cannot be covered by test cases */
390 return "MetadataPacketHeader [magic=0x" //$NON-NLS-1$
391 + Integer.toHexString(magic) + ", uuid=" //$NON-NLS-1$
392 + Arrays.toString(uuid) + ", checksum=" + checksum //$NON-NLS-1$
393 + ", contentSize=" + contentSize + ", packetSize=" //$NON-NLS-1$ //$NON-NLS-2$
394 + packetSize + ", compressionScheme=" + compressionScheme //$NON-NLS-1$
395 + ", encryptionScheme=" + encryptionScheme //$NON-NLS-1$
396 + ", checksumScheme=" + checksumScheme //$NON-NLS-1$
397 + ", ctfMajorVersion=" + ctfMajorVersion //$NON-NLS-1$
398 + ", ctfMinorVersion=" + ctfMinorVersion + ']'; //$NON-NLS-1$
399 }
400
401 }
402 }
This page took 0.040564 seconds and 5 git commands to generate.