0%

LZMA Utils NDK编译及LZMA文件格式解析

最近做项目时需要从一个设备的FPGA回读之前保存的xml配置文件。为了节省空间,xml文件是经过压缩之后保存的,压缩方式是LZMA。

在网上最先搜到的7-Zip网站的LZMA-SDK,不过只有Windows平台的,我要在Android平台上面使用,所以需要Linux平台能够编译的。

最后找到了LZMA Utils 4.32.7.

编译LZMA Utils

因为要在Android平台使用,LZMA Utils只有Linux平台通用的configure, 所以要用NDK的独立工具链进行交叉编译。

首先设置环境变量 CC, CXX 为arm-linux-androideabi-gcc和arm-linux-androideabi-g++ 的路径,再运行 configure.

export CC=/path/to/toolchain-arm/bin/arm-linux-androideabi-gcc
export CXX=/path/to/toolchain-arm/bin/arm-linux-androideabi-g++
./configure --host=arm-linux-androideabi
make

configure 遇到错误 `androideabi’ not recognized

Invalid configuration `arm-linux-androideabi': system `androideabi' not recognized

解决方法:拷贝 config.{sub,guess} 到编译文件夹

cp /usr/share/misc/config.{sub,guess} .

make 遇到错误 undefined reference to ‘__atomic_fetch_add_4’ , 按网上说的添加了 -latomic 到 LDFLAGS, 不过并没有解决。好在我需要的liblzmadec库文件已经成功生成了。

ls -l src/liblzmadec/.libs/
total 136
-rw-rw-r-- 1 lvliang lvliang  5416 Dec 10 10:50 buffer.o
-rw-rw-r-- 1 lvliang lvliang 11888 Dec 10 10:50 io.o
-rw-rw-r-- 1 lvliang lvliang 43052 Dec 10 10:50 liblzmadec.a
lrwxrwxrwx 1 lvliang lvliang    16 Dec 10 10:50 liblzmadec.la -> ../liblzmadec.la
-rw-rw-r-- 1 lvliang lvliang   822 Dec 10 10:50 liblzmadec.lai
lrwxrwxrwx 1 lvliang lvliang    19 Dec 10 10:50 liblzmadec.so -> liblzmadec.so.0.0.0
lrwxrwxrwx 1 lvliang lvliang    19 Dec 10 10:50 liblzmadec.so.0 -> liblzmadec.so.0.0.0
-rwxrwxr-x 1 lvliang lvliang 38996 Dec 10 10:50 liblzmadec.so.0.0.0
-rw-rw-r-- 1 lvliang lvliang 25228 Dec 10 10:50 main.o

我需要的是静态库liblzmadec.a文件,在Android.mk文件中添加

include $(CLEAR_VARS)
LOCAL_MODULE := lzmadec
LOCAL_SRC_FILES := /path/to/lzma-4.32.7/src/liblzmadec/.libs/liblzmadec.a
include $(PREBUILT_STATIC_LIBRARY)

LOCAL_STATIC_LIBRARIES := liblzmadec

然后把lzmadec.h文件添加到项目中就可以使用LZMA解压功能了。

LZMA文件格式

LZMA文件由13个字节的文件头和LZMA压缩数据组成,所以LZMA只能压缩一个文件,不能像其他压缩工具一样一次压缩多个文档到一个压缩包。

文件头

+-----+----+----+----+----+--+--+--+--+--+--+--+--+
|     属性    |   字典大小   |   解压后的文件大小   |
+-----+----+----+----+----+--+--+--+--+--+--+--+--+

属性占1个字节,包含 lc(literal context bits),lp(literal position bits),pb(position bits)。属性值的计算方法是

Properties = (pb * 5 + lp) * 9 + lc

解析属性的方法是

uint8_t lc, lp, pb;
uint8_t prop = get_lzma_properties();
if (prop > (4 * 5 + 4) * 9 + 8)
    return LZMA_PROPERTIES_ERROR;

pb = prop / (9 * 5);
prop -= pb * 9 * 5;
lp = prop / 9;
lc = prop - lp * 9;

字典大小占4个字节,是用小端方式存储的unsigned long数据。

解压后文件大小占8个字节,是用小端方式存储的 unsigned long long数据。

知道了LZMA的文件格式,并且有了LZMA Utils的库文件,便可以解压LZMA的数据了。