Android sparse格式

翻墙不方便。不方便的地方在于前天的梯子,今天就会没用。所以把手头用到的东西记录到墙内显得尤为重要,哪怕只不过是芝麻点儿的小事。

// 小端存储
struct sparse_header_t {
    uint32_t magic; // 幻数, 值为 0xed26ff3a
    uint16_t major_version; // 主版本号
    uint16_t minor_version; // 副版本号
    uint16_t file_hdr_sz; // 文件头大小, 为28字节,就是这个结构体的尺寸
    uint16_t chunk_hdr_sz; // CHUNK的头大小, 1.0中 固定为12
    uint32_t blk_sz; // 块大小, 必须为4的整数倍,默认值为:4096
    uint32_t total_blks; // 总块数
    uint32_t total_chunks; // 总CHUNK数
    uint32_t image_checksum; // CRC, 802.3多项式
};
// 什么是CHUNK,什么是BLOCK?
// CHUNK是sparse文件的基本单元,一个sparse文件由28字节的文件头加上
// 连续的CHUNK组成。BLOCK为CHUNK的基本单元,一个CHUNK由一个
// CHUNK头(12字节)和若干个BLOCK组成,每个BLOCK的大小由文件头中
// 的blk_sz决定.

enum ChunkType {
    CHUNK_TYPE_RAW = 0xcac1, // 该CHUNK中的数据为原始数据, 由若干(头中的chunk_sz)个块组成
    CHUNK_TYPE_FILL = 0xcac2, // 该CHUNK是填充块, CHUNK中有4个字节
                              // 表示CHUNK定义的若干(头中的chunk_sz)个块全部填充为CHUNK中附带的4个字节数据
    CHUNK_TYPE_DONT_CARE = 0xcac3, // 无需关心的块, 跳过即可
    CHUNK_TYPE_CRC32 = 0xcac4 // CHUNK中数据为CRC32, 4字节
};

#define SPARSE_HEADER_MAGIC 0xed26ff3a

struct chunk_header_t {
    uint16_t chunk_type; // CHUNK的类型
    uint16_t reserved; // 保留, 用于结构体对齐
    uint32_t chunk_sz; // CHUNK中块的个数
    uint32_t total_sz; // CHUNK的大小, 以字节为单位,表示CHUNK头的大小加CHUNK中
                       // 数据大大小, 例如, 对于填充的CHUNK,total_sz为16,对于RAW, 
                       // total_sz为blk_sz * chunk_sz + sizeof(chunk_header_t)
};

测试程序

// 将输入sparse格式的文件转存为原始格式
void dump(const char* file, const char* file_raw)
{
    FILE* fp = fopen(file, "rb");
    if (!fp) {
        printf("can't open file:%s\n", file);
    } else {
        sparse_header_t hdr;
        ssize_t hdr_sz = fread(&hdr, 1, sizeof(hdr), fp);
                if (!check_file_format(&hdr, hdr_sz)) {
                        printf("\"%s\" is not a sparse file\n", file);
                } else {
            FILE* fp_raw = fopen(file_raw, "wb");
            if (fp_raw) {
                // allocate
                uint32_t raw_sz = hdr.blk_sz * hdr.total_blks;
                printf("Allocated %10u bytes\n", raw_sz);
                char* blk = new char[hdr.blk_sz]; memset(blk, 0, hdr.blk_sz);
                for (uint32_t k = 0; k < hdr.total_blks; ++k) {
                    fwrite(blk, 1, hdr.blk_sz, fp_raw);
                }
                rewind(fp_raw);

                uint32_t chunk_cnt = 0;
                while (!feof(fp)) {
                    chunk_header_t chunk;
                    ssize_t chunk_sz = fread(&chunk, 1, sizeof(chunk), fp);
                    if (chunk_sz != sizeof(chunk)) break;
                    switch (chunk.chunk_type) {
                    case CHUNK_TYPE_RAW:
                        printf("write raw chunk: %10u bytes\n", hdr.blk_sz*chunk.chunk_sz);
                        for (uint32_t k = 0; k < chunk.chunk_sz; ++k) {
                            fread(blk, 1, hdr.blk_sz, fp);
                            fwrite(blk, 1, hdr.blk_sz, fp_raw);
                        }
                        break;
                    case CHUNK_TYPE_FILL:
                        uint32_t pattern; fread(&pattern, 1, 4, fp);
                        for (uint32_t k = 0; k < hdr.blk_sz / 4; ++k) {
                            *(uint32_t*)(blk + k*4) = pattern;
                        }
                        printf("write fil chunk: %10u bytes, pattern:%08x\n", 
                                4*chunk.chunk_sz,
                                *(uint32_t*)blk);
                        for (uint32_t k = 0; k < chunk.chunk_sz; ++k) {
                            fwrite(blk, 1, hdr.blk_sz, fp_raw);
                        }
                        break;
                    case CHUNK_TYPE_CRC32:
                        fread(blk, 1, 4, fp);
                        break;
                    }
                }
                delete[] blk;
                fclose(fp_raw);
            } else {
                printf("can't create file:%s\n", file_raw);
            }
        }
        fclose(fp);
    }
}

你可能感兴趣的:(Android sparse格式)