• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.trace;
18 
19 import io.opencensus.internal.Utils;
20 import java.util.Arrays;
21 
22 final class BigendianEncoding {
23   static final int LONG_BYTES = Long.SIZE / Byte.SIZE;
24   static final int BYTE_BASE16 = 2;
25   static final int LONG_BASE16 = BYTE_BASE16 * LONG_BYTES;
26   private static final String ALPHABET = "0123456789abcdef";
27   private static final int ASCII_CHARACTERS = 128;
28   private static final char[] ENCODING = buildEncodingArray();
29   private static final byte[] DECODING = buildDecodingArray();
30 
buildEncodingArray()31   private static char[] buildEncodingArray() {
32     char[] encoding = new char[512];
33     for (int i = 0; i < 256; ++i) {
34       encoding[i] = ALPHABET.charAt(i >>> 4);
35       encoding[i | 0x100] = ALPHABET.charAt(i & 0xF);
36     }
37     return encoding;
38   }
39 
buildDecodingArray()40   private static byte[] buildDecodingArray() {
41     byte[] decoding = new byte[ASCII_CHARACTERS];
42     Arrays.fill(decoding, (byte) -1);
43     for (int i = 0; i < ALPHABET.length(); i++) {
44       char c = ALPHABET.charAt(i);
45       decoding[c] = (byte) i;
46     }
47     return decoding;
48   }
49 
50   /**
51    * Returns the {@code long} value whose big-endian representation is stored in the first 8 bytes
52    * of {@code bytes} starting from the {@code offset}.
53    *
54    * @param bytes the byte array representation of the {@code long}.
55    * @param offset the starting offset in the byte array.
56    * @return the {@code long} value whose big-endian representation is given.
57    * @throws IllegalArgumentException if {@code bytes} has fewer than 8 elements.
58    */
longFromByteArray(byte[] bytes, int offset)59   static long longFromByteArray(byte[] bytes, int offset) {
60     Utils.checkArgument(bytes.length >= offset + LONG_BYTES, "array too small");
61     return (bytes[offset] & 0xFFL) << 56
62         | (bytes[offset + 1] & 0xFFL) << 48
63         | (bytes[offset + 2] & 0xFFL) << 40
64         | (bytes[offset + 3] & 0xFFL) << 32
65         | (bytes[offset + 4] & 0xFFL) << 24
66         | (bytes[offset + 5] & 0xFFL) << 16
67         | (bytes[offset + 6] & 0xFFL) << 8
68         | (bytes[offset + 7] & 0xFFL);
69   }
70 
71   /**
72    * Stores the big-endian representation of {@code value} in the {@code dest} starting from the
73    * {@code destOffset}.
74    *
75    * @param value the value to be converted.
76    * @param dest the destination byte array.
77    * @param destOffset the starting offset in the destination byte array.
78    */
longToByteArray(long value, byte[] dest, int destOffset)79   static void longToByteArray(long value, byte[] dest, int destOffset) {
80     Utils.checkArgument(dest.length >= destOffset + LONG_BYTES, "array too small");
81     dest[destOffset + 7] = (byte) (value & 0xFFL);
82     dest[destOffset + 6] = (byte) (value >> 8 & 0xFFL);
83     dest[destOffset + 5] = (byte) (value >> 16 & 0xFFL);
84     dest[destOffset + 4] = (byte) (value >> 24 & 0xFFL);
85     dest[destOffset + 3] = (byte) (value >> 32 & 0xFFL);
86     dest[destOffset + 2] = (byte) (value >> 40 & 0xFFL);
87     dest[destOffset + 1] = (byte) (value >> 48 & 0xFFL);
88     dest[destOffset] = (byte) (value >> 56 & 0xFFL);
89   }
90 
91   /**
92    * Returns the {@code long} value whose base16 representation is stored in the first 16 chars of
93    * {@code chars} starting from the {@code offset}.
94    *
95    * @param chars the base16 representation of the {@code long}.
96    * @param offset the starting offset in the {@code CharSequence}.
97    */
longFromBase16String(CharSequence chars, int offset)98   static long longFromBase16String(CharSequence chars, int offset) {
99     Utils.checkArgument(chars.length() >= offset + LONG_BASE16, "chars too small");
100     return (decodeByte(chars.charAt(offset), chars.charAt(offset + 1)) & 0xFFL) << 56
101         | (decodeByte(chars.charAt(offset + 2), chars.charAt(offset + 3)) & 0xFFL) << 48
102         | (decodeByte(chars.charAt(offset + 4), chars.charAt(offset + 5)) & 0xFFL) << 40
103         | (decodeByte(chars.charAt(offset + 6), chars.charAt(offset + 7)) & 0xFFL) << 32
104         | (decodeByte(chars.charAt(offset + 8), chars.charAt(offset + 9)) & 0xFFL) << 24
105         | (decodeByte(chars.charAt(offset + 10), chars.charAt(offset + 11)) & 0xFFL) << 16
106         | (decodeByte(chars.charAt(offset + 12), chars.charAt(offset + 13)) & 0xFFL) << 8
107         | (decodeByte(chars.charAt(offset + 14), chars.charAt(offset + 15)) & 0xFFL);
108   }
109 
110   /**
111    * Appends the base16 encoding of the specified {@code value} to the {@code dest}.
112    *
113    * @param value the value to be converted.
114    * @param dest the destination char array.
115    * @param destOffset the starting offset in the destination char array.
116    */
longToBase16String(long value, char[] dest, int destOffset)117   static void longToBase16String(long value, char[] dest, int destOffset) {
118     byteToBase16((byte) (value >> 56 & 0xFFL), dest, destOffset);
119     byteToBase16((byte) (value >> 48 & 0xFFL), dest, destOffset + BYTE_BASE16);
120     byteToBase16((byte) (value >> 40 & 0xFFL), dest, destOffset + 2 * BYTE_BASE16);
121     byteToBase16((byte) (value >> 32 & 0xFFL), dest, destOffset + 3 * BYTE_BASE16);
122     byteToBase16((byte) (value >> 24 & 0xFFL), dest, destOffset + 4 * BYTE_BASE16);
123     byteToBase16((byte) (value >> 16 & 0xFFL), dest, destOffset + 5 * BYTE_BASE16);
124     byteToBase16((byte) (value >> 8 & 0xFFL), dest, destOffset + 6 * BYTE_BASE16);
125     byteToBase16((byte) (value & 0xFFL), dest, destOffset + 7 * BYTE_BASE16);
126   }
127 
128   /**
129    * Encodes the specified byte, and returns the encoded {@code String}.
130    *
131    * @param value the value to be converted.
132    * @param dest the destination char array.
133    * @param destOffset the starting offset in the destination char array.
134    */
byteToBase16String(byte value, char[] dest, int destOffset)135   static void byteToBase16String(byte value, char[] dest, int destOffset) {
136     byteToBase16(value, dest, destOffset);
137   }
138 
139   /**
140    * Decodes the specified two character sequence, and returns the resulting {@code byte}.
141    *
142    * @param chars the character sequence to be decoded.
143    * @param offset the starting offset in the {@code CharSequence}.
144    * @return the resulting {@code byte}
145    * @throws IllegalArgumentException if the input is not a valid encoded string according to this
146    *     encoding.
147    */
byteFromBase16String(CharSequence chars, int offset)148   static byte byteFromBase16String(CharSequence chars, int offset) {
149     Utils.checkArgument(chars.length() >= offset + 2, "chars too small");
150     return decodeByte(chars.charAt(offset), chars.charAt(offset + 1));
151   }
152 
decodeByte(char hi, char lo)153   private static byte decodeByte(char hi, char lo) {
154     Utils.checkArgument(lo < ASCII_CHARACTERS && DECODING[lo] != -1, "invalid character " + lo);
155     Utils.checkArgument(hi < ASCII_CHARACTERS && DECODING[hi] != -1, "invalid character " + hi);
156     int decoded = DECODING[hi] << 4 | DECODING[lo];
157     return (byte) decoded;
158   }
159 
160   private static void byteToBase16(byte value, char[] dest, int destOffset) {
161     int b = value & 0xFF;
162     dest[destOffset] = ENCODING[b];
163     dest[destOffset + 1] = ENCODING[b | 0x100];
164   }
165 
166   private BigendianEncoding() {}
167 }
168