Add binary operations for lua
This is something I was always missing - posibbility to operate on binary files or streams in pure lua. In most cases we do only need to read simple variables from files such as integers with different amount of bytes. This "class" will provide that ability. It's a simple implementation of following C module for lua: http://www.inf.puc-rio.br/~roberto/struct/ It has much less, though. Following elements have been implemented: ">" flag to set mode to big endian. "<" flag to set mode to little endian. "b" a signed char. "B" an unsigned char. "h" a signed short (2 bytes). "H" an unsigned short (2 bytes). "i" a signed int (4 bytes). "I" an unsigned int (4 bytes). "l" a signed long (8 bytes). "L" an unsigned long (8 bytes). "s" a zero-terminated string. An example how to use it: ```lua local packed = Struct.pack('<LIhBsb', 123456789123456789, 123456789, -3200, 255, 'Test message', -1) -- packed is now a lua string we can save to file as binary data local L, I, h, B, s, b = Struct.unpack('<LIhBsb', packed) print(L, I, h, B, s, b) ``` You can use g_resources.readFileContents as function to read binary files and parse them via this class.
This commit is contained in:
parent
0597ded1d3
commit
7ea6c46b2c
|
@ -10,6 +10,7 @@ Module
|
||||||
dofile 'string'
|
dofile 'string'
|
||||||
dofile 'table'
|
dofile 'table'
|
||||||
dofile 'bitwise'
|
dofile 'bitwise'
|
||||||
|
dofile 'struct'
|
||||||
|
|
||||||
dofile 'const'
|
dofile 'const'
|
||||||
dofile 'util'
|
dofile 'util'
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
Struct = {}
|
||||||
|
|
||||||
|
function Struct.pack(format, ...)
|
||||||
|
local stream = ''
|
||||||
|
local vars = {...}
|
||||||
|
local endianness = true
|
||||||
|
|
||||||
|
for i = 1, string.len(format) do
|
||||||
|
local opt = string.sub(format, i, i)
|
||||||
|
|
||||||
|
if opt == '<' or opt == '>' then
|
||||||
|
endianness = opt == '<' and true or false
|
||||||
|
elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then
|
||||||
|
local val = tonumber(table.remove(vars, 1))
|
||||||
|
local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1
|
||||||
|
|
||||||
|
if val < 0 then
|
||||||
|
val = val + 2 ^ (n * 8 - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local binary = ''
|
||||||
|
for j = 1, n do
|
||||||
|
binary = binary .. string.char(val % (2 ^ 8))
|
||||||
|
val = math.floor(val / (2 ^ 8))
|
||||||
|
end
|
||||||
|
|
||||||
|
if not endianness then
|
||||||
|
binary = string.reverse(binary)
|
||||||
|
end
|
||||||
|
|
||||||
|
stream = stream .. binary
|
||||||
|
elseif opt == 's' then
|
||||||
|
stream = stream .. tostring(table.remove(vars, 1))
|
||||||
|
stream = stream .. string.char(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return stream
|
||||||
|
end
|
||||||
|
|
||||||
|
function Struct.unpack(format, stream)
|
||||||
|
local vars = {}
|
||||||
|
local endianness = true
|
||||||
|
|
||||||
|
for i = 1, string.len(format) do
|
||||||
|
local opt = string.sub(format, i, i)
|
||||||
|
|
||||||
|
if opt == '<' or opt == '>' then
|
||||||
|
endianness = opt == '<' and true or false
|
||||||
|
elseif opt == 'b' or opt == 'B' or opt == 'h' or opt == 'H' or opt == 'i' or opt == 'I' or opt == 'l' or opt == 'L' then
|
||||||
|
local n = ((opt == 'h' or opt == 'H') and 2) or ((opt == 'i' or opt == 'I') and 4) or ((opt == 'l' or opt == 'L') and 8) or 1
|
||||||
|
local signed = opt == 'b' or opt == 'h' or opt == 'i'
|
||||||
|
|
||||||
|
local val = 0
|
||||||
|
for j = 1, n do
|
||||||
|
local byte = string.byte(string.sub(stream, 1, 1))
|
||||||
|
if endianness then
|
||||||
|
val = val + byte * (2 ^ ((j - 1) * 8))
|
||||||
|
else
|
||||||
|
val = val + byte * (2 ^ ((n - j) * 8))
|
||||||
|
end
|
||||||
|
stream = string.sub(stream, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
if signed then
|
||||||
|
val = val - 2 ^ (n * 8 - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(vars, val)
|
||||||
|
elseif opt == 's' then
|
||||||
|
local str = ''
|
||||||
|
for j = 1, string.len(stream) do
|
||||||
|
if string.sub(stream, j, j) == string.char(0) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
str = str .. string.sub(stream, j, j)
|
||||||
|
end
|
||||||
|
|
||||||
|
stream = string.sub(stream, string.len(str) + 2)
|
||||||
|
table.insert(vars, str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return unpack(vars)
|
||||||
|
end
|
Loading…
Reference in New Issue