1 /*******************************************************************************
2 * Copyright (c) 2011, 2013 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
10 * Matthew Khouzam - Initial API and implementation
11 * Simon Marchi - Initial API and implementation
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
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
;
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
;
42 * The CTF trace metadata file
45 * @author Matthew Khouzam
46 * @author Simon Marchi
48 public class Metadata
{
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
55 * Name of the metadata file in the trace directory
57 private static final String METADATA_FILENAME
= "metadata"; //$NON-NLS-1$
60 * Size of the metadata packet header, in bytes, computed by hand.
62 private static final int METADATA_PACKET_HEADER_SIZE
= 37;
64 // ------------------------------------------------------------------------
66 // ------------------------------------------------------------------------
69 * Reference to the metadata file
71 private File metadataFile
= null;
74 * Byte order as detected when reading the TSDL magic number.
76 private ByteOrder detectedByteOrder
= null;
79 * The trace file to which belongs this metadata file.
81 private CTFTrace trace
= null;
83 // ------------------------------------------------------------------------
85 // ------------------------------------------------------------------------
88 * Constructs a Metadata object.
91 * The trace to which belongs this metadata file.
93 public Metadata(CTFTrace trace
) {
96 /* Path of metadata file = trace directory path + metadata filename */
97 String metadataPath
= trace
.getTraceDirectory().getPath()
98 + Utils
.SEPARATOR
+ METADATA_FILENAME
;
100 /* Create a file reference to the metadata file */
101 metadataFile
= new File(metadataPath
);
104 // ------------------------------------------------------------------------
105 // Getters/Setters/Predicates
106 // ------------------------------------------------------------------------
109 * Returns the ByteOrder that was detected while parsing the metadata.
111 * @return The byte order.
113 public ByteOrder
getDetectedByteOrder() {
114 return detectedByteOrder
;
117 // ------------------------------------------------------------------------
119 // ------------------------------------------------------------------------
122 * Parse the metadata file.
124 * @throws CTFReaderException
125 * If there was a problem parsing the metadata
127 public void parse() throws CTFReaderException
{
128 CTFReaderException tempException
= null;
130 FileInputStream fis
= null;
131 FileChannel metadataFileChannel
= null;
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
138 Reader metadataTextInput
= null;
141 fis
= new FileInputStream(metadataFile
);
142 metadataFileChannel
= fis
.getChannel();
144 /* Check if metadata is packet-based */
145 if (isPacketBased(metadataFileChannel
)) {
146 /* Create StringBuffer to receive metadata text */
147 StringBuffer metadataText
= new StringBuffer();
150 * Read metadata packet one by one, appending the text to the
153 MetadataPacketHeader packetHeader
= readMetadataPacket(
154 metadataFileChannel
, metadataText
);
155 while (packetHeader
!= null) {
156 packetHeader
= readMetadataPacket(metadataFileChannel
,
160 /* Wrap the metadata string with a StringReader */
161 metadataTextInput
= new StringReader(metadataText
.toString());
163 /* Wrap the metadata file with a FileReader */
164 metadataTextInput
= new FileReader(metadataFile
);
167 CommonTree tree
= createAST(metadataTextInput
);
169 /* Generate IO structures (declarations) */
170 IOStructGen gen
= new IOStructGen(tree
, trace
);
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
);
186 /* Ghetto resource management. Java 7 will deliver us from this... */
187 if (metadataTextInput
!= null) {
189 metadataTextInput
.close();
190 } catch (IOException e
) {
194 if (metadataFileChannel
!= null) {
196 metadataFileChannel
.close();
197 } catch (IOException e
) {
204 } catch (IOException e
) {
209 if (tempException
!= null) {
214 private static CommonTree
createAST(Reader metadataTextInput
) throws IOException
,
215 RecognitionException
{
216 /* Create an ANTLR reader */
217 ANTLRReaderStream antlrStream
;
218 antlrStream
= new ANTLRReaderStream(metadataTextInput
);
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);
225 parse_return pr
= ctfParser
.parse();
226 return (CommonTree
) pr
.getTree();
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.
234 * @param metadataFileChannel
235 * FileChannel of the metadata file.
236 * @return True if the metadata is packet-based.
237 * @throws CTFReaderException
239 private boolean isPacketBased(FileChannel metadataFileChannel
)
240 throws CTFReaderException
{
242 * Create a ByteBuffer to read the TSDL magic number (default is big
245 ByteBuffer magicByteBuffer
= ByteBuffer
.allocate(Utils
.TSDL_MAGIC_LEN
);
247 /* Read without changing file position */
249 metadataFileChannel
.read(magicByteBuffer
, 0);
250 } catch (IOException e
) {
251 throw new CTFReaderException("Unable to read metadata file channel.", e
); //$NON-NLS-1$
254 /* Get the first int from the file */
255 int magic
= magicByteBuffer
.getInt(0);
257 /* Check if it matches */
258 if (Utils
.TSDL_MAGIC
== magic
) {
259 detectedByteOrder
= ByteOrder
.BIG_ENDIAN
;
263 /* Try the same thing, but with little endian */
264 magicByteBuffer
.order(ByteOrder
.LITTLE_ENDIAN
);
265 magic
= magicByteBuffer
.getInt(0);
267 if (Utils
.TSDL_MAGIC
== magic
) {
268 detectedByteOrder
= ByteOrder
.LITTLE_ENDIAN
;
276 * Reads a metadata packet from the given metadata FileChannel, do some
277 * basic validation and append the text to the StringBuffer.
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
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
);
293 /* Read the header */
296 nbBytesRead
= metadataFileChannel
.read(headerByteBuffer
);
297 } catch (IOException e
) {
298 throw new CTFReaderException("Error reading the metadata header.", e
); //$NON-NLS-1$
301 /* Return null if EOF */
302 if (nbBytesRead
< 0) {
306 /* Set ByteBuffer's position to 0 */
307 headerByteBuffer
.position(0);
309 /* Use byte order that was detected with the magic number */
310 headerByteBuffer
.order(detectedByteOrder
);
312 assert (nbBytesRead
== METADATA_PACKET_HEADER_SIZE
);
314 MetadataPacketHeader header
= new MetadataPacketHeader();
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();
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$
334 UUID uuid
= Utils
.makeUUID(header
.uuid
);
335 if (!trace
.uuidIsSet()) {
338 if (!trace
.getUUID().equals(uuid
)) {
339 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
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$
348 int skipSize
= (header
.packetSize
- header
.contentSize
) / 8;
350 /* Read the payload + the padding in a ByteBuffer */
351 ByteBuffer payloadByteBuffer
= ByteBuffer
.allocateDirect(payloadSize
354 metadataFileChannel
.read(payloadByteBuffer
);
355 } catch (IOException e
) {
356 throw new CTFReaderException("Error reading metadata packet payload.", e
); //$NON-NLS-1$
358 payloadByteBuffer
.rewind();
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
);
364 /* Convert the byte array to a String */
365 String str
= new String(payloadByteArray
, 0, payloadSize
);
367 /* Append it to the existing metadata */
368 metadataText
.append(str
);
373 private static class MetadataPacketHeader
{
376 public byte uuid
[] = new byte[16];
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
;
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$