blob: a1c10be7b4c18f47593297040be694a7f3305b72 [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.util;
/**
* Static methods for reading and writing packed integers.
*
* <p>Most applications should use the classes in the {@link
* com.sleepycat.bind.tuple} package rather than using this class directly.</p>
*
* @see <a href="../bind/tuple/package-summary.html#integerFormats">Integer Formats</a>
*/
public class PackedInteger {
/**
* The maximum number of bytes needed to store an int value (5).
*/
public static final int MAX_LENGTH = 5;
/**
* The maximum number of bytes needed to store a long value (9).
*/
public static final int MAX_LONG_LENGTH = 9;
/**
* Reads a packed integer at the given buffer offset and returns it.
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the integer that was read.
*/
public static int readInt(byte[] buf, int off) {
boolean negative;
int byteLen;
int b1 = buf[off++];
if (b1 < -119) {
negative = true;
byteLen = -b1 - 119;
} else if (b1 > 119) {
negative = false;
byteLen = b1 - 119;
} else {
return b1;
}
int value = buf[off++] & 0xFF;
if (byteLen > 1) {
value |= (buf[off++] & 0xFF) << 8;
if (byteLen > 2) {
value |= (buf[off++] & 0xFF) << 16;
if (byteLen > 3) {
value |= (buf[off++] & 0xFF) << 24;
}
}
}
return negative ? (-value - 119) : (value + 119);
}
/**
* Reads a packed long integer at the given buffer offset and returns it.
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the long integer that was read.
*/
public static long readLong(byte[] buf, int off) {
boolean negative;
int byteLen;
int b1 = buf[off++];
if (b1 < -119) {
negative = true;
byteLen = -b1 - 119;
} else if (b1 > 119) {
negative = false;
byteLen = b1 - 119;
} else {
return b1;
}
long value = buf[off++] & 0xFFL;
if (byteLen > 1) {
value |= (buf[off++] & 0xFFL) << 8;
if (byteLen > 2) {
value |= (buf[off++] & 0xFFL) << 16;
if (byteLen > 3) {
value |= (buf[off++] & 0xFFL) << 24;
if (byteLen > 4) {
value |= (buf[off++] & 0xFFL) << 32;
if (byteLen > 5) {
value |= (buf[off++] & 0xFFL) << 40;
if (byteLen > 6) {
value |= (buf[off++] & 0xFFL) << 48;
if (byteLen > 7) {
value |= (buf[off++] & 0xFFL) << 56;
}
}
}
}
}
}
}
return negative ? (-value - 119) : (value + 119);
}
/**
* Returns the number of bytes that would be read by {@link #readInt}.
*
* <p>Because the length is stored in the first byte, this method may be
* called with only the first byte of the packed integer in the given
* buffer. This method only accesses one byte at the given offset.</p>
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the number of bytes that would be read.
*/
public static int getReadIntLength(byte[] buf, int off) {
int b1 = buf[off];
if (b1 < -119) {
return -b1 - 119 + 1;
} else if (b1 > 119) {
return b1 - 119 + 1;
} else {
return 1;
}
}
/**
* Returns the number of bytes that would be read by {@link #readLong}.
*
* <p>Because the length is stored in the first byte, this method may be
* called with only the first byte of the packed integer in the given
* buffer. This method only accesses one byte at the given offset.</p>
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the number of bytes that would be read.
*/
public static int getReadLongLength(byte[] buf, int off) {
/* The length is stored in the same way for int and long. */
return getReadIntLength(buf, off);
}
/**
* Writes a packed integer starting at the given buffer offset and returns
* the next offset to be written.
*
* @param buf the buffer to write to.
*
* @param offset the offset in the buffer at which to start writing.
*
* @param value the integer to be written.
*
* @return the offset past the bytes written.
*/
public static int writeInt(byte[] buf, int offset, int value) {
int byte1Off = offset;
boolean negative;
if (value < -119) {
negative = true;
value = -value - 119;
} else if (value > 119) {
negative = false;
value = value - 119;
} else {
buf[offset++] = (byte) value;
return offset;
}
offset++;
buf[offset++] = (byte) value;
if ((value & 0xFFFFFF00) == 0) {
buf[byte1Off] = negative ? (byte) -120 : (byte) 120;
return offset;
}
buf[offset++] = (byte) (value >>> 8);
if ((value & 0xFFFF0000) == 0) {
buf[byte1Off] = negative ? (byte) -121 : (byte) 121;
return offset;
}
buf[offset++] = (byte) (value >>> 16);
if ((value & 0xFF000000) == 0) {
buf[byte1Off] = negative ? (byte) -122 : (byte) 122;
return offset;
}
buf[offset++] = (byte) (value >>> 24);
buf[byte1Off] = negative ? (byte) -123 : (byte) 123;
return offset;
}
/**
* Writes a packed long integer starting at the given buffer offset and
* returns the next offset to be written.
*
* @param buf the buffer to write to.
*
* @param offset the offset in the buffer at which to start writing.
*
* @param value the long integer to be written.
*
* @return the offset past the bytes written.
*/
public static int writeLong(byte[] buf, int offset, long value) {
int byte1Off = offset;
boolean negative;
if (value < -119) {
negative = true;
value = -value - 119;
} else if (value > 119) {
negative = false;
value = value - 119;
} else {
buf[offset++] = (byte) value;
return offset;
}
offset++;
buf[offset++] = (byte) value;
if ((value & 0xFFFFFFFFFFFFFF00L) == 0) {
buf[byte1Off] = negative ? (byte) -120 : (byte) 120;
return offset;
}
buf[offset++] = (byte) (value >>> 8);
if ((value & 0xFFFFFFFFFFFF0000L) == 0) {
buf[byte1Off] = negative ? (byte) -121 : (byte) 121;
return offset;
}
buf[offset++] = (byte) (value >>> 16);
if ((value & 0xFFFFFFFFFF000000L) == 0) {
buf[byte1Off] = negative ? (byte) -122 : (byte) 122;
return offset;
}
buf[offset++] = (byte) (value >>> 24);
if ((value & 0xFFFFFFFF00000000L) == 0) {
buf[byte1Off] = negative ? (byte) -123 : (byte) 123;
return offset;
}
buf[offset++] = (byte) (value >>> 32);
if ((value & 0xFFFFFF0000000000L) == 0) {
buf[byte1Off] = negative ? (byte) -124 : (byte) 124;
return offset;
}
buf[offset++] = (byte) (value >>> 40);
if ((value & 0xFFFF000000000000L) == 0) {
buf[byte1Off] = negative ? (byte) -125 : (byte) 125;
return offset;
}
buf[offset++] = (byte) (value >>> 48);
if ((value & 0xFF00000000000000L) == 0) {
buf[byte1Off] = negative ? (byte) -126 : (byte) 126;
return offset;
}
buf[offset++] = (byte) (value >>> 56);
buf[byte1Off] = negative ? (byte) -127 : (byte) 127;
return offset;
}
/**
* Returns the number of bytes that would be written by {@link #writeInt}.
*
* @param value the integer to be written.
*
* @return the number of bytes that would be used to write the given
* integer.
*/
public static int getWriteIntLength(int value) {
if (value < -119) {
value = -value - 119;
} else if (value > 119) {
value = value - 119;
} else {
return 1;
}
if ((value & 0xFFFFFF00) == 0) {
return 2;
}
if ((value & 0xFFFF0000) == 0) {
return 3;
}
if ((value & 0xFF000000) == 0) {
return 4;
}
return 5;
}
/**
* Returns the number of bytes that would be written by {@link #writeLong}.
*
* @param value the long integer to be written.
*
* @return the number of bytes that would be used to write the given long
* integer.
*/
public static int getWriteLongLength(long value) {
if (value < -119) {
value = -value - 119;
} else if (value > 119) {
value = value - 119;
} else {
return 1;
}
if ((value & 0xFFFFFFFFFFFFFF00L) == 0) {
return 2;
}
if ((value & 0xFFFFFFFFFFFF0000L) == 0) {
return 3;
}
if ((value & 0xFFFFFFFFFF000000L) == 0) {
return 4;
}
if ((value & 0xFFFFFFFF00000000L) == 0) {
return 5;
}
if ((value & 0xFFFFFF0000000000L) == 0) {
return 6;
}
if ((value & 0xFFFF000000000000L) == 0) {
return 7;
}
if ((value & 0xFF00000000000000L) == 0) {
return 8;
}
return 9;
}
/**
* Reads a sorted packed integer at the given buffer offset and returns it.
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the integer that was read.
*/
public static int readSortedInt(byte[] buf, int off) {
int byteLen;
boolean negative;
/* The first byte of the buf stores the length of the value part. */
int b1 = buf[off++] & 0xff;
/* Adjust the byteLen to the real length of the value part. */
if (b1 < 0x08) {
byteLen = 0x08 - b1;
negative = true;
} else if (b1 > 0xf7) {
byteLen = b1 - 0xf7;
negative = false;
} else {
return b1 - 127;
}
/*
* The following bytes on the buf store the value as a big endian
* integer. We extract the significant bytes from the buf and put them
* into the value in big endian order.
*/
int value;
if (negative) {
value = 0xFFFFFFFF;
} else {
value = 0;
}
if (byteLen > 3) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 2) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 1) {
value = (value << 8) | (buf[off++] & 0xFF);
}
value = (value << 8) | (buf[off++] & 0xFF);
/*
* After get the adjusted value, we have to adjust it back to the
* original value.
*/
if (negative) {
value -= 119;
} else {
value += 121;
}
return value;
}
/**
* Reads a sorted packed long integer at the given buffer offset and
* returns it.
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the long integer that was read.
*/
public static long readSortedLong(byte[] buf, int off) {
int byteLen;
boolean negative;
/* The first byte of the buf stores the length of the value part. */
int b1 = buf[off++] & 0xff;
/* Adjust the byteLen to the real length of the value part. */
if (b1 < 0x08) {
byteLen = 0x08 - b1;
negative = true;
} else if (b1 > 0xf7) {
byteLen = b1 - 0xf7;
negative = false;
} else {
return b1 - 127;
}
/*
* The following bytes on the buf store the value as a big endian
* integer. We extract the significant bytes from the buf and put them
* into the value in big endian order.
*/
long value;
if (negative) {
value = 0xFFFFFFFFFFFFFFFFL;
} else {
value = 0;
}
if (byteLen > 7) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 6) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 5) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 4) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 3) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 2) {
value = (value << 8) | (buf[off++] & 0xFF);
}
if (byteLen > 1) {
value = (value << 8) | (buf[off++] & 0xFF);
}
value = (value << 8) | (buf[off++] & 0xFF);
/*
* After obtaining the adjusted value, we have to adjust it back to the
* original value.
*/
if (negative) {
value -= 119;
} else {
value += 121;
}
return value;
}
/**
* Returns the number of bytes that would be read by {@link
* #readSortedInt}.
*
* <p>Because the length is stored in the first byte, this method may be
* called with only the first byte of the packed integer in the given
* buffer. This method only accesses one byte at the given offset.</p>
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the number of bytes that would be read.
*/
public static int getReadSortedIntLength(byte[] buf, int off) {
/* The first byte of the buf stores the length of the value part. */
int b1 = buf[off] & 0xff;
if (b1 < 0x08) {
return 1 + 0x08 - b1;
}
if (b1 > 0xf7) {
return 1 + b1 - 0xf7;
}
return 1;
}
/**
* Returns the number of bytes that would be read by {@link
* #readSortedLong}.
*
* <p>Because the length is stored in the first byte, this method may be
* called with only the first byte of the packed integer in the given
* buffer. This method only accesses one byte at the given offset.</p>
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading.
*
* @return the number of bytes that would be read.
*/
public static int getReadSortedLongLength(byte[] buf, int off) {
/* The length is stored in the same way for int and long. */
return getReadSortedIntLength(buf, off);
}
/**
* Writes a packed sorted integer starting at the given buffer offset and
* returns the next offset to be written.
*
* @param buf the buffer to write to.
*
* @param offset the offset in the buffer at which to start writing.
*
* @param value the integer to be written.
*
* @return the offset past the bytes written.
*/
public static int writeSortedInt(byte[] buf, int offset, int value) {
/*
* Values in the inclusive range [-119,120] are stored in a single
* byte. For values outside that range, the first byte stores the
* number of additional bytes. The additional bytes store
* (value + 119 for negative and value - 121 for positive) as an
* unsigned big endian integer.
*/
int byte1Off = offset;
offset++;
if (value < -119) {
/*
* If the value < -119, then first adjust the value by adding 119.
* Then the adjusted value is stored as an unsigned big endian
* integer.
*/
value += 119;
/*
* Store the adjusted value as an unsigned big endian integer.
* For an negative integer, from left to right, the first
* significant byte is the byte which is not equal to 0xFF. Also
* please note that, because the adjusted value is stored in big
* endian integer, we extract the significant byte from left to
* right.
*
* In the left to right order, if the first byte of the adjusted
* value is a significant byte, it will be stored in the 2nd byte
* of the buf. Then we will look at the 2nd byte of the adjusted
* value to see if this byte is the significant byte, if yes, this
* byte will be stored in the 3rd byte of the buf, and the like.
*/
if ((value | 0x00FFFFFF) != 0xFFFFFFFF) {
buf[offset++] = (byte) (value >> 24);
}
if ((value | 0x0000FFFF) != 0xFFFFFFFF) {
buf[offset++] = (byte) (value >> 16);
}
if ((value | 0x000000FF) != 0xFFFFFFFF) {
buf[offset++] = (byte) (value >> 8);
}
buf[offset++] = (byte) value;
/*
* valueLen is the length of the value part stored in buf. Because
* the first byte of buf is used to stored the length, we need
* to subtract one.
*/
int valueLen = offset - byte1Off - 1;
/*
* The first byte stores the number of additional bytes. Here we
* store the result of 0x08 - valueLen, rather than directly store
* valueLen. The reason is to implement natural sort order for
* byte-by-byte comparison.
*/
buf[byte1Off] = (byte) (0x08 - valueLen);
} else if (value > 120) {
/*
* If the value > 120, then first adjust the value by subtracting
* 121. Then the adjusted value is stored as an unsigned big endian
* integer.
*/
value -= 121;
/*
* Store the adjusted value as an unsigned big endian integer.
* For a positive integer, from left to right, the first
* significant byte is the byte which is not equal to 0x00.
*
* In the left to right order, if the first byte of the adjusted
* value is a significant byte, it will be stored in the 2nd byte
* of the buf. Then we will look at the 2nd byte of the adjusted
* value to see if this byte is the significant byte, if yes, this
* byte will be stored in the 3rd byte of the buf, and the like.
*/
if ((value & 0xFF000000) != 0) {
buf[offset++] = (byte) (value >> 24);
}
if ((value & 0xFFFF0000) != 0) {
buf[offset++] = (byte) (value >> 16);
}
if ((value & 0xFFFFFF00) != 0) {
buf[offset++] = (byte) (value >> 8);
}
buf[offset++] = (byte) value;
/*
* valueLen is the length of the value part stored in buf. Because
* the first byte of buf is used to stored the length, we need to
* subtract one.
*/
int valueLen = offset - byte1Off - 1;
/*
* The first byte stores the number of additional bytes. Here we
* store the result of 0xF7 + valueLen, rather than directly store
* valueLen. The reason is to implement natural sort order for
* byte-by-byte comparison.
*/
buf[byte1Off] = (byte) (0xF7 + valueLen);
} else {
/*
* If -119 <= value <= 120, only one byte is needed to store the
* value. The stored value is the original value plus 127.
*/
buf[byte1Off] = (byte) (value + 127);
}
return offset;
}
/**
* Writes a packed sorted long integer starting at the given buffer offset
* and returns the next offset to be written.
*
* @param buf the buffer to write to.
*
* @param offset the offset in the buffer at which to start writing.
*
* @param value the long integer to be written.
*
* @return the offset past the bytes written.
*/
public static int writeSortedLong(byte[] buf, int offset, long value) {
/*
* Values in the inclusive range [-119,120] are stored in a single
* byte. For values outside that range, the first byte stores the
* number of additional bytes. The additional bytes store
* (value + 119 for negative and value - 121 for positive) as an
* unsigned big endian integer.
*/
int byte1Off = offset;
offset++;
if (value < -119) {
/*
* If the value < -119, then first adjust the value by adding 119.
* Then the adjusted value is stored as an unsigned big endian
* integer.
*/
value += 119;
/*
* Store the adjusted value as an unsigned big endian integer.
* For an negative integer, from left to right, the first
* significant byte is the byte which is not equal to 0xFF. Also
* please note that, because the adjusted value is stored in big
* endian integer, we extract the significant byte from left to
* right.
*
* In the left to right order, if the first byte of the adjusted
* value is a significant byte, it will be stored in the 2nd byte
* of the buf. Then we will look at the 2nd byte of the adjusted
* value to see if this byte is the significant byte, if yes, this
* byte will be stored in the 3rd byte of the buf, and the like.
*/
if ((value | 0x00FFFFFFFFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 56);
}
if ((value | 0x0000FFFFFFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 48);
}
if ((value | 0x000000FFFFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 40);
}
if ((value | 0x00000000FFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 32);
}
if ((value | 0x0000000000FFFFFFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 24);
}
if ((value | 0x000000000000FFFFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 16);
}
if ((value | 0x00000000000000FFL) != 0xFFFFFFFFFFFFFFFFL) {
buf[offset++] = (byte) (value >> 8);
}
buf[offset++] = (byte) value;
/*
* valueLen is the length of the value part stored in buf. Because
* the first byte of buf is used to stored the length, so we need
* to minus one.
*/
int valueLen = offset - byte1Off - 1;
/*
* The first byte stores the number of additional bytes. Here we
* store the result of 0x08 - valueLen, rather than directly store
* valueLen. The reason is to implement nature sort order for
* byte-by-byte comparison.
*/
buf[byte1Off] = (byte) (0x08 - valueLen);
} else if (value > 120) {
/*
* If the value > 120, then first adjust the value by subtracting
* 119. Then the adjusted value is stored as an unsigned big endian
* integer.
*/
value -= 121;
/*
* Store the adjusted value as an unsigned big endian integer.
* For a positive integer, from left to right, the first
* significant byte is the byte which is not equal to 0x00.
*
* In the left to right order, if the first byte of the adjusted
* value is a significant byte, it will be stored in the 2nd byte
* of the buf. Then we will look at the 2nd byte of the adjusted
* value to see if this byte is the significant byte, if yes, this
* byte will be stored in the 3rd byte of the buf, and the like.
*/
if ((value & 0xFF00000000000000L) != 0L) {
buf[offset++] = (byte) (value >> 56);
}
if ((value & 0xFFFF000000000000L) != 0L) {
buf[offset++] = (byte) (value >> 48);
}
if ((value & 0xFFFFFF0000000000L) != 0L) {
buf[offset++] = (byte) (value >> 40);
}
if ((value & 0xFFFFFFFF00000000L) != 0L) {
buf[offset++] = (byte) (value >> 32);
}
if ((value & 0xFFFFFFFFFF000000L) != 0L) {
buf[offset++] = (byte) (value >> 24);
}
if ((value & 0xFFFFFFFFFFFF0000L) != 0L) {
buf[offset++] = (byte) (value >> 16);
}
if ((value & 0xFFFFFFFFFFFFFF00L) != 0L) {
buf[offset++] = (byte) (value >> 8);
}
buf[offset++] = (byte) value;
/*
* valueLen is the length of the value part stored in buf. Because
* the first byte of buf is used to stored the length, so we need
* to minus one.
*/
int valueLen = offset - byte1Off - 1;
/*
* The first byte stores the number of additional bytes. Here we
* store the result of 0xF7 + valueLen, rather than directly store
* valueLen. The reason is to implement nature sort order for
* byte-by-byte comparison.
*/
buf[byte1Off] = (byte) (0xF7 + valueLen);
} else {
/*
* If -119 <= value <= 120, only one byte is needed to store the
* value. The stored value is the original value adds 127.
*/
buf[byte1Off] = (byte) (value + 127);
}
return offset;
}
/**
* Returns the number of bytes that would be written by {@link
* #writeSortedInt}.
*
* @param value the integer to be written.
*
* @return the number of bytes that would be used to write the given
* integer.
*/
public static int getWriteSortedIntLength(int value) {
if (value < -119) {
/* Adjust the value. */
value += 119;
/*
* Find the left most significant byte of the adjusted value, and
* return the length accordingly.
*/
if ((value | 0x000000FF) == 0xFFFFFFFF) {
return 2;
}
if ((value | 0x0000FFFF) == 0xFFFFFFFF) {
return 3;
}
if ((value | 0x00FFFFFF) == 0xFFFFFFFF) {
return 4;
}
} else if (value > 120) {
/* Adjust the value. */
value -= 121;
/*
* Find the left most significant byte of the adjusted value, and
* return the length accordingly.
*/
if ((value & 0xFFFFFF00) == 0) {
return 2;
}
if ((value & 0xFFFF0000) == 0) {
return 3;
}
if ((value & 0xFF000000) == 0) {
return 4;
}
} else {
/*
* If -119 <= value <= 120, only one byte is needed to store the
* value.
*/
return 1;
}
return 5;
}
/**
* Returns the number of bytes that would be written by {@link
* #writeSortedLong}.
*
* @param value the long integer to be written.
*
* @return the number of bytes that would be used to write the given long
* integer.
*/
public static int getWriteSortedLongLength(long value) {
if (value < -119) {
/* Adjust the value. */
value += 119;
/*
* Find the left most significant byte of the adjusted value, and
* return the length accordingly.
*/
if ((value | 0x00000000000000FFL) == 0xFFFFFFFFFFFFFFFFL) {
return 2;
}
if ((value | 0x000000000000FFFFL) == 0xFFFFFFFFFFFFFFFFL) {
return 3;
}
if ((value | 0x0000000000FFFFFFL) == 0xFFFFFFFFFFFFFFFFL) {
return 4;
}
if ((value | 0x00000000FFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) {
return 5;
}
if ((value | 0x000000FFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) {
return 6;
}
if ((value | 0x0000FFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) {
return 7;
}
if ((value | 0x00FFFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) {
return 8;
}
} else if (value > 120) {
/* Adjust the value. */
value -= 121;
/*
* Find the left most significant byte of the adjusted value, and
* return the length accordingly.
*/
if ((value & 0xFFFFFFFFFFFFFF00L) == 0L) {
return 2;
}
if ((value & 0xFFFFFFFFFFFF0000L) == 0L) {
return 3;
}
if ((value & 0xFFFFFFFFFF000000L) == 0L) {
return 4;
}
if ((value & 0xFFFFFFFF00000000L) == 0L) {
return 5;
}
if ((value & 0xFFFFFF0000000000L) == 0L) {
return 6;
}
if ((value & 0xFFFF000000000000L) == 0L) {
return 7;
}
if ((value & 0xFF00000000000000L) == 0L) {
return 8;
}
} else {
/*
* If -119 <= value <= 120, only one byte is needed to store the
* value.
*/
return 1;
}
return 9;
}
/* <!-- begin JE only --> */
/**
* @hidden
* Reads a reverse-packed integer ending at the given buffer offset and
* returns it.
*
* To get the length of a reverse-packed integer before reading, call
* {@link #getReadIntLength} passing the offset to the last byte.
*
* @param buf the buffer to read from.
*
* @param off the offset in the buffer at which to start reading, which is
* the index of the last byte of the integer in the buffer.
*
* @return the integer that was read.
*/
public static int readReverseInt(byte[] buf, int off) {
boolean negative;
int byteLen;
int b1 = buf[off];
if (b1 < -119) {
negative = true;
byteLen = -b1 - 119;
} else if (b1 > 119) {
negative = false;
byteLen = b1 - 119;
} else {
return b1;
}
int value = buf[--off] & 0xFF;
if (byteLen > 1) {
value |= (buf[--off] & 0xFF) << 8;
if (byteLen > 2) {
value |= (buf[--off] & 0xFF) << 16;
if (byteLen > 3) {
value |= (buf[--off] & 0xFF) << 24;
}
}
}
return negative ? (-value - 119) : (value + 119);
}
/**
* @hidden
* Writes a reverse-packed integer starting at the given buffer offset and
* returns the next offset to be written.
*
* To get the length of a reverse-packed integer before writing, call
* {@link #getWriteIntLength}.
*
* @param buf the buffer to write to.
*
* @param off the offset in the buffer at which to start writing, which
* will be the index of the first byte of the integer in the buffer.
*
* @param value the integer to be written.
*
* @return the offset past the bytes written.
*/
public static int writeReverseInt(byte[] buf, int off, int value) {
final boolean negative;
final int nextOff = off + getWriteIntLength(value);
if (value < -119) {
negative = true;
value = -value - 119;
} else if (value > 119) {
negative = false;
value = value - 119;
} else {
buf[off] = (byte) value;
return off + 1;
}
final int byte1Off = nextOff - 1;
off = byte1Off;
buf[--off] = (byte) value;
if ((value & 0xFFFFFF00) == 0) {
buf[byte1Off] = negative ? (byte) -120 : (byte) 120;
return nextOff;
}
buf[--off] = (byte) (value >>> 8);
if ((value & 0xFFFF0000) == 0) {
buf[byte1Off] = negative ? (byte) -121 : (byte) 121;
return nextOff;
}
buf[--off] = (byte) (value >>> 16);
if ((value & 0xFF000000) == 0) {
buf[byte1Off] = negative ? (byte) -122 : (byte) 122;
return nextOff;
}
buf[--off] = (byte) (value >>> 24);
buf[byte1Off] = negative ? (byte) -123 : (byte) 123;
return nextOff;
}
/* <!-- end JE only --> */
}