Files
MeowOS-SDK/tuku/logic/zip/zip.h
T

87 lines
4.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* zip.h — 纯 C zip 容器读取器(只依赖 libz 的 inflate/crc32 + stdio)。
*
* 定位:tuku 漫画阅读器的 CBZ/zip 容器层——开包、列目录、按需解压单条目。
* 不依赖 meow_ui.h / SDK / tuku 其它逻辑,宿主可裸测(见 tuku/test/test_zip.c)。
*
* 用法:
* mz_archive *z = NULL;
* int rc = mz_open("book.cbz", &z);
* if (rc != MZ_OK) { fprintf(stderr, "%s\n", mz_strerror(rc)); return; }
* for (int i = 0; i < mz_count(z); i++) {
* const mz_entry *e = mz_entry_at(z, i);
* if (mz_entry_is_dir(e) || !is_image_name(e->name)) continue;
* size_t n = 0;
* void *px = NULL;
* if (mz_read_alloc(z, e, &px, &n) == MZ_OK) { decode(px, n); free(px); }
* }
* mz_close(z);
*
* 线程约束:单个 mz_archive 不是线程安全的(共享 FILE* 位置与条目表只读);
* 多线程请各自 mz_open 自己的 archive,或由调用方加锁。模块内无全局可变状态。
*
* 内存:mz_open 只把 central directory 的条目元数据(条目表 + 名字副本)读进内存,
* 不展开条目数据。mz_read 解压到调用方缓冲(缓冲需 >= 该条目 uncomp_size);
* mz_read_alloc 只为单个条目分配一次。
*
* 安全:所有偏移/长度都按文件实际大小校验;越界、截断、坏 magic、坏 CRC 一律
* 返回错误码而不崩溃。条目名按原始字节透传(通常是 UTF-8,不做规范化/解码)。
* 名字可能是 ".."、绝对路径或反斜杠——调用方若把它落到文件系统,必须自行拒绝
* 越界路径。加密、zip64、分卷压缩包明确返回 MZ_ERR_UNSUPPORTED。
*
* 错误码均为负值;MZ_OK 为 0。mz_strerror 对所有已知码返回静态字符串。
*/
#ifndef TUKU_LOGIC_ZIP_ZIP_H
#define TUKU_LOGIC_ZIP_ZIP_H
#include <stddef.h>
#include <stdint.h>
enum {
MZ_OK = 0,
MZ_ERR_IO = -1, /* 文件读写失败(打开/seek/read) */
MZ_ERR_FORMAT = -2, /* 结构非法:坏 magic、central directory 不一致、流损坏 */
MZ_ERR_TRUNCATED = -3, /* 声明的偏移/长度越过文件尾(含局部头越界) */
MZ_ERR_UNSUPPORTED = -4, /* 加密 / zip64 / 分卷 / 非 stored-deflate 压缩方式 */
MZ_ERR_BUF = -5, /* 调用方缓冲小于条目 uncomp_size */
MZ_ERR_MEM = -6, /* 内存分配失败 */
MZ_ERR_ARG = -7, /* 空指针 / 越界 index 等调用错误 */
MZ_ERR_CRC = -8 /* 解压结果 CRC-32 与 central directory 不符 */
};
typedef struct mz_entry {
const char *name; /* NUL 结尾;内容为 zip 内原始字节,生命周期同 archive */
uint32_t name_len; /* 原始名字字节数(不含结尾 NUL,name 中可能有内嵌 NUL) */
uint16_t method; /* 0=stored, 8=deflate;其它值在 mz_read 时返回 UNSUPPORTED */
uint16_t flags; /* zip general purpose flags(bit0=加密,bit11=UTF-8 名) */
uint32_t crc; /* 条目内容 CRC-32 */
uint64_t comp_size; /* 压缩后字节数(archive 内) */
uint64_t uncomp_size; /* 原始字节数 */
uint64_t local_offset; /* local file header 在 archive 内的偏移 */
} mz_entry;
typedef struct mz_archive mz_archive;
/* 打开 zip。成功时 *out 为新 archive(mz_close 释放);失败时 *out == NULL。 */
int mz_open(const char *path, mz_archive **out);
void mz_close(mz_archive *z);
int mz_count(const mz_archive *z);
const mz_entry *mz_entry_at(const mz_archive *z, int index); /* 越界返回 NULL */
const mz_entry *mz_find(const mz_archive *z, const char *name); /* 精确 strcmp,找不到 NULL */
/* 目录条目(名字以 '/' 结尾)。注意 zip 常见但没有强制要求目录条目存在。 */
int mz_entry_is_dir(const mz_entry *e);
/* 解压单条目到 buf。buf_size 必须 >= e->uncomp_size,否则 MZ_ERR_BUF。
* 成功时 *out_size = uncomp_size(可为 0)。out_size 可为 NULL。
* 校验 CRC 与声明尺寸;失败时 buf 内容不可用。 */
int mz_read(mz_archive *z, const mz_entry *e, void *buf, size_t buf_size, size_t *out_size);
/* mz_read 的便捷版:malloc 恰好 uncomp_size 字节(0 长度条目分配 1 字节)。
* 成功时 *out_buf 由调用方 free。 */
int mz_read_alloc(mz_archive *z, const mz_entry *e, void **out_buf, size_t *out_size);
const char *mz_strerror(int err);
#endif /* TUKU_LOGIC_ZIP_ZIP_H */