fix(amsd): app 显示名 name[17]→[49] + UTF-8 整序列截断(utf8_trim_incomplete)——修「流媒体客户端」18 字节被砍成 16 致 am list 输出非法 UTF-8、面板 /api/overview 被浏览器 JSON.parse 拒收(非 JSON 响应)

This commit is contained in:
AskaEth committed 2026-09-02 02:15:19 +08:00
1 parent 9d54cf89c5
commit 8588a6b453
1 file changed
+19 -1
+19 -1
View File
@@ -91,7 +91,7 @@ struct ams_route {
struct ams_app {
char pkg[MEOW_APP_ID_MAX]; /* app_id=package */
char name[17];
char name[49]; /* 显示名(UTF-8;截断必须整序列,见 utf8_trim_incomplete) */
char exec[129];
int known; /* 注册表(app.json 扫描)命中 */
int state; /* AMS_* */
@@ -374,6 +374,22 @@ static void poll_card(void)
}
/* ---- 注册表扫描(app.json 迷你解析:package/name/exec) ---- */
/* 把字符串末尾不完整的 UTF-8 序列砍掉(截断到最后一个完整码点边界)。
* 根因记录:name 截断若落在多字节序列中间,下游 JSON 嵌进面板会被浏览器
* JSON.parse 以非法 UTF-8 拒收(「非 JSON 响应」事故 2026-09-02)。 */
static void utf8_trim_incomplete(char *s)
{
size_t n = strlen(s), i = 0, last_good = 0;
while (i < n) {
unsigned char c = (unsigned char)s[i];
int len = (c < 0x80) ? 1 : (c >= 0xF0) ? 4 : (c >= 0xE0) ? 3 : (c >= 0xC0) ? 2 : 1;
if (i + (size_t)len > n) break; /* 不完整序列 */
i += (size_t)len;
last_good = i;
}
s[last_good] = '\0';
}
static void appjson_get(const char *content, const char *key, char *out, size_t n)
{
out[0] = '\0';
@@ -394,6 +410,7 @@ static void appjson_get(const char *content, const char *key, char *out, size_t
if (l >= n) l = n - 1;
memcpy(out, c, l);
out[l] = '\0';
utf8_trim_incomplete(out);
}
/* §6.2 二期:在 content 二分/扁平解析 route.<id>=<chain>(或 JSON "route.<id>":"<chain>")到 app。
@@ -540,6 +557,7 @@ static void registry_scan(int verbose)
appjson_get(content, "name", tmp, sizeof tmp);
if (!tmp[0]) scopy(tmp, sizeof tmp, nm);
scopy(a->name, sizeof a->name, tmp);
utf8_trim_incomplete(a->name); /* scopy 截断同样走整序列边界 */
appjson_get(content, "exec", tmp, sizeof tmp);
if (tmp[0]) scopy(a->exec, sizeof a->exec, tmp);
else if (!a->exec[0] || !strcmp(a->exec, "?")) {