James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame^] | 1 | local bit = require("bit") |
| 2 | local ffi = require("ffi") |
| 3 | local band = bit.band |
| 4 | local bnot = bit.bnot |
| 5 | |
| 6 | |
| 7 | local m = {} |
| 8 | local Uint8Bound = 256 -- bound is the max uintN + 1 |
| 9 | local Uint16Bound = 65536 |
| 10 | local Uint32Bound = 4294967296 |
| 11 | |
| 12 | if not table.unpack then |
| 13 | table.unpack = unpack |
| 14 | end |
| 15 | |
| 16 | if not table.pack then |
| 17 | table.pack = pack |
| 18 | end |
| 19 | |
| 20 | m.GetAlignSize = function(k, size) |
| 21 | return band((bnot(k) + 1), (size - 1)) |
| 22 | end |
| 23 | |
| 24 | |
| 25 | local function pack_I1(n) |
| 26 | return string.char(n) |
| 27 | end |
| 28 | local function pack_i1(n) |
| 29 | if n < 0 then |
| 30 | n = Uint8Bound + n |
| 31 | end |
| 32 | return pack_I1(n) |
| 33 | end |
| 34 | |
| 35 | local function unpack_I1(n, pos) |
| 36 | return string.byte(n, pos) |
| 37 | end |
| 38 | local function unpack_i1(n, pos) |
| 39 | local res = unpack_I1(n, pos) |
| 40 | if res >= Uint8Bound / 2 then |
| 41 | return res - Uint8Bound |
| 42 | end |
| 43 | return res |
| 44 | end |
| 45 | |
| 46 | local b2 = ffi.new("unsigned char[2]") |
| 47 | local function pack_I2(n) |
| 48 | for i = 0, 1 do |
| 49 | b2[i] = bit.band(n, 255) |
| 50 | n = bit.rshift(n, 8) |
| 51 | end |
| 52 | return ffi.string(b2, 2) |
| 53 | end |
| 54 | local function pack_i2(n) |
| 55 | if n < 0 then |
| 56 | n = Uint16Bound + n |
| 57 | end |
| 58 | return pack_I2(n) |
| 59 | end |
| 60 | |
| 61 | local function unpack_I2(n, pos) |
| 62 | local a, b = string.byte(n, pos, pos + 1) |
| 63 | return b * Uint8Bound + a |
| 64 | end |
| 65 | local function unpack_i2(n, pos) |
| 66 | local res = unpack_I2(n, pos) |
| 67 | if res >= Uint16Bound / 2 then |
| 68 | return res - Uint16Bound |
| 69 | end |
| 70 | return res |
| 71 | end |
| 72 | |
| 73 | local b4 = ffi.new("unsigned char[4]") |
| 74 | local function pack_I4(n) |
| 75 | for i = 0, 3 do |
| 76 | b4[i] = bit.band(n, 255) |
| 77 | n = bit.rshift(n, 8) |
| 78 | end |
| 79 | return ffi.string(b4, 4) |
| 80 | end |
| 81 | local function pack_i4(n) |
| 82 | if n < 0 then |
| 83 | n = Uint32Bound + n |
| 84 | end |
| 85 | return pack_I4(n) |
| 86 | end |
| 87 | |
| 88 | local function unpack_I4(n, pos) |
| 89 | local a, b, c, d = string.byte(n, pos, pos + 3) |
| 90 | return Uint8Bound * (Uint8Bound * ((Uint8Bound * d) + c) + b) + a |
| 91 | end |
| 92 | local function unpack_i4(n, pos) |
| 93 | local res = unpack_I4(n, pos) |
| 94 | if res >= Uint32Bound / 2 then |
| 95 | return res - Uint32Bound |
| 96 | end |
| 97 | return res |
| 98 | end |
| 99 | |
| 100 | local b8 = ffi.new("unsigned char[8]") |
| 101 | local function pack_I8(n) |
| 102 | n = ffi.cast("unsigned long long", n) |
| 103 | local hi = math.floor(tonumber(n / Uint32Bound)) |
| 104 | local li = n % Uint32Bound |
| 105 | for i = 0, 3 do |
| 106 | b8[i] = bit.band(li, 255) |
| 107 | li = bit.rshift(li, 8) |
| 108 | end |
| 109 | for i = 4, 7 do |
| 110 | b8[i] = bit.band(hi, 255) |
| 111 | hi = bit.rshift(hi, 8) |
| 112 | end |
| 113 | return ffi.string(b8, 8) |
| 114 | end |
| 115 | local function pack_i8(n) |
| 116 | n = ffi.cast("signed long long", n) |
| 117 | return pack_I8(n) |
| 118 | end |
| 119 | |
| 120 | local function unpack_I8(n, pos) |
| 121 | local a, b, c, d = string.byte(n, pos, pos + 3) |
| 122 | local li = Uint8Bound * (Uint8Bound * ((Uint8Bound * d) + c) + b) + a |
| 123 | local a, b, c, d = string.byte(n, pos + 4, pos + 7) |
| 124 | local hi = Uint8Bound * (Uint8Bound * ((Uint8Bound * d) + c) + b) + a |
| 125 | return ffi.cast("unsigned long long", hi) * Uint32Bound + li |
| 126 | end |
| 127 | local function unpack_i8(n, pos) |
| 128 | local res = unpack_I8(n, pos) |
| 129 | return ffi.cast("signed long long", res) |
| 130 | end |
| 131 | |
| 132 | local bf = ffi.new("float[1]") |
| 133 | local function pack_f(n) |
| 134 | bf[0] = n |
| 135 | return ffi.string(bf, 4) |
| 136 | end |
| 137 | |
| 138 | local function unpack_f(n, pos) |
| 139 | ffi.copy(bf, ffi.cast("char *", n) + pos - 1, 4) |
| 140 | return tonumber(bf[0]) |
| 141 | end |
| 142 | |
| 143 | local bd = ffi.new("double[1]") |
| 144 | local function pack_d(n) |
| 145 | bd[0] = n |
| 146 | return ffi.string(bd, 8) |
| 147 | end |
| 148 | |
| 149 | local function unpack_d(n, pos) |
| 150 | ffi.copy(bd, ffi.cast("char *", n) + pos - 1, 8) |
| 151 | return tonumber(bd[0]) |
| 152 | end |
| 153 | |
| 154 | |
| 155 | m.string_pack = function(fmt, i, ...) |
| 156 | if fmt == "<I1" then |
| 157 | return pack_I1(i) |
| 158 | elseif fmt == "<I2" then |
| 159 | return pack_I2(i) |
| 160 | elseif fmt == "<I4" then |
| 161 | return pack_I4(i) |
| 162 | elseif fmt == "<I8" then |
| 163 | return pack_I8(i) |
| 164 | elseif fmt == "<i1" then |
| 165 | return pack_i1(i) |
| 166 | elseif fmt == "<i2" then |
| 167 | return pack_i2(i) |
| 168 | elseif fmt == "<i4" then |
| 169 | return pack_i4(i) |
| 170 | elseif fmt == "<i8" then |
| 171 | return pack_i8(i) |
| 172 | elseif fmt == "<f" then |
| 173 | return pack_f(i) |
| 174 | elseif fmt == "<d" then |
| 175 | return pack_d(i) |
| 176 | else |
| 177 | error(string.format("FIXME: support fmt %s", fmt)) |
| 178 | end |
| 179 | end |
| 180 | |
| 181 | |
| 182 | m.string_unpack = function(fmt, s, pos) |
| 183 | if not pos then |
| 184 | pos = 1 |
| 185 | end |
| 186 | |
| 187 | if fmt == "<I1" then |
| 188 | return unpack_I1(s, pos) |
| 189 | elseif fmt == "<I2" then |
| 190 | return unpack_I2(s, pos) |
| 191 | elseif fmt == "<I4" then |
| 192 | return unpack_I4(s, pos) |
| 193 | elseif fmt == "<I8" then |
| 194 | return unpack_I8(s, pos) |
| 195 | elseif fmt == "<i1" then |
| 196 | return unpack_i1(s, pos) |
| 197 | elseif fmt == "<i2" then |
| 198 | return unpack_i2(s, pos) |
| 199 | elseif fmt == "<i4" then |
| 200 | return unpack_i4(s, pos) |
| 201 | elseif fmt == "<i8" then |
| 202 | return unpack_i8(s, pos) |
| 203 | elseif fmt == "<f" then |
| 204 | return unpack_f(s, pos) |
| 205 | elseif fmt == "<d" then |
| 206 | return unpack_d(s, pos) |
| 207 | else |
| 208 | error(string.format("FIXME: support fmt %s", fmt)) |
| 209 | end |
| 210 | end |
| 211 | |
| 212 | |
| 213 | return m |