- 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 上限/ 启动清孤儿/续读角标/封面首图。
107 lines
5.8 KiB
C
107 lines
5.8 KiB
C
/* 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 */
|