- 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 推卡自刷验收全绿
436 lines
16 KiB
C
436 lines
16 KiB
C
/* app/book.c — 书桥实现(见 app/book.h):把 rd_src(TXT/FB2/EPUB/MOBI 段契约 + CBZ 图页)
|
||
* + engine(FreeType/rdimg) 串成「一本书」。
|
||
*
|
||
* 文本格式:build_index 逐段 rd_src_next → 每段 utf8→码点→rd_layout → 页索引(flat:段+段内字符偏移)
|
||
* (即 rdtxt 同款 UTF-8 段契约喂排版器);渲染按段重显。锚定 (段,字符偏移) 与字号无关。
|
||
* CBZ:纯图页,npages=图片数,render 用 rdimg 解码+降采样写内容区。
|
||
*/
|
||
#include "book.h"
|
||
#include "rdsrc.h"
|
||
#include "rdtxt.h"
|
||
#include "rdlayout.h"
|
||
#include "rdimg.h"
|
||
#include "../engine/rdft.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
typedef struct seg {
|
||
int page_start; /* 全局页表起点 */
|
||
int page_count; /* 本段页数 */
|
||
} seg_t;
|
||
|
||
struct rd_book {
|
||
char path[400];
|
||
char font[400];
|
||
char base[256];
|
||
const char *encname; /* TXT 有效编码可读名(含覆盖后);非 TXT = "" */
|
||
rd_enc_t enc; /* TXT 有效编码;非 TXT = RD_ENC_UTF8 */
|
||
rdft *ft;
|
||
rd_src *src;
|
||
rd_fmt_t fmt;
|
||
int is_img; /* 1=CBZ 图片书 */
|
||
|
||
int fs, ls, pw, ph, mx, my, top;
|
||
int content_w, content_h;
|
||
|
||
seg_t *segs; int nsegs;
|
||
rd_book_page *pages; int npages; /* flat 页表(文本) */
|
||
int cur;
|
||
|
||
/* 当前渲染段复用缓冲 */
|
||
uint8_t *seg_utf8; size_t seg_utf8_cap;
|
||
uint32_t *seg_cps; size_t seg_cps_n, seg_cps_cap;
|
||
rd_line *seg_lines; rd_page *seg_pages; int seg_nlines, seg_npages;
|
||
int seg_cache_idx;
|
||
};
|
||
|
||
/* 编码枚举 → 可读名(R3:Big5 正确解码后名实相符)。 */
|
||
static const char *enc_to_name(rd_enc_t enc)
|
||
{
|
||
switch (enc) {
|
||
case RD_ENC_UTF8: return "UTF-8";
|
||
case RD_ENC_UTF16LE: return "UTF-16LE";
|
||
case RD_ENC_UTF16BE: return "UTF-16BE";
|
||
case RD_ENC_GB18030: return "GB18030";
|
||
case RD_ENC_BIG5: return "Big5";
|
||
case RD_ENC_ASCII: return "ASCII";
|
||
default: return "";
|
||
}
|
||
}
|
||
static const char *fmt_encname(rd_fmt_t f, rd_enc_t enc)
|
||
{
|
||
if (f == RD_FMT_TXT) return enc_to_name(enc);
|
||
return "";
|
||
}
|
||
|
||
static int book_meas(uint32_t cp, int fs, int *adv, void *ctx)
|
||
{
|
||
(void)fs;
|
||
rd_book *b = (rd_book *)ctx;
|
||
return rdft_advance(b->ft, cp, adv);
|
||
}
|
||
|
||
/* ---- 文本:建索引(逐段 layout) ---- */
|
||
static int build_index(rd_book *b)
|
||
{
|
||
rd_src_reset(b->src);
|
||
size_t cap_segs = 64, cap_pages = 1024;
|
||
b->segs = (seg_t *)malloc(cap_segs * sizeof(seg_t));
|
||
b->pages = (rd_book_page *)malloc(cap_pages * sizeof(rd_book_page));
|
||
if (!b->segs || !b->pages) return -6;
|
||
b->nsegs = b->npages = 0;
|
||
|
||
uint8_t *utf8 = (uint8_t *)malloc(RDTXT_SEG_UTF8_MAX + 8);
|
||
if (!utf8) return -6;
|
||
|
||
int seg_idx = 0;
|
||
size_t ulen = 0;
|
||
while (rd_src_next(b->src, utf8, RDTXT_SEG_UTF8_MAX + 8, &ulen) == 0) {
|
||
if (seg_idx >= (int)cap_segs) { cap_segs *= 2; b->segs = (seg_t *)realloc(b->segs, cap_segs * sizeof(seg_t)); }
|
||
uint32_t *cps = NULL; size_t n = 0;
|
||
rd_utf8_to_cp(utf8, ulen, &cps, &n);
|
||
rd_layout_in in;
|
||
rd_layout_out out;
|
||
rd_line *lines = (rd_line *)malloc((n ? n : 1) * sizeof(rd_line));
|
||
rd_page *pages = (rd_page *)malloc((n ? n : 1) * sizeof(rd_page));
|
||
if (!lines || !pages) { free(lines); free(pages); free(cps); free(utf8); return -6; }
|
||
in.chars = cps; in.n = (int32_t)n; in.fs = b->fs; in.line_scale = b->ls;
|
||
in.page_w = b->content_w; in.page_h = b->content_h; in.indent = b->fs;
|
||
in.meas = book_meas; in.mctx = b;
|
||
out.lines = lines; out.pages = pages; out.max_lines = (int)(n ? n : 1); out.max_pages = (int)(n ? n : 1);
|
||
int lrc = rd_layout(&in, &out);
|
||
free(cps);
|
||
if (lrc != RD_LAYOUT_OK) { free(lines); free(pages); break; }
|
||
b->segs[seg_idx].page_start = b->npages;
|
||
b->segs[seg_idx].page_count = out.npages;
|
||
for (int p = 0; p < out.npages; p++) {
|
||
if (b->npages >= (int)cap_pages) { cap_pages *= 2; b->pages = (rd_book_page *)realloc(b->pages, cap_pages * sizeof(rd_book_page)); }
|
||
b->pages[b->npages].seg = seg_idx;
|
||
b->pages[b->npages].seg_char = out.pages[p].first_char;
|
||
b->npages++;
|
||
}
|
||
free(lines); free(pages);
|
||
seg_idx++;
|
||
}
|
||
free(utf8);
|
||
b->nsegs = seg_idx;
|
||
return 0;
|
||
}
|
||
|
||
/* ---- 正文重显 + 布局到复用缓冲 ---- */
|
||
static int load_seg(rd_book *b, int seg_idx)
|
||
{
|
||
if (seg_idx == b->seg_cache_idx) return 0;
|
||
size_t cap = RDTXT_SEG_UTF8_MAX + 8;
|
||
if (!b->seg_utf8) b->seg_utf8 = (uint8_t *)malloc(cap);
|
||
if (!b->seg_utf8) return -6;
|
||
size_t ulen = 0;
|
||
if (rd_src_seg(b->src, seg_idx, b->seg_utf8, cap, &ulen) != 0) return -4;
|
||
size_t n = 0;
|
||
free(b->seg_cps); b->seg_cps = NULL;
|
||
if (rd_utf8_to_cp(b->seg_utf8, ulen, &b->seg_cps, &n) != RD_ENC_OK) return -5;
|
||
b->seg_cps_n = n;
|
||
if (b->seg_lines) free(b->seg_lines);
|
||
if (b->seg_pages) free(b->seg_pages);
|
||
b->seg_lines = (rd_line *)malloc((n ? n : 1) * sizeof(rd_line));
|
||
b->seg_pages = (rd_page *)malloc((n ? n : 1) * sizeof(rd_page));
|
||
if (!b->seg_lines || !b->seg_pages) return -6;
|
||
rd_layout_in in;
|
||
rd_layout_out out;
|
||
in.chars = b->seg_cps; in.n = (int32_t)n; in.fs = b->fs; in.line_scale = b->ls;
|
||
in.page_w = b->content_w; in.page_h = b->content_h; in.indent = b->fs;
|
||
in.meas = book_meas; in.mctx = b;
|
||
out.lines = b->seg_lines; out.pages = b->seg_pages; out.max_lines = (int)(n ? n : 1); out.max_pages = (int)(n ? n : 1);
|
||
int lrc = rd_layout(&in, &out);
|
||
if (lrc != RD_LAYOUT_OK) { b->seg_nlines = b->seg_npages = 0; b->seg_cache_idx = -1; return -4; }
|
||
b->seg_nlines = out.nlines; b->seg_npages = out.npages;
|
||
b->seg_cache_idx = seg_idx;
|
||
return 0;
|
||
}
|
||
|
||
int rd_book_open(rd_book **b, const char *path, const char *font_path,
|
||
int fs, int ls, int pw, int ph, int mx, int my, int top)
|
||
{
|
||
if (!b || !path) return -1;
|
||
rd_book *x = (rd_book *)calloc(1, sizeof *x);
|
||
if (!x) return -6;
|
||
if (strlen(path) >= sizeof x->path) { free(x); return -2; }
|
||
strcpy(x->path, path);
|
||
if (font_path) { if (strlen(font_path) >= sizeof x->font) { free(x); return -2; } strcpy(x->font, font_path); }
|
||
const char *sl = strrchr(path, '/');
|
||
strncpy(x->base, sl ? sl + 1 : path, sizeof x->base - 1); x->base[sizeof x->base - 1] = 0;
|
||
char *dot = strrchr(x->base, '.'); if (dot) *dot = 0;
|
||
|
||
if (fs <= 0) fs = 20;
|
||
if (ls <= 0) ls = 130;
|
||
x->fs = fs; x->ls = ls; x->pw = pw; x->ph = ph; x->mx = mx; x->my = my; x->top = top;
|
||
x->content_w = pw - 2 * mx;
|
||
x->content_h = ph - top - my;
|
||
if (x->content_w < 10 || x->content_h < 10) { goto close; }
|
||
|
||
if (rd_src_open(&x->src, path) != 0) goto close;
|
||
x->fmt = rd_src_fmt(x->src);
|
||
x->enc = RD_ENC_UTF8;
|
||
rd_enc_t tmp_enc = RD_ENC_UTF8;
|
||
if (rd_src_txt_enc(x->src, &tmp_enc) == 0) x->enc = tmp_enc;
|
||
x->encname = fmt_encname(x->fmt, x->enc);
|
||
x->is_img = (x->fmt == RD_FMT_CBZ);
|
||
|
||
if (!x->is_img) {
|
||
if (rdft_init(&x->ft) != 0) goto close;
|
||
if (font_path && rdft_load_font(x->ft, x->font) != 0) { rdft_free(x->ft); x->ft = NULL; goto close; }
|
||
if (x->ft) rdft_set_px(x->ft, fs);
|
||
x->seg_cache_idx = -1;
|
||
if (build_index(x) != 0) goto close;
|
||
} else {
|
||
int pages = rd_src_pages(x->src);
|
||
x->npages = pages > 0 ? pages : 0;
|
||
}
|
||
x->cur = 0;
|
||
*b = x;
|
||
return 0;
|
||
close:
|
||
rd_book_close(x);
|
||
return -1;
|
||
}
|
||
|
||
void rd_book_close(rd_book *b)
|
||
{
|
||
if (!b) return;
|
||
free(b->segs);
|
||
free(b->pages);
|
||
free(b->seg_utf8);
|
||
free(b->seg_cps);
|
||
free(b->seg_lines);
|
||
free(b->seg_pages);
|
||
if (b->ft) rdft_free(b->ft);
|
||
if (b->src) rd_src_free(b->src);
|
||
free(b);
|
||
}
|
||
|
||
int rd_book_pages(rd_book *b) { return b ? b->npages : 0; }
|
||
int rd_book_current(rd_book *b) { return b ? b->cur : 0; }
|
||
int rd_book_font(rd_book *b) { return b ? b->fs : 0; }
|
||
int rd_book_ls(rd_book *b) { return b ? b->ls : 0; }
|
||
int rd_book_is_image(rd_book *b) { return b ? b->is_img : 0; }
|
||
const char *rd_book_encname(const rd_book *b) { return b ? (b->encname ? b->encname : "") : ""; }
|
||
rd_enc_t rd_book_enc_get(const rd_book *b) { return b ? b->enc : RD_ENC_UTF8; }
|
||
|
||
void rd_book_geom(rd_book *b, int *fs, int *ls, int *pw, int *ph, int *mx, int *my, int *top)
|
||
{
|
||
if (!b) return;
|
||
if (fs) *fs = b->fs;
|
||
if (ls) *ls = b->ls;
|
||
if (pw) *pw = b->pw;
|
||
if (ph) *ph = b->ph;
|
||
if (mx) *mx = b->mx;
|
||
if (my) *my = b->my;
|
||
if (top) *top = b->top;
|
||
}
|
||
const char *rd_book_basename(const rd_book *b) { return b ? b->base : ""; }
|
||
const char *rd_book_path(const rd_book *b) { return b ? b->path : ""; }
|
||
|
||
/* R3:TXT 编码切换——重开 src(带覆盖编码)、重建页索引、回锚当前页。非 TXT/CBZ 返回 -1。
|
||
* 事务式:先开新 src 成功才换(失败保留旧 src,书仍可用,返回负值)。 */
|
||
int rd_book_set_enc(rd_book *b, rd_enc_t enc)
|
||
{
|
||
if (!b || b->is_img || b->fmt != RD_FMT_TXT) return -1;
|
||
if (enc == b->enc) return b->cur; /* 同编码,无需重建 */
|
||
int seg; int32_t ch;
|
||
rd_book_anchor(b, &seg, &ch);
|
||
|
||
rd_src *ns = NULL;
|
||
if (rd_src_open_with_enc(&ns, b->path, &enc) != 0) return -2; /* 旧 src 未动 */
|
||
rd_src_free(b->src); b->src = ns; /* 换新 */
|
||
b->enc = enc;
|
||
b->encname = fmt_encname(b->fmt, b->enc);
|
||
|
||
/* 重建索引(复用现值 fs/ls/content_*),再回锚 */
|
||
free(b->segs); free(b->pages); b->segs = NULL; b->pages = NULL;
|
||
b->nsegs = b->npages = 0;
|
||
if (build_index(b) != 0) return -3; /* 新 src 有效但索引空 → 渲染返回 -1,安全降级 */
|
||
return rd_book_jump_to_anchor(b, seg, ch, b->fs, b->ls);
|
||
}
|
||
|
||
void rd_book_anchor(rd_book *b, int *seg, int32_t *ch)
|
||
{
|
||
if (!b || b->npages <= 0) { if (seg) *seg = 0; if (ch) *ch = 0; return; }
|
||
int p = b->cur < 0 ? 0 : (b->cur >= b->npages ? b->npages - 1 : b->cur);
|
||
if (seg) *seg = b->pages[p].seg;
|
||
if (ch) *ch = b->pages[p].seg_char;
|
||
}
|
||
|
||
int rd_book_turn(rd_book *b, int delta)
|
||
{
|
||
if (!b || b->npages <= 0) return 0;
|
||
int np = b->cur + delta;
|
||
if (np < 0) np = 0;
|
||
if (np >= b->npages) np = b->npages - 1;
|
||
b->cur = np;
|
||
return np;
|
||
}
|
||
|
||
int rd_book_set_page(rd_book *b, int page)
|
||
{
|
||
if (!b || b->npages <= 0) return 0;
|
||
if (page < 0) page = 0;
|
||
if (page >= b->npages) page = b->npages - 1;
|
||
b->cur = page;
|
||
return page;
|
||
}
|
||
|
||
/* ---- 文本页渲染(FreeType 字形 → 全屏 565) ---- */
|
||
static int render_text_page(rd_book *b, int page_no, uint16_t *out, int pitch, uint16_t bg565, uint16_t fg565)
|
||
{
|
||
int npix = b->pw * b->ph;
|
||
for (int i = 0; i < npix; i++) out[i] = bg565;
|
||
rd_book_page *pg = &b->pages[page_no];
|
||
int seg_idx = (int)pg->seg;
|
||
if (seg_idx < 0 || seg_idx >= b->nsegs) return -1;
|
||
if (load_seg(b, seg_idx) != 0) return -2;
|
||
int local_page = page_no - b->segs[seg_idx].page_start;
|
||
if (local_page < 0 || local_page >= b->seg_npages) return 1;
|
||
rd_page *pp = &b->seg_pages[local_page];
|
||
int asc = rdft_ascender(b->ft);
|
||
int screen_x0 = b->mx;
|
||
int screen_y0 = b->top;
|
||
for (int li = 0; li < pp->nlines; li++) {
|
||
rd_line *ln = &b->seg_lines[pp->first_line + li];
|
||
int pen = screen_x0 + ln->x;
|
||
int baseline = screen_y0 + ln->y + asc;
|
||
for (int32_t ci = ln->s; ci < ln->e; ci++) {
|
||
uint32_t cp = b->seg_cps[ci];
|
||
int adv = 0, bw = 0, bh = 0, left = 0, btop = 0;
|
||
const uint8_t *bmp = NULL;
|
||
rdft_glyph(b->ft, cp, &adv, &bmp, &bw, &bh, &left, &btop);
|
||
if (bmp && bw > 0)
|
||
rdft_blend565(out, pitch, b->pw, b->ph, pen, baseline, bmp, bw, bh, left, btop, fg565, bg565);
|
||
pen += adv;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* ---- CBZ 图片页渲染(rdimg 解码+降采样 → 内容区居中) ---- */
|
||
static int render_img_page(rd_book *b, int page_no, uint16_t *out, int pitch, uint16_t bg565)
|
||
{
|
||
int npix = b->pw * b->ph;
|
||
for (int i = 0; i < npix; i++) out[i] = bg565;
|
||
uint8_t *data = NULL; size_t size = 0;
|
||
if (rd_src_page(b->src, page_no, &data, &size) != 0) return -1;
|
||
uint16_t *scaled = NULL; int sw = 0, sh = 0;
|
||
if (rdimg_decode_scale(data, size, b->content_w, b->content_h, &scaled, &sw, &sh) != 0) {
|
||
free(data); return -2;
|
||
}
|
||
int x0 = b->mx + (b->content_w - sw) / 2;
|
||
int y0 = b->top + (b->content_h - sh) / 2;
|
||
int pitch_px = pitch / 2;
|
||
for (int y = 0; y < sh; y++) {
|
||
int ty = y0 + y; if (ty < 0 || ty >= b->ph) continue;
|
||
for (int x = 0; x < sw; x++) {
|
||
int tx = x0 + x; if (tx < 0 || tx >= b->pw) continue;
|
||
out[(size_t)ty * pitch_px + tx] = scaled[(size_t)y * sw + x];
|
||
}
|
||
}
|
||
free(scaled);
|
||
free(data);
|
||
return 0;
|
||
}
|
||
|
||
int rd_book_render(rd_book *b, int page_no, uint16_t *out, int pitch, uint16_t bg565, uint16_t fg565)
|
||
{
|
||
if (!b || !out || b->npages <= 0 || page_no < 0 || page_no >= b->npages) return -1;
|
||
if (b->is_img) return render_img_page(b, page_no, out, pitch, bg565);
|
||
return render_text_page(b, page_no, out, pitch, bg565, fg565);
|
||
}
|
||
|
||
/* ---- 重排 + 回锚 ---- */
|
||
int rd_book_set_size(rd_book *b, int fs, int ls)
|
||
{
|
||
if (!b) return -1;
|
||
if (b->is_img) { b->fs = fs; b->ls = ls; return 0; }
|
||
if (fs <= 0) fs = b->fs;
|
||
if (ls <= 0) ls = b->ls;
|
||
int anchor_seg, anchor_ch;
|
||
rd_book_anchor(b, &anchor_seg, &anchor_ch);
|
||
return rd_book_jump_to_anchor(b, anchor_seg, anchor_ch, fs, ls);
|
||
}
|
||
|
||
int rd_book_jump_to_anchor(rd_book *b, int seg, int32_t ch, int fs, int ls)
|
||
{
|
||
if (!b) return -1;
|
||
if (b->is_img) {
|
||
if (seg >= 0 && seg < b->npages) b->cur = seg;
|
||
return b->cur;
|
||
}
|
||
if (fs != b->fs || ls != b->ls) {
|
||
b->fs = fs; b->ls = ls;
|
||
b->content_w = b->pw - 2 * b->mx;
|
||
b->content_h = b->ph - b->top - b->my;
|
||
if (b->ft) rdft_set_px(b->ft, fs);
|
||
seg_t *nos = b->segs; int n_oldsegs = b->nsegs;
|
||
rd_book_page *nop = b->pages; int n_oldpages = b->npages;
|
||
b->segs = NULL; b->pages = NULL; b->nsegs = b->npages = 0;
|
||
if (build_index(b) != 0) { b->segs = nos; b->pages = nop; b->nsegs = n_oldsegs; b->npages = n_oldpages; return -5; }
|
||
free(nos); free(nop);
|
||
}
|
||
int target = 0;
|
||
for (int p = 0; p < b->npages; p++) {
|
||
int ps = b->pages[p].seg;
|
||
if (ps < seg) { target = p + 1; continue; }
|
||
if (ps > seg) break;
|
||
if (b->pages[p].seg_char >= ch) { target = p; break; }
|
||
target = p;
|
||
}
|
||
if (target >= b->npages) target = b->npages - 1;
|
||
if (target < 0) target = 0;
|
||
b->cur = target;
|
||
return target;
|
||
}
|
||
|
||
/* ---- SDK 字库兜底(文本格式) ---- */
|
||
int rd_book_render_text(rd_book *b, int page_no, rd_book_line_fn fn, void *ctx)
|
||
{
|
||
if (!b || !fn || b->is_img || b->npages <= 0 || page_no < 0 || page_no >= b->npages) return -1;
|
||
rd_book_page *pg = &b->pages[page_no];
|
||
int seg_idx = (int)pg->seg;
|
||
if (seg_idx < 0 || seg_idx >= b->nsegs) return -1;
|
||
if (load_seg(b, seg_idx) != 0) return -2;
|
||
int local_page = page_no - b->segs[seg_idx].page_start;
|
||
if (local_page < 0 || local_page >= b->seg_npages) return 1;
|
||
rd_page *pp = &b->seg_pages[local_page];
|
||
uint8_t *line_utf8 = (uint8_t *)malloc((size_t)(b->content_w * 4 + 32));
|
||
if (!line_utf8) return -6;
|
||
for (int li = 0; li < pp->nlines; li++) {
|
||
rd_line *ln = &b->seg_lines[pp->first_line + li];
|
||
int x = b->mx + ln->x, y = b->top + ln->y;
|
||
size_t o = 0;
|
||
for (int32_t ci = ln->s; ci < ln->e; ci++) {
|
||
uint8_t tmp[4];
|
||
int n = rd_cp_to_utf8(b->seg_cps[ci], tmp);
|
||
memcpy(line_utf8 + o, tmp, (size_t)n); o += (size_t)n;
|
||
}
|
||
line_utf8[o] = 0;
|
||
fn(x, y, (const char *)line_utf8, (int)o, ctx);
|
||
}
|
||
free(line_utf8);
|
||
return 0;
|
||
}
|
||
|
||
/* ---- 目录(转 rd_src) ---- */
|
||
int rd_book_toc_n(const rd_book *b)
|
||
{
|
||
return (b && b->src && !b->is_img) ? rd_src_toc_n(b->src) : 0;
|
||
}
|
||
int rd_book_toc(const rd_book *b, int i, char *title, int tsz, int *seg, int32_t *ch)
|
||
{
|
||
if (!b || !b->src || b->is_img || !title) return -1;
|
||
rd_toc_entry t;
|
||
if (rd_src_toc(b->src, i, &t) != 0) return -1;
|
||
strncpy(title, t.title, (size_t)tsz - 1); title[tsz - 1] = 0;
|
||
if (seg) *seg = t.seg;
|
||
if (ch) *ch = t.ch;
|
||
return 0;
|
||
}
|