123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- #include "pack.h"
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Pack
- //
- int Pack(ui8* buf, ui32 value) {
- ui8* p = buf;
- for (;;) {
- ui8 v = (ui8)value & 0x7f;
- value >>= 7;
- if (!value) {
- *p++ = v;
- break;
- }
- *p++ = (v | 0x80);
- }
- return (int)(p - buf);
- }
- ui32 Unpack(const ui8*& data) {
- ui32 value = 0;
- const ui8* p = data;
- for (int off = 0;; ++p, off += 7) {
- value |= (*p & 0x7f) << off;
- if ((*p & 0x80) == 0) {
- ++p;
- break;
- }
- }
- data = p;
- return value;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PackU32
- //
- int PackU32(ui32 value, void* buf) {
- ui8* p = (ui8*)buf; // 654 3210 <-- bit of 'value' (7 bits total)
- if (value < (1u << 7)) { // [0--- ----]
- p[0] = (ui8)value; // ^ ^
- return 1; // MSB LSB
- }
- value -= (1u << 7); // DC BA98 7654 3210 <-- bit of 'value' (14 == 0xD bits total)
- if (value < (1u << 14)) { // [10-- ----] [---- ----]
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0x80 | (ui8)value;
- return 2;
- }
- value -= (1u << 14); // And so on...
- if (value < (1u << 21)) { // [110- ----] [---- ----] [---- ----]
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xc0 | (ui8)value;
- return 3;
- }
- value -= (1u << 21);
- if (value < (1u << 28)) { // [1110 ----] [---- ----] [---- ----] [---- ----]
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xe0 | (ui8)value;
- return 4;
- } // ...but for largest numbers, whole first byte is reserved.
- value -= (1u << 28); // [1111 0000] [---- ----] [---- ----] [---- ----] [---- ----]
- p[4] = (ui8)value; value >>= 8;
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value;
- p[0] = 0xf0;
- return 5;
- }
- int UnpackU32(ui32* value, const void* buf) {
- const ui8* p = (const ui8*)buf;
- ui8 b = p[0];
- if (!(b & 0x80)) {
- *value = b;
- return 1;
- }
- if (!(b & 0x40)) {
- *value = 0x80 + (((b & 0x3f) << 8) | p[1]);
- return 2;
- }
- if (!(b & 0x20)) {
- *value = 0x4080 + (((b & 0x1f) << 16) | (p[1] << 8) | p[2]);
- return 3;
- }
- if (!(b & 0x10)) {
- *value = 0x204080 + (((b & 0x0f) << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
- return 4;
- }
- *value = 0x10204080 + ((p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]);
- return 5;
- }
- int SkipU32(const void* buf) {
- static const i8 skip[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5 };
- int i = ((const ui8*)buf)[0] >> 4;
- return skip[i];
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PackU64
- //
- int PackU64(ui64 value, void* buf) { // Packing scheme is analogous to PackU32()
- ui8* p = (ui8*)buf;
- if (value < (1u << 7)) {
- p[0] = (ui8)value;
- return 1;
- }
- value -= (1u << 7);
- if (value < (1u << 14)) {
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0x80 | (ui8)value;
- return 2;
- }
- value -= (1u << 14);
- if (value < (1u << 21)) {
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xc0 | (ui8)value;
- return 3;
- }
- value -= (1u << 21);
- if (value < (1u << 28)) {
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xe0 | (ui8)value;
- return 4;
- }
- value -= (1u << 28);
- if (value < (ui64(1) << 35)) {
- p[4] = (ui8)value; value >>= 8;
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xf0 | (ui8)value;
- return 5;
- }
- value -= ui64(1) << 35;
- if (value < (ui64(1) << 42)) {
- p[5] = (ui8)value; value >>= 8;
- p[4] = (ui8)value; value >>= 8;
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xf8 | (ui8)value;
- return 6;
- }
- value -= ui64(1) << 42;
- if (value < (ui64(1) << 49)) { // [1111 110-] [---- ----] ... (+ 5 bytes)
- p[6] = (ui8)value; value >>= 8;
- p[5] = (ui8)value; value >>= 8;
- p[4] = (ui8)value; value >>= 8;
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xfc | (ui8)value;
- return 7;
- }
- value -= ui64(1) << 49;
- if (value < (ui64(1) << 56)) { // [1111 1110] [---- ----] ... (+ 6 bytes)
- p[7] = (ui8)value; value >>= 8;
- p[6] = (ui8)value; value >>= 8;
- p[5] = (ui8)value; value >>= 8;
- p[4] = (ui8)value; value >>= 8;
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xfe | (ui8)value;
- return 8;
- }
- value -= ui64(1) << 56; // [1111 1111] [---- ----] ... (+ 7 bytes)
- p[8] = (ui8)value; value >>= 8; // ^
- p[7] = (ui8)value; value >>= 8; // not a zero; contains actual bit
- p[6] = (ui8)value; value >>= 8;
- p[5] = (ui8)value; value >>= 8;
- p[4] = (ui8)value; value >>= 8;
- p[3] = (ui8)value; value >>= 8;
- p[2] = (ui8)value; value >>= 8;
- p[1] = (ui8)value; value >>= 8;
- p[0] = 0xff;
- return 9;
- }
- int UnpackU64(ui64* value, const void* buf) {
- const ui8* p = (const ui8*)buf;
- ui8 b = p[0];
- if (!(b & 0x80)) {
- *value = b;
- return 1;
- }
- if (!(b & 0x40)) {
- *value = 0x80 + (((b & 0x3f) << 8) | p[1]);
- return 2;
- }
- if (!(b & 0x20)) {
- *value = 0x4080 + (((b & 0x1f) << 16) | (p[1] << 8) | p[2]);
- return 3;
- }
- if (!(b & 0x10)) {
- *value = 0x204080 + (((b & 0x0f) << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
- return 4;
- }
- if (!(b & 0x08)) {
- *value = 0x10204080 + (
- (ui64(b & 0x07) << 32) |
- (ui32(p[1]) << 24) |
- ( p[2] << 16) |
- ( p[3] << 8) |
- p[4]
- );
- return 5;
- }
- if (!(b & 0x04)) {
- *value = 0x0810204080ull + (
- (ui64(b & 0x03) << 40) |
- (ui64(p[1]) << 32) |
- (ui32(p[2]) << 24) |
- ( p[3] << 16) |
- ( p[4] << 8) |
- p[5]
- );
- return 6;
- }
- if (!(b & 0x02)) {
- *value = 0x040810204080ull + (
- (ui64(b & 0x01) << 48) |
- (ui64(p[1]) << 40) |
- (ui64(p[2]) << 32) |
- (ui32(p[3]) << 24) |
- ( p[4] << 16) |
- ( p[5] << 8) |
- p[6]
- );
- return 7;
- }
- if (!(b & 0x01)) {
- *value = 0x02040810204080ull + (
- (ui64(p[1]) << 48) |
- (ui64(p[2]) << 40) |
- (ui64(p[3]) << 32) |
- (ui32(p[4]) << 24) |
- ( p[5] << 16) |
- ( p[6] << 8) |
- p[7]
- );
- return 8;
- }
- *value = 0x0102040810204080ull + (
- (ui64(p[1]) << 56) |
- (ui64(p[2]) << 48) |
- (ui64(p[3]) << 40) |
- (ui64(p[4]) << 32) |
- (ui32(p[5]) << 24) |
- ( p[6] << 16) |
- ( p[7] << 8) |
- p[8]
- );
- return 9;
- }
- #define REPEAT_16(x) x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x
- #define REPEAT_32(x) REPEAT_16(x), REPEAT_16(x)
- #define REPEAT_64(x) REPEAT_32(x), REPEAT_32(x)
- #define REPEAT_128(x) REPEAT_64(x), REPEAT_64(x)
- int SkipU64(const void* buf) {
- static const i8 skip[256] = {
- REPEAT_128(1), REPEAT_64(2), REPEAT_32(3), REPEAT_16(4),
- 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 9
- };
- return skip[*(const ui8*)buf];
- }
- #undef REPEAT_16
- #undef REPEAT_32
- #undef REPEAT_64
- #undef REPEAT_128
|