最便携的 base64 实现

和我差不多一样老的程序员小四,在微博上提了个问题:“现在只有一个 busybox 支持的 awk,没有 od、hexdump、base64、uuencode 等等,如何用一个纯种的 awk 脚本完成对指定二进制文件的 base64 encode?搜到的大多数都依赖 od、hexdump 啥的。”

这个命题作文的难点有两个,一是不能依赖其它外部工具,二是 awk 本身如何处理二进制数据流。引起老夫兴趣的原因,当然就是这些难点啦!开始动用搜索引擎,练手。

gawk 对二进制数据的支持要比 awk 好,在 google groups 上有个“Using awk to parse binary files”的求助帖子,里面有人说,

Standard awk is not the right tool for this purpose.

On the other hand, gawk handles binary files well, and without introducing a new, awful language in the process. For your particular purpose, there is a special variable called FIELDWIDTHS, which is a list of integers. If you set it, gawk’s processing of input changes from the standard awk delimited record/delimited field approach, to a fixed-length record approach.

For instance, according to /usr/include/elf.h, an elf executable starts with a 4-byte magic number, a byte giving the class of machine, a byte giving the data format, a byte giving the ELF version, a byte of padding, 8 bytes of brand information, and various other crap. You could set FIELDWIDTHS to
FIELDWIDTHS = “4 1 1 1 1 8”

and then parse this much of the file header with

[note that nextfile is a gawk language extension]

可惜,原题并没有说 awk 是 gawk,把此信息记录下来,仅供备查而已。

从搜索结果来看,还是有不少人致力于使用 awk 来实现 base64 的相关功能的。发现的一份实现是在 https://gist.github.com/markusfisch/2648733,这份实现是 bash 兼容的,具有参考价值的点在于它处理 od 工具缺失的方法。在其下的评论中,已经有人指出,此脚本无法在 busybox 的 ash 下工作,同时给出一份可以工作的实现:https://github.com/mateusza/shellscripthttpd/blob/master/base64.sh,本以为到此故事就可以结束,结果一看,这个实现用到了 hexdump 等命令,一声长叹,如果这些可用何须如此大费周章。

顺便说一句,markusfisch 的 shell 代码里直接引用了 dannychouinard 的 awk 实现(https://sites.google.com/site/dannychouinard/Home/unix-linux-trinkets/little-utilities/base64-and-base85-encoding-awk-scripts)。

如果命题要求不是 encode 而是 decode,则还有另外一个达人的成果可资利用,他不但公布了代码(https://github.com/shane-kerr/AWK-base64decode),而且还有详细的讲解:https://dnshane.wordpress.com/2017/03/10/decoding-base64-in-awk/

如果可以写一段 busybox 中的 ash 兼容的 od 实现,也许可以曲线救国,因此有了以下代码。

这段代码在 Ubuntu 自带的 busybox 下测试,其最大的问题在于,read 命令不支持 -d 参数,因此无法阻止读取输入的过程中自动将 \n 字符转为 \0 字符的发生。当然还有个问题,那就是运行速度实在是太慢了。至于各种数学运算和逻辑判断的语句之所以写得看起来比较幼稚,一部分是因为老夫 shell 的水平本就很差,二则是因为要配合 ash 本身的幼稚。

截至目前,似乎还没有什么解决之道。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注