feat: M6.10–M6.19 批量收编 + M6.19 推卡验收
- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘) - OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复 - ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640 - 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫) - 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
This commit is contained in:
1 parent
c2ee7626a4
commit
3d70a3dd2c
176 files changed
+15507
-597
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,7 @@
|
||||
/* rdenc.c — 文本编码检测 + GB18030→UTF-8 + UTF-8 工具(实现见 rdenc.h)。 */
|
||||
/* rdenc.c — 文本编码检测 + GB18030/Big5→UTF-8 + UTF-8 工具(实现见 rdenc.h)。 */
|
||||
#include "rdenc.h"
|
||||
#include "gb18030_table.h"
|
||||
#include "big5_table.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -39,6 +40,14 @@ static inline int gb_trail_ok(unsigned b)
|
||||
{
|
||||
return (b >= 0x40 && b <= 0x7E) || (b >= 0x80 && b <= 0xFE);
|
||||
}
|
||||
static inline int gb_trail_q(unsigned b)
|
||||
{
|
||||
return gb_trail_ok(b);
|
||||
}
|
||||
static inline int big5_trail_q(unsigned b)
|
||||
{
|
||||
return (b >= 0x40 && b <= 0x7E) || (b >= 0xA1 && b <= 0xFE);
|
||||
}
|
||||
static inline int gb_col(unsigned b)
|
||||
{
|
||||
/* 列 = b - 0x40 - (b >= 0x80);b 已在合法范围(不含 0x7F) */
|
||||
@@ -128,16 +137,45 @@ int rd_gb18030_to_utf8(const uint8_t *in, size_t inlen, uint8_t *out, size_t out
|
||||
return RD_ENC_OK;
|
||||
}
|
||||
|
||||
/* ================= 编码检测 ================= */
|
||||
static inline int gb_trail_q(unsigned b)
|
||||
/* ================= Big5 双字节 → UTF-8 ================= */
|
||||
int rd_big5_to_utf8(const uint8_t *in, size_t inlen, uint8_t *out, size_t outcap, size_t *outlen)
|
||||
{
|
||||
return (b >= 0x40 && b <= 0x7E) || (b >= 0x80 && b <= 0xFE);
|
||||
}
|
||||
static inline int big5_trail_q(unsigned b)
|
||||
{
|
||||
return (b >= 0x40 && b <= 0x7E) || (b >= 0xA1 && b <= 0xFE);
|
||||
if (!in || !outlen) return RD_ENC_ERR_INVAL;
|
||||
if (!out && outcap) return RD_ENC_ERR_INVAL;
|
||||
size_t o = 0;
|
||||
size_t i = 0;
|
||||
while (i < inlen) {
|
||||
uint8_t b = in[i];
|
||||
if (b < 0x80) {
|
||||
if (o + 1 > outcap) { *outlen = o + 1; return RD_ENC_ERR_BUFSZ; }
|
||||
out[o++] = b; i++; continue;
|
||||
}
|
||||
if (b >= 0x81 && b <= 0xFE && i + 1 < inlen) {
|
||||
uint8_t t = in[i + 1];
|
||||
if (big5_trail_q(t)) {
|
||||
uint32_t cp = big5_2byte[b - RD_B5_LEAD0][gb_col(t)];
|
||||
uint8_t tmp[4];
|
||||
int n;
|
||||
if (cp == 0) { cp = 0xFFFD; }
|
||||
n = enc_utf8(cp, tmp);
|
||||
if (o + (size_t)n > outcap) { *outlen = o + (size_t)n; return RD_ENC_ERR_BUFSZ; }
|
||||
memcpy(out + o, tmp, (size_t)n); o += (size_t)n;
|
||||
i += 2; continue;
|
||||
}
|
||||
}
|
||||
/* 非法首字节 / 尾字节不成对 → U+FFFD */
|
||||
{
|
||||
uint8_t tmp[4]; int n = enc_utf8(0xFFFD, tmp);
|
||||
if (o + (size_t)n > outcap) { *outlen = o + (size_t)n; return RD_ENC_ERR_BUFSZ; }
|
||||
memcpy(out + o, tmp, (size_t)n); o += (size_t)n;
|
||||
i++; continue;
|
||||
}
|
||||
}
|
||||
*outlen = o;
|
||||
return RD_ENC_OK;
|
||||
}
|
||||
|
||||
/* ================= 编码检测 ================= */
|
||||
rd_enc_t rd_enc_detect(const uint8_t *buf, size_t len, rd_enc_stats *st)
|
||||
{
|
||||
if (st) { st->gb_pairs = st->big5_pairs = st->stray = 0; }
|
||||
@@ -156,33 +194,27 @@ rd_enc_t rd_enc_detect(const uint8_t *buf, size_t len, rd_enc_stats *st)
|
||||
return ascii ? RD_ENC_ASCII : RD_ENC_UTF8;
|
||||
}
|
||||
|
||||
/* 3) 双字节区段统计(GB18030 兼容 GBK;Big5 尾字节不同)。
|
||||
* GB 有效 = 码表 gb_2byte 查到非 0(GBK/GB18030 已映射码位);
|
||||
* Big5 专属 = 结构上 Big5 合法、但对 GB 码表无效(Big5 独有码位)。
|
||||
* 二者比较更可靠(结构上每个 GBK 双字节对也是合法 Big5 结构,无法区分)。 */
|
||||
long gb = 0, big5 = 0, stray = 0;
|
||||
/* 3) 双字节区段统计(GB18030 兼容 GBK)。
|
||||
* GB 有效 = 码表 gb_2byte 查到非 0(GBK/GB18030 已映射码位);stray = 无法成对字节。
|
||||
* R3 注:Big5 双字节区间是 GB18030 双字节区间的**严格子集**(Big5 尾字节
|
||||
* 0x40..0x7E|0xA1..0xFE ⊂ GB 尾字节 0x40..0x7E|0x80..0xFE;常见 GBK 简体字尾字节大量
|
||||
* 落在 0xA1..0xFE 与 Big5 重叠),故字节结构**无法可靠区分 Big5 与 GB18030**——盲判必然
|
||||
* 误伤(误把 GBK 判成 Big5 或反之)。自动检测统一兜底 GB18030(简体最常见、误伤代价
|
||||
* 最小);Big5 书由 UI 提供「编码切换」显式选中(对应正确解码走 rd_big5_to_utf8)。 */
|
||||
long gb = 0, stray = 0;
|
||||
for (size_t i = 0; i < len; ) {
|
||||
uint8_t b = buf[i];
|
||||
if (b < 0x80) { i++; continue; }
|
||||
if (b >= 0x81 && b <= 0xFE && i + 1 < len) {
|
||||
uint8_t t = buf[i + 1];
|
||||
int gb_ok = gb_trail_q(t) &&
|
||||
gb_2byte[b - RD_GB_LEAD0][gb_col(t)] != 0;
|
||||
int b5_ok = big5_trail_q(t);
|
||||
if (gb_ok) gb++;
|
||||
if (b5_ok && !gb_ok) big5++; /* Big5 专属:GB 码表无效 */
|
||||
if (gb_trail_q(t) && gb_2byte[b - RD_GB_LEAD0][gb_col(t)] != 0) gb++;
|
||||
i += 2; continue;
|
||||
}
|
||||
stray++; i++;
|
||||
}
|
||||
if (st) { st->gb_pairs = gb; st->big5_pairs = big5; st->stray = stray; }
|
||||
if (st) { st->gb_pairs = gb; st->big5_pairs = 0; st->stray = stray; }
|
||||
|
||||
/* 阈值(经验值):双字节对太少 → 乱码/不确定 → 兜底 GB18030(最常见中文编码)。
|
||||
* 注(READER_ENGINE_NOTES §3.5 风险):Big5 与 GB18030 双字节区大量重叠,码表有效性
|
||||
* 无法可靠区分(简体 GB2312 文本 trail 0xA1-0xFE 恰是 Big5 trail 区)。R1 双字节一律
|
||||
* 按 GB18030 兜底;Big5 经此检测也按 GB18030 试(v1 不转),真实区分需用户手动切编码
|
||||
* (列 R2)。 */
|
||||
if (gb + big5 < (long)(len / 5)) return RD_ENC_GB18030;
|
||||
if (gb < (long)(len / 5)) return RD_ENC_GB18030; /* 双字节对太少 → 不确定 → GB18030 */
|
||||
return RD_ENC_GB18030;
|
||||
}
|
||||
|
||||
@@ -231,7 +263,8 @@ int rd_to_utf8(rd_enc_t enc, const uint8_t *in, size_t inlen, uint8_t *out, size
|
||||
memcpy(out, in + off, inlen - off); *outlen = inlen - off;
|
||||
return RD_ENC_OK;
|
||||
}
|
||||
/* GB18030 / Big5(v1 按 GB18030 试) */
|
||||
if (enc == RD_ENC_BIG5) return rd_big5_to_utf8(in, inlen, out, outcap, outlen);
|
||||
/* GB18030 兜底 */
|
||||
return rd_gb18030_to_utf8(in, inlen, out, outcap, outlen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
/* rdenc.h — 阅读器文本编码检测 + GB18030→UTF-8 解码 + UTF-8 工具(纯 C,宿主可测)。
|
||||
/* rdenc.h — 阅读器文本编码检测 + GB18030/Big5→UTF-8 解码 + UTF-8 工具(纯 C,宿主可测)。
|
||||
*
|
||||
* 对齐 devdocs/plan/READER_ENGINE_NOTES.md §3(zLibrary 轻量化:BOM + 严格 UTF-8 + 双字节区段统计,
|
||||
* 不抄 N-gram 马尔可夫):
|
||||
* - BOM 优先:FE FF=UTF-16BE、FF FE=UTF-16LE、EF BB BF=UTF-8;
|
||||
* - 无 BOM → 严格 UTF-8 校验(合法即 UTF-8;ASCII 属 UTF-8 子集);
|
||||
* - 非 UTF-8 → GB18030(GBK 超集) / Big5 双字节区段统计(阈值经验值,见 READER_ENGINE_NOTES §3.3);
|
||||
* - **R1 只做 GB18030→UTF-8 双字节映射**(uint16[126][190] 码表),4 字节扩展段 → U+FFFD;
|
||||
* Big5 检测出来也按 GB18030 试(v1 不转 Big5,正文会乱但可读,注明)。
|
||||
* - 非 UTF-8 → GB18030(GBK 超集) 双字节映射(uint16[126][190] 码表);4 字节扩展段 → U+FFFD。
|
||||
*
|
||||
* 无 SDK 依赖;`#include "gb18030_table.h"`(生成物,见 tools/gen_gb18030_table.py)。
|
||||
* **Big5(R3)**:Big5 双字节区间是 GB18030 双字节区间的**严格子集**(Big5 尾字节
|
||||
* 0x40..0x7E|0xA1..0xFE ⊂ GB 尾字节 0x40..0x7E|0x80..0xFE,且常用 GBK 简体字尾字节
|
||||
* 大量落在 0xA1..0xFE 与 Big5 重叠),故**字节结构无法自动区分 Big5 与 GB18030**——
|
||||
* 盲判必然误伤。R3 方案:解码器支持 RD_ENC_BIG5(big5_2byte 码表),由 UI 提供编码
|
||||
* 切换(Auto→GB18030/Big5/UTF-8/UTF-16LE/BE),用户对繁体乱码书手动选 Big5 即正确
|
||||
* 渲染;自动检测默认 GB18030(简体最常见,误伤代价最小)。详见 READER_ENGINE_NOTES §3.5。
|
||||
*
|
||||
* 无 SDK 依赖;`#include "gb18030_table.h"` 与 `"big5_table.h"`(生成物,见 tools/)。
|
||||
*/
|
||||
#ifndef RDENC_H
|
||||
#define RDENC_H
|
||||
@@ -26,7 +31,7 @@ typedef enum {
|
||||
RD_ENC_UTF16LE,
|
||||
RD_ENC_UTF16BE,
|
||||
RD_ENC_GB18030, /* GBK 超集(解码器按 2 字节码表) */
|
||||
RD_ENC_BIG5, /* v1 检测但按 GB18030 解码 */
|
||||
RD_ENC_BIG5, /* Big5 → UTF-8(R3:big5_2byte 码表;需显式选中,不自动检测) */
|
||||
} rd_enc_t;
|
||||
|
||||
/* 检测统计(诊断 + 阈值用;值可为 0)。 */
|
||||
@@ -49,6 +54,9 @@ int rd_utf8_validate(const uint8_t *buf, size_t len);
|
||||
#define RD_ENC_ERR_BUFSZ -2 /* out 不足;*outlen 已填所需 */
|
||||
int rd_gb18030_to_utf8(const uint8_t *in, size_t inlen, uint8_t *out, size_t outcap, size_t *outlen);
|
||||
|
||||
/* Big5 双字节 → UTF-8(与 GB 版同构;Big5 非法双字节 → U+FFFD)。成功 0;输出不足 RD_ENC_ERR_BUFSZ。 */
|
||||
int rd_big5_to_utf8(const uint8_t *in, size_t inlen, uint8_t *out, size_t outcap, size_t *outlen);
|
||||
|
||||
/* UTF-8 → 码点数组(布局用;malloc 分配 *cps,调用方 free)。成功 0。 *n = 码点数。
|
||||
* 非法序列按一个 U+FFFD 收(宽松);len 为输入字节长。 */
|
||||
#define RD_UTF8_ERR_INVAL -1
|
||||
@@ -59,7 +67,7 @@ int rd_utf8_to_cp(const uint8_t *utf8, size_t len, uint32_t **cps, size_t *n);
|
||||
int rd_cp_to_utf8(uint32_t cp, uint8_t out[4]);
|
||||
|
||||
/* 通用:任意检测编码 → UTF-8(rdenc 已知的各编码)。UTF-16LE/BE 走简易 BOM 对齐 + 码点转换;
|
||||
* Big5 v1 按 GB18030 双字节表转(会乱但可读,注明)。返回码同 rd_gb18030_to_utf8。 */
|
||||
* Big5 走 rd_big5_to_utf8。返回码同 rd_gb18030_to_utf8。 */
|
||||
int rd_to_utf8(rd_enc_t enc, const uint8_t *in, size_t inlen, uint8_t *out, size_t outcap, size_t *outlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -40,6 +40,8 @@ static int txt_open(rd_src *s)
|
||||
if (!m) return -6;
|
||||
s->impl = m;
|
||||
if (rdtxt_probe(s->path, &m->info) != 0) { txt_free(s); return -1; }
|
||||
/* R3:显式编码覆盖(Big5 书)——探测只取 file_size/path,编码改用覆盖值 */
|
||||
if (s->enc_override_set) m->info.enc = s->enc_override;
|
||||
/* 建段表:一次扫描(off,len) */
|
||||
rdtxt_reader *r = NULL;
|
||||
if (rdtxt_reader_open(s->path, &m->info, &r) != 0) { txt_free(s); return -2; }
|
||||
@@ -105,7 +107,7 @@ static int is_ext(const char *path, const char *ext)
|
||||
return strcasecmp(path + pl - el, ext) == 0; /* ext 含点(如 ".cbz") */
|
||||
}
|
||||
|
||||
int rd_src_open(rd_src **out, const char *path)
|
||||
static int src_open_common(rd_src **out, const char *path, const rd_enc_t *enc)
|
||||
{
|
||||
if (!out || !path) return -1;
|
||||
/* 读前 64 字节做 magic 探测 */
|
||||
@@ -127,6 +129,7 @@ int rd_src_open(rd_src **out, const char *path)
|
||||
if (strlen(path) >= sizeof s->path) { free(s); return -2; }
|
||||
strcpy(s->path, path);
|
||||
s->fmt = pick->fmt;
|
||||
if (enc) { s->enc_override = *enc; s->enc_override_set = 1; }
|
||||
int rc = pick->open(s);
|
||||
if (rc != 0) { s->vt = NULL; s->impl = NULL; rd_src_free(s); return rc; }
|
||||
s->vt = pick->vt;
|
||||
@@ -134,6 +137,16 @@ int rd_src_open(rd_src **out, const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rd_src_open(rd_src **out, const char *path)
|
||||
{
|
||||
return src_open_common(out, path, NULL);
|
||||
}
|
||||
|
||||
int rd_src_open_with_enc(rd_src **out, const char *path, const rd_enc_t *enc)
|
||||
{
|
||||
return src_open_common(out, path, enc);
|
||||
}
|
||||
|
||||
void rd_src_free(rd_src *s)
|
||||
{
|
||||
if (!s) return;
|
||||
@@ -141,6 +154,14 @@ void rd_src_free(rd_src *s)
|
||||
free(s);
|
||||
}
|
||||
rd_fmt_t rd_src_fmt(const rd_src *s) { return s ? s->fmt : RD_FMT_TXT; }
|
||||
int rd_src_txt_enc(const rd_src *s, rd_enc_t *out)
|
||||
{
|
||||
if (!s || s->fmt != RD_FMT_TXT || !out) return -1;
|
||||
txt_impl *m = (txt_impl *)s->impl;
|
||||
if (!m) return -1;
|
||||
*out = m->info.enc;
|
||||
return 0;
|
||||
}
|
||||
const char *rd_src_title(const rd_src *s) { return (s && s->title[0]) ? s->title : (s ? s->path : ""); }
|
||||
const char *rd_src_author(const rd_src *s) { return (s && s->author[0]) ? s->author : "佚名"; }
|
||||
const char *rd_src_cover(const rd_src *s) { return (s && s->cover[0]) ? s->cover : NULL; }
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#ifndef RDSRC_H
|
||||
#define RDSRC_H
|
||||
|
||||
#include "rdenc.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -38,9 +39,15 @@ typedef struct rd_toc_entry {
|
||||
|
||||
/* 打开(按扩展名/magic 探测格式)。0=成功;负值=不支持/打不开。 */
|
||||
int rd_src_open(rd_src **out, const char *path);
|
||||
|
||||
/* 同 rd_src_open,但用 *enc 显式覆盖文本编码(TXT;ENC 为 NULL=自动探测)。
|
||||
* 非 TXT 格式忽略覆盖。R3 编码切换用(Big5 书显式选中)。 */
|
||||
int rd_src_open_with_enc(rd_src **out, const char *path, const rd_enc_t *enc);
|
||||
void rd_src_free(rd_src *s);
|
||||
|
||||
rd_fmt_t rd_src_fmt(const rd_src *s);
|
||||
/* TXT 有效文本编码(含覆盖);*out 填 rd_enc_t。非 TXT 返回 -1(XML/结构化固定 UTF-8 内部码)。 */
|
||||
int rd_src_txt_enc(const rd_src *s, rd_enc_t *out);
|
||||
const char *rd_src_title(const rd_src *s);
|
||||
const char *rd_src_author(const rd_src *s);
|
||||
const char *rd_src_cover(const rd_src *s); /* 封面 ref;无则 NULL */
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define RDSRC_INT_H
|
||||
|
||||
#include "rdsrc.h"
|
||||
#include "rdenc.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -29,6 +30,10 @@ struct rd_src {
|
||||
char author[160];
|
||||
char cover[320];
|
||||
void *impl;
|
||||
/* R3:文本编码显式覆盖(rd_src_open_with_enc)。enc_override_set=1 时 TXT loader 用该编码;
|
||||
* 非 TXT 格式(XML/结构化)固定 UTF-8 内部编码,忽略覆盖。 */
|
||||
rd_enc_t enc_override;
|
||||
int enc_override_set;
|
||||
};
|
||||
|
||||
/* 注册一个格式(供 rdsrc.c 调度)。 */
|
||||
|
||||
Reference in new issue
Block a user