summaryrefslogtreecommitdiff
path: root/src/main/java/com
diff options
context:
space:
mode:
authorBrian S. O'Neill <bronee@gmail.com>2008-07-18 04:39:37 +0000
committerBrian S. O'Neill <bronee@gmail.com>2008-07-18 04:39:37 +0000
commit88194f7f16e705c21ea890febb8f1f2f3e2420b7 (patch)
treecdcf93f35989c9806201b8d4c85ce76865a01ef2 /src/main/java/com
parentd90258bfa37ec69cd4795feeb2d2ff94623b0199 (diff)
Added utilities for encoding and decoding BigIntegers.
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/amazon/carbonado/raw/DataDecoder.java21
-rw-r--r--src/main/java/com/amazon/carbonado/raw/DataEncoder.java57
-rw-r--r--src/main/java/com/amazon/carbonado/raw/KeyDecoder.java89
-rw-r--r--src/main/java/com/amazon/carbonado/raw/KeyEncoder.java107
4 files changed, 274 insertions, 0 deletions
diff --git a/src/main/java/com/amazon/carbonado/raw/DataDecoder.java b/src/main/java/com/amazon/carbonado/raw/DataDecoder.java
index 635b52e..5ea5c1d 100644
--- a/src/main/java/com/amazon/carbonado/raw/DataDecoder.java
+++ b/src/main/java/com/amazon/carbonado/raw/DataDecoder.java
@@ -18,6 +18,8 @@
package com.amazon.carbonado.raw;
+import java.math.BigInteger;
+
import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
@@ -370,6 +372,25 @@ public class DataDecoder {
}
/**
+ * Decodes a BigInteger.
+ *
+ * @param src source of encoded data
+ * @param srcOffset offset into encoded data
+ * @param valueRef decoded BigInteger is stored in element 0, which may be null
+ * @return amount of bytes read from source
+ * @throws CorruptEncodingException if source data is corrupt
+ * @since 1.2
+ */
+ public static int decode(byte[] src, int srcOffset, BigInteger[] valueRef)
+ throws CorruptEncodingException
+ {
+ byte[][] bytesRef = new byte[1][];
+ int amt = decode(src, srcOffset, bytesRef);
+ valueRef[0] = (bytesRef[0] == null) ? null : new BigInteger(bytesRef[0]);
+ return amt;
+ }
+
+ /**
* Decodes the given byte array.
*
* @param src source of encoded data
diff --git a/src/main/java/com/amazon/carbonado/raw/DataEncoder.java b/src/main/java/com/amazon/carbonado/raw/DataEncoder.java
index e8383b9..7f4f5d3 100644
--- a/src/main/java/com/amazon/carbonado/raw/DataEncoder.java
+++ b/src/main/java/com/amazon/carbonado/raw/DataEncoder.java
@@ -18,6 +18,8 @@
package com.amazon.carbonado.raw;
+import java.math.BigInteger;
+
import java.io.IOException;
import java.io.OutputStream;
@@ -307,6 +309,61 @@ public class DataEncoder {
}
/**
+ * Encodes the given optional BigInteger into a variable amount of
+ * bytes. If the BigInteger is null, exactly 1 byte is written. Otherwise,
+ * the amount written can be determined by calling calculateEncodedLength.
+ *
+ * @param value BigInteger value to encode, may be null
+ * @param dst destination for encoded bytes
+ * @param dstOffset offset into destination array
+ * @return amount of bytes written
+ * @since 1.2
+ */
+ public static int encode(BigInteger value, byte[] dst, int dstOffset) {
+ if (value == null) {
+ dst[dstOffset] = NULL_BYTE_HIGH;
+ return 1;
+ }
+
+ byte[] bytes = value.toByteArray();
+
+ // Write the byte array length first, in a variable amount of bytes.
+ int amt = encodeLength(bytes.length, dst, dstOffset);
+
+ // Now write the byte array.
+ System.arraycopy(bytes, 0, dst, dstOffset + amt, bytes.length);
+
+ return amt + bytes.length;
+ }
+
+ /**
+ * Returns the amount of bytes required to encode the given BigInteger.
+ *
+ * @param value BigInteger value to encode, may be null
+ * @return amount of bytes needed to encode
+ * @since 1.2
+ */
+ public static int calculateEncodedLength(BigInteger value) {
+ if (value == null) {
+ return 1;
+ }
+
+ int byteCount = (value.bitLength() >> 3) + 1;
+
+ if (byteCount < 128) {
+ return 1 + byteCount;
+ } else if (byteCount < 16384) {
+ return 2 + byteCount;
+ } else if (byteCount < 2097152) {
+ return 3 + byteCount;
+ } else if (byteCount < 268435456) {
+ return 4 + byteCount;
+ } else {
+ return 5 + byteCount;
+ }
+ }
+
+ /**
* Encodes the given optional byte array into a variable amount of
* bytes. If the byte array is null, exactly 1 byte is written. Otherwise,
* the amount written can be determined by calling calculateEncodedLength.
diff --git a/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java b/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java
index 4f78738..8c4bf02 100644
--- a/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java
+++ b/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java
@@ -18,6 +18,8 @@
package com.amazon.carbonado.raw;
+import java.math.BigInteger;
+
import com.amazon.carbonado.CorruptEncodingException;
import static com.amazon.carbonado.raw.EncodingConstants.*;
@@ -332,6 +334,93 @@ public class KeyDecoder {
}
/**
+ * Decodes the given BigInteger as originally encoded for ascending order.
+ *
+ * @param src source of encoded data
+ * @param srcOffset offset into encoded data
+ * @param valueRef decoded BigInteger is stored in element 0, which may be null
+ * @return amount of bytes read from source
+ * @throws CorruptEncodingException if source data is corrupt
+ * @since 1.2
+ */
+ public static int decode(byte[] src, int srcOffset, BigInteger[] valueRef)
+ throws CorruptEncodingException
+ {
+ int header = src[srcOffset];
+ if (header == NULL_BYTE_HIGH || header == NULL_BYTE_LOW) {
+ valueRef[0] = null;
+ return 1;
+ }
+
+ header &= 0xff;
+
+ int headerSize;
+ int bytesLength;
+ if (header > 1 && header < 0xfe) {
+ if (header < 0x80) {
+ bytesLength = 0x80 - header;
+ } else {
+ bytesLength = header - 0x7f;
+ }
+ headerSize = 1;
+ } else {
+ bytesLength = Math.abs(DataDecoder.decodeInt(src, srcOffset + 1));
+ headerSize = 5;
+ }
+
+ byte[] bytes = new byte[bytesLength];
+ System.arraycopy(src, srcOffset + headerSize, bytes, 0, bytesLength);
+ valueRef[0] = new BigInteger(bytes);
+ return headerSize + bytesLength;
+ }
+
+ /**
+ * Decodes the given BigInteger as originally encoded for descending order.
+ *
+ * @param src source of encoded data
+ * @param srcOffset offset into encoded data
+ * @param valueRef decoded BigInteger is stored in element 0, which may be null
+ * @return amount of bytes read from source
+ * @throws CorruptEncodingException if source data is corrupt
+ * @since 1.2
+ */
+ public static int decodeDesc(byte[] src, int srcOffset, BigInteger[] valueRef)
+ throws CorruptEncodingException
+ {
+ int header = src[srcOffset];
+ if (header == NULL_BYTE_HIGH || header == NULL_BYTE_LOW) {
+ valueRef[0] = null;
+ return 1;
+ }
+
+ header &= 0xff;
+
+ int headerSize;
+ int bytesLength;
+ if (header > 1 && header < 0xfe) {
+ if (header < 0x80) {
+ bytesLength = 0x80 - header;
+ } else {
+ bytesLength = header - 0x7f;
+ }
+ headerSize = 1;
+ } else {
+ bytesLength = Math.abs(DataDecoder.decodeInt(src, srcOffset + 1));
+ headerSize = 5;
+ }
+
+ byte[] bytes = new byte[bytesLength];
+
+ srcOffset += headerSize;
+ for (int i=0; i<bytesLength; i++) {
+ bytes[i] = (byte) ~src[srcOffset + i];
+ }
+
+ valueRef[0] = new BigInteger(bytes);
+ return headerSize + bytesLength;
+ }
+
+ /**
* Decodes the given byte array as originally encoded for ascending order.
* The decoding stops when any kind of terminator or illegal byte has been
* read. The decoded bytes are stored in valueRef.
diff --git a/src/main/java/com/amazon/carbonado/raw/KeyEncoder.java b/src/main/java/com/amazon/carbonado/raw/KeyEncoder.java
index 8d374a1..2d2dd71 100644
--- a/src/main/java/com/amazon/carbonado/raw/KeyEncoder.java
+++ b/src/main/java/com/amazon/carbonado/raw/KeyEncoder.java
@@ -18,6 +18,8 @@
package com.amazon.carbonado.raw;
+import java.math.BigInteger;
+
import static com.amazon.carbonado.raw.EncodingConstants.*;
/**
@@ -298,6 +300,111 @@ public class KeyEncoder {
}
/**
+ * Encodes the given optional BigInteger into a variable amount of
+ * bytes. If the BigInteger is null, exactly 1 byte is written. Otherwise,
+ * the amount written can be determined by calling calculateEncodedLength.
+ *
+ * @param value byte array value to encode, may be null
+ * @param dst destination for encoded bytes
+ * @param dstOffset offset into destination array
+ * @return amount of bytes written
+ * @since 1.2
+ */
+ public static int encode(BigInteger value, byte[] dst, int dstOffset) {
+ if (value == null) {
+ dst[dstOffset] = NULL_BYTE_HIGH;
+ return 1;
+ }
+
+ byte[] bytes = value.toByteArray();
+ // Always at least one.
+ int bytesLength = bytes.length;
+
+ int headerSize;
+ if (bytesLength < 0x7f) {
+ // First byte is 0x02..0x7f for negative values and 0x80..0xfd for
+ // positive values.
+ if (value.signum() < 0) {
+ dst[dstOffset] = (byte) (0x80 - bytesLength);
+ } else {
+ dst[dstOffset] = (byte) (bytesLength + 0x7f);
+ }
+ headerSize = 1;
+ } else {
+ dst[dstOffset] = (byte) (value.signum() < 0 ? 1 : 0xfe);
+ int encodedLen = value.signum() < 0 ? -bytesLength : bytesLength;
+ DataEncoder.encode(encodedLen, dst, dstOffset + 1);
+ headerSize = 5;
+ }
+
+ System.arraycopy(bytes, 0, dst, headerSize + dstOffset, bytesLength);
+
+ return headerSize + bytesLength;
+ }
+
+ /**
+ * Encodes the given optional BigInteger into a variable amount of bytes
+ * for descending order. If the BigInteger is null, exactly 1 byte is
+ * written. Otherwise, the amount written can be determined by calling
+ * calculateEncodedLength.
+ *
+ * @param value byte array value to encode, may be null
+ * @param dst destination for encoded bytes
+ * @param dstOffset offset into destination array
+ * @return amount of bytes written
+ * @since 1.2
+ */
+ public static int encodeDesc(BigInteger value, byte[] dst, int dstOffset) {
+ if (value == null) {
+ dst[dstOffset] = NULL_BYTE_LOW;
+ return 1;
+ }
+
+ byte[] bytes = value.toByteArray();
+ // Always at least one.
+ int bytesLength = bytes.length;
+
+ int headerSize;
+ if (bytesLength < 0x7f) {
+ // First byte is 0x02..0x7f for negative values and 0x80..0xfd for
+ // positive values.
+ if (value.signum() < 0) {
+ dst[dstOffset] = (byte) (bytesLength + 0x7f);
+ } else {
+ dst[dstOffset] = (byte) (0x80 - bytesLength);
+ }
+ headerSize = 1;
+ } else {
+ dst[dstOffset] = (byte) (value.signum() < 0 ? 0xfe : 1);
+ int encodedLen = value.signum() < 0 ? bytesLength : -bytesLength;
+ DataEncoder.encode(encodedLen, dst, dstOffset + 1);
+ headerSize = 5;
+ }
+
+ dstOffset += headerSize;
+ for (int i=0; i<bytesLength; i++) {
+ dst[dstOffset + i] = (byte) ~bytes[i];
+ }
+
+ return headerSize + bytesLength;
+ }
+
+ /**
+ * Returns the amount of bytes required to encode a BigInteger.
+ *
+ * @param value BigInteger value to encode, may be null
+ * @return amount of bytes needed to encode
+ * @since 1.2
+ */
+ public static int calculateEncodedLength(BigInteger value) {
+ if (value == null) {
+ return 1;
+ }
+ int bytesLength = (value.bitLength() >> 3) + 1;
+ return bytesLength < 0x7f ? (1 + bytesLength) : (5 + bytesLength);
+ }
+
+ /**
* Encodes the given optional unsigned byte array into a variable amount of
* bytes. If the byte array is null, exactly 1 byte is written. Otherwise,
* the amount written can be determined by calling calculateEncodedLength.