1 /// Little Endian Base - see https://en.wikipedia.org/wiki/LEB128 2 module leb128; 3 4 import std.conv, std.traits, std.outbuffer; 5 6 /// Decode LEB128 value encoded in `buf`. 7 const(T) fromLEB128(T)(const ubyte[] buf, ref size_t processed) { 8 static if (isScalarType!T && !isFloatingPoint!T) { 9 T result; 10 size_t shift; 11 ubyte b; 12 static if (isSigned!T) 13 immutable size = T.sizeof * 8; 14 do { 15 b = buf[processed]; 16 result |= to!T(b & 0x7f) << shift; 17 shift += 7; 18 processed++; 19 } while (b & 0x80); 20 static if (isSigned!T) 21 if ((shift < size) && (b & 0x40) != 0) 22 result |= to!T(~0 << shift); 23 return result; 24 } else { 25 static assert(0, T.stringof ~ " is not an integral type"); 26 } 27 } // fromLEB() 28 29 /// Decode LEB128 value encoded in `buf` into array `val`. 30 void arrayFromLEB128(T)(const ubyte[] buf, ref size_t processed, ref T val) { 31 static if (isArray!T && !isFloatingPoint!(T[0])) { 32 size_t n = processed; 33 foreach (ref result; val) { 34 static if (isSigned!(typeof(val[0]))) 35 immutable size = result.sizeof * 8; 36 size_t shift; 37 ubyte b; 38 do { 39 b = buf[n]; 40 result |= to!(typeof(result))(b & 0x7f) << shift; 41 shift += 7; 42 n++; 43 } while (b & 0x80); 44 static if (isSigned!(typeof(val[0]))) 45 if ((shift < size) && (b & 0x40) != 0) 46 result |= to!(typeof(result))(~0 << shift); 47 } 48 processed = n; 49 } else { 50 static assert(0, T.stringof ~ " is not an integral array type"); 51 } 52 } // arrayFromLEB() 53 54 /// Encode value `_val` of type `T` into given `buf`. 55 void toLEB128(T)(OutBuffer buf, const T _val) { 56 static if (isScalarType!T && !isFloatingPoint!T) { 57 bool more = true; 58 ubyte[32] d; 59 size_t idx; 60 static if (isSigned!T) 61 long val = _val; 62 else 63 ulong val = _val; 64 do { 65 ubyte b = val & 0x7f; 66 val >>= 7; 67 static if (isSigned!T) { 68 if ((val == 0 && (b & 0x40) == 0) || (val == -1 && (b & 0x40) != 0)) 69 more = false; 70 else 71 b |= 0x80; 72 } else { 73 if (val != 0) 74 b |= 0x80; 75 else 76 more = false; 77 } 78 d[idx] = b; 79 idx++; 80 } while (more); 81 if (idx > 0) 82 buf.write(d[0..idx]); 83 } else static if (isArray!T && !isFloatingPoint!(typeof(_val[0]))) { 84 ubyte[8192] d; 85 size_t idx; 86 foreach (v; _val) { 87 bool more = true; 88 static if (isSigned!(typeof(v))) 89 long val = v; 90 else 91 ulong val = v; 92 do { 93 ubyte b = val & 0x7f; 94 val >>= 7; 95 static if (isSigned!(typeof(v))) { 96 if ((val == 0 && (b & 0x40) == 0) || (val == -1 && (b & 0x40) != 0)) 97 more = false; 98 else 99 b |= 0x80; 100 } else { 101 if (val != 0) 102 b |= 0x80; 103 else 104 more = false; 105 } 106 d[idx] = b; 107 if (++idx >= d.length) { 108 buf.write(d); 109 idx = 0; 110 } 111 } while (more); 112 } 113 if (idx > 0) 114 buf.write(d[0..idx]); 115 } else { 116 static assert(0, T.stringof ~ " is not an integral type"); 117 } 118 } // toLEB128()