118 lines
2.5 KiB
Lua
Executable File
118 lines
2.5 KiB
Lua
Executable File
-- write formats
|
|
-- return true if they have consumed a value from the input stream
|
|
-- return false/nil otherwise (ie, the next value will be preserved
|
|
-- for subsequent calls, eg skip/pad)
|
|
-- Copyright © 2008 Ben "ToxicFrog" Kelly; see COPYING
|
|
|
|
local name = (...):gsub('%.[^%.]+$', '')
|
|
local struct = require (name)
|
|
local common = require (name..".common")
|
|
local write = setmetatable({}, { __index = common })
|
|
local fp = require (name..".fp")
|
|
|
|
-- boolean
|
|
function write.b(fd, d, w)
|
|
return write.u(fd, (d and 1) or 0, w)
|
|
end
|
|
|
|
-- counted string
|
|
-- a string immediately prefaced with its length as a uint
|
|
function write.c(fd, d, w)
|
|
write.u(fd, #d, w)
|
|
return write.s(fd, d)
|
|
end
|
|
|
|
-- floating point
|
|
function write.f(fd, d, w)
|
|
if not fp.w[w] then
|
|
error("struct.pack: illegal floating point width")
|
|
end
|
|
-- local f = fp.w[w](d)
|
|
-- print(f, type(f))
|
|
return write.s(fd, fp.w[w](d), w)
|
|
end
|
|
|
|
-- signed int
|
|
function write.i(fd, d, w)
|
|
if d < 0 then
|
|
d = d + 2^(w*8)
|
|
end
|
|
return write.u(fd, d, w)
|
|
end
|
|
|
|
-- bitmask
|
|
-- we use a string here because using an unsigned will lose data on bitmasks
|
|
-- wider than lua's native number format
|
|
function write.m(fd, d, w)
|
|
local buf = ""
|
|
|
|
for i=1,w*8,8 do
|
|
local bits = { unpack(d, i, i+7) }
|
|
local byte = string.char(struct.implode(bits))
|
|
if write.is_bigendian then
|
|
buf = byte..buf
|
|
else
|
|
buf = buf..byte
|
|
end
|
|
end
|
|
return write.s(fd, buf, w)
|
|
end
|
|
|
|
-- fixed point bit aligned
|
|
function write.P(fd, d, dp, fp)
|
|
assert((dp+fp) % 8 == 0, "total width of fixed point value must be byte multiple")
|
|
return write.u(fd, d * 2^fp, (dp+fp)/8)
|
|
end
|
|
|
|
-- fixed point byte aligned
|
|
function write.p(fd, d, dp, fp)
|
|
return write.P(fd, d, dp*8, fp*8)
|
|
end
|
|
|
|
-- fixed length string
|
|
-- length 0 is write string as is
|
|
-- length >0 is write exactly w bytes, truncating or padding as needed
|
|
function write.s(fd, d, w)
|
|
w = w or #d
|
|
if #d < w then
|
|
d = d..string.char(0):rep(w-#d)
|
|
end
|
|
return fd:write(d:sub(1,w))
|
|
end
|
|
|
|
-- unsigned int
|
|
function write.u(fd, d, w)
|
|
local s = ""
|
|
|
|
for i=1,w do
|
|
if write.is_bigendian then
|
|
s = string.char(d % 2^8) .. s
|
|
else
|
|
s = s .. string.char(d % 2^8)
|
|
end
|
|
d = math.floor(d/2^8)
|
|
end
|
|
|
|
return write.s(fd, s, w)
|
|
end
|
|
|
|
-- skip/pad
|
|
function write.x(fd, d, w)
|
|
write.s(fd, "", w)
|
|
return false
|
|
end
|
|
|
|
-- null terminated string
|
|
-- w==nil is write string as is + termination
|
|
-- w>0 is write exactly w bytes, truncating/padding and terminating
|
|
function write.z(fd, d, w)
|
|
w = w or #d+1
|
|
if #d >= w then
|
|
d = d:sub(1, w-1)
|
|
end
|
|
|
|
return write.s(fd, d.."\0", w)
|
|
end
|
|
|
|
return write
|