Created
May 12, 2009 11:36
-
-
Save ArtemGr/110426 to your computer and use it in GitHub Desktop.
VariableLengthInteger
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Format should be compatible with the one described in http://www.dlugosz.com/ZIP2/VLI.html, | |
* although we currently use and support only the first "0", "10" and "11" selectors. */ | |
object VariableLengthInteger { | |
/** Encodes an unsigned integer with a value up to 134217727. | |
* Returns the position in the "out" array directly after the encoded integer. */ | |
def encodeInt (num: Int, out: Array[Byte], pos: Int): Int = { | |
if (num < 0) throw new Exception ("Signed integers are not supported.") | |
else if (num <= 127) {out(pos) = num.toByte; pos + 1} | |
// Integer.toString (Integer.parseInt ("10000000", 2), 16) == "80" | |
else if (num <= 16383) {out(pos) = (0x80 + (num >>> 8)).toByte; out(pos+1) = (num & 0xFF).toByte; pos + 2} | |
// Integer.toString (Integer.parseInt ("11000000", 2), 16) == "c0" | |
else if (num <= 2097151) {out(pos) = (0xC0 + (num >>> 16)).toByte; | |
out(pos+1) = ((num >>> 8) & 0xFF).toByte; out(pos+2) = (num & 0xFF).toByte; pos + 3} | |
// Integer.toString (Integer.parseInt ("11100" + "000", 2), 16) == "e0" | |
else if (num <= 134217727) {out(pos) = (0xE0 + (num >>> 24)).toByte; | |
out(pos+1) = ((num >>> 16) & 0xFF).toByte; out(pos+2) = ((num >>> 8) & 0xFF).toByte; | |
out(pos+3) = (num & 0xFF).toByte; pos + 4} | |
else throw new Exception ("Encoding integers larger than 134,217,727 is not supported: " + num) | |
} | |
/** Decodes an unsigned variable-length integer with a value up to 134217727. | |
* Returns the position in the "in" array directly after the decoded integer and the integer itself. */ | |
def decodeInt (in: Array[Byte], pos: Int): (Int, Int) = { | |
val first = in(pos) | |
if ((first & 0x80) == 0) (pos + 1, first & 0x7F) // "0" | |
else if ((first & 0xC0) == 0x80) (pos + 2, ((first & 0x3F) << 8) + (in(pos+1) & 0xFF)) // "10" | |
else if ((first & 0xE0) == 0xC0) (pos + 3, ((first & 0x1F) << 16) + ((in(pos+1) & 0xFF) << 8) + (in(pos+2) & 0xFF)) // "11" | |
else if ((first & 0xF8) == 0xE0) (pos + 4, ((first & 0x7) << 24) + ((in(pos+1) & 0xFF) << 16) + // "111 00" | |
((in(pos+2) & 0xFF) << 8) + (in(pos+3) & 0xFF)) | |
else throw new Exception ("Unsupported variable-length integer selector - 111 01") | |
} | |
def test: Unit = { | |
val buf = new Array[Byte] (10) | |
assert (encodeInt (0, buf, 0) == 1); assert (decodeInt (buf, 0) == (1, 0)) | |
assert (encodeInt (9, buf, 0) == 1); assert (decodeInt (buf, 0) == (1, 9)) | |
assert (encodeInt (127, buf, 0) == 1); assert (decodeInt (buf, 0) == (1, 127)) | |
assert (encodeInt (128, buf, 0) == 2); assert (decodeInt (buf, 0) == (2, 128), decodeInt (buf, 0)) | |
assert (encodeInt (16383, buf, 0) == 2); assert (decodeInt (buf, 0) == (2, 16383), decodeInt (buf, 0)) | |
assert (encodeInt (16384, buf, 0) == 3); assert (decodeInt (buf, 0) == (3, 16384)) | |
assert (encodeInt (2097151, buf, 0) == 3); assert (decodeInt (buf, 0) == (3, 2097151), decodeInt (buf, 0)) | |
assert (encodeInt (12345678, buf, 0) == 4); assert (decodeInt (buf, 0) == (4, 12345678), decodeInt (buf, 0)) | |
assert (encodeInt (123456789, buf, 0) == 4); assert (decodeInt (buf, 0) == (4, 123456789), decodeInt (buf, 0)) | |
assert (encodeInt (134217727, buf, 0) == 4); assert (decodeInt (buf, 0) == (4, 134217727), decodeInt (buf, 0)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment