ctf: preserve byte order if explicitly set in a typedef
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / event / types / IntegerDeclaration.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 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 * Marc-Andre Laperle - Add min/maximum for validation
13 *******************************************************************************/
14
15 package org.eclipse.tracecompass.ctf.core.event.types;
16
17 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
18
19 import java.math.BigInteger;
20 import java.nio.ByteOrder;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.eclipse.tracecompass.ctf.core.CTFException;
25 import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
26 import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;
27
28 /**
29 * A CTF integer declaration.
30 *
31 * The declaration of a integer basic data type.
32 *
33 * @version 1.0
34 * @author Matthew Khouzam
35 * @author Simon Marchi
36 */
37 @NonNullByDefault
38 public final class IntegerDeclaration extends Declaration implements ISimpleDatatypeDeclaration {
39
40 // ------------------------------------------------------------------------
41 // Helpers
42 // ------------------------------------------------------------------------
43
44 private static final int SIZE_64 = 64;
45 private static final int SIZE_32 = 32;
46 private static final int SIZE_27 = 27;
47 private static final int SIZE_16 = 16;
48 private static final int SIZE_8 = 8;
49 private static final int SIZE_5 = 5;
50 private static final int BYTE_ALIGN = 8;
51 private static final int BASE_10 = 10;
52 /**
53 * unsigned int 32 bits big endian
54 */
55 public static final IntegerDeclaration UINT_32B_DECL = new IntegerDeclaration(32, false, ByteOrder.BIG_ENDIAN);
56 /**
57 * unsigned int 32 bits little endian
58 */
59 public static final IntegerDeclaration UINT_32L_DECL = new IntegerDeclaration(32, false, ByteOrder.LITTLE_ENDIAN);
60 /**
61 * signed int 32 bits big endian
62 */
63 public static final IntegerDeclaration INT_32B_DECL = new IntegerDeclaration(32, true, ByteOrder.BIG_ENDIAN);
64 /**
65 * signed int 32 bits little endian
66 */
67 public static final IntegerDeclaration INT_32L_DECL = new IntegerDeclaration(32, true, ByteOrder.LITTLE_ENDIAN);
68 /**
69 * unsigned int 32 bits big endian
70 */
71 public static final IntegerDeclaration UINT_64B_DECL = new IntegerDeclaration(64, false, ByteOrder.BIG_ENDIAN);
72 /**
73 * unsigned int 64 bits little endian
74 */
75 public static final IntegerDeclaration UINT_64L_DECL = new IntegerDeclaration(64, false, ByteOrder.LITTLE_ENDIAN);
76 /**
77 * signed int 64 bits big endian
78 */
79 public static final IntegerDeclaration INT_64B_DECL = new IntegerDeclaration(64, true, ByteOrder.BIG_ENDIAN);
80 /**
81 * signed int 64 bits little endian
82 */
83 public static final IntegerDeclaration INT_64L_DECL = new IntegerDeclaration(64, true, ByteOrder.LITTLE_ENDIAN);
84 /**
85 * unsigned 8 bit int endianness doesn't matter since it's 8 bits (byte)
86 */
87 public static final IntegerDeclaration UINT_8_DECL = new IntegerDeclaration(8, false, ByteOrder.BIG_ENDIAN);
88 /**
89 * signed 8 bit int endianness doesn't matter since it's 8 bits (char)
90 */
91 public static final IntegerDeclaration INT_8_DECL = new IntegerDeclaration(8, true, ByteOrder.BIG_ENDIAN);
92 /**
93 * Unsigned 5 bit int, used for event headers
94 */
95 public static final IntegerDeclaration UINT_5B_DECL = new IntegerDeclaration(5, false, 10, ByteOrder.BIG_ENDIAN, Encoding.NONE, "", 1); //$NON-NLS-1$
96 /**
97 * Unsigned 5 bit int, used for event headers
98 */
99 public static final IntegerDeclaration UINT_5L_DECL = new IntegerDeclaration(5, false, 10, ByteOrder.LITTLE_ENDIAN, Encoding.NONE, "", 1); //$NON-NLS-1$
100 /**
101 * Unsigned 5 bit int, used for event headers
102 */
103 public static final IntegerDeclaration UINT_27B_DECL = new IntegerDeclaration(27, false, 10, ByteOrder.BIG_ENDIAN, Encoding.NONE, "", 1); //$NON-NLS-1$
104 /**
105 * Unsigned 5 bit int, used for event headers
106 */
107 public static final IntegerDeclaration UINT_27L_DECL = new IntegerDeclaration(27, false, 10, ByteOrder.LITTLE_ENDIAN, Encoding.NONE, "", 1); //$NON-NLS-1$
108 /**
109 * Unsigned 16 bit int, used for event headers
110 */
111 public static final IntegerDeclaration UINT_16B_DECL = new IntegerDeclaration(16, false, ByteOrder.BIG_ENDIAN);
112 /**
113 * Unsigned 16 bit int, used for event headers
114 */
115 public static final IntegerDeclaration UINT_16L_DECL = new IntegerDeclaration(16, false, ByteOrder.LITTLE_ENDIAN);
116 // ------------------------------------------------------------------------
117 // Attributes
118 // ------------------------------------------------------------------------
119
120 private final int fLength;
121 private final boolean fSigned;
122 private final int fBase;
123 private final boolean fIsByteOrderSet;
124 private final ByteOrder fByteOrder;
125 private final Encoding fEncoding;
126 private final long fAlignment;
127 private final String fClock;
128
129 // ------------------------------------------------------------------------
130 // Constructors
131 // ------------------------------------------------------------------------
132
133 /**
134 * Factory, some common types cached
135 *
136 * @param len
137 * The length in bits
138 * @param signed
139 * Is the integer signed? false == unsigned
140 * @param base
141 * The base (10-16 are most common)
142 * @param byteOrder
143 * Big-endian little-endian or other
144 * @param encoding
145 * ascii, utf8 or none.
146 * @param clock
147 * The clock path, can be null
148 * @param alignment
149 * The minimum alignment. Should be >= 1
150 * @return the integer declaration
151 */
152 public static IntegerDeclaration createDeclaration(int len, boolean signed, int base,
153 @Nullable ByteOrder byteOrder, Encoding encoding, String clock, long alignment) {
154 if (encoding.equals(Encoding.NONE) && (clock.equals("")) && base == BASE_10 && byteOrder != null) { //$NON-NLS-1$
155 if (alignment == BYTE_ALIGN) {
156 switch (len) {
157 case SIZE_8:
158 return signed ? INT_8_DECL : UINT_8_DECL;
159 case SIZE_16:
160 if (!signed) {
161 if (isBigEndian(byteOrder)) {
162 return UINT_16B_DECL;
163 }
164 return UINT_16L_DECL;
165 }
166 break;
167 case SIZE_32:
168 if (signed) {
169 if (isBigEndian(byteOrder)) {
170 return INT_32B_DECL;
171 }
172 return INT_32L_DECL;
173 }
174 if (isBigEndian(byteOrder)) {
175 return UINT_32B_DECL;
176 }
177 return UINT_32L_DECL;
178 case SIZE_64:
179 if (signed) {
180 if (isBigEndian(byteOrder)) {
181 return INT_64B_DECL;
182 }
183 return INT_64L_DECL;
184 }
185 if (isBigEndian(byteOrder)) {
186 return UINT_64B_DECL;
187 }
188 return UINT_64L_DECL;
189
190 default:
191
192 }
193
194 } else if (alignment == 1) {
195 switch (len) {
196 case SIZE_5:
197 if (!signed) {
198 if (isBigEndian(byteOrder)) {
199 return UINT_5B_DECL;
200 }
201 return UINT_5L_DECL;
202 }
203 break;
204 case SIZE_27:
205 if (!signed) {
206 if (isBigEndian(byteOrder)) {
207 return UINT_27B_DECL;
208 }
209 return UINT_27L_DECL;
210 }
211 break;
212 default:
213 break;
214 }
215 }
216 }
217 return new IntegerDeclaration(len, signed, base, byteOrder, encoding, clock, alignment);
218 }
219
220 private static boolean isBigEndian(@Nullable ByteOrder byteOrder) {
221 return (byteOrder != null) && byteOrder.equals(ByteOrder.BIG_ENDIAN);
222 }
223
224 /**
225 * Constructor
226 *
227 * @param len
228 * The length in bits
229 * @param signed
230 * Is the integer signed? false == unsigned
231 * @param base
232 * The base (10-16 are most common)
233 * @param byteOrder
234 * Big-endian little-endian or other
235 * @param encoding
236 * ascii, utf8 or none.
237 * @param clock
238 * The clock path, can be null
239 * @param alignment
240 * The minimum alignment. Should be ≥ 1
241 */
242 private IntegerDeclaration(int len, boolean signed, int base,
243 @Nullable ByteOrder byteOrder, Encoding encoding, String clock, long alignment) {
244 fLength = len;
245 fSigned = signed;
246 fBase = base;
247 fIsByteOrderSet = byteOrder != null;
248 fByteOrder = (byteOrder == null) ? ByteOrder.nativeOrder() : byteOrder;
249 fEncoding = encoding;
250 fClock = clock;
251 fAlignment = Math.max(alignment, 1);
252 }
253
254 private IntegerDeclaration(int len, boolean signed, @Nullable ByteOrder byteOrder) {
255 this(len, signed, BASE_10, byteOrder, Encoding.NONE, "", BYTE_ALIGN); //$NON-NLS-1$
256 }
257
258 // ------------------------------------------------------------------------
259 // Getters/Setters/Predicates
260 // ------------------------------------------------------------------------
261
262 /**
263 * Is the integer signed?
264 *
265 * @return the is the integer signed
266 */
267 public boolean isSigned() {
268 return fSigned;
269 }
270
271 /**
272 * Get the integer base commonly decimal or hex
273 *
274 * @return the integer base
275 */
276 public int getBase() {
277 return fBase;
278 }
279
280 /**
281 * @since 2.0
282 */
283 @Override
284 public boolean isByteOrderSet() {
285 return fIsByteOrderSet;
286 }
287
288 @Override
289 public ByteOrder getByteOrder() {
290 return fByteOrder;
291 }
292
293 /**
294 * Get encoding, chars are 8 bit ints
295 *
296 * @return the encoding
297 */
298 public Encoding getEncoding() {
299 return fEncoding;
300 }
301
302 /**
303 * Is the integer a character (8 bits and encoded?)
304 *
305 * @return is the integer a char
306 */
307 public boolean isCharacter() {
308 return (fLength == SIZE_8) && (fEncoding != Encoding.NONE);
309 }
310
311 /**
312 * Is the integer an unsigned byte (8 bits and no sign)?
313 *
314 * @return is the integer an unsigned byte
315 */
316 public boolean isUnsignedByte() {
317 return (fLength == SIZE_8) && (!fSigned);
318 }
319
320 /**
321 * Get the length in bits for this integer
322 *
323 * @return the length of the integer
324 */
325 public int getLength() {
326 return fLength;
327 }
328
329 @Override
330 public long getAlignment() {
331 return fAlignment;
332 }
333
334 /**
335 * The integer's clock, since timestamps are stored in ints
336 *
337 * @return the integer's clock, can be null. (most often it is)
338 */
339 public String getClock() {
340 return fClock;
341 }
342
343 @Override
344 public int getMaximumSize() {
345 return fLength;
346 }
347
348 // ------------------------------------------------------------------------
349 // Operations
350 // ------------------------------------------------------------------------
351
352 @Override
353 public IntegerDefinition createDefinition(@Nullable IDefinitionScope definitionScope,
354 String fieldName, BitBuffer input) throws CTFException {
355 ByteOrder byteOrder = input.getByteOrder();
356 input.setByteOrder(fByteOrder);
357 long value = read(input);
358 input.setByteOrder(byteOrder);
359 return new IntegerDefinition(this, definitionScope, fieldName, value);
360 }
361
362 @Override
363 public String toString() {
364 return "[declaration] integer[length:" + fLength + (fSigned ? " " : " un") + "signed" + " base:" + fBase + " byteOrder:" + fByteOrder + " encoding:" + fEncoding + " alignment:" + fAlignment + " clock:" + fClock + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$
365 }
366
367 /**
368 * Get the maximum value for this integer declaration.
369 *
370 * @return The maximum value for this integer declaration
371 */
372 public BigInteger getMaxValue() {
373 /*
374 * Compute the number of bits able to represent an unsigned number,
375 * ignoring sign bit.
376 */
377 int significantBits = fLength - (fSigned ? 1 : 0);
378 /*
379 * For a given N significant bits, compute the maximal value which is (1
380 * << N) - 1.
381 */
382 return checkNotNull(BigInteger.ONE.shiftLeft(significantBits).subtract(BigInteger.ONE));
383 }
384
385 /**
386 * Get the minimum value for this integer declaration.
387 *
388 * @return The minimum value for this integer declaration
389 */
390 public BigInteger getMinValue() {
391 if (!fSigned) {
392 return checkNotNull(BigInteger.ZERO);
393 }
394
395 /*
396 * Compute the number of bits able to represent an unsigned number,
397 * without the sign bit.
398 */
399 int significantBits = fLength - 1;
400 /*
401 * For a given N significant bits, compute the minimal value which is -
402 * (1 << N).
403 */
404 return checkNotNull(BigInteger.ONE.shiftLeft(significantBits).negate());
405 }
406
407 private long read(BitBuffer input) throws CTFException {
408 /* Offset the buffer position wrt the current alignment */
409 alignRead(input);
410
411 boolean signed = isSigned();
412 int length = getLength();
413 long bits = 0;
414
415 /*
416 * Is the endianness of this field the same as the endianness of the
417 * input buffer? If not, then temporarily set the buffer's endianness to
418 * this field's just to read the data
419 */
420 ByteOrder previousByteOrder = input.getByteOrder();
421 if ((getByteOrder() != input.getByteOrder())) {
422 input.setByteOrder(getByteOrder());
423 }
424
425 if (length > SIZE_64) {
426 throw new CTFException("Cannot read an integer with over 64 bits. Length given: " + length); //$NON-NLS-1$
427 }
428
429 bits = input.get(length, signed);
430
431 /*
432 * Put the input buffer's endianness back to original if it was changed
433 */
434 if (previousByteOrder != input.getByteOrder()) {
435 input.setByteOrder(previousByteOrder);
436 }
437
438 return bits;
439 }
440
441 @Override
442 public int hashCode() {
443 final int prime = 31;
444 int result = 1;
445 result = prime * result + (int) (fAlignment ^ (fAlignment >>> 32));
446 result = prime * result + fBase;
447 result = prime * result + fByteOrder.toString().hashCode();
448 result = prime * result + fClock.hashCode();
449 result = prime * result + fEncoding.hashCode();
450 result = prime * result + fLength;
451 result = prime * result + (fSigned ? 1231 : 1237);
452 return result;
453 }
454
455 @Override
456 public boolean equals(@Nullable Object obj) {
457 if (this == obj) {
458 return true;
459 }
460 if (obj == null) {
461 return false;
462 }
463 if (getClass() != obj.getClass()) {
464 return false;
465 }
466 IntegerDeclaration other = (IntegerDeclaration) obj;
467 if (!isBinaryEquivalent(other)) {
468 return false;
469 }
470 if (!fByteOrder.equals(other.fByteOrder)) {
471 return false;
472 }
473 if (!fClock.equals(other.fClock)) {
474 return false;
475 }
476 if (fEncoding != other.fEncoding) {
477 return false;
478 }
479 if (fBase != other.fBase) {
480 return false;
481 }
482 return true;
483 }
484
485 @Override
486 public boolean isBinaryEquivalent(@Nullable IDeclaration obj) {
487 if (this == obj) {
488 return true;
489 }
490 if (obj == null) {
491 return false;
492 }
493 if (getClass() != obj.getClass()) {
494 return false;
495 }
496 IntegerDeclaration other = (IntegerDeclaration) obj;
497 return isBinaryEquivalent(other);
498 }
499
500 private boolean isBinaryEquivalent(IntegerDeclaration other) {
501 if (fAlignment != other.fAlignment) {
502 return false;
503 }
504 if (fLength != other.fLength) {
505 return false;
506 }
507 if (fSigned != other.fSigned) {
508 return false;
509 }
510 // no need for base
511 // no need for encoding
512 // no need for clock
513 // byte inversion is ok on byte order if the element is one byte long
514 if ((fLength != BYTE_ALIGN) && !fByteOrder.equals(other.fByteOrder)) {
515 return false;
516 }
517 return true;
518 }
519
520 }
This page took 0.045704 seconds and 5 git commands to generate.