Add cn option to struct

"cn" a sequence of exactly n chars corresponding to a single lua string.
This commit is contained in:
Konrad Kuśnierz 2015-05-19 18:50:02 +02:00
parent 02ab50d8dd
commit c5ea8c98fb
1 changed files with 38 additions and 21 deletions

View File

@ -5,13 +5,13 @@ function Struct.pack(format, ...)
local vars = {...} local vars = {...}
local endianness = true local endianness = true
for i = 1, string.len(format) do for i = 1, format:len() do
local opt = string.sub(format, i, i) local opt = format:sub(i, i)
if opt == '<' or opt == '>' then if opt == '>' then
endianness = opt == '<' and true or false endianness = 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 elseif opt:find('[bBhHiIlL]') 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 n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1
local val = tonumber(table.remove(vars, 1)) local val = tonumber(table.remove(vars, 1))
if val < 0 then if val < 0 then
@ -29,7 +29,7 @@ function Struct.pack(format, ...)
else else
table.insert(stream, table.concat(bytes)) table.insert(stream, table.concat(bytes))
end end
elseif opt == 'f' or opt == 'd' then elseif opt:find('[fd]') then
local val = tonumber(table.remove(vars, 1)) local val = tonumber(table.remove(vars, 1))
local sign = 0 local sign = 0
@ -74,6 +74,18 @@ function Struct.pack(format, ...)
elseif opt == 's' then elseif opt == 's' then
table.insert(stream, tostring(table.remove(vars, 1))) table.insert(stream, tostring(table.remove(vars, 1)))
table.insert(stream, string.char(0)) table.insert(stream, string.char(0))
elseif opt == 'c' then
local n = format:sub(i + 1):match('%d+')
local length = tonumber(n)
if length > 0 then
local str = tostring(table.remove(vars, 1))
if length - str:len() > 0 then
str = str .. string.rep(' ', length - str:len())
end
table.insert(stream, str:sub(1, length))
end
i = i + n:len()
end end
end end
@ -85,18 +97,18 @@ function Struct.unpack(format, stream)
local iterator = 1 local iterator = 1
local endianness = true local endianness = true
for i = 1, string.len(format) do for i = 1, format:len() do
local opt = string.sub(format, i, i) local opt = format:sub(i, i)
if opt == '<' or opt == '>' then if opt == '>' then
endianness = opt == '<' and true or false endianness = 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 elseif opt:find('[bBhHiIlL]') 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 n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1
local signed = opt == 'b' or opt == 'h' or opt == 'i' local signed = opt:lower() == opt
local val = 0 local val = 0
for j = 1, n do for j = 1, n do
local byte = string.byte(string.sub(stream, iterator, iterator)) local byte = string.byte(stream:sub(iterator, iterator))
if endianness then if endianness then
val = val + byte * (2 ^ ((j - 1) * 8)) val = val + byte * (2 ^ ((j - 1) * 8))
else else
@ -110,9 +122,9 @@ function Struct.unpack(format, stream)
end end
table.insert(vars, val) table.insert(vars, val)
elseif opt == 'f' or opt == 'd' then elseif opt:find('[fd]') then
local n = (opt == 'd') and 8 or 4 local n = (opt == 'd') and 8 or 4
local x = string.sub(stream, iterator, iterator + n - 1) local x = stream:sub(iterator, iterator + n - 1)
iterator = iterator + n iterator = iterator + n
if not endianness then if not endianness then
@ -138,17 +150,22 @@ function Struct.unpack(format, stream)
end end
elseif opt == 's' then elseif opt == 's' then
local bytes = {} local bytes = {}
for j = iterator, string.len(stream) do for j = iterator, stream:len() do
if string.sub(stream, j, j) == string.char(0) then if stream:sub(j, j) == string.char(0) then
break break
end end
table.insert(bytes, string.sub(stream, j, j)) table.insert(bytes, stream:sub(j, j))
end end
local str = table.concat(bytes) local str = table.concat(bytes)
iterator = iterator + string.len(str) + 1 iterator = iterator + str:len() + 1
table.insert(vars, str) table.insert(vars, str)
elseif opt == 'c' then
local n = format:sub(i + 1):match('%d+')
table.insert(vars, stream:sub(iterator, iterator + tonumber(n)))
iterator = iterator + tonumber(n)
i = i + n:len()
end end
end end