@@ -17,86 +17,81 @@ internal object PrimitiveDecoder {
1717 private const val BYTE_BIT_MASK = 0xFF
1818 private const val BYTE_BIT_MASK_L = 0xFFL
1919 private const val INT_BIT_MASK = 0xFF_FF_FF_FFL
20+ private const val BYTE_BIT_MASK_UL = 0xFFuL
2021
2122 @JvmStatic
22- private fun ByteArray.getShort (position : Int ): Short {
23- return (
24- (this [position].toInt() and 0xFF ) or
25- ((this [position + 1 ].toInt() and 0xFF ) shl 8 )
26- ).toShort()
27- }
28- @JvmStatic
29- private fun ByteArray.getInt24 (position : Int ): Int {
30- return (this [position].toInt() and 0xFF ) or
31- ((this [position + 1 ].toInt() and 0xFF ) shl 8 ) or
32- // Shift left into 4th byte and then back down a byte here spreads the sign
33- // across high byte, which is needed for negatives
34- ((this [position + 2 ].toInt() and 0xFF ) shl 24 shr 8 )
23+ fun readFixedInt8AsShort (source : ByteArray , start : Int ): Short {
24+ // TODO: ion-java#1114
25+ if (source.size < start + 1 ) throw IonException (" Incomplete data: start=$start , length=1, limit=${source.size} " )
26+ return source[start].toShort()
3527 }
28+
3629 @JvmStatic
37- private fun ByteArray.getInt (position : Int ): Int {
38- return (this [position].toInt() and 0xFF ) or
39- ((this [position + 1 ].toInt() and 0xFF ) shl 8 ) or
40- ((this [position + 2 ].toInt() and 0xFF ) shl 16 ) or
41- ((this [position + 3 ].toInt() and 0xFF ) shl 24 )
30+ fun readFixedInt16 (source : ByteArray , start : Int ): Short {
31+ // TODO: ion-java#1114
32+ if (source.size < start + 2 ) throw IonException (" Incomplete data: start=$start , length=2, limit=${source.size} " )
33+ return read2IntBytes(source[start], source, start).shr(16 ).toShort()
4234 }
35+
4336 @JvmStatic
44- private fun ByteArray.getLong (position : Int ): Long {
45- return (this [position].toLong() and 0xFF ) or
46- ((this [position + 1 ].toLong() and 0xFF ) shl 8 ) or
47- ((this [position + 2 ].toLong() and 0xFF ) shl 16 ) or
48- ((this [position + 3 ].toLong() and 0xFF ) shl 24 ) or
49- ((this [position + 4 ].toLong() and 0xFF ) shl 32 ) or
50- ((this [position + 5 ].toLong() and 0xFF ) shl 40 ) or
51- ((this [position + 6 ].toLong() and 0xFF ) shl 48 ) or
52- ((this [position + 7 ].toLong() and 0xFF ) shl 56 )
37+ fun readFixedInt24AsInt (source : ByteArray , start : Int ): Int {
38+ // TODO: ion-java#1114
39+ if (source.size < start + 3 ) throw IonException (" Incomplete data: start=$start , length=3, limit=${source.size} " )
40+ return read3IntBytes(source[start], source, start).shr(8 )
5341 }
5442
5543 @JvmStatic
56- fun ByteArray. readFixedInt8AsShort ( start : Int ): Short {
44+ fun readFixedInt32 ( source : ByteArray , start : Int ): Int {
5745 // TODO: ion-java#1114
58- if (this .size < start + 1 ) throw IonException (" Incomplete data: start=$start , length=${ 1 } , limit=${this .size} " )
59- return this [start].toShort( )
46+ if (source .size < start + 4 ) throw IonException (" Incomplete data: start=$start , length=4 , limit=${source .size} " )
47+ return read4IntBytes(source [start], source, start )
6048 }
6149
6250 @JvmStatic
63- fun ByteArray. readFixedInt16AsShort ( start : Int ): Short {
51+ fun readFixedInt64 ( source : ByteArray , start : Int ): Long {
6452 // TODO: ion-java#1114
65- if (this .size < start + 2 ) throw IonException (" Incomplete data: start=$start , length=${ 2 } , limit=${this .size} " )
66- return this .getShort( start)
53+ if (source .size < start + 8 ) throw IonException (" Incomplete data: start=$start , length=8 , limit=${source .size} " )
54+ return read8IntBytes(source[start], source, start)
6755 }
6856
6957 @JvmStatic
70- fun ByteArray. readFixedInt24AsInt ( start : Int ) : Int {
58+ fun readFixedIntAsLong ( source : ByteArray , start : Int , length : Int ): Long {
7159 // TODO: ion-java#1114
72- if (this .size < start + 3 ) throw IonException (" Incomplete data: start=$start , length=${3 } , limit=${this .size} " )
73- return this .getInt24(start)
60+ if (source.size < start + length) throw IonException (" Incomplete data: start=$start , length=$length , limit=${source.size} " )
61+ val firstByte = source[start]
62+ return when (length) {
63+ 1 -> firstByte.toLong()
64+ 2 -> read2IntBytes(firstByte, source, start).shr(16 ).toLong()
65+ 3 -> read3IntBytes(firstByte, source, start).shr(8 ).toLong()
66+ 4 -> read4IntBytes(firstByte, source, start).toLong()
67+ 5 -> read5IntBytes(firstByte, source, start).shr(24 )
68+ 6 -> read6IntBytes(firstByte, source, start).shr(16 )
69+ 7 -> read7IntBytes(firstByte, source, start).shr(8 )
70+ 8 -> read8IntBytes(firstByte, source, start)
71+ // TODO: Technically, it's possible that the FixedInt is over-padded with 0-bytes, but we can deal with that later.
72+ else -> throw IonException (" FixedInt with length $length is too large to fit in a Long" )
73+ }
7474 }
7575
7676 @JvmStatic
77- fun ByteArray. readFixedInt32AsInt ( start : Int ): Int {
77+ fun readFixedUInt16 ( source : ByteArray , position : Int ): UShort {
7878 // TODO: ion-java#1114
79- if (this .size < start + 4 ) throw IonException (" Incomplete data: start=$start , length=${ 4 } , limit=${this .size} " )
80- return this .getInt(start )
79+ if (source .size < position + 2 ) throw IonException (" Incomplete data: start=$position , length=2 , limit=${source .size} " )
80+ return read2IntBytes(source[position], source, position).shr( 16 ).toUShort( )
8181 }
8282
8383 @JvmStatic
84- fun ByteArray. readFixedIntAsInt ( start : Int , length : Int ): Int {
84+ fun readFixedUInt32 ( source : ByteArray , position : Int ): UInt {
8585 // TODO: ion-java#1114
86- if (this .size < start + length ) throw IonException (" Incomplete data: start=$start , length=$length , limit=${this .size} " )
87- return ( this .getInt(start - 4 + length) shr (( 4 - length) * 8 ) )
86+ if (source .size < position + 4 ) throw IonException (" Incomplete data: start=$position , length=4 , limit=${source .size} " )
87+ return read4IntBytes(source[position], source, position).toUInt( )
8888 }
8989
9090 @JvmStatic
91- fun ByteArray. readFixedIntAsLong ( start : Int , length : Int ): Long {
91+ fun readFixedUInt64 ( source : ByteArray , position : Int ): ULong {
9292 // TODO: ion-java#1114
93- if (this .size < start + length) throw IonException (" Incomplete data: start=$start , length=$length , limit=${this .size} " )
94- if (length > 4 ) {
95- // TODO: See if we can simplify some of the calculations
96- return this .getLong(start - 8 + length) shr ((8 - length) * 8 )
97- } else {
98- return (this .getInt(start - 4 + length) shr ((4 - length) * 8 )).toLong()
99- }
93+ if (source.size < position + 8 ) throw IonException (" Incomplete data: start=$position , length=8, limit=${source.size} " )
94+ return read8IntBytes(source[position], source, position).toULong()
10095 }
10196
10297 // ==== FLEX INT AND UINT FUNCTIONS ==== //
@@ -253,6 +248,33 @@ internal object PrimitiveDecoder {
253248 return value.toLong().and (INT_BIT_MASK ) or numBytes.toLong().shl(Int .SIZE_BITS )
254249 }
255250
251+ /* *
252+ * Reads a FlexUInt as a ULong. Throws if value is too large for a ULong.
253+ */
254+ @JvmStatic
255+ fun readFlexUIntAsULong (source : ByteArray , position : Int ): ULong {
256+ val firstByte = source[position]
257+ val numBytes = firstByte.countTrailingZeroBits() + 1
258+ val value = when (numBytes) {
259+ 1 -> firstByte.toULong().and (BYTE_BIT_MASK_UL ).shr(1 )
260+ // These `shr` amounts are not arbitrary. See the `read*IntBytes` method documentation.
261+ 2 -> read2IntBytes(firstByte, source, position).ushr(18 ).toULong()
262+ 3 -> read3IntBytes(firstByte, source, position).ushr(11 ).toULong()
263+ 4 -> read4IntBytes(firstByte, source, position).ushr(4 ).toULong()
264+ 5 -> read5IntBytes(firstByte, source, position).ushr(29 ).toULong()
265+ 6 -> read6IntBytes(firstByte, source, position).ushr(22 ).toULong()
266+ 7 -> read7IntBytes(firstByte, source, position).ushr(15 ).toULong()
267+ 8 -> read8IntBytes(firstByte, source, position).ushr(8 ).toULong()
268+ else -> {
269+ val bigInt = readFlexUIntAsBigInteger(source, position)
270+ // bitLength() does not include a sign bit.
271+ if (bigInt.bitLength() > Long .SIZE_BITS ) throw IonException (" FlexInt value too large to find in a ULong" )
272+ bigInt.toLong().toULong()
273+ }
274+ }
275+ return value
276+ }
277+
256278 /* *
257279 * Does exactly what the function name says. This is slow. This method should rarely, if ever, be invoked.
258280 */
0 commit comments