Files
MeowOS-SDK/tuku/logic/library.h
T
AskaEth 562cc44931 feat(tuku): CBZ 档案册集成——档案页源/书库列册/解压缓存
- logic/reader/archive_source.c:档案册页源实现 M6 mr_book 契约
  (mz_open/mz_count/mz_entry_at/mz_read_alloc),条目自然序 + 图片后缀 +
  路径安全(`..`/绝对路径/反斜杠/隐藏段/内嵌 NUL)+ 单页尺寸上限过滤;
  meta 按需解压只读图片头(不落缓存,结果按页记忆);mr_book_open_auto
  统一目录册/档案册开册,翻页与条漫两套消费代码零改动。
- logic/reader/page_cache.c/h:解压页落 MeowData/<pkg>/cache,LRU 64 页或
  32MiB,启动清 mrpage_* 孤儿,写入 .part + rename;与缩略图缓存同目录、
  前缀隔离;互斥量保护,解码/缩略图线程可并发。
- logic/library.c/h:扫描直接子文件里的 .cbz/.zip 成册(行=文件名+页数,
  点入直接阅读);档案探测由调用方注入(logic 不依赖 zip 容器),不注入时
  与 M7 行为逐字一致;册间衔接兄弟表=含图目录∪含页档案册,同列自然序。
  条目构造/副标题/角标/兄弟判据拆成小函数,便于 M13 书库重写拼接。
- ui/library:档案册行 + 封面缩略图(解压档内首图)、扫描注入探测、缓存
  目录统一由 page_cache 推导(一份规则)。
- ui/reader:open_book 走 mr_book_open_auto;跨册衔接纳入档案册。
- build_tuku.sh 补 zip/archive/cache 源与 sysroot zlib 头(zip.c include
  <zlib.h>);run_tests.sh 纳入 zip+cbz 用例;run_webtoon_tests.sh 的宿主
  集成构建补新源与 -lz;.gitignore 同步测试产物。
- test/test_cbz.c(267 项断言)+ make_cbz_samples.py 真实 cbz 夹具:
  列档/自然序/解压字节 CRC/路径安全/坏档与 zip 炸弹容错/LRU 与 32MiB 上限/
  启动清孤儿/续读角标/封面首图。
2026-11-05 11:58:12 +08:00

