From 9558c829e05b68d79216969128183b6567b8e1bc Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sun, 20 Jul 2008 01:43:15 +0000 Subject: Added utilities for encoding and decoding BigDecimals. --- .../java/com/amazon/carbonado/raw/KeyDecoder.java | 222 +++++++++++++++++---- 1 file changed, 183 insertions(+), 39 deletions(-) (limited to 'src/main/java/com/amazon/carbonado/raw/KeyDecoder.java') diff --git a/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java b/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java index 8c4bf02..dc838e6 100644 --- a/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java +++ b/src/main/java/com/amazon/carbonado/raw/KeyDecoder.java @@ -18,6 +18,7 @@ package com.amazon.carbonado.raw; +import java.math.BigDecimal; import java.math.BigInteger; import com.amazon.carbonado.CorruptEncodingException; @@ -346,30 +347,37 @@ public class KeyDecoder { 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; + byte[] bytes; + + try { + int header = src[srcOffset]; + if (header == NULL_BYTE_HIGH || header == NULL_BYTE_LOW) { + valueRef[0] = null; + return 1; + } + + header &= 0xff; + + if (header > 1 && header < 0xfe) { + if (header < 0x80) { + bytesLength = 0x80 - header; + } else { + bytesLength = header - 0x7f; + } + headerSize = 1; } else { - bytesLength = header - 0x7f; + bytesLength = Math.abs(DataDecoder.decodeInt(src, srcOffset + 1)); + headerSize = 5; } - headerSize = 1; - } else { - bytesLength = Math.abs(DataDecoder.decodeInt(src, srcOffset + 1)); - headerSize = 5; + + bytes = new byte[bytesLength]; + System.arraycopy(src, srcOffset + headerSize, bytes, 0, bytesLength); + } catch (IndexOutOfBoundsException e) { + throw new CorruptEncodingException(null, e); } - byte[] bytes = new byte[bytesLength]; - System.arraycopy(src, srcOffset + headerSize, bytes, 0, bytesLength); valueRef[0] = new BigInteger(bytes); return headerSize + bytesLength; } @@ -387,39 +395,175 @@ public class KeyDecoder { 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; + byte[] bytes; + + try { + int header = src[srcOffset]; + if (header == NULL_BYTE_HIGH || header == NULL_BYTE_LOW) { + valueRef[0] = null; + return 1; + } + + header &= 0xff; + + if (header > 1 && header < 0xfe) { + if (header < 0x80) { + bytesLength = 0x80 - header; + } else { + bytesLength = header - 0x7f; + } + headerSize = 1; } else { - bytesLength = header - 0x7f; + bytesLength = Math.abs(DataDecoder.decodeInt(src, srcOffset + 1)); + headerSize = 5; } - headerSize = 1; - } else { - bytesLength = Math.abs(DataDecoder.decodeInt(src, srcOffset + 1)); - headerSize = 5; - } - byte[] bytes = new byte[bytesLength]; + bytes = new byte[bytesLength]; - srcOffset += headerSize; - for (int i=0; i 0 && header < 0xff) { + scale = header - 0x80; + } else { + scale = DataDecoder.decodeInt(src, srcOffset); + srcOffset += 4; + } + + unscaledValue = unscaledRef[0]; + if (unscaledValue.signum() < 0) { + scale = ~scale; + } + } catch (IndexOutOfBoundsException e) { + throw new CorruptEncodingException(null, e); + } + + valueRef[0] = new BigDecimal(unscaledValue, scale); + return srcOffset - originalOffset; + } + + /** + * Decodes the given BigDecimal as originally encoded for descending order. + * + * @param src source of encoded data + * @param srcOffset offset into encoded data + * @param valueRef decoded BigDecimal 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, BigDecimal[] valueRef) + throws CorruptEncodingException + { + final int originalOffset; + BigInteger unscaledValue; + int scale; + + try { + int header = src[srcOffset] & 0xff; + + int headerSize; + switch (header) { + case (NULL_BYTE_HIGH & 0xff): case (NULL_BYTE_LOW & 0xff): + valueRef[0] = null; + return 1; + + case 0x7f: case 0x80: + valueRef[0] = BigDecimal.ZERO; + return 1; + + case 1: case 0x7e: case 0x81: case 0xfe: + headerSize = 5; + break; + + default: + headerSize = 1; + break; + } + + originalOffset = srcOffset; + srcOffset += headerSize; + + BigInteger[] unscaledRef = new BigInteger[1]; + srcOffset += decodeDesc(src, srcOffset, unscaledRef); + + header = src[srcOffset++] & 0xff; + if (header > 0 && header < 0xff) { + scale = 0x7f - header; + } else { + scale = ~DataDecoder.decodeInt(src, srcOffset); + srcOffset += 4; + } + + unscaledValue = unscaledRef[0]; + if (unscaledValue.signum() < 0) { + scale = ~scale; + } + } catch (IndexOutOfBoundsException e) { + throw new CorruptEncodingException(null, e); + } + + valueRef[0] = new BigDecimal(unscaledValue, scale); + return srcOffset - originalOffset; + } + /** * Decodes the given byte array as originally encoded for ascending order. * The decoding stops when any kind of terminator or illegal byte has been -- cgit v1.2.3