Files
MeowOS-SDK/tuku/logic/zip/zip.h
T
AskaEth 7036020005 图库: 阅读器页槽改 RGB565 常驻,页图内存减半(M32)
- 页槽从 RGBA 改成「已落框的 RGB565 位图」(2B/px):真机 480×853 页 1599KB → 800KB,
  两页常驻 3.2MB → 1.6MB。解码仍在 worker 里产出 RGBA,当场转 565 并释放 RGBA。
- SDK 新增 565 原语(meow_ui_draw.h / meow_ui_gfx.c):meow_gfx_blit_rgb565 命中页每行
  一次 memcpy(单次拷贝、无每帧重采样),缩放兜底走 565 最近邻。量化与 back_buf 用同一个
  rgb565(),565 屏上落下的像素与旧 RGBA 路径逐像素一致(不引入色偏/新增色带)。
- 预算按 565 重算:单页像素上限沿用旧 3MB@RGBA 的同几何口径(=1.5MB@565),
  MR_RESIDENT_CAP = 3 槽 + 1 张在途 = 3.2MB;reader_estimate_peak 新增 convert_bytes
  (落槽暂存 2B/px)与 peak_bytes 一起参与门控,避免实测超预算。
- 结果队列(已解码、未落槽)字节计入总预算(pending_bytes),不再「偷吃」最多 2 页。
- CBZ meta() 改读条目 4KB 前缀(mz_read_prefix;deflate 解到 4KB 即停,输入缓冲走栈),
  500 页排版不再触发 500 次全量解压。
- 测试:B3/B8 的 565 常驻与在途预算断言、CBZ 500 页 stored/deflate 前后对比、
  P12 565 与 RGBA 路径的逐像素颜色对比(量化误差/RMSE/灰阶梯)。
2026-11-06 18:43:11 +08:00

96 lines
5.1 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);
/* 只解压条目**前缀**到 buf(buf_size = 容量):stored 直接读前 buf_size 字节,
* deflate 在 inflate 出 buf_size 字节后即停(不整条目解压)。
* *out_size = 实际写入字节数(= min(buf_size, uncomp_size))。
* 用途:CBZ 排版只看图片头取宽高(PNG IHDR 33 字节 / JPEG SOF / BMP 头都在前 4KB)。
* 注意:没有读完整条目,因此**不校验整段 CRC**(只校验结构/长度),不要用它取内容。
* 出错语义与 mz_read 相同(越界/坏流/加密/zip64 一律返回错误码)。 */
int mz_read_prefix(mz_archive *z, const mz_entry *e, void *buf, size_t buf_size,
size_t *out_size);
const char *mz_strerror(int err);
#endif /* TUKU_LOGIC_ZIP_ZIP_H */