ByteReader transforms Lua inputs adhering to a simple protocol into
a bytes-count pair that other C and C++ APIs are able to safely consume.
The protocol goes as follows:
The object at index
arg (in Lua state
L) is examined.
If it happens to be a string, we can use its bytes and length directly.
Failing that, the object's metatable (if it has one) is queried for field __bytes. If no value is found, the object clearly does not honor the protocol, so we error out.
If __bytes is neither a light userdata nor a function, we have a garden-variety object and can use its bytes and length directly, as with strings.
When __bytes is a light userdata, it is assumed to point to a
struct, containing a reader function
mGetBytes and a user-supplied context
mContext. (The light userdata must also be present as a key in the Lua
registry.) This is called as
mGetBytes(L, reader, arg, mContext), where
reader is our byte reader, whose mBytes and mCount members the
function should supply. (See below how to handle errors.)
The object in the foregoing cases must be a full userdata.
The remaining possibility is that __bytes is a function, to be called as
object = func(object)
The process (i.e. is the object a string? if not, does it have a __bytes metafield? et al.) then recurses on this new object, using the final result.
When bytes are successfully found, the reader's mBytes member will point
to them, with the byte count stored in mCount. If
bReplace is true
(the default), the final bytes object—either a string or full
userdata—is moved into slot
arg, overwriting the original object
(this only matters in the __bytes-as-function case, since otherwise the
object will already be in position).
Should an error happen along the way, mBytes will be
NULL and an error
message is pushed on the stack.