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