dobrograd-13-06-2022/garrysmod/addons/util-dlib/lua/dlib/modules/bytesbuffer.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

1134 lines
21 KiB
Lua

-- Copyright (C) 2017-2020 DBotThePony
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do so,
-- subject to the following conditions:
-- The above copyright notice and this permission notice shall be included in all copies
-- or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.
jit.on()
local DLib = DLib
local meta = FindMetaTable('LBytesBuffer') or {}
debug.getregistry().LBytesBuffer = meta
DLib.BytesBufferMeta = meta
local bitworker = DLib.bitworker
local type = type
local math = math
local assert = assert
local table = table
local rawget = rawget
local rawset = rawset
local setmetatable = setmetatable
local string = string
local bit = bit
local lshift = bit.lshift
local rshift = bit.rshift
local band = bit.band
local bor = bit.bor
local bxor = bit.bxor
meta.__index = meta
--[[
@doc
@fname DLib.BytesBuffer
@args string binary = ''
@desc
entry point of BytesBuffer creation
you can pass a string to it to construct bytes array from it
**BUFFER ONLY WORK WITH BIG ENDIAN BYTES**
@descdesc
@returns
BytesBuffer: newly created object
]]
DLib.BytesBuffer = setmetatable({proto = meta, meta = meta}, {__call = function(self, stringIn)
local obj = setmetatable({}, meta)
obj.bytes = {}
obj.pointer = 0
obj.length = 0
if type(stringIn) == 'string' then
obj.bytes = DLib.string.bbyte(stringIn, 1, #stringIn)
obj.length = #obj.bytes
end
-- obj:Seek(0)
return obj
end})
--[[
@doc
@fname BytesBuffer:Seek
@args number position
@returns
BytesBuffer: self
]]
-- Operations
function meta:Seek(moveTo)
if moveTo < 0 or moveTo > self.length then
error('Seek - invalid position (' .. moveTo .. '; ' .. self.length .. ')', 2)
end
self.pointer = moveTo
return self
end
--[[
@doc
@fname BytesBuffer:Tell
@alias BytesBuffer:Ask
@returns
number: pointer position
]]
function meta:Tell()
return self.pointer
end
meta.Ask = meta.Tell
--[[
@doc
@fname BytesBuffer:Move
@alias BytesBuffer:Walk
@args number delta
@returns
BytesBuffer: self
]]
function meta:Move(moveBy)
return self:Seek(self.pointer + moveBy)
end
meta.Walk = meta.Move
--[[
@doc
@fname BytesBuffer:Reset
@desc
alias of BytesBuffer:Seek(0)
@enddesc
@returns
BytesBuffer: self
]]
function meta:Reset()
return self:Seek(0)
end
--[[
@doc
@fname BytesBuffer:Release
@desc
sets pointer to 0 and removes internal bytes array
@enddesc
@returns
BytesBuffer: self
]]
function meta:Release()
self.pointer = 0
self.bytes = {}
return self
end
--[[
@doc
@fname BytesBuffer:GetBytes
@internal
@returns
table: of integers (for optimization purpose). editing this array will affect the object! be careful
]]
function meta:GetBytes()
return self.bytes
end
local function wrap(num, maximal)
if num >= 0 then
return num
end
return maximal * 2 + num
end
local function unwrap(num, maximal)
if num < maximal then
return num
end
return num - maximal * 2
end
local function assertType(valueIn, desiredType, funcName)
if type(valueIn) == desiredType then return end
error(funcName .. ' - input is not a ' .. desiredType .. '! typeof ' .. type(valueIn), 3)
end
local function assertRange(valueIn, min, max, funcName)
if valueIn >= min and valueIn <= max then return end
error(funcName .. ' - size overflow (' .. min .. ' -> ' .. max .. ' vs ' .. valueIn .. ')', 3)
end
--[[
@doc
@fname BytesBuffer:EndOfStream
@returns
boolean
]]
function meta:EndOfStream()
return self.pointer >= self.length
end
--[[
@doc
@fname BytesBuffer:WriteUByte
@args number value
@returns
BytesBuffer: self
]]
function meta:WriteUByte(valueIn)
assertType(valueIn, 'number', 'WriteUByte')
assertRange(valueIn, 0, 0xFF, 'WriteUByte')
valueIn = math.floor(valueIn)
self.bytes[self.pointer + 1] = valueIn
self.pointer = self.pointer + 1
self.length = #self.bytes
return self
end
--[[
@doc
@fname BytesBuffer:WriteByte_2
@args number value
@desc
with value shift
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteByte
@args number value
@desc
with negative number overflow
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteCHar
@args string char
@returns
BytesBuffer: self
]]
-- Primitive read/write
-- wrap overflow
function meta:WriteByte_2(valueIn)
assertType(valueIn, 'number', 'WriteByte')
assertRange(valueIn, -0x80, 0x7F, 'WriteByte')
return self:WriteUByte(math.floor(valueIn) + 0x80)
end
-- one's component
function meta:WriteByte(valueIn)
assertType(valueIn, 'number', 'WriteByte')
assertRange(valueIn, -0x80, 0x7F, 'WriteByte')
return self:WriteUByte(wrap(math.floor(valueIn), 0x80))
end
meta.WriteInt8 = meta.WriteByte
meta.WriteUInt8 = meta.WriteUByte
function meta:WriteChar(char)
assertType(char, 'string', 'WriteChar')
assert(#char == 1, 'Input is not a single char!')
self:WriteUByte(string.byte(char))
return self
end
--[[
@doc
@fname BytesBuffer:WriteShort_2
@alias BytesBuffer:WriteInt16_2
@args number value
@desc
with value shift
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteShort
@alias BytesBuffer:WriteInt16
@args number value
@desc
with negative number overflow
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteUShort
@alias BytesBuffer:WriteUInt16
@args number value
@returns
BytesBuffer: self
]]
function meta:WriteInt16_2(valueIn)
assertType(valueIn, 'number', 'WriteInt16')
assertRange(valueIn, -0x8000, 0x7FFF, 'WriteInt16')
return self:WriteUInt16(math.floor(valueIn) + 0x8000)
end
function meta:WriteInt16(valueIn)
assertType(valueIn, 'number', 'WriteInt16')
assertRange(valueIn, -0x8000, 0x7FFF, 'WriteInt16')
return self:WriteUInt16(wrap(math.floor(valueIn), 0x8000))
end
function meta:WriteUInt16(valueIn)
assertType(valueIn, 'number', 'WriteUInt16')
assertRange(valueIn, 0, 0xFFFF, 'WriteUInt16')
self.bytes[self.pointer + 1] = band(rshift(valueIn, 8), 0xFF)
self.bytes[self.pointer + 2] = band(valueIn, 0xFF)
self.pointer = self.pointer + 2
self.length = #self.bytes
return self
end
meta.WriteShort = meta.WriteInt16
meta.WriteShort_2 = meta.WriteInt16_2
meta.WriteUShort = meta.WriteUInt16
--[[
@doc
@fname BytesBuffer:WriteInt_2
@alias BytesBuffer:WriteInt32_2
@args number value
@desc
with value shift
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteInt
@alias BytesBuffer:WriteInt32
@args number value
@desc
with negative number overflow
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteUInt
@alias BytesBuffer:WriteUInt32
@args number value
@returns
BytesBuffer: self
]]
function meta:WriteInt32_2(valueIn)
assertType(valueIn, 'number', 'WriteInt32')
assertRange(valueIn, -0x80000000, 0x7FFFFFFF, 'WriteInt32')
return self:WriteUInt32(math.floor(valueIn) + 0x80000000)
end
function meta:WriteInt32(valueIn)
assertType(valueIn, 'number', 'WriteInt32')
assertRange(valueIn, -0x80000000, 0x7FFFFFFF, 'WriteInt32')
return self:WriteUInt32(wrap(math.floor(valueIn), 0x80000000))
end
function meta:WriteUInt32(valueIn)
assertType(valueIn, 'number', 'WriteUInt32')
assertRange(valueIn, 0, 0xFFFFFFFF, 'WriteUInt32')
self.bytes[self.pointer + 1] = band(rshift(valueIn, 24), 0xFF)
self.bytes[self.pointer + 2] = band(rshift(valueIn, 16), 0xFF)
self.bytes[self.pointer + 3] = band(rshift(valueIn, 8), 0xFF)
self.bytes[self.pointer + 4] = band(valueIn, 0xFF)
self.pointer = self.pointer + 4
self.length = #self.bytes
return self
end
meta.WriteInt = meta.WriteInt32
meta.WriteInt_2 = meta.WriteInt32_2
meta.WriteUInt = meta.WriteUInt32
--[[
@doc
@fname BytesBuffer:WriteLong_2
@alias BytesBuffer:WriteInt64_2
@args number value
@desc
with value shift
due to precision errors, this not actually accurate operation
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteLong
@alias BytesBuffer:WriteInt64
@args number value
@desc
with negative number overflow
due to precision errors, this not actually accurate operation
@enddesc
@returns
BytesBuffer: self
]]
--[[
@doc
@fname BytesBuffer:WriteULong
@alias BytesBuffer:WriteUInt64
@args number value
@desc
due to precision errors, this not actually accurate operation
@enddesc
@returns
BytesBuffer: self
]]
function meta:WriteInt64_2(valueIn)
self:WriteUInt64(valueIn + 0x100000000)
return self
end
function meta:WriteInt64(valueIn)
self:WriteUInt64(wrap(valueIn, 0x100000000))
return self
end
function meta:WriteUInt64(valueIn)
self:WriteUInt32((valueIn - valueIn % 0xFFFFFFFF) / 0xFFFFFFFF)
valueIn = valueIn % 0xFFFFFFFF
self:WriteUInt32(valueIn)
return self
end
function meta:CheckOverflow(name, moveBy)
if self.pointer + moveBy > self.length then
error('Read' .. name .. ' - bytes amount overflow (' .. self.pointer .. ' + ' .. moveBy .. ' vs ' .. self.length .. ')', 3)
end
end
meta.WriteLong = meta.WriteInt64
meta.WriteLong_2 = meta.WriteInt64_2
meta.WriteULong = meta.WriteUInt64
--[[
@doc
@fname BytesBuffer:ReadByte_2
@desc
with value shift
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadByte
@desc
with negative number overflow
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadChar
@returns
string
]]
function meta:ReadByte_2()
return self:ReadUByte() - 0x80
end
function meta:ReadByte()
return unwrap(self:ReadUByte(), 0x80)
end
function meta:ReadUByte()
self:CheckOverflow('UByte', 1)
local value = self.bytes[self.pointer + 1]
self.pointer = self.pointer + 1
return value
end
meta.ReadInt8 = meta.ReadByte
meta.ReadUInt8 = meta.ReadUByte
--[[
@doc
@fname BytesBuffer:ReadInt16_2
@desc
with value shift
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadInt16
@desc
with negative number overflow
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadUInt16
@returns
number
]]
function meta:ReadInt16_2()
return self:ReadUInt16() - 0x8000
end
function meta:ReadInt16()
return unwrap(self:ReadUInt16(), 0x8000)
end
function meta:ReadUInt16()
self:CheckOverflow('UInt16', 2)
local value =
lshift(self.bytes[self.pointer + 1], 8) +
self.bytes[self.pointer + 2]
self.pointer = self.pointer + 2
return value
end
--[[
@doc
@fname BytesBuffer:ReadInt32_2
@desc
with value shift
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadInt32
@desc
with negative number overflow
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadUInt32
@returns
number
]]
function meta:ReadInt32_2()
return self:ReadUInt32() - 0x80000000
end
function meta:ReadInt32()
return unwrap(self:ReadUInt32(), 0x80000000)
end
function meta:ReadUInt32()
self:CheckOverflow('UInt32', 4)
local value =
lshift(self.bytes[self.pointer + 1], 24) +
lshift(self.bytes[self.pointer + 2], 16) +
lshift(self.bytes[self.pointer + 3], 8) +
self.bytes[self.pointer + 4]
self.pointer = self.pointer + 4
return value
end
--[[
@doc
@fname BytesBuffer:ReadInt64_2
@desc
with value shift
due to precision errors, this not actually accurate operation
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadInt64
@desc
with negative number overflow
due to precision errors, this not actually accurate operation
@enddesc
@returns
number
]]
--[[
@doc
@fname BytesBuffer:ReadUInt64
@desc
due to precision errors, this not actually accurate operation
@enddesc
@returns
number
]]
function meta:ReadInt64_2()
return self:ReadUInt64() - 0x100000000
end
function meta:ReadInt64()
return unwrap(self:ReadUInt64(), 0x100000000)
end
function meta:ReadUInt64()
self:CheckOverflow('UInt64', 8)
return
self:ReadUByte() * 0x100000000000000 +
self:ReadUByte() * 0x1000000000000 +
self:ReadUByte() * 0x10000000000 +
self:ReadUByte() * 0x100000000 +
self:ReadUByte() * 0x1000000 +
self:ReadUByte() * 0x10000 +
self:ReadUByte() * 0x100 +
self:ReadUByte()
end
--[[
@doc
@fname BytesBuffer:WriteFloatSlow
@args number float
@desc
due to precision errors, this is a slightly inaccurate operation
*This function internally utilize tables, so it can hog memory*
@enddesc
@returns
BytesBuffer: self
]]
function meta:WriteFloatSlow(valueIn)
assertType(valueIn, 'number', 'WriteFloat')
local bits = bitworker.FloatToBinaryIEEE(valueIn, 8, 23)
local bitsInNumber = bitworker.BinaryToUInteger(bits)
return self:WriteUInt32(bitsInNumber)
end
--[[
@doc
@fname BytesBuffer:WriteFloat
@args number float
@desc
due to precision errors, this is a slightly inaccurate operation
@enddesc
@returns
BytesBuffer: self
]]
function meta:WriteFloat(valueIn)
assertType(valueIn, 'number', 'WriteFloat')
return self:WriteInt32(bitworker.FastFloatToBinaryIEEE(valueIn))
end
--[[
@doc
@fname BytesBuffer:ReadFloatSlow
@desc
due to precision errors, this is a slightly inaccurate operation
*This function internally utilize tables, so it can hog memory*
@enddesc
@returns
number
]]
function meta:ReadFloatSlow()
local bitsInNumber = self:ReadUInt32()
local bits = bitworker.UIntegerToBinary(bitsInNumber, 32)
return bitworker.BinaryToFloatIEEE(bits, 8, 23)
end
--[[
@doc
@fname BytesBuffer:ReadFloat
@desc
due to precision errors, this is a slightly inaccurate operation
@enddesc
@returns
number
]]
function meta:ReadFloat()
return bitworker.FastBinaryToFloatIEEE(self:ReadUInt32())
end
--[[
@doc
@fname BytesBuffer:WriteDoubleSlow
@args number double
@desc
due to precision errors, this is a inaccurate operation
*This function internally utilize tables, so it can hog memory*
@enddesc
@returns
BytesBuffer: self
]]
function meta:WriteDoubleSlow(valueIn)
assertType(valueIn, 'number', 'WriteDouble')
local bits = bitworker.FloatToBinaryIEEE(valueIn, 11, 52)
local bytes = bitworker.BitsToBytes(bits)
self.bytes[self.pointer + 1] = bytes[1]
self.bytes[self.pointer + 2] = bytes[2]
self.bytes[self.pointer + 3] = bytes[3]
self.bytes[self.pointer + 4] = bytes[4]
self.bytes[self.pointer + 5] = bytes[5]
self.bytes[self.pointer + 6] = bytes[6]
self.bytes[self.pointer + 7] = bytes[7]
self.bytes[self.pointer + 8] = bytes[8]
self.pointer = self.pointer + 8
self.length = #self.bytes
return self
end
--[[
@doc
@fname BytesBuffer:WriteDouble
@args number double
@desc
due to precision errors, this is a inaccurate operation
@enddesc
@returns
BytesBuffer: self
]]
function meta:WriteDouble(valueIn)
assertType(valueIn, 'number', 'WriteDouble')
local int1, int2 = bitworker.FastDoubleToBinaryIEEE(valueIn)
self:WriteInt32(int1)
self:WriteInt32(int2)
return self
end
--[[
@doc
@fname BytesBuffer:ReadDoubleSlow
@desc
due to precision errors, this is a slightly inaccurate operation
*This function internally utilize tables, so it can hog memory*
@enddesc
@returns
number
]]
function meta:ReadDoubleSlow()
local bytes1 = self:ReadUInt32()
local bytes2 = self:ReadUInt32()
local bits = {}
table.append(bits, bitworker.UIntegerToBinary(bytes1, 32))
table.append(bits, bitworker.UIntegerToBinary(bytes2, 32))
return bitworker.BinaryToFloatIEEE(bits, 11, 52)
end
--[[
@doc
@fname BytesBuffer:ReadDouble
@desc
due to precision errors, this is a slightly inaccurate operation
@enddesc
@returns
number
]]
function meta:ReadDouble()
return bitworker.FastBinaryToDoubleIEEE(self:ReadUInt32(), self:ReadUInt32())
end
--[[
@doc
@fname BytesBuffer:WriteString
@args string data
@desc
writes NUL terminated string to buffer
errors if NUL is present in string
@enddesc
@returns
BytesBuffer: self
]]
-- String
function meta:WriteString(stringIn)
assertType(stringIn, 'string', 'WriteString')
if #stringIn == 0 then return self end
local bytes = DLib.string.bbyte(stringIn, 1, #stringIn)
local i = 0
local len = #bytes
::loop::
i = i + 1
if bytes[i] == 0 then
error('Binary data in a string?!')
end
self:WriteUByte(bytes[i])
if i < len then
goto loop
end
self:WriteUByte(0)
return self
end
--[[
@doc
@fname BytesBuffer:ReadString
@args string data
@desc
reads buffer until it hits NUL symbol
errors if buffer depleted before NUL is found
@enddesc
@returns
string
]]
function meta:ReadString()
self:CheckOverflow('ReadString', 1)
local readNext = self:ReadUByte()
local output = {}
if readNext == 0 then return '' end
::loop::
table.insert(output, readNext)
if self:EndOfStream() then
error('No NUL terminator was found, buffer overflow!')
end
readNext = self:ReadUByte()
if readNext ~= 0 and readNext ~= nil then
goto loop
end
return DLib.string.bcharTable(output)
end
-- Binary Data
--[[
@doc
@fname BytesBuffer:WriteBinary
@alias BytesBuffer:WriteData
@args string binary
@returns
BytesBuffer: self
]]
function meta:WriteBinary(binaryString)
assertType(binaryString, 'string', 'WriteBinary')
if #binaryString == 0 then return self end
for i = 1, #binaryString do
self:WriteUByte(binaryString:byte(i, i))
end
return self
end
--[[
@doc
@fname BytesBuffer:ReadBinary
@alias BytesBuffer:ReadData
@args number bytesToRead
@returns
string
]]
function meta:ReadBinary(readAmount)
assert(readAmount >= 0, 'Read amount must be positive')
if readAmount == 0 then return '' end
self:CheckOverflow('Binary', readAmount)
local output = {}
local i = 0
::loop::
i = i + 1
table.insert(output, self:ReadUByte())
if i < readAmount then
goto loop
end
return DLib.string.bcharTable(output)
end
meta.WriteData = meta.WriteBinary
meta.ReadData = meta.ReadBinary
function meta:ReadChar()
return string.char(self:ReadUByte())
end
--[[
@doc
@fname BytesBuffer:ToString
@deprecated
@returns
string
]]
function meta:ToString()
local pointer = self.pointer
self:Seek(0)
local str = self:ReadBinary(self.length)
self:Seek(pointer)
return str
end
--[[
@doc
@fname BytesBuffer:ToFileStream
@args File stream
@returns
File
]]
function meta:ToFileStream(fileStream)
local bytes = #self.bytes
if bytes == 0 then return fileStream end
for i, byte in ipairs(self.bytes) do
fileStream:WriteByte(byte)
end
return fileStream
end
--[[
@doc
@fname DLib.BytesBuffer.CompileStructure
@args string structureDef, table customTypes
@desc
Reads a structure from current pointer position
this is somewhat fancy way of reading typical headers and stuff
The string is in next format:
```
type identifier with any symbols
type on_next_line
uint32 thing
```
Supported types:
`int8`
`int16`
`int32`
`int64`
`bigint`
`float`
`double`
`uint8`
`uint16`
`uint32`
`uint64`
`ubigint`
`string` - NUL terminated string
@enddesc
@returns
function: a function to pass `BytesBuffer` to get readed structure
]]
function DLib.BytesBuffer.CompileStructure(structureDef, callbacks)
local output = {}
for i, line in ipairs(structureDef:split('\n')) do
line = line:trim()
--assert(line ~= '', 'Invalid line definition at ' .. i)
if line ~= '' then
local findSpace = assert(line:find('%s'), 'Can\'t find variable name at line ' .. i)
local rtype2 = line:sub(1, findSpace):trim()
local rtype = rtype2:lower()
local rname = line:sub(findSpace + 1):trim()
local findCommentary = rname:find('%s//')
if findCommentary then
rname = rname:sub(1, findCommentary):trim()
end
if rtype == 'int8' or rtype == 'byte' then
table.insert(output, {rname, meta.ReadByte})
elseif rtype == 'int16' or rtype == 'short' then
table.insert(output, {rname, meta.ReadInt16})
elseif rtype == 'int32' or rtype == 'long' or rtype == 'int' then
table.insert(output, {rname, meta.ReadInt32})
elseif rtype == 'int64' or rtype == 'longlong' or rtype == 'bigint' then
table.insert(output, {rname, meta.ReadInt64})
elseif rtype == 'uint8' or rtype == 'ubyte' then
table.insert(output, {rname, meta.ReadUByte})
elseif rtype == 'uint16' or rtype == 'ushort' then
table.insert(output, {rname, meta.ReadUInt16})
elseif rtype == 'uint32' or rtype == 'ulong' or rtype == 'uint' then
table.insert(output, {rname, meta.ReadUInt32})
elseif rtype == 'uint64' or rtype == 'ulong64' or rtype == 'biguint' or rtype == 'ubigint' then
table.insert(output, {rname, meta.ReadUInt64})
elseif rtype == 'float' then
table.insert(output, {rname, meta.ReadFloat})
elseif rtype == 'double' then
table.insert(output, {rname, meta.ReadDouble})
elseif rtype == 'variable' or rtype == 'string' then
table.insert(output, {rname, meta.ReadString})
elseif callbacks and callbacks[rtype2] then
table.insert(output, {rname, callbacks[rtype2]})
else
DLib.MessageError(debug.traceback('Undefined type: ' .. rtype))
end
end
end
return function(self)
local read = {}
for i, data in ipairs(output) do
read[data[1]] = data[2](self, read)
end
return read
end
end
--[[
@doc
@fname BytesBuffer:ReadStructure
@args string structureDef, table customTypes
@desc
`DLib.BytesBuffer.CompileStructure(structureDef, customTypes)(self)`
@enddesc
@returns
table: the read structure
]]
function meta:ReadStructure(structureDef, callbacks)
return DLib.BytesBuffer.CompileStructure(structureDef, callbacks)(self)
end