107 lines
5.8 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.
/* logic/library.h — 漫画书库扫描/排序(纯 C,不依赖 meow_ui.h)。
*
* 分层契约同 examples/hello:logic 层只含文件系统与纯数据,宿主 gcc 可直接裸测。
* (M7 起另提供每册续读角标与册间顺序查询;续读状态本身由 logic/reader.c 持久化,
* 本层只读它来拼副标题,宿主测试用配置存根顶替。)
* 书库语义:
* - 从 TF 卡根(MR_ROOT_DIR)起列「直接子目录」;M11 起另列直接子文件里的
* .cbz/.zip(档案册即一本书,与文件夹册同列自然序混排);
* - 只保留自身含 PNG/JPEG/BMP 的目录,或子树中最终含书的中间目录(可继续导航);
* - 行的 pages=该目录直接图片数(档案册=档内图片页数);subdirs=其下含图子目录数;
* - cover=缩略图源文件:优先该目录自然序第一张图,否则取第一个含图子目录的 cover
* (档案册留空,UI 解压档内首图);
* - 条目按名称自然排序(page2 < page10),含前导零与数字/字母混合名。
*
* 深度上限 MR_LIB_MAX_DEPTH 用于防止坏卡/超大树的无限递归;隐藏目录与系统目录
* (. 开头、MeowAPPs/MeowData/MeowOS/lost+found)不参与书库。符号链接跳过(防环)。
*/
#ifndef MR_LIBRARY_H
#define MR_LIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
#define MR_PATH_MAX 512
#define MR_NAME_MAX 256
#define MR_LIB_MAX_DEPTH 8
typedef struct mr_library_entry {
char name[MR_NAME_MAX]; /* 目录名/档案文件名(行主标题) */
char path[MR_PATH_MAX]; /* 完整路径(导航/进 reader 用) */
char cover[MR_PATH_MAX]; /* 缩略图源图(空=none;档案册由 UI 解压首图) */
char subtitle[48]; /* 预先格式化好的 "N pages" / "N books" / "N folders" */
int pages; /* 本目录直接图片数(档案册=档内图片页数) */
int subdirs; /* 本目录下含图子目录数 */
int has_images; /* 1=可直接阅读(直接含图 或 档案册) */
} mr_library_entry;
typedef struct mr_library {
mr_library_entry *items;
int count;
int cap;
} mr_library;
/* 扩展名判断:png/jpg/jpeg/bmp(大小写不敏感)。1=受支持图片。 */
int mr_path_is_image(const char *name);
/* 档案册扩展名判断:cbz / zip(大小写不敏感)。1=档案册。
* 注意这只是路径判据;能不能当书读还要看档案里有没有图片页(探测回调)。 */
int mr_path_is_archive(const char *name);
/* 自然排序比较:数字段按数值比(page2 < page10),数字相等时前导零少的在前;
* 非数字段 ASCII 大小写不敏感,完全等价时按原始字节序定序。 */
int mr_natural_cmp(const char *a, const char *b);
/* 扫描 dir 的直接子目录,写入 lib(先释放 lib 旧内容)。
* 返回条目数(>=0);dir 不可读返回 -1(lib 仍为空且可安全 mr_library_free)。
* max_depth<=0 或超过 MR_LIB_MAX_DEPTH 时按上限处理。 */
int mr_library_scan(mr_library *lib, const char *dir, int max_depth);
/* ============================================================ */
/* 档案册(M11):.cbz/.zip 当一本书,与文件夹册同列 */
/* ------------------------------------------------------------
* logic 层不依赖 zip 容器(保持宿主裸测/链接面干净):档案册探测由 UI 注入。
* archive_pages(path, ud) 对普通文件返回图片页数(>0=是一本书),0=不是/坏档。
* 传 NULL 时行为与 mr_library_scan 完全一致(纯目录书库),M7 语义不变。
*
* 档案册行的口径:name=文件名(含扩展名)、path=档案文件路径、pages=档内页数、
* has_images=1(点入直接阅读)、cover 留空(缩略图由 UI 解压首图生成)、
* 副标题 "N pages"、续读角标同文件夹册(按档案路径记)。
* 只含档案册的子目录算「可导航」(nav),副标题写 "N books"。
* ============================================================ */
typedef int (*mr_lib_archive_fn)(const char *path, void *ud);
int mr_library_scan_ex(mr_library *lib, const char *dir, int max_depth,
mr_lib_archive_fn archive_pages, void *ud);
/* 释放条目数组并清零(可重复调用)。 */
void mr_library_free(mr_library *lib);
/* 取父目录路径(去掉末尾 '/' 后截断最后一段)。根 "/" 返回 "/"。
* 成功 0;参数非法/输出缓冲不足 -1。 */
int mr_path_parent(const char *path, char *out, int outsz);
/* 目录是否**直接**含受支持图片(= 书库语义里的「一本书」,可直接进 reader)。
* 1=有;0=没有/不可读。 */
int mr_library_dir_has_images(const char *dir);
/* 册间衔接(M7):同父目录下按书库自然序排列的「可直接阅读」兄弟册。
* delta=+1 下一册 / -1 上一册。1=找到并写入 out 完整路径;
* 0=没有相邻册(当前册是首/末册,或当前册不在兄弟表中);-1=参数非法。
* 语义与书库一致:跳过隐藏/系统目录与符号链接,排序同 mr_natural_cmp。
* 只算文件夹册(直接含图目录)——M7 口径不变。 */
int mr_book_adjacent(const char *dir, int delta, char *out, int outsz);
/* 册间衔接 + 档案册(M11):兄弟表 = 「直接含图目录」∪「含图片页的 .cbz/.zip」,
* 两者同列按名称自然序混排(mission 基线:跨册衔接按同父目录自然序)。
* 因此末页前进可以从文件夹册进到同目录的档案册,反之亦然。
* archive_pages 传 NULL 时与 mr_book_adjacent 完全等价。 */
int mr_book_adjacent_ex(const char *dir, int delta, char *out, int outsz,
mr_lib_archive_fn archive_pages, void *ud);
#ifdef __cplusplus
}
#endif
#endif /* MR_LIBRARY_H */