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
.FileInputStream
;
17 import java
.io
.FileNotFoundException
;
18 import java
.io
.FileReader
;
19 import java
.io
.IOException
;
20 import java
.io
.Reader
;
21 import java
.io
.StringReader
;
22 import java
.nio
.ByteBuffer
;
23 import java
.nio
.ByteOrder
;
24 import java
.nio
.channels
.FileChannel
;
25 import java
.util
.Arrays
;
26 import java
.util
.UUID
;
28 import org
.antlr
.runtime
.ANTLRReaderStream
;
29 import org
.antlr
.runtime
.CommonTokenStream
;
30 import org
.antlr
.runtime
.RecognitionException
;
31 import org
.antlr
.runtime
.tree
.CommonTree
;
32 import org
.eclipse
.linuxtools
.ctf
.parser
.CTFLexer
;
33 import org
.eclipse
.linuxtools
.ctf
.parser
.CTFParser
;
34 import org
.eclipse
.linuxtools
.ctf
.parser
.CTFParser
.parse_return
;
35 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.metadata
.IOStructGen
;
36 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.metadata
.exceptions
.ParseException
;
39 * <b><u>Metadata</u></b>
41 * Represents a metadata file
43 public class Metadata
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
50 * Name of the metadata file in the trace directory
52 final static String METADATA_FILENAME
= "metadata"; //$NON-NLS-1$
55 * Size of the metadata packet header, in bytes, computed by hand.
57 final static int METADATA_PACKET_HEADER_SIZE
= 37;
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
64 * Reference to the metadata file
66 private File metadataFile
= null;
69 * Byte order as detected when reading the TSDL magic number.
71 private ByteOrder detectedByteOrder
= null;
74 * The trace file to which belongs this metadata file.
76 private CTFTrace trace
= null;
78 // ------------------------------------------------------------------------
80 // ------------------------------------------------------------------------
83 * Constructs a Metadata object.
86 * The trace to which belongs this metadata file.
88 public Metadata(CTFTrace trace
) {
91 /* Path of metadata file = trace directory path + metadata filename */
92 String metadataPath
= trace
.getTraceDirectory().getPath()
93 + Utils
.SEPARATOR
+ METADATA_FILENAME
;
95 /* Create a file reference to the metadata file */
96 metadataFile
= new File(metadataPath
);
99 // ------------------------------------------------------------------------
100 // Getters/Setters/Predicates
101 // ------------------------------------------------------------------------
104 * Returns the ByteOrder that was detected while parsing the metadata.
106 * @return The byte order.
108 public ByteOrder
getDetectedByteOrder() {
109 return detectedByteOrder
;
112 // ------------------------------------------------------------------------
114 // ------------------------------------------------------------------------
117 * Parse the metadata file.
119 * @throws CTFReaderException
121 public void parse() throws CTFReaderException
{
122 CTFReaderException tempException
= null;
124 FileInputStream fis
= null;
125 FileChannel metadataFileChannel
= null;
128 * Reader. It will contain a StringReader if we are using packet-based
129 * metadata and it will contain a FileReader if we have text-based
132 Reader metadataTextInput
= null;
135 fis
= new FileInputStream(metadataFile
);
136 metadataFileChannel
= fis
.getChannel();
138 /* Check if metadata is packet-based */
139 if (isPacketBased(metadataFileChannel
)) {
140 /* Create StringBuffer to receive metadata text */
141 StringBuffer metadataText
= new StringBuffer();
144 * Read metadata packet one by one, appending the text to the
147 MetadataPacketHeader packetHeader
= readMetadataPacket(
148 metadataFileChannel
, metadataText
);
149 while (packetHeader
!= null) {
150 packetHeader
= readMetadataPacket(metadataFileChannel
,
154 /* Wrap the metadata string with a StringReader */
155 metadataTextInput
= new StringReader(metadataText
.toString());
157 /* Wrap the metadata file with a FileReader */
158 metadataTextInput
= new FileReader(metadataFile
);
161 /* Create an ANTLR reader */
162 ANTLRReaderStream antlrStream
;
163 antlrStream
= new ANTLRReaderStream(metadataTextInput
);
165 /* Parse the metadata text and get the AST */
166 CTFLexer ctfLexer
= new CTFLexer(antlrStream
);
167 CommonTokenStream tokens
= new CommonTokenStream(ctfLexer
);
168 CTFParser ctfParser
= new CTFParser(tokens
, false);
171 ret
= ctfParser
.parse();
173 CommonTree tree
= (CommonTree
) ret
.getTree();
175 /* Generate IO structures (declarations) */
176 IOStructGen gen
= new IOStructGen(tree
, trace
);
179 } catch (FileNotFoundException e
) {
180 tempException
= new CTFReaderException("Cannot find metadata file!"); //$NON-NLS-1$
181 } catch (IOException e
) {
182 /* This would indicate a problem with the ANTLR library... */
183 tempException
= new CTFReaderException(e
);
184 } catch (ParseException e
) {
185 tempException
= new CTFReaderException(e
);
186 } catch (RecognitionException e
) {
188 * We don't want to expose this ANTLR-specific exception type to the
191 tempException
= new CTFReaderException(e
);
194 /* Ghetto resource management. Java 7 will deliver us from this... */
195 if (metadataTextInput
!= null) {
197 metadataTextInput
.close();
198 } catch (IOException e
) {
202 if (metadataFileChannel
!= null) {
204 metadataFileChannel
.close();
205 } catch (IOException e
) {
212 } catch (IOException e
) {
217 if (tempException
!= null) {
223 * Determines whether the metadata file is packet-based by looking at the
224 * TSDL magic number. If it is packet-based, it also gives information about
225 * the endianness of the trace using the detectedByteOrder attribute.
227 * @param metadataFileChannel
228 * FileChannel of the metadata file.
229 * @return True if the metadata is packet-based.
230 * @throws CTFReaderException
232 private boolean isPacketBased(FileChannel metadataFileChannel
)
233 throws CTFReaderException
{
235 * Create a ByteBuffer to read the TSDL magic number (default is big
238 ByteBuffer magicByteBuffer
= ByteBuffer
.allocate(Utils
.TSDL_MAGIC_LEN
);
240 /* Read without changing file position */
242 metadataFileChannel
.read(magicByteBuffer
, 0);
243 } catch (IOException e
) {
244 throw new CTFReaderException(
245 "Unable to read metadata file channel."); //$NON-NLS-1$
248 /* Get the first int from the file */
249 int magic
= magicByteBuffer
.getInt(0);
251 /* Check if it matches */
252 if (Utils
.TSDL_MAGIC
== magic
) {
253 detectedByteOrder
= ByteOrder
.BIG_ENDIAN
;
257 /* Try the same thing, but with little endian */
258 magicByteBuffer
.order(ByteOrder
.LITTLE_ENDIAN
);
259 magic
= magicByteBuffer
.getInt(0);
261 if (Utils
.TSDL_MAGIC
== magic
) {
262 detectedByteOrder
= ByteOrder
.LITTLE_ENDIAN
;
270 * Reads a metadata packet from the given metadata FileChannel, do some
271 * basic validation and append the text to the StringBuffer.
273 * @param metadataFileChannel
274 * Metadata FileChannel
275 * @param metadataText
276 * StringBuffer to which the metadata text will be appended.
277 * @return A structure describing the header of the metadata packet, or null
278 * if the end of the file is reached.
279 * @throws CTFReaderException
281 private MetadataPacketHeader
readMetadataPacket(
282 FileChannel metadataFileChannel
, StringBuffer metadataText
)
283 throws CTFReaderException
{
284 /* Allocate a ByteBuffer for the header */
285 ByteBuffer headerByteBuffer
= ByteBuffer
.allocate(METADATA_PACKET_HEADER_SIZE
);
287 /* Read the header */
290 nbBytesRead
= metadataFileChannel
.read(headerByteBuffer
);
291 } catch (IOException e
) {
292 throw new CTFReaderException("Error reading the metadata header."); //$NON-NLS-1$
295 /* Return null if EOF */
296 if (nbBytesRead
< 0) {
300 /* Set ByteBuffer's position to 0 */
301 headerByteBuffer
.position(0);
303 /* Use byte order that was detected with the magic number */
304 headerByteBuffer
.order(detectedByteOrder
);
306 assert (nbBytesRead
== METADATA_PACKET_HEADER_SIZE
);
308 MetadataPacketHeader header
= new MetadataPacketHeader();
310 /* Read from the ByteBuffer */
311 header
.magic
= headerByteBuffer
.getInt();
312 headerByteBuffer
.get(header
.uuid
);
313 header
.checksum
= headerByteBuffer
.getInt();
314 header
.contentSize
= headerByteBuffer
.getInt();
315 header
.packetSize
= headerByteBuffer
.getInt();
316 header
.compressionScheme
= headerByteBuffer
.get();
317 header
.encryptionScheme
= headerByteBuffer
.get();
318 header
.checksumScheme
= headerByteBuffer
.get();
319 header
.ctfMajorVersion
= headerByteBuffer
.get();
320 header
.ctfMinorVersion
= headerByteBuffer
.get();
322 /* Check TSDL magic number */
323 if (header
.magic
!= Utils
.TSDL_MAGIC
) {
324 throw new CTFReaderException("TSDL magic number does not match"); //$NON-NLS-1$
328 UUID uuid
= Utils
.makeUUID(header
.uuid
);
329 if (!trace
.UUIDIsSet()) {
332 if (!trace
.getUUID().equals(uuid
)) {
333 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
337 /* Extract the text from the packet */
338 int payloadSize
= ((header
.contentSize
/ 8) - METADATA_PACKET_HEADER_SIZE
);
339 int skipSize
= (header
.packetSize
- header
.contentSize
) / 8;
341 /* Read the payload + the padding in a ByteBuffer */
342 ByteBuffer payloadByteBuffer
= ByteBuffer
.allocateDirect(payloadSize
345 metadataFileChannel
.read(payloadByteBuffer
);
346 } catch (IOException e
) {
347 throw new CTFReaderException(
348 "Error reading metadata packet payload."); //$NON-NLS-1$
350 payloadByteBuffer
.rewind();
352 /* Read only the payload from the ByteBuffer into a byte array */
353 byte payloadByteArray
[] = new byte[payloadByteBuffer
.remaining()];
354 payloadByteBuffer
.get(payloadByteArray
, 0, payloadSize
);
356 /* Convert the byte array to a String */
357 String str
= new String(payloadByteArray
, 0, payloadSize
);
359 /* Append it to the existing metadata */
360 metadataText
.append(str
);
365 static class MetadataPacketHeader
{
368 public byte uuid
[] = new byte[16];
370 public int contentSize
;
371 public int packetSize
;
372 public byte compressionScheme
;
373 public byte encryptionScheme
;
374 public byte checksumScheme
;
375 public byte ctfMajorVersion
;
376 public byte ctfMinorVersion
;
379 public String
toString() {
380 /* Only for debugging, shouldn't be externalized */
381 /* Therefore it cannot be covered by test cases */
382 return "MetadataPacketHeader [magic=0x" //$NON-NLS-1$
383 + Integer
.toHexString(magic
) + ", uuid=" //$NON-NLS-1$
384 + Arrays
.toString(uuid
) + ", checksum=" + checksum
//$NON-NLS-1$
385 + ", contentSize=" + contentSize
+ ", packetSize=" //$NON-NLS-1$ //$NON-NLS-2$
386 + packetSize
+ ", compressionScheme=" + compressionScheme
//$NON-NLS-1$
387 + ", encryptionScheme=" + encryptionScheme
//$NON-NLS-1$
388 + ", checksumScheme=" + checksumScheme
//$NON-NLS-1$
389 + ", ctfMajorVersion=" + ctfMajorVersion
//$NON-NLS-1$
390 + ", ctfMinorVersion=" + ctfMinorVersion
+ ']'; //$NON-NLS-1$