【问题标题】:How to store binary data in a Lua string如何将二进制数据存储在 Lua 字符串中
【发布时间】:2010-09-28 17:02:00
【问题描述】:

我需要创建一个包含嵌入元信息的自定义文件格式。我决定只使用 Lua,而不是创建自己的格式。

texture
{
   format=GL_LUMINANCE_ALPHA;
   type=GL_UNSIGNED_BYTE;
   width=256;
   height=128;
   pixels=[[
<binary-data-here>]];
}

texture 是一个以表为唯一参数的函数。然后它在表中按名称查找各种参数,并将调用转发到 C++ 例程。我希望没有任何异常。

有时文件无法解析并出现以下错误:

my_file.lua:8: unexpected symbol near ']'

这是怎么回事?
有没有更好的方法在 Lua 中存储二进制数据?


更新

原来存储二进制数据的Lua字符串是non-trivial。但是在处理 3 个序列时是可能的。

  • Long-format-string-literals 不能有嵌入的 close-long-bracket]]]=] 等)。
    这个很明显。

  • Long-format-string-literals 不能以 ]== 之类的结尾,这将匹配所选的 closure-long-bracket
    这个比较微妙。幸运的是,如果执行错误,脚本将无法编译。

  • 数据不能嵌入\n\r
    Lua 的built in line-end processing 把这些搞砸了。这个问题要微妙得多。该脚本可以正常编译,但会产生错误的数据。 0x13 => 0x10、0x1013 => 0x10 等

为了解决这些限制,我将二进制数据拆分为\r\n,然后选择一个有效的长括号,最后发出将各个部分连接在一起的 Lua。我使用了一个为我执行此操作的脚本。
输入:XXXX\nXX]]XX\r\nXX]]XX]=

texture
{
  --other fields omitted      
  pixels= '' ..
     [[XXXX]] ..
     '\n' ..
     [=[XX]]XX]=] ..
     '\r\n' ..
     [==[XX]]XX]=]==];
}

【问题讨论】:

  • 您确定您的二进制数据不包含任何可能被读取为 ']]' 的内容吗?
  • 我检查了,像素数据中没有']]'。

标签: string lua binary-data


【解决方案1】:

Lua 能够以长括号格式编码大多数字符,包括空值。但是,Lua 以文本模式打开脚本文件,这会导致一些问题。在我的 Windows 系统上,以下字符有问题:

字符代码问题 -------------- ------------------- 13 (CR) 被翻译成 10 (LF) 13 10 (CR LF) 被翻译成 10 (LF) 26(EOF)导致“''附近未完成的长字符串”

如果您不使用 Windows,则这些可能不会导致问题,但可能存在基于不同文本模式的问题。


我只能通过编码多个右括号来产生您收到的错误:

a=[[
]]] --> a.lua:2: unexpected symbol near ']'

但是,这很容易通过以下方式解决:

a=[==[
]]==]

【讨论】:

  • 做到了!谢谢。除了检查二进制数据中没有]] 之外,我还需要检查数据是否以] 结尾。当我找到其中任何一个时,我会在字符串分隔符中添加一些 =s。
  • 嗯,差不多就行了。当数据结尾为]== 时,[==[ 仍会产生错误。所以现在我检查分隔符的第一部分(]=*)没有出现在二进制数据的末尾。当它出现时,我会不断添加 =s,直到在字符串中找不到 ]={n}] 并且最后没有出现 ]={n}
【解决方案2】:

二进制数据需要编码成可打印的字符。用于解码的最简单方法是对所有字节使用C-like escape sequences。例如,十六进制字节 13 41 42 1E 将被编码为 '\19\65\66\30'。当然,那么编码后的数据要比源二进制大三到四倍。

或者,您可以使用 Base64 之类的东西,但这必须在运行时进行解码,而不是依赖 Lua 解释器。就个人而言,我可能会走 Base64 路线。有Lua examples of Base64 encoding and decoding

另一种选择是有两个文件。使用定义明确的图像格式文件(例如TGA),该文件由带有附加元数据的单独 Lua 脚本指向。如果您不想移动两个文件,则可以将它们合并为 archive

【讨论】:

  • 在阅读了 Lua 原始字符串允许嵌入 NULL 的注释后,我选择使用它们。 NULL 是不可打印的,所以我认为它也可以嵌入其他的。通常(> 90%)它有效。引用手册 §2.1 中的内容,“Lua 中的字符串可以包含任何 8 位值,包括嵌入的零” 并谈到 long bracket 形式的字符串 “它们可以包含除结束符之外的任何内容适当级别的括号。”
  • 前一个引用专门指转义值(即 \ddd),而后者可能假定使用文本编辑器——因此专门使用可打印字符——来生成源代码。跨度>
  • 如何将二进制数据放入脚本文件中?
  • 用python。我可以用任何编程语言做到这一点。我的脚本在命令行上接受图像文件。抓取和过滤图像数据。将 lua 代码写入[[\n,然后转储图像数据。最后它写结束]];\n}
  • 我不确定这一点,但我想 Lua 解释器会阻塞不可打印的字符。是的,Lua 字符串可以包含不可打印的字符,但这并不意味着 Lua 解释器可以。我仍然建议使用文本编码,然后在运行时解码成二进制文件。
猜你喜欢
  • 2011-08-13
  • 2011-11-18
  • 2011-04-26
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 2017-09-06
  • 2013-01-27
  • 1970-01-01
相关资源
最近更新 更多