summaryrefslogtreecommitdiff
path: root/src/varint.c
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2011-05-25 13:59:21 +0200
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2011-05-25 14:05:28 +0200
commit52049f3d0a61e93879a8c783f2ac8225d9322905 (patch)
treecc1e677dc72bf76069d92dacf3e6baca91719c98 /src/varint.c
parent46a635499b56969dfd38132ab5062afd4ee7b1cc (diff)
downloadcmumble-52049f3d0a61e93879a8c783f2ac8225d9322905.tar.gz
cmumble-52049f3d0a61e93879a8c783f2ac8225d9322905.tar.bz2
cmumble-52049f3d0a61e93879a8c783f2ac8225d9322905.zip
Talk!
Diffstat (limited to 'src/varint.c')
-rw-r--r--src/varint.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/varint.c b/src/varint.c
new file mode 100644
index 0000000..da7e480
--- /dev/null
+++ b/src/varint.c
@@ -0,0 +1,103 @@
+#include <stdint.h>
+
+void
+encode_varint(uint8_t *data, uint32_t *write, int64_t value, uint32_t left)
+{
+ uint32_t pos = 0;
+
+ if (value < 0) {
+ *write = 0;
+ return;
+ }
+
+ if (value < 0x80) {
+ data[pos++] = value & 0xFF;
+ } else if (value < 0x4000) {
+ data[pos++] = 0x80 | ((value & 0xFF00 ) >> 8);
+ data[pos++] = value & 0xFF;
+ } else if (value < 0x200000) {
+ data[pos++] = 0xC0 | ((value & 0xFF0000) >> 16);
+ data[pos++] = ((value & 0xFF00) >> 8) & 0xFF;
+ data[pos++] = value & 0xFF;
+ } else if (value < 0x10000000) {
+ data[pos++] = 0xE0 | ((value ) >> 24);
+ data[pos++] = (value >> 16) & 0xFF;
+ data[pos++] = (value >> 8) & 0xFF;
+ data[pos++] = value & 0xFF;
+ } else if (value < 0x100000000LL) {
+ data[pos++] = 0xF0;
+ data[pos++] = (value >> 24) & 0xFF;
+ data[pos++] = (value >> 16) & 0xFF;
+ data[pos++] = (value >> 8) & 0xFF;
+ data[pos++] = value & 0xFF;
+ } else {
+ data[pos++] = 0xF4;
+ data[pos++] = (value >> 56) & 0xFF;
+ data[pos++] = (value >> 48) & 0xFF;
+ data[pos++] = (value >> 40) & 0xFF;
+ data[pos++] = (value >> 32) & 0xFF;
+ data[pos++] = (value >> 24) & 0xFF;
+ data[pos++] = (value >> 16) & 0xFF;
+ data[pos++] = (value >> 8) & 0xFF;
+ data[pos++] = value & 0xFF;
+ }
+
+ *write = pos;
+}
+
+int64_t
+decode_varint(uint8_t *data, uint32_t *read, uint32_t left)
+{
+ int64_t varint = 0;
+
+ /* 1 byte with 7 · 8 + 1 leading zeroes */
+ if ((data[0] & 0x80) == 0x00) {
+ varint = data[0] & 0x7F;
+ *read = 1;
+ /* 2 bytes with 6 · 8 + 2 leading zeroes */
+ } else if ((data[0] & 0xC0) == 0x80) {
+ varint = ((data[0] & 0x3F) << 8) | data[1];
+ *read = 2;
+ /* 3 bytes with 5 · 8 + 3 leading zeroes */
+ } else if ((data[0] & 0xE0) == 0xC0) {
+ varint = (((data[0] & 0x1F) << 16) |
+ (data[1] << 8) | (data[2]));
+ *read = 3;
+ /* 4 bytes with 4 · 8 + 4 leading zeroes */
+ } else if ((data[0] & 0xF0) == 0xE0) {
+ varint = (((data[0] & 0x0F) << 24) | (data[1] << 16) |
+ (data[2] << 8) | (data[3]));
+ *read = 4;
+ } else /* if ((data[pos] & 0xF0) == 0xF0) */ {
+ switch (data[0] & 0xFC) {
+ /* 32-bit positive number */
+ case 0xF0:
+ varint = ((data[1] << 24) | (data[2] << 16) |
+ (data[3] << 8) | data[4]);
+ *read = 1 + 4;
+ break;
+ /* 64-bit number */
+ case 0xF4:
+ varint =
+ ((int64_t)data[1] << 56) | ((int64_t)data[2] << 48) |
+ ((int64_t)data[3] << 40) | ((int64_t)data[4] << 32) |
+ (data[5] << 24) | (data[6] << 16) |
+ (data[7] << 8) | (data[8] << 0);
+ *read = 1 + 8;
+ break;
+ /* Negative varint */
+ case 0xF8:
+ /* FIXME: handle endless recursion */
+ varint = -decode_varint(&data[1], read, left - 1);
+ *read += 1;
+ break;
+ /* Negative two bit number */
+ case 0xFC:
+ varint = -(int)(data[0] & 0x03);
+ *read = 1;
+ break;
+ }
+ }
+
+ return varint;
+}