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