basE91で少し効率よくバイナリをテキストに変換

バイナリを利用できない環境でのデータ転送時にUNIX環境では古くは uudecode, uuencode が,日本のパソコン通信では ish などが使われていました.近頃は base64 がよく使われているように感じます.

これらのツールではバイナリをASCIIで表現するためサイズが大きくなってしまいます.でも全てのASCIIを使っていません.

今回見つけたbasE91はASCIIの0x21-0x7Eのうち -, \, ' を除いた91文字を使ってデコードすることで効率よくするもののようです.

早速試してみます.Debianパッケージがないかなと探しましたがありませんでした.

sourceを貰ってきてmakeします.
※hashは「 basE91 – Browse /basE91/0.6.0 at SourceForge.net 」で確認できる.

$ wget http://downloads.sourceforge.net/base91/base91-0.6.0.tar.gz
$ md5sum base91-0.6.0.tar.gz
e227841d900cc463a162bd79775aeb54  base91-0.6.0.tar.gz
$ sha1sum base91-0.6.0.tar.gz
00cfd573ec8b3d0160dbf53e2c7a49b99a1aa720  base91-0.6.0.tar.gz
$ tar tvf base91-0.6.0.tar.gz
-rw-r--r-- 0/0             575 2005-06-25 00:00 base91-0.6.0/AWK/README
-rwxr-xr-x 0/0             727 2006-11-02 05:13 base91-0.6.0/AWK/b91dec.awk
-rw-r--r-- 0/0             932 2006-09-04 03:00 base91-0.6.0/PHP4/README
-rw-r--r-- 0/0            1513 2006-11-02 05:13 base91-0.6.0/PHP4/base91.php
-rw-r--r-- 0/0             149 2006-09-04 03:00 base91-0.6.0/test/Makefile
-rw-r--r-- 0/0            4265 2006-11-02 05:13 base91-0.6.0/test/test.sh
-rw-r--r-- 0/0             332 2006-08-25 17:00 base91-0.6.0/DOS-asm/readme.txt
-rw-r--r-- 0/0            3487 2006-11-02 05:13 base91-0.6.0/DOS-asm/b91enc.asm
-rw-r--r-- 0/0            5034 2006-11-02 05:13 base91-0.6.0/Java/b91cli.java
-rw-r--r-- 0/0            3297 2006-11-02 05:13 base91-0.6.0/Java/basE91.java
-rw-r--r-- 0/0            1526 2006-11-02 05:13 base91-0.6.0/Java/license.txt
-rw-r--r-- 0/0             793 2006-11-02 05:13 base91-0.6.0/Java/readme.txt
-rw-r--r-- 0/0             112 2006-09-04 03:00 base91-0.6.0/Java/manifest.mf
-rwxr-xr-x 0/0             178 2006-11-02 05:13 base91-0.6.0/Java/build_jar.sh
-rw-r--r-- 0/0            7502 2006-11-02 05:13 base91-0.6.0/cli.c
-rw-r--r-- 0/0            5066 2006-11-02 05:13 base91-0.6.0/base91.c
-rw-r--r-- 0/0            1501 2006-11-02 05:13 base91-0.6.0/LICENSE
-rw-r--r-- 0/0             561 2006-11-02 05:13 base91-0.6.0/base91.h
-rw-r--r-- 0/0            2360 2006-11-02 05:13 base91-0.6.0/README
-rw-r--r-- 0/0            1762 2006-11-02 05:13 base91-0.6.0/base91.1
-rw-r--r-- 0/0             903 2006-09-04 03:00 base91-0.6.0/Makefile
-rw-r--r-- 0/0            2330 2006-11-02 05:13 base91-0.6.0/NEWS
$ tar xf base91-0.6.0.tar.gz
$ cd base91-0.6.0
$ make
$ ./base91 -h
Usage: base91 [OPTION]... [FILE]
basE91 encode or decode FILE, or standard input, to standard output.

  -d, --decode          decode data
  -m SIZE               use SIZE bytes of memory for buffers (suffixes b, K, M)
  -o, --output=FILE     write to FILE instead of standard output
  -v, --verbose         verbose mode
  -w, --wrap=COLS       wrap encoded lines after COLS characters (default 76)
  --help                display this help and exit
  --version             output version information and exit

With no FILE, or when FILE is -, read standard input.

encodeしてdecodeしてみます.
当たり前ですが,encode, decodeしてもdiffもhashも同じです.

