blob: 1ad9bd159644b7dd2acd6a6350eb00f0b51e85fd [file] [log] [blame]
James Kuszmaul8e62b022022-03-22 09:33:25 -07001local bit = require("bit")
2local ffi = require("ffi")
3local band = bit.band
4local bnot = bit.bnot
5
6
7local m = {}
8local Uint8Bound = 256 -- bound is the max uintN + 1
9local Uint16Bound = 65536
10local Uint32Bound = 4294967296
11
12if not table.unpack then
13 table.unpack = unpack
14end
15
16if not table.pack then
17 table.pack = pack
18end
19
20m.GetAlignSize = function(k, size)
21 return band((bnot(k) + 1), (size - 1))
22end
23
24
25local function pack_I1(n)
26 return string.char(n)
27end
28local function pack_i1(n)
29 if n < 0 then
30 n = Uint8Bound + n
31 end
32 return pack_I1(n)
33end
34
35local function unpack_I1(n, pos)
36 return string.byte(n, pos)
37end
38local 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
44end
45
46local b2 = ffi.new("unsigned char[2]")
47local 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)
53end
54local function pack_i2(n)
55 if n < 0 then
56 n = Uint16Bound + n
57 end
58 return pack_I2(n)
59end
60
61local function unpack_I2(n, pos)
62 local a, b = string.byte(n, pos, pos + 1)
63 return b * Uint8Bound + a
64end
65local 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
71end
72
73local b4 = ffi.new("unsigned char[4]")
74local 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)
80end
81local function pack_i4(n)
82 if n < 0 then
83 n = Uint32Bound + n
84 end
85 return pack_I4(n)
86end
87
88local 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
91end
92local 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
98end
99
100local b8 = ffi.new("unsigned char[8]")
101local 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)
114end
115local function pack_i8(n)
116 n = ffi.cast("signed long long", n)
117 return pack_I8(n)
118end
119
120local 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
126end
127local function unpack_i8(n, pos)
128 local res = unpack_I8(n, pos)
129 return ffi.cast("signed long long", res)
130end
131
132local bf = ffi.new("float[1]")
133local function pack_f(n)
134 bf[0] = n
135 return ffi.string(bf, 4)
136end
137
138local function unpack_f(n, pos)
139 ffi.copy(bf, ffi.cast("char *", n) + pos - 1, 4)
140 return tonumber(bf[0])
141end
142
143local bd = ffi.new("double[1]")
144local function pack_d(n)
145 bd[0] = n
146 return ffi.string(bd, 8)
147end
148
149local function unpack_d(n, pos)
150 ffi.copy(bd, ffi.cast("char *", n) + pos - 1, 8)
151 return tonumber(bd[0])
152end
153
154
155m.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
179end
180
181
182m.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
210end
211
212
213return m