1 /*******************************************************************************
2 * Copyright (c) 2011, 2013 Ericsson, École Polytechnique de Montréal
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 * Alexandre Montplaisir - Initial API and implementation, extend TmfEventField
12 * Bernd Hufmann - Add Enum field handling
13 * Geneviève Bastien - Add Struct and Variant field handling
14 * Jean-Christian Kouame - Correct handling of unsigned integer fields
15 *******************************************************************************/
17 package org
.eclipse
.linuxtools
.tmf
.core
.ctfadaptor
;
19 import java
.math
.BigInteger
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Arrays
;
22 import java
.util
.List
;
23 import java
.util
.Map
.Entry
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.ArrayDeclaration
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.ArrayDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.EnumDefinition
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.FloatDefinition
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDeclaration
;
31 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
32 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SequenceDeclaration
;
33 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SequenceDefinition
;
34 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StringDefinition
;
35 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
36 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
37 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Messages
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEventField
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfEventField
;
42 * The CTF implementation of the TMF event field model
45 * @author Matthew Khouzam
46 * @author Alexandre Montplaisir
48 public abstract class CtfTmfEventField
extends TmfEventField
{
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
55 * Standard constructor. Only to be used internally, call parseField() to
56 * generate a new field object.
59 * The name of this field
61 * The value of this field. Its type should match the field type.
63 * The children fields. Useful for composite fields
66 protected CtfTmfEventField(String name
, Object value
, ITmfEventField
[] fields
) {
67 super(/* Strip the underscore from the field name if there is one */
68 name
.startsWith("_") ? name
.substring(1) : name
, //$NON-NLS-1$
73 // ------------------------------------------------------------------------
75 // ------------------------------------------------------------------------
78 * Factory method to instantiate CtfTmfEventField objects.
81 * The CTF Definition of this event field
83 * String The name to assign to this field
84 * @return The resulting CtfTmfEventField object
86 public static CtfTmfEventField
parseField(Definition fieldDef
,
88 CtfTmfEventField field
= null;
90 /* Determine the Definition type */
91 if (fieldDef
instanceof IntegerDefinition
) {
92 IntegerDefinition intDef
= (IntegerDefinition
) fieldDef
;
93 int base
= intDef
.getDeclaration().getBase();
94 field
= new CTFIntegerField(fieldName
, intDef
.getValue(), base
, intDef
.getDeclaration().isSigned());
96 } else if (fieldDef
instanceof EnumDefinition
) {
97 EnumDefinition enumDef
= (EnumDefinition
) fieldDef
;
98 field
= new CTFEnumField(fieldName
, new CtfEnumPair(enumDef
.getValue(), enumDef
.getIntegerValue()));
100 } else if (fieldDef
instanceof StringDefinition
) {
101 field
= new CTFStringField(fieldName
, ((StringDefinition
) fieldDef
).getValue());
103 } else if (fieldDef
instanceof FloatDefinition
) {
104 FloatDefinition floatDef
= (FloatDefinition
) fieldDef
;
105 field
= new CTFFloatField(fieldName
, floatDef
.getValue());
107 } else if (fieldDef
instanceof ArrayDefinition
) {
108 ArrayDefinition arrayDef
= (ArrayDefinition
) fieldDef
;
109 ArrayDeclaration arrayDecl
= arrayDef
.getDeclaration();
111 if (arrayDef
.isString()) {
112 /* This is an array of UTF-8 bytes, a.k.a. a String! */
113 field
= new CTFStringField(fieldName
, fieldDef
.toString());
115 } else if (arrayDecl
.getElementType() instanceof IntegerDeclaration
) {
116 /* This is a an array of CTF Integers */
117 List
<Long
> values
= new ArrayList
<Long
>(arrayDecl
.getLength());
118 for (int i
= 0; i
< arrayDecl
.getLength(); i
++) {
119 values
.add(((IntegerDefinition
) arrayDef
.getElem(i
)).getValue());
121 long[] valuesArray
= convertListToArray(values
);
122 field
= new CTFIntegerArrayField(fieldName
, valuesArray
,
123 ((IntegerDeclaration
) arrayDecl
.getElementType()).getBase(),
124 ((IntegerDeclaration
) arrayDecl
.getElementType()).isSigned());
126 /* Add other types of arrays here */
128 } else if (fieldDef
instanceof SequenceDefinition
) {
129 SequenceDefinition seqDef
= (SequenceDefinition
) fieldDef
;
130 SequenceDeclaration seqDecl
= seqDef
.getDeclaration();
132 if (seqDef
.getLength() == 0) {
133 /* Some sequences have length = 0. Simply use an empty string */
134 field
= new CTFStringField(fieldName
, ""); //$NON-NLS-1$
135 } else if (seqDef
.isString()) {
136 /* Interpret this sequence as a String */
137 field
= new CTFStringField(fieldName
, seqDef
.toString());
138 } else if (seqDecl
.getElementType() instanceof IntegerDeclaration
) {
139 /* Sequence of integers => CTFIntegerArrayField */
140 List
<Long
> values
= new ArrayList
<Long
>(seqDef
.getLength());
141 for (int i
= 0; i
< seqDef
.getLength(); i
++) {
142 values
.add(((IntegerDefinition
) seqDef
.getElem(i
)).getValue());
144 long[] valuesArray
= convertListToArray(values
);
145 field
= new CTFIntegerArrayField(fieldName
, valuesArray
,
146 ((IntegerDeclaration
) seqDecl
.getElementType()).getBase(),
147 ((IntegerDeclaration
) seqDecl
.getElementType()).isSigned());
149 /* Add other Sequence types here */
151 } else if (fieldDef
instanceof StructDefinition
) {
152 StructDefinition strDef
= (StructDefinition
) fieldDef
;
154 String curFieldName
= null;
155 Definition curFieldDef
;
156 CtfTmfEventField curField
;
157 List
<ITmfEventField
> list
= new ArrayList
<ITmfEventField
>();
158 /* Recursively parse the fields */
159 for (Entry
<String
, Definition
> entry
: strDef
.getDefinitions().entrySet()) {
160 curFieldName
= entry
.getKey();
161 curFieldDef
= entry
.getValue();
162 curField
= CtfTmfEventField
.parseField(curFieldDef
, curFieldName
);
165 field
= new CTFStructField(fieldName
, list
.toArray(new CtfTmfEventField
[list
.size()]));
167 } else if (fieldDef
instanceof VariantDefinition
) {
168 VariantDefinition varDef
= (VariantDefinition
) fieldDef
;
170 String curFieldName
= varDef
.getCurrentFieldName();
171 Definition curFieldDef
= varDef
.getDefinitions().get(curFieldName
);
172 if (curFieldDef
!= null) {
173 CtfTmfEventField subField
= CtfTmfEventField
.parseField(curFieldDef
, curFieldName
);
174 field
= new CTFVariantField(fieldName
, subField
);
176 /* A safe-guard, but curFieldDef should never be null */
177 field
= new CTFStringField(curFieldName
, ""); //$NON-NLS-1$
182 * Safe-guard, to avoid null exceptions later, field is expected not
185 field
= new CTFStringField(fieldName
, Messages
.TmfEventField_UnsupportedType
+ fieldDef
.getClass().toString());
191 public String
toString() {
192 return getName() + '=' + getFormattedValue();
196 * Print a numeric value as a string in a given base
199 * The value to print as string
201 * The base for this value
203 * Is the value signed or not
204 * @return formatted number string
207 public final static String
formatNumber(long value
, int base
, boolean signed
) {
210 /* Format the number correctly according to the integer's base */
213 s
= "0b" + Long
.toBinaryString(value
); //$NON-NLS-1$
216 s
= "0" + Long
.toOctalString(value
); //$NON-NLS-1$
220 s
= "0x" + Long
.toHexString(value
); //$NON-NLS-1$
224 /* For non-standard base, we'll just print it as a decimal number */
225 if (!signed
&& value
< 0) {
226 /* Since there are no 'unsigned long', handle this case with BigInteger */
227 BigInteger bigInteger
= BigInteger
.valueOf(value
);
229 * powerOfTwo = 2^64 we add 2^64 to the negative number to get
230 * the real unsigned value
232 BigInteger powerOfTwo
= (BigInteger
.valueOf(Long
.MAX_VALUE
)).add(BigInteger
.valueOf(1));
233 powerOfTwo
= powerOfTwo
.multiply(BigInteger
.valueOf(2));
234 bigInteger
= bigInteger
.add(powerOfTwo
);
236 s
= bigInteger
.toString();
238 s
= Long
.toString(value
);
246 * We cannot use List.toArray(T[]) for primitives types, so do it manually.
248 private static long[] convertListToArray(List
<Long
> list
) {
249 long[] array
= new long[list
.size()];
250 for (int i
= 0; i
< list
.size(); i
++) {
251 array
[i
] = list
.get(i
);
259 * The CTF field implementation for integer fields.
263 final class CTFIntegerField
extends CtfTmfEventField
{
265 private final int base
;
266 private final boolean signed
;
269 * A CTF "IntegerDefinition" can be an integer of any byte size, so in the
270 * Java parser this is interpreted as a long.
273 * The name of this field
275 * The integer value of this field
277 * Is the value signed or not
279 CTFIntegerField(String name
, long longValue
, int base
, boolean signed
) {
280 super(name
, longValue
, null);
281 this.signed
= signed
;
286 public Long
getValue() {
287 return (Long
) super.getValue();
291 public String
getFormattedValue() {
292 return formatNumber(getValue(), base
, signed
);
298 * The CTF field implementation for string fields
302 final class CTFStringField
extends CtfTmfEventField
{
305 * Constructor for CTFStringField.
308 * The string value of this field
310 * The name of this field
312 CTFStringField(String name
, String strValue
) {
313 super(name
, strValue
, null);
317 public String
getValue() {
318 return (String
) super.getValue();
323 * CTF field implementation for arrays of integers.
327 final class CTFIntegerArrayField
extends CtfTmfEventField
{
329 private final int base
;
330 private final boolean signed
;
331 private String formattedValue
= null;
334 * Constructor for CTFIntegerArrayField.
337 * The name of this field
339 * The array of integers (as longs) that compose this field's
342 * Are the values in the array signed or not
344 CTFIntegerArrayField(String name
, long[] longValues
, int base
, boolean signed
) {
345 super(name
, longValues
, null);
347 this.signed
= signed
;
351 public long[] getValue() {
352 return (long[]) super.getValue();
356 public String
getFormattedValue() {
357 if (formattedValue
== null) {
358 List
<String
> strings
= new ArrayList
<String
>();
359 for (long value
: getValue()) {
360 strings
.add(formatNumber(value
, base
, signed
));
362 formattedValue
= strings
.toString();
364 return formattedValue
;
370 * CTF field implementation for floats.
374 final class CTFFloatField
extends CtfTmfEventField
{
377 * Constructor for CTFFloatField.
380 * The float value (actually a double) of this field
382 * The name of this field
384 protected CTFFloatField(String name
, double value
) {
385 super(name
, value
, null);
389 public Double
getValue() {
390 return (Double
) super.getValue();
395 * The CTF field implementation for Enum fields
397 * @author Bernd Hufmann
399 final class CTFEnumField
extends CtfTmfEventField
{
402 * Constructor for CTFEnumField.
405 * The Enum value consisting of a pair of Enum value name and its
408 * The name of this field
410 CTFEnumField(String name
, CtfEnumPair enumValue
) {
411 super(name
, new CtfEnumPair(enumValue
.getFirst(),
412 enumValue
.getSecond().longValue()), null);
416 public CtfEnumPair
getValue() {
417 return (CtfEnumPair
) super.getValue();
422 * The CTF field implementation for struct fields with sub-fields
426 final class CTFStructField
extends CtfTmfEventField
{
429 * Constructor for CTFStructField.
432 * The children of this field
434 * The name of this field
436 CTFStructField(String name
, CtfTmfEventField
[] fields
) {
437 super(name
, fields
, fields
);
441 public CtfTmfEventField
[] getValue() {
442 return (CtfTmfEventField
[]) super.getValue();
446 public String
getFormattedValue() {
447 return Arrays
.toString(getValue());
453 * The CTF field implementation for variant fields its child
457 final class CTFVariantField
extends CtfTmfEventField
{
460 * Constructor for CTFVariantField.
463 * The field selected for this variant
465 * The name of this field
467 CTFVariantField(String name
, CtfTmfEventField field
) {
468 super(name
, field
, new CtfTmfEventField
[] { field
});
472 public CtfTmfEventField
getValue() {
473 return (CtfTmfEventField
) super.getValue();
478 /* Implement other possible fields types here... */