$ ./base91 ./base91 -o ./base91.base91
$ ./base91 -d ./base91.base91 -o ./base91.tmp
$ diff ./base91 ./base91.tmp
$ sha512sum ./base91
bc903be7c5b694841a9d0303351846f80f4798ad8848e8f298cf2c4818c68a2270b065db495b969503b25cdf672632e1cced18094f935fed47b75718c3c3e976  ./base91
$ ./base91 ./base91 | ./base91 -d | sha512sum
bc903be7c5b694841a9d0303351846f80f4798ad8848e8f298cf2c4818c68a2270b065db495b969503b25cdf672632e1cced18094f935fed47b75718c3c3e976  -

basE91, base64, base32, uudecode で変換してみます.
basE91 が一番小さいですね

$ ls --block-size=1 -s ./base91
16384 ./base91
$ ./base91 ./base91 | wc -c
17340
$ base64 ./base91 | wc -c
19615
$ uuencode ./base91 - | wc -c
20024
$ base32 ./base91 | wc -c
23538

圧縮すると大分小さくなります.圧縮のほうがずっと効きますね.

$ xz -c ./base91 | wc -c
4528
$ xz -c ./base91 | ./base91 | wc -c
5640
$ xz -c ./base91 | base64 | wc -c
6120
$ xz -c ./base91 | uuencode - | wc -c
6260
$ xz -c ./base91 | base32 | wc -c
7344

他のファイルも試してみます./usr/bin 以下のファイルを適当に見繕って比較x5です.

#!/bin/bash

XZ=`mktemp`
for i in `seq 1 5`
do
  CMD=`find /usr/bin -type f | shuf -n 1`
  echo $CMD
  echo -n "raw  "
  stat -c %s $CMD
  xz -9 -c $CMD > $XZ
  echo -n "xz "
  stat -c %s $XZ
  echo -n "xz.uu  "
  uuencode $XZ - | wc -c
  echo -n "xz.base64  "
  base64 $XZ | wc -c
  echo -n "xz.base91  "
  base91 $XZ | wc -c
done
rm $XZ
$ bash ./bin2ascii.bash | column -t
/usr/bin/lxc-snapshot
raw                          27632
xz                           6756
xz.uu                        9328
xz.base64                    9127
xz.base91                    8418
/usr/bin/dh_installtmpfiles
raw                          3263
xz                           1540
xz.uu                        2144
xz.base64                    2084
xz.base91                    1917
/usr/bin/pbmtogo
raw                          10384
xz                           3164
xz.uu                        4380
xz.base64                    4276
xz.base91                    3942
/usr/bin/chartread
raw                          3966528
xz                           772956
xz.uu                        1064980
xz.base64                    1044169
xz.base91                    963047
/usr/bin/spamassassin
raw                          29898
xz                           9608
xz.uu                        13258
xz.base64                    12981
xz.base91                    11971

おまけ?armelでstatic linkなバイナリを作ってみました.Sipeed Lichee Nano で動かないかな?と.

$ git diff HEAD~~ Makefile
diff --git a/Makefile b/Makefile
index 246aede..129acff 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
-CFLAGS = -Wall -W -O2
-LDFLAGS = -s
+CFLAGS = -static -Wall -W -O2
+LDFLAGS = -static -s

-CC = gcc
+CC = arm-linux-gnueabi-gcc
 INSTALL = install
 INSTALL_DATA = $(INSTALL) -m 444
 INSTALL_PROGRAM = $(INSTALL) -m 555

qemu-arm-static では動くのを確認したけど実機では未確認です.

$ file ./base91
./base91: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=88ec4ccbf69c4bb41640b5de63b6b5373b7e5365, for GNU/Linux 3.2.0, stripped
$ ldd ./base91
        not a dynamic executable
$ echo 😺 | qemu-arm-static ./base91 | pee cat "qemu-arm-static ./base91 -d"
=~m6xHA
😺

以下にバイナリとuuencodeしたものが置いてあります.

blog元のmemo

環境
$ dpkg-query -W gcc-10-arm-linux-gnueabi qemu-user-static gcc coreutils sharutils
coreutils       8.32-3
gcc     4:10.1.0-1
gcc-10-arm-linux-gnueabi        10.2.0-3cross2
qemu-user-static        1:5.0-13
sharutils       1:4.15.2-5
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64