1. lua 5.3 string.pack 和 string.unpack
http://cloudwu.github.io/lua53doc/manual.html#6.4.2
用于 string.pack
, string.packsize
, string.unpack
的第一个参数。 它是一个描述了需要创建或读取的结构之布局。
格式串是由转换选项构成的序列。 这些转换选项列在后面:
<
: 设为小端编码>
: 设为大端编码=
: 大小端遵循本地设置![n]
: 将最大对齐数设为n
(默认遵循本地对齐设置)b
: 一个有符号字节 (char
)B
: 一个无符号字节 (char
)h
: 一个有符号short
(本地大小)H
: 一个无符号short
(本地大小)l
: 一个有符号long
(本地大小)L
: 一个无符号long
(本地大小)j
: 一个lua_Integer
J
: 一个lua_Unsigned
T
: 一个size_t
(本地大小)i[n]
: 一个n
字节长(默认为本地大小)的有符号int
I[n]
: 一个n
字节长(默认为本地大小)的无符号int
f
: 一个float
(本地大小)d
: 一个double
(本地大小)n
: 一个lua_Number
cn
:n
字节固定长度的字符串z
: 零结尾的字符串s[n]
: 长度加内容的字符串,其长度编码为一个n
字节(默认是个size_t
) 长的无符号整数。x
: 一个字节的填充Xop
: 按选项op
的方式对齐(忽略它的其它方面)的一个空条目- '
( "[n]
" 表示一个可选的整数。) 除填充、空格、配置项(选项 "xX <=>!
")外, 每个选项都关联一个参数(对于 string.pack
) 或结果(对于 string.unpack
)。
对于选项 "!n
", "sn
", "in
", "In
", n
可以是 1 到 16 间的整数。 所有的整数选项都将做溢出检查; string.pack
检查提供的值是否能用指定的字长表示; string.unpack
检查读出的值能否置入 Lua 整数中。
任何格式串都假设有一个 "!1=
" 前缀, 即最大对齐为 1 (无对齐)且采用本地大小端设置。
对齐行为按如下规则工作: 对每个选项,格式化时都会填充一些字节直到数据从一个特定偏移处开始, 这个位置是该选项的大小和最大对齐数中较小的那个数的倍数; 这个较小值必须是 2 个整数次方。 选项 "c
" 及 "z
" 不做对齐处理; 选项 "s
" 对对齐遵循其开头的整数。
string.pack
用零去填充 (string.unpack
则忽略它)。
2. lpack
http://www.luteus.biz/Download/LoriotPro_Doc/LUA/LUA_For_Windows/lpack/
z
: zero-terminated string p
: string preceded by length byte P
: string preceded by length word a
: string preceded by length size_t A
: string f
: float d
: double n
: Lua number c
: char b
: byte (unsigned char) h
: short H
: unsigned short i
: int I
: unsigned int l
: long L
: unsigned long
<
: little endian >
: big endian =
: native endian
3.查看了lpack和 lua5.3 的string.pack,string.unpack后发现两者 有些差别
3.1 lpack.pack 的fmt b10 在 string.pack fmt bbbbbbbbbb
3.2 lpack.unpack 和 string.unpack 参数位置不一样, lpack fmt 在后面, string.pack在前面
3.3 unpack 在5.3移到table下了,所以unpack 修改成 table.unpack
要想使用zrong的ByteArray必需修改
下面是修改后代码 暂时没有报错。主要是
string.pack 和 string.unpack的修改
--[[ Serialzation bytes stream like ActionScript flash.utils.ByteArray. It depends on lpack. A sample: https://github.com/zrong/lua#ByteArray @see http://underpop.free.fr/l/lua/lpack/ @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/ByteArray.html @author zrong(zengrong.net) Creation 2013-11-14 Last Modification 2014-07-09 ]] local ByteArray = cc.class("ByteArray") ByteArray.ENDIAN_LITTLE = "ENDIAN_LITTLE" ByteArray.ENDIAN_BIG = "ENDIAN_BIG" ByteArray.radix = {[10]="%03u",[8]="%03o",[16]="%02X"} -- require("pack") --- Return a string to display. -- If self is ByteArray, read string from self. -- Else, treat self as byte string. -- @param __radix radix of display, value is 8, 10 or 16, default is 10. -- @param __separator default is " ". -- @return string, number function ByteArray.toString(self, __radix, __separator) __radix = __radix or 16 __radix = ByteArray.radix[__radix] or "%02X" __separator = __separator or " " local __fmt = __radix..__separator local __format = function(__s) return string.format(__fmt, string.byte(__s)) end if type(self) == "string" then return string.gsub(self, "(.)", __format) end local __bytes = {} for i=1,#self._buf do __bytes[i] = __format(self._buf[i]) end return table.concat(__bytes) ,#__bytes end function ByteArray:ctor(__endian) self._endian = __endian self._buf = {} self._pos = 1 end function ByteArray:getLen() return #self._buf end function ByteArray:getAvailable() return #self._buf - self._pos + 1 end function ByteArray:getPos() return self._pos end function ByteArray:setPos(__pos) self._pos = __pos return self end function ByteArray:getEndian() return self._endian end function ByteArray:setEndian(__endian) self._endian = __endian end --- Get all byte array as a lua string. -- Do not update position. function ByteArray:getBytes(__offset, __length) __offset = __offset or 1 __length = __length or #self._buf --printf("getBytes,offset:%u, length:%u", __offset, __length) return table.concat(self._buf, "", __offset, __length) end --- Get pack style string by lpack. -- The result use ByteArray.getBytes to get is unavailable for lua socket. -- E.g. the #self:_buf is 18, but #ByteArray.getBytes is 63. -- I think the cause is the table.concat treat every item in ByteArray._buf as a general string, not a char. -- So, I use lpack repackage the ByteArray._buf, theretofore, I must convert them to a byte number. function ByteArray:getPack(__offset, __length) __offset = __offset or 1 __length = __length or #self._buf local __fmt = self:_getLC("c" .. (__length - __offset + 1)) -- print("fmt:", __fmt, #__t) local __s = string.pack(__fmt, self:getBytes(__offset, __length)) return __s end --- rawUnPack perform like lpack.pack, but return the ByteArray. function ByteArray:rawPack(__fmt, ...) local __s = string.pack(__fmt, ...) self:writeBuf(__s) return self end --- rawUnPack perform like lpack.unpack, but it is only support FORMAT parameter. -- Because ByteArray include a position itself, so we haven't to save another. function ByteArray:rawUnPack(__fmt) -- read all of bytes. local __s = self:getBytes(self._pos) local __next, __val = string.unpack(__fmt, __s) -- update position of the ByteArray self._pos = self._pos + __next -- Alternate value and next return __val, __next end function ByteArray:readBool() -- When char > 256, the readByte method will show an error. -- So, we have to use readChar return self:readChar() ~= 0 end function ByteArray:writeBool(__bool) if __bool then self:writeByte(1) else self:writeByte(0) end return self end function ByteArray:readDouble() local __v, __ = string.unpack(self:_getLC("d"), self:readBuf(8)) return __v end function ByteArray:writeDouble(__double) local __s = string.pack( self:_getLC("d"), __double) self:writeBuf(__s) return self end function ByteArray:readFloat() local __v, __ = string.unpack(self:_getLC("f"), self:readBuf(4)) return __v end function ByteArray:writeFloat(__float) local __s = string.pack( self:_getLC("f"), __float) self:writeBuf(__s) return self end function ByteArray:readInt() local __v, __ = string.unpack(self:_getLC("i"), self:readBuf(4)) return __v end function ByteArray:writeInt(__int) local __s = string.pack( self:_getLC("i"), __int) self:writeBuf(__s) return self end function ByteArray:readUInt() local __v, __ = string.unpack(self:_getLC("I"), self:readBuf(4)) return __v end function ByteArray:writeUInt(__uint) local __s = string.pack(self:_getLC("I"), __uint) self:writeBuf(__s) return self end function ByteArray:readShort() local __v, __ = string.unpack(self:_getLC("h"), self:readBuf(2)) return __v end function ByteArray:writeShort(__short) local __s = string.pack( self:_getLC("h"), __short) self:writeBuf(__s) return self end function ByteArray:readUShort() local __v, __ = string.unpack(self:_getLC("H"), self:readBuf(2)) return __v end function ByteArray:writeUShort(__ushort) local __s = string.pack(self:_getLC("H"), __ushort) self:writeBuf(__s) return self end --[[ -- 2014-07-09 Remove all of methods about Long in ByteArray. -- @see http://zengrong.net/post/2134.htm function ByteArray:readLong() local __v, __ = string.unpack(self:_getLC("l"), self:readBuf(8)) return __v end function ByteArray:writeLong(__long) local __s = string.pack( self:_getLC("l"), __long) self:writeBuf(__s) return self end function ByteArray:readULong() local __v, __ = string.unpack(self:_getLC("L"), self:readBuf(4)) return __v end function ByteArray:writeULong(__ulong) local __s = string.pack( self:_getLC("L"), __ulong) self:writeBuf(__s) return self end ]] function ByteArray:readUByte() local __v, __al = string.unpack("b", self:readRawByte()) return __val end function ByteArray:writeUByte(__ubyte) local __s = string.pack("b", __ubyte) self:writeBuf(__s) return self end function ByteArray:readLuaNumber(__number) local __v, __ = string.unpack(self:_getLC("n"), self:readBuf(8)) return __v end function ByteArray:writeLuaNumber(__number) local __s = string.pack(self:_getLC("n"), __number) self:writeBuf(__s) return self end --- The differently about (read/write)StringBytes and (read/write)String -- are use pack libraty or not. function ByteArray:readStringBytes(__len) assert(__len, "Need a length of the string!") if __len == 0 then return "" end self:_checkAvailable() local __v, __ = string.unpack(self:_getLC("A"..__len), self:readBuf(__len)) return __v end function ByteArray:writeStringBytes(__string) local __s = string.pack(self:_getLC("A"), __string) self:writeBuf(__s) return self end function ByteArray:readString(__len) assert(__len, "Need a length of the string!") if __len == 0 then return "" end self:_checkAvailable() return self:readBuf(__len) end function ByteArray:writeString(__string) self:writeBuf(__string) return self end function ByteArray:readStringUInt() self:_checkAvailable() local __len = self:readUInt() return self:readStringBytes(__len) end function ByteArray:writeStringUInt(__string) self:writeUInt(#__string) self:writeStringBytes(__string) return self end --- The length of size_t in C/C++ is mutable. -- In 64bit os, it is 8 bytes. -- In 32bit os, it is 4 bytes. function ByteArray:readStringSizeT() self:_checkAvailable() local __s = self:rawUnPack(self:_getLC("a")) return __s end --- Perform rawPack() simply. function ByteArray:writeStringSizeT(__string) self:rawPack(self:_getLC("a"), __string) return self end function ByteArray:readStringUShort() self:_checkAvailable() local __len = self:readUShort() return self:readStringBytes(__len) end function ByteArray:writeStringUShort(__string) local __s = string.pack(self:_getLC("P"), __string) self:writeBuf(__s) return self end --- Read some bytes from buf -- @return a bit string function ByteArray:readBytes(__bytes, __offset, __length) assert(cc.iskindof(__bytes, "ByteArray"), "Need a ByteArray instance!") local __selfLen = #self._buf local __availableLen = __selfLen - self._pos __offset = __offset or 1 if __offset > __selfLen then __offset = 1 end __length = __length or 0 if __length == 0 or __length > __availableLen then __length = __availableLen end __bytes:setPos(__offset) for i=__offset,__offset+__length do __bytes:writeRawByte(self:readRawByte()) end end --- Write some bytes into buf function ByteArray:writeBytes(__bytes, __offset, __length) assert(cc.iskindof(__bytes, "ByteArray"), "Need a ByteArray instance!") local __bytesLen = __bytes:getLen() if __bytesLen == 0 then return end __offset = __offset or 1 if __offset > __bytesLen then __offset = 1 end local __availableLen = __bytesLen - __offset __length = __length or __availableLen if __length == 0 or __length > __availableLen then __length = __availableLen end local __oldPos = __bytes:getPos() __bytes:setPos(__offset) for i=__offset,__offset+__length do self:writeRawByte(__bytes:readRawByte()) end __bytes:setPos(__oldPos) return self end --- Actionscript3 readByte == lpack readChar -- A signed char function ByteArray:readChar() local __v, __al = string.unpack("c", self:readRawByte()) return __val end function ByteArray:writeChar(__char) self:writeRawByte(string.pack("c", __char)) return self end --- Use the lua string library to get a byte -- A unsigned char function ByteArray:readByte() return string.byte(self:readRawByte()) end --- Use the lua string library to write a byte. -- The byte is a number between 0 and 255, otherwise, the lua will get an error. function ByteArray:writeByte(__byte) self:writeRawByte(string.char(__byte)) return self end function ByteArray:readRawByte() self:_checkAvailable() local __byte = self._buf[self._pos] self._pos = self._pos + 1 return __byte end function ByteArray:writeRawByte(__rawByte) if self._pos > #self._buf+1 then for i=#self._buf+1,self._pos-1 do self._buf[i] = string.char(0) end end self._buf[self._pos] = string.sub(__rawByte, 1,1) self._pos = self._pos + 1 return self end --- Read a byte array as string from current position, then update the position. function ByteArray:readBuf(__len) --printf("readBuf,len:%u, pos:%u", __len, self._pos) local __ba = self:getBytes(self._pos, self._pos + __len - 1) self._pos = self._pos + __len return __ba end --- Write a encoded char array into buf function ByteArray:writeBuf(__s) for i=1,#__s do self:writeRawByte(string.sub(__s,i,i)) end return self end ---------------------------------------- -- private ---------------------------------------- function ByteArray:_checkAvailable() assert(#self._buf >= self._pos, string.format("End of file was encountered. pos: %d, len: %d.", self._pos, #self._buf)) end --- Get Letter Code function ByteArray:_getLC(__fmt) __fmt = __fmt or "" if self._endian == ByteArray.ENDIAN_LITTLE then return "<"..__fmt elseif self._endian == ByteArray.ENDIAN_BIG then return ">"..__fmt end return "="..__fmt end return ByteArray
转载。 https://blog.csdn.net/lovehappy108/article/details/52070737