/* * squeeze - 電子ブック/EPWING 書籍軽量化 * * Written by Junn Ohta (ohta@src.ricoh.co.jp). Public Domain. * Modified by yamagata@nwgpc.kek.jp on 2000/04/13 */ char *progname = "squeeze"; char *version = "1.1"; char *date = "2000/04/13"; char *author = "Junn Ohta (ohta@src.ricoh.co.jp)"; #include #include #include #include #include #include #include #include "epw.h" /* * 書籍構成要素種別 */ #define T_UNKNOWN 0 /* 不明 */ #define T_TEXT 1 /* 本文、メニュー、見出し */ #define T_INDEX 2 /* インデックス */ #define T_DATA 3 /* 音声、図版、外字 */ #define T_CINFO 4 /* 複合検索管理情報 */ /* * インデックス種別 */ #define IT_UNKNOWN 0 /* 不明 */ #define IT_DIRECT 1 /* 見出しを経由せず直接本文へ */ #define IT_NORMAL 2 /* 見出し経由で本文へ */ #define IT_COND 3 /* 条件検索 */ #define IT_ITEM 4 /* 項目別条件検索 */ /* * 書籍構成要素属性表 */ typedef struct itype_t { byte idmin; byte idmax; int must; /* 新しい書籍にコピーするか? */ int type; int idxtype; } ITYPE_T; ITYPE_T itypetbl[] = { { 0x00, 0x00, TRUE, T_TEXT, 0 }, /* 本文 */ { 0x01, 0x01, TRUE, T_TEXT, 0 }, /* メニュー */ { 0x02, 0x02, TRUE, T_TEXT, 0 }, /* 著作権表示 */ { 0x03, 0x03, FALSE, T_TEXT, 0 }, /* 条件検索見出し */ { 0x04, 0x04, TRUE, T_TEXT, 0 }, /* 前方一致かな見出し */ { 0x05, 0x05, TRUE, T_TEXT, 0 }, /* 前方一致表記形見出し */ { 0x06, 0x06, TRUE, T_TEXT, 0 }, /* 後方一致かな見出し */ { 0x07, 0x07, TRUE, T_TEXT, 0 }, /* 後方一致表記形見出し */ { 0x08, 0x08, TRUE, T_TEXT, 0 }, /* 前方一致英字見出し */ { 0x09, 0x09, TRUE, T_TEXT, 0 }, /* 後方一致英字見出し */ { 0x0a, 0x0a, FALSE, T_TEXT, 0 }, /* クロス検索見出し */ { 0x0b, 0x0b, FALSE, T_TEXT, 0 }, /* 項目番号見出し */ { 0x0d, 0x0d, FALSE, T_TEXT, 0 }, /* 項目別条件検索見出し */ { 0x0f, 0x0f, FALSE, T_TEXT, 0 }, /* 図版見出し */ { 0x20, 0x20, FALSE, T_TEXT, 0 }, /* メニュー */ { 0x21, 0x21, FALSE, T_TEXT, 0 }, /* 著作権表示 */ { 0x23, 0x23, FALSE, T_TEXT, 0 }, /* 著作権表示(1行表示用) */ { 0x24, 0x24, FALSE, T_TEXT, 0 }, /* 音声見出し */ { 0x30, 0x30, FALSE, T_INDEX, IT_DIRECT }, /* かなINDEX */ { 0x40, 0x40, FALSE, T_INDEX, IT_DIRECT }, /* 英字INDEX */ { 0x50, 0x50, FALSE, T_INDEX, IT_DIRECT }, /* 漢字INDEX */ { 0x60, 0x60, FALSE, T_INDEX, IT_DIRECT }, /* 表記形INDEX */ { 0x70, 0x70, TRUE, T_INDEX, IT_NORMAL }, /* 後方一致かなINDEX */ { 0x71, 0x71, TRUE, T_INDEX, IT_NORMAL }, /* 後方一致表記形INDEX */ { 0x72, 0x72, TRUE, T_INDEX, IT_NORMAL }, /* 後方一致英字INDEX */ { 0x80, 0x80, FALSE, T_INDEX, IT_COND }, /* 条件検索INDEX */ { 0x81, 0x81, FALSE, T_INDEX, IT_COND }, /* クロス検索INDEX */ { 0x90, 0x90, TRUE, T_INDEX, IT_NORMAL }, /* 前方一致かなINDEX */ { 0x91, 0x91, TRUE, T_INDEX, IT_NORMAL }, /* 前方一致表記形INDEX */ { 0x92, 0x92, TRUE, T_INDEX, IT_NORMAL }, /* 前方一致英字INDEX */ { 0xa0, 0xa0, FALSE, T_INDEX, IT_ITEM }, /* 項目番号INDEX */ { 0xa1, 0xa1, FALSE, T_INDEX, IT_ITEM }, /* 項目別条件検索INDEX */ { 0xb0, 0xb0, FALSE, T_INDEX, IT_UNKNOWN }, /* ページ検索INDEX */ { 0xb1, 0xb1, FALSE, T_INDEX, IT_UNKNOWN }, /* 漢字INDEX */ { 0xd0, 0xd0, FALSE, T_DATA, 0 }, /* モノクロ図版 */ { 0xd1, 0xd1, FALSE, T_DATA, 0 }, /* 拡張モノクロ図版 */ { 0xd2, 0xd2, FALSE, T_DATA, 0 }, /* カラー図版 */ { 0xd8, 0xd8, FALSE, T_DATA, 0 }, /* PCM音声 */ { 0xe0, 0xe0, FALSE, T_DATA, 0 }, /* 色見本 */ { 0xf0, 0xf0, FALSE, T_DATA, 0 }, /* 暗証 */ { 0xf1, 0xf1, TRUE, T_DATA, 0 }, /* 外字(16×16ドット) */ { 0xf2, 0xf2, TRUE, T_DATA, 0 }, /* 外字(8×16ドット) */ { 0xf3, 0xf3, TRUE, T_DATA, 0 }, /* 外字(24×24ドット) */ { 0xf4, 0xf4, TRUE, T_DATA, 0 }, /* 外字(12×24ドット) */ { 0xf5, 0xf5, TRUE, T_DATA, 0 }, /* 外字(30×30ドット) */ { 0xf6, 0xf6, TRUE, T_DATA, 0 }, /* 外字(15×30ドット) */ { 0xf7, 0xf7, TRUE, T_DATA, 0 }, /* 外字(48×48ドット) */ { 0xf8, 0xf8, TRUE, T_DATA, 0 }, /* 外字(24×48ドット) */ { 0xff, 0xff, FALSE, T_CINFO, 0 }, /* 複合検索管理情報 */ { 0x00, 0x2f, FALSE, T_TEXT, 0 }, /* その他のテキストデータ */ { 0x70, 0x7f, FALSE, T_INDEX, IT_NORMAL }, /* その他の後方一致INDEX */ { 0x80, 0x8f, FALSE, T_INDEX, IT_COND }, /* その他の条件検索INDEX */ { 0x90, 0x9f, FALSE, T_INDEX, IT_NORMAL }, /* その他の前方一致INDEX */ { 0xa0, 0xbf, FALSE, T_INDEX, IT_UNKNOWN }, /* その他のINDEX */ { 0xd0, 0xdf, FALSE, T_DATA, 0 } /* マルチメディアデータ */ }; /* * 書籍構成要素再配置用のテーブル */ typedef struct slot_t { byte id; /* 構成要素識別子 */ dword topblk; /* 構成要素の先頭ブロック */ dword endblk; /* 構成要素の最終ブロック */ dword blks; /* 構成要素のブロック数 */ dword ntopblk; /* コピー先の先頭ブロック */ } SLOT_T; long blkno; uchr *bookfile; uchr *nbookfile; uchr *logfile; SLOT_T *slot; /* 再配置計算用テーブル */ int slots; /* 再配置計算用テーブルの要素数 */ long totalblks; byte buf[BLKSIZ]; byte tmpbuf[BLKSIZ]; int tty; int EBGmode = 0; int main(); void usage(); void init(); void term(); int squeeze(); int nonzero(); ulng val(); INFO_T *mknewinfo(); int checkslot(); long reloc(); int idmust(); int idtype(); int ididxtype(); int markdel(); int hex(); int copybook(); void putvoid(); int copytext(); int copyindex(); int copydata(); int main(ac, av) int ac; char **av; { int ret; ac--, av++; while (ac > 0 && **av == '-') { switch (av[0][1]) { case 'g': case 'G': EBGmode = 1; break; case 'd': case 'D': if (markdel(&av[0][2]) == ERR) usage(); break; default: usage(); } ac--, av++; } if (ac != 2) usage(); bookfile = av[0]; nbookfile = av[1]; init(); blkno = 1L; ret = squeeze(bookfile, blkno, nbookfile); term(); if (ret == ERR) exit(1); exit(0); } void usage() { fprintf(stderr, "電子ブック/EPWING 書籍軽量化"); fprintf(stderr, " Ver.%s (%s)\n Written by %s, Public Domain.\n\n", version, date, author); fprintf(stderr, "使用法: %s [-g] [-d<削除IDリスト>]", progname); fprintf(stderr, " <入力書籍ファイル> <出力書籍ファイル>\n\n"); fprintf(stderr, "オプション:\n"); fprintf(stderr, " -g: EBG 専用モードにする\n"); fprintf(stderr, " -d: 指定IDの構成要素を取り除く\n"); exit(1); } void init() { time_t t; FILE *fp; tty = isatty(fileno(stderr)); logfile = (uchr *)malloc(strlen(progname) + strlen(".log") + 1); sprintf(logfile, "%s.log", progname); if ((fp = fopen(logfile, "a")) == NULL) return; time(&t); fprintf(fp, "処理開始: %s\n", ctime(&t)); fclose(fp); } void term() { time_t t; FILE *fp; if ((fp = fopen(logfile, "a")) == NULL) return; time(&t); fprintf(fp, "\n処理終了: %s\n", ctime(&t)); fclose(fp); } #ifdef VARARGS #include void log(va_alist) va_dcl #else #include void log(uchr *fmt, ...) #endif { FILE *fp; #ifdef VARARGS va_list va; uchr *fmt; va_start(va); fmt = va_arg(va, uchr *); #else va_list va; va_start(va, fmt); #endif vfprintf(stderr, fmt, va); if ((fp = fopen(logfile, "a")) != NULL) { vfprintf(fp, fmt, va); fclose(fp); } va_end(va); } int squeeze(bookfile, blkno, nbookfile) char *bookfile, *nbookfile; long blkno; { int i; INFO_T *infop, *ninfop; SLOT_T *slotp; if (open_book(bookfile) == ERR) { log("%s がオープンできません\n", bookfile); return ERR; } if ((infop = getinfo(blkno)) == NULL) { log("書籍管理情報が取得できません\n"); return ERR; } ninfop = mknewinfo(infop); if (ninfop == NULL) { log("メモリーが足りません\n"); return ERR; } log("入力ファイル = %s\n", bookfile); log("出力ファイル = %s\n\n", nbookfile); log("《再配置プラン》\n\n"); log("ID 開始ブロック 終了ブロック サイズ 再配置先\n"); slotp = slot; for (i = 0; i < slots; i++) { log("%02X %8lu %8lu %8lu %8lu\n", slotp->id, slotp->topblk, slotp->endblk, slotp->blks, slotp->ntopblk); slotp++; } log("\n"); if (checkslot() == ERR) { log("書籍ファイルの再構成を中止しました\n"); return ERR; } if (open_newbook(nbookfile) == ERR) { log("%s がオープンできません\n", nbookfile); return ERR; } if (putinfo(ninfop, 1L) == ERR) { log("書籍管理情報が書き込めません\n"); return ERR; } if (copybook() == ERR) { log("書籍ファイルの再構成を中止しました\n"); return ERR; } close_book(); if (close_newbook() == ERR) { log("書籍ファイルがクローズできません\n"); return ERR; } return OK; } int nonzero(p, len) uchr *p; int len; { while (len--) if (*p++) return TRUE; return FALSE; } ulng val(str, len) uchr *str; int len; { ulng l; l = 0L; while (len--) l = (l << 8) + *str++; return l; } INFO_T * mknewinfo(infop) INFO_T *infop; { int i, j, k, m, n; int items, cents, citems, cinfos; long topblk; INFO_T *ninfop; ITEM_T *itemp, *nitemp; CINFO_T *cinfop, *ncinfop; CENT_T *centp, *ncentp; CITEM_T *citemp, *ncitemp; /* * コピーする構成要素の数(items)と * 複合検索管理情報の数(cinfos)と * 再配置計算用テーブルの要素数(slots)を数える。 * 構成要素が複合検索管理情報(ID_CINFO)の場合、 * itemsには1、slotsには下位構成要素の総数が加算される。 * 複合検索の下位構成要素は重複することがあるが、 * ここでは重複してもかまわずカウントする。 */ items = 0; cinfos = 0; slots = 0; itemp = infop->item; for (i = 0; i < infop->items; i++) { if (!idmust(itemp->itemid)) { itemp++; continue; } if (itemp->itemid != ID_CINFO) { items++; slots++; itemp++; continue; } items++; cinfos++; cinfop = itemp->cinfo; centp = cinfop->cent; for (j = 0; j < cinfop->cents; j++) { citemp = centp->citem; for (k = 0; k < centp->citems; k++) { slots++; citemp++; } centp++; } itemp++; } /* * 構成要素情報をコピーし、複合検索管理情報を再配置する。 * 書籍管理情報は最初のブロックに書き込まれるので、 * 複合検索管理情報は2ブロックめ以降に再配置される。 */ ninfop = (INFO_T *)malloc(sizeof(INFO_T)); if (ninfop == NULL) return NULL; *ninfop = *infop; ninfop->items = items; nitemp = (ITEM_T *)malloc(sizeof(ITEM_T) * items); if (nitemp == NULL) return NULL; ninfop->item = nitemp; topblk = 2L; /* 複合検索管理情報の開始ブロック */ itemp = infop->item; nitemp = ninfop->item; for (i = 0; i < infop->items; i++) { if (!idmust(itemp->itemid)) { itemp++; continue; } *nitemp = *itemp; if (itemp->itemid != ID_CINFO) { /* * 複合検索管理情報以外の構成要素 */ itemp++; nitemp++; continue; } /* * 複合検索管理情報 */ nitemp->topblk = topblk++; cinfop = itemp->cinfo; ncinfop = (CINFO_T *)malloc(sizeof(CINFO_T)); if (ncinfop == NULL) return NULL; nitemp->cinfo = ncinfop; *ncinfop = *cinfop; centp = cinfop->cent; ncentp = (CENT_T *)malloc(sizeof(CENT_T) * ncinfop->cents); if (ncentp == NULL) return NULL; ncinfop->cent = ncentp; for (j = 0; j < cinfop->cents; j++) { *ncentp = *centp; citemp = centp->citem; ncitemp = (CITEM_T *)malloc(sizeof(CITEM_T) * ncentp->citems); if (ncitemp == NULL) return NULL; ncentp->citem = ncitemp; for (k = 0; k < centp->citems; k++) { *ncitemp = *citemp; citemp++; ncitemp++; } centp++; ncentp++; } itemp++; nitemp++; } /* * 再配置計算用テーブルを作ると同時に、 * 複合検索管理情報以外の構成要素も再配置する。 */ slot = (SLOT_T *)malloc(sizeof(SLOT_T) * slots); if (slot == NULL) return NULL; slots = 0; /* 重複を除いたslotsの個数を再計算する */ nitemp = ninfop->item; for (i = 0; i < ninfop->items; i++) { if (nitemp->itemid != ID_CINFO) { /* * 複合検索管理情報以外の構成要素 */ for (m = 0; m < slots; m++) { if (slot[m].topblk == nitemp->topblk) { nitemp->topblk = slot[m].ntopblk; break; } } if (m == slots) { slot[slots].id = nitemp->itemid; slot[slots].topblk = nitemp->topblk; slot[slots].endblk = nitemp->topblk + nitemp->blks - 1; slot[slots].blks = nitemp->blks; slot[slots].ntopblk = topblk; nitemp->topblk = topblk; topblk += nitemp->blks; slots++; } nitemp++; continue; } /* * 複合検索管理情報 */ ncinfop = nitemp->cinfo; ncentp = ncinfop->cent; for (j = 0; j < ncinfop->cents; j++) { ncitemp = ncentp->citem; for (k = 0; k < ncentp->citems; k++) { for (m = 0; m < slots; m++) { if (slot[m].topblk == ncitemp->ctopblk) { ncitemp->ctopblk = slot[m].ntopblk; break; } } if (m == slots) { slot[slots].id = ncitemp->citemid; slot[slots].topblk = ncitemp->ctopblk; slot[slots].endblk = ncitemp->ctopblk + ncitemp->cblks - 1; slot[slots].blks = ncitemp->cblks; slot[slots].ntopblk = topblk; ncitemp->ctopblk = topblk; topblk += ncitemp->cblks; slots++; } ncitemp++; } ncentp++; } nitemp++; } return ninfop; } int checkslot() { int i, err; err = 0; for (i = 0; i < slots; i++) { if (idtype(slot[i].id) == T_UNKNOWN) { log("構造が不明の書籍構成要素があります(ID=%02X)\n", slot[i].id); err++; } if (idtype(slot[i].id) == T_INDEX && ididxtype(slot[i].id) == IT_UNKNOWN) { log("構造が不明のインデックスがあります(ID=%02X)\n", slot[i].id); err++; } } if (err) return ERR; return OK; } long reloc(blk) long blk; { int i; SLOT_T *slotp; slotp = slot; for (i = 0; i < slots; i++) { if (blk >= slotp->topblk && blk <= slotp->endblk) return blk - slotp->topblk + slotp->ntopblk; slotp++; } return 0L; } int idmust(id) int id; { int i, n; n = sizeof(itypetbl) / sizeof(itypetbl[0]); for (i = 0; i < n; i++) { if (id >= itypetbl[i].idmin && id <= itypetbl[i].idmax) return itypetbl[i].must; } return FALSE; } int idtype(id) int id; { int i, n; n = sizeof(itypetbl) / sizeof(itypetbl[0]); for (i = 0; i < n; i++) { if (id >= itypetbl[i].idmin && id <= itypetbl[i].idmax) return itypetbl[i].type; } return T_UNKNOWN; } int ididxtype(id) int id; { int i, n; n = sizeof(itypetbl) / sizeof(itypetbl[0]); for (i = 0; i < n; i++) { if (id >= itypetbl[i].idmin && id <= itypetbl[i].idmax) return itypetbl[i].idxtype; } return IT_UNKNOWN; } int markdel(str) uchr *str; { int i, n; int dmin, dmax; n = sizeof(itypetbl) / sizeof(itypetbl[0]); for (i = 0; i < n; i++) itypetbl[i].must = TRUE; while (*str) { dmin = dmax = hex(str); if (dmin < 0) return ERR; str += 2; if (*str == '-') { str++; dmax = hex(str); if (dmax < 0) return ERR; str += 2; } for (i = 0; i < n; i++) { if (dmax >= itypetbl[i].idmin && dmin <= itypetbl[i].idmax) itypetbl[i].must = FALSE; } if (*str == ',') str++; } return OK; } int hex(s) uchr *s; { int n; if (!isxdigit(s[0]) || !isxdigit(s[1])) return -1; if (s[0] >= '0' && s[0] <= '9') n = s[0] - '0'; else if (s[0] >= 'A' && s[0] <= 'F') n = s[0] - 'A' + 10; else if (s[0] >= 'a' && s[0] <= 'f') n = s[0] - 'a' + 10; n <<= 4; if (s[1] >= '0' && s[1] <= '9') n += s[1] - '0'; else if (s[1] >= 'A' && s[1] <= 'F') n += s[1] - 'A' + 10; else if (s[1] >= 'a' && s[1] <= 'f') n += s[1] - 'a' + 10; return n; } int copybook() { int i, ret; SLOT_T *p; if (tty) { fprintf(stderr, "処理中です(0%%)"); fflush(stderr); } totalblks = slot[slots-1].ntopblk + slot[slots-1].blks - 1; p = slot; for (i = 0; i < slots; i++) { if (locate_block(p->topblk) == ERR) { if (tty) putc('\n', stderr); log("ファイルの読み込みに失敗しました\n"); return ERR; } if (locate_newblock(p->ntopblk) == ERR) { if (tty) putc('\n', stderr); log("ファイルの書き込みに失敗しました\n"); return ERR; } switch (idtype(p->id)) { case T_TEXT: ret = copytext(p->id, p->topblk, p->blks); break; case T_INDEX: ret = copyindex(p->id, p->topblk, p->blks, ididxtype(p->id)); break; case T_DATA: ret = copydata(p->id, p->topblk, p->blks); break; } if (ret == ERR) return ERR; p++; } if (tty) fprintf(stderr, "\r終了しました \n"); else log("終了しました\n"); return OK; } void putvoid(n) int n; { if (n >= 2) { /* * "→□"を書き込む */ if (!EBGmode) { putword(0x222a); putword(0x2222); } else { putbyte('-'); putbyte('>'); putbyte('['); putbyte(']'); } n -= 2; } if (n >= 3 && n & 1) { putword(0x1fe0); /* 拡張強調表示開始 */ putword(0x0001); putword(0x1fe1); /* 拡張強調表示終了 */ n -= 3; } while (n >= 2) { putword(0x1f04); /* 半角開始 */ putword(0x1f05); /* 半角終了 */ n -= 2; } while (n--) if (!EBGmode) { putword(0x2121); /* 空白 */ } else { putbyte(' '); /* 空白 */ putbyte(' '); /* 空白 */ } } int copytext(itemid, topblk, blks) int itemid; long topblk, blks; { int i, pc, npc, curoff, erroff; long err, rel, curblk, endblk, errblk; long blk1, blk2, off1, off2, bcd1, bcd2; word w, w1, w2; byte *p; #ifdef TEST long nerr = 0L; #endif if (tty) { pc = -1; putc('\r', stderr); } log("ID=%02X, 種別=テキスト, 開始ブロック=%ld, ブロック数=%ld\n", itemid, topblk, blks); err = 0L; rel = 0L; reset_error(); endblk = topblk + blks - 1; for (;;) { if (get_error() > 0) { if (tty) putc('\n', stderr); log("ファイルの書き込み中にエラーが発生しました\n"); return ERR; } curblk = cur_block(); curoff = cur_off(); if (curblk > endblk || curblk == endblk && curoff == BLKSIZ) break; if (tty) { npc = (int)(cur_newblock() * 100 / totalblks); if (npc > pc) { fprintf(stderr, "\r処理中です(%d%%)", npc); fflush(stderr); pc = npc; } } if (!EBGmode) { w = getword(); } else { w = getbyte(); } again: if (!EBGmode) { if (w >= 0x2121 && w <= 0x7e7e || w >= 0xa121 && w <= 0xfe7e) { /* * JIS文字。仕様上の文字範囲は以下の通りのはず。 * 通常文字: 2121〜7426 * 外字: a121〜fe7e * しかし三省堂ワードハンターの現代国語辞典に7671、 * 電子ブック版研究社新英和・和英中辞典に7440がある。 */ putword(w); w = getword(); goto again; } } else { if (w == 0) { } else if (w == 0x1f) { w = w << 8 | getbyte(); } else { putbyte(w & 0xff); if (0 < w && w < 0x1f) { /* EBG gaiji */ w = getbyte(); putbyte(w & 0xff); } w = getbyte(); goto again; } } if (w == 0x0000) { /* * パディング */ if (!EBGmode) { putword(w); } else { putbyte(w); } continue; } /* * 表示制御記述子 */ if ((w & 0xff00) == 0x1f00) { switch (w & 0x00ff) { case 0x09: /* 字下げ指定 */ case 0x1a: /* JIS X4081附属書の指示による */ case 0x1b: /* JIS X4081附属書の指示による */ case 0x1c: /* JIS X4081附属書の指示による */ case 0x1d: /* JIS X4081附属書の指示による */ case 0x1e: /* JIS X4081附属書の指示による */ case 0x1f: /* JIS X4081附属書の指示による */ case 0x41: /* 検索キー記述子 */ case 0x45: /* 図版データ群識別子 (DIC 0.23による) */ case 0xe0: /* 拡張強調表示開始指定 */ case 0xe2: /* 保護開始指定 (DIC 0.23による) */ /* * 直後の1WORDをそのままコピーする。 * 1f45は電子ブック版広辞苑第四版に出てくる。 */ putword(w); w1 = getword(); putword(w1); break; case 0x31: /* 図版見出し中の指示開始? */ case 0x32: /* 電子ブック拡張モノクロ図版 */ case 0x42: /* 別項目参照記述子 */ case 0x44: /* 図版データ識別子 (DIC 0.23による) */ case 0x46: /* 図版メニュー識別子 (DIC 0.23による) */ case 0x49: /* 未確認: 表? (cdrom2による) */ case 0x4b: /* 未確認: 図形枠? (cdrom2による) */ case 0x4c: /* 未確認: 図形枠? (cdrom2による) */ case 0x4e: /* 未確認: ポインタ? (cdrom2による) */ case 0x4f: /* 未確認: ポインタ? (cdrom2による) */ /* * 終了識別子までを一時的に保存しておき、 * 終了識別子の直後にあるBCD4+BCD2を見て、 * 参照先がなければ全体を「→□」で置き換える。 * * 電子ブック版研究社新英和・和英中辞典では * 1f42の終了識別子1f62でオフセットが * 2048以上になっている箇所がある。 * データを見るとオフセットから2048を引いて * 次のブロックを参照するという方法で * つじつまがあっているようだ。 */ p = tmpbuf; *p++ = w >> 8; *p++ = w & 0xff; w1 = w + 0x0020; if (!EBGmode) { while ((w = getword()) != w1) { *p++ = w >> 8; *p++ = w & 0xff; } } else { int ww; while (1) { w = getbyte(); if (w == 0x1f) { ww = getbyte(); if (w << 8 | ww == w1) { w = w1; break; } else { *p++ = w; *p++ = ww; } } else { *p++ = w; } } } blk1 = getbcd(4); off1 = getbcd(2); if (blk1 < 0 || off1 < 0 || off1 >= BLKSIZ) { err++; errblk = cur_block(); erroff = cur_off(); #ifdef TEST if (tty) putc('\r', stderr); log("err: pos=%lu:%d\n", cur_block(), cur_off()); #endif } blk1 = reloc(blk1); if (blk1 == 0L) { putvoid((p - tmpbuf) / 2 + 4); } else { putbytes(tmpbuf, p - tmpbuf); putword(w); putbcd(blk1, 4); putbcd(off1, 2); rel++; } break; case 0x33: /* 電子ブック音声 (ndtpdによる) */ /* * ハードディスク上では再生不能なので * 全体を「→□」で置き換える。 */ i = 1; while ((w = getword()) != 0x1f53) i++; i++; w = getword(); /* * 電子ブック版広辞苑第四版の図版見出しを見る限り、 * ここに来るのはBCD4+BCD2ではないようだ。 */ bcd1 = getbcd(3); bcd2 = getbcd(3); if (bcd1 < 0 || bcd2 < 0) { err++; errblk = cur_block(); erroff = cur_off(); #ifdef TEST if (tty) putc('\r', stderr); log("err: pos=%lu:%d\n", cur_block(), cur_off()); #endif } i += 4; putvoid(i); break; case 0x48: /* 音声データ識別子 (DIC 0.23による) */ /* * 1f48直後の5WORDはCDトラックを参照している。 * ハードディスク上では再生不能なので * 1f68までの全体を「→□」で置き換える。 * 1f68の後にはポインターは来ない。 * 1f48を使っている例はEPWING版大辞林にある。 */ i = 1; while ((w = getword()) != 0x1f68) i++; i++; putvoid(i); break; case 0x4a: /* EPWING PCM音声 */ /* * 1f4a+WORD+WORD+BCD4+BCD2+BCD4+BCD2+〜+1f6a * という構造をしている。 */ w1 = getword(); w2 = getword(); blk1 = getbcd(4); off1 = getbcd(2); blk2 = getbcd(4); off2 = getbcd(2); if (blk1 < 0 || off1 < 0 || off1 >= BLKSIZ || blk2 < 0 || off2 < 0 || off2 >= BLKSIZ) { err++; errblk = cur_block(); erroff = cur_off(); #ifdef TEST if (tty) putc('\r', stderr); log("err: pos=%lu:%d\n", cur_block(), cur_off()); #endif } blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { i = 9; while (getword() != 0x1f6a) i++; i++; putvoid(i); } else { putword(w); putword(w1); putword(w2); putbcd(blk1, 4); putbcd(off1, 2); putbcd(blk2, 4); putbcd(off2, 2); rel++; rel++; while ((w = getword()) != 0x1f6a) putword(w); putword(0x1f6a); } break; case 0x4d: /* カラー図版 */ /* * ここは非常にあやしい。実例はいまのところ * EPWING版広辞苑第四版の本文にしか見かけない。 * 例としては「アイガー」で2枚のカラー図版を * 参照しているところがある。すべての箇所が * 1f4d+0009+0000*5+BCD4+BCD2+ラベル+1f6d * という形であり、それ以外の組み合わせはない。 * とりあえず * 1f4d+WORD*6+BCD4+BCD2+ラベル+1f6d * という形式であると解釈しておく。 */ p = tmpbuf; *p++ = w >> 8; *p++ = w & 0xff; for (i = 0; i < 6; i++) { w = getword(); *p++ = w >> 8; *p++ = w & 0xff; } blk1 = getbcd(4); off1 = getbcd(2); if (blk1 < 0 || off1 < 0 || off1 >= BLKSIZ) { err++; errblk = cur_block(); erroff = cur_off(); #ifdef TEST if (tty) putc('\r', stderr); log("err: pos=%lu:%d\n", cur_block(), cur_off()); #endif } blk1 = reloc(blk1); if (blk1 == 0L) { i = 1 + 6 + 3; while (getword() != 0x1f6d) i++; i++; putvoid(i); } else { putbytes(tmpbuf, p - tmpbuf); putbcd(blk1, 4); putbcd(off1, 2); rel++; while ((w = getword()) != 0x1f6d) putword(w); putword(0x1f6d); } break; case 0x62: /* 別項目参照終了記述子 */ case 0x63: /* メニュー終了記述子 */ /* * アスキー辞・典・盤97のマイペディア97で、 * 「日本」の別項目参照中、「→ポツダム宣言」 * の直後に「ヌ→二・一スト」という項目がある。 * どうやら1f42が254cに化けているようだ。 * case 0x42で1f62まで読んで処理しているのに * case 0x62があるのは、これに対応するため。 * (しかしデータ化けを訂正するわけではない。) */ putword(w); blk1 = getbcd(4); off1 = getbcd(2); if (blk1 < 0 || off1 < 0 || off1 >= BLKSIZ) { err++; errblk = cur_block(); erroff = cur_off(); #ifdef TEST if (tty) putc('\r', stderr); log("err: pos=%lu:%d\n", cur_block(), cur_off()); #endif } blk1 = reloc(blk1); putbcd(blk1, 4); putbcd(off1, 2); rel++; break; case 0x14: /* 色指定開始指定 (DIC 0.23による) */ case 0x67: /* 色見本メニュー終了識別子 (DIC 0.23による) */ do { putword(w); w = getword(); } while ((w & 0xff00) == 0x1e00); goto again; case 0x15: /* 色指定終了指定 (DIC 0.23による) */ /* * EPWNIG版広辞苑第四版CD-ROM(カラー)版の * 条件検索で「あんりょくしょく」を検索すると * 「オリーブ色」の見出し末尾の「】」の後で、 * 1f15の直後にどういうわけか0260が出てくる。 * ことといVer.2、富士通CD辞書検索V1.3L12、 * OASYS-CDView/Win V3.0L10では表示が化けないが、 * DDwin、ViewIng95、WordEngine2では化ける。 * 広辞苑のバグか? */ putword(w); w = getword(); if ((w & 0xff00) == 0x1f00) goto again; putword(w); break; default: putword(w); break; } continue; } /* * 電子ブック版三省堂マック辞典の英和・和英辞典 * 「センチュリ+ビジネス+クラウン」では書籍構成要素 * 0F(図版一覧)の中にD1(拡張モノクロ図版)のデータも * ごちゃまぜで入っているようだ。たいていのデータは * エラーとしてここに落ちてくるが、データの一部が * 表示制御記述子とたまたま一致してしまうと、開始・ * 終了記述子の対応がとれずにプログラムが異常終了 * してしまう可能性がある。うまい対策がないので、 * ここでは放置しておく。 */ putword(w); #ifdef TEST if (nerr++ < 20L) { if (tty) putc('\r', stderr); log("ERR: word=%04X, pos=%lu:%d(%04x)\n", w, curblk, curoff, curoff); } #endif err++; errblk = cur_block(); erroff = cur_off(); } if (err) { if (tty) putc('\n', stderr); log("未知の表示制御構造がありました(個数=%ld, 最終位置=%lu:%d)\n", err, errblk, erroff); } return OK; } int copyindex(itemid, topblk, blks, idxtype) int itemid; long topblk, blks; int idxtype; { int i, pc, npc, id, eid; int off1, off2, erroff; long n, err, ref, rel, errblk; long blk1, blk2; word len, cnt, num, dum; if (tty) { pc = -1; putc('\r', stderr); } log("ID=%02X, 種別=インデックス, 開始ブロック=%ld, ブロック数=%ld\n", itemid, topblk, blks); err = 0L; ref = 0L; rel = 0L; reset_error(); n = cur_newblock(); while (blks--) { if (tty) { npc = (int)(n++ * 100 / totalblks); if (npc > pc) { fprintf(stderr, "\r処理中です(%d%%)", npc); fflush(stderr); pc = npc; } } id = getbyte(); len = getbyte(); cnt = getword(); putbyte(id); putbyte(len); putword(cnt); if ((id & 0x80) == 0x00) { /* * 上位インデックスブロック */ for (i = 0; i < cnt; i++) { getbytes(buf, len); blk1 = getdword(); blk1 = reloc(blk1); if (blk1 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbytes(buf, len); putdword(blk1); rel++; } goto nextblock; } /* * 最下位インデックスブロック */ if ((id & 0x10) == 0x00) { /* * 一般型エントリ */ switch (idxtype) { case IT_DIRECT: for (i = 0; i < cnt; i++) { len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); if (off1 >= BLKSIZ) err++; blk1 = reloc(blk1); if (blk1 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); rel++; } break; default: for (i = 0; i < cnt; i++) { len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); blk2 = getdword(); off2 = getword(); if (off1 > BLKSIZ || off2 >= BLKSIZ) { /* * 電子ブック版研究社新英和・和英中辞典では * オフセットoff1が2048になっている箇所がある。 * 次のブロックの先頭を参照すると解釈すれば * つじつまがあっているので、エラーにはしない。 * これに対応するため、ここだけエラーの範囲を * 「>= BLKSIZ」ではなく「> BLKSIZ」とする。 */ err++; } blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); putdword(blk2); putword(off2); rel++; rel++; } break; } goto nextblock; } /* * 集団概念付きエントリ */ switch (idxtype) { case IT_DIRECT: for (i = 0; i < cnt; i++) { eid = getbyte(); putbyte(eid); if (eid == 0x00) { /* * 基本エントリ */ len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); if (off1 >= BLKSIZ) err++; blk1 = reloc(blk1); if (blk1 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); rel++; } else if (eid == 0x80) { /* * 集団エントリ */ len = getbyte(); num = getword(); getbytes(buf, len); putbyte(len); putword(num); putbytes(buf, len); } else if (eid == 0xc0) { /* * メンバ情報 */ len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); if (off1 >= BLKSIZ) err++; blk1 = reloc(blk1); if (blk1 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); rel++; } else { err++; break; } } break; case IT_NORMAL: for (i = 0; i < cnt; i++) { eid = getbyte(); putbyte(eid); if (eid == 0x00) { /* * 基本エントリ */ len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); blk2 = getdword(); off2 = getword(); if (off1 >= BLKSIZ || off2 >= BLKSIZ) err++; blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); putdword(blk2); putword(off2); rel++; } else if (eid == 0x80) { /* * 集団エントリ */ len = getbyte(); num = getword(); getbytes(buf, len); putbyte(len); putword(num); putbytes(buf, len); } else if (eid == 0xc0) { /* * メンバ情報 */ len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); blk2 = getdword(); off2 = getword(); if (off1 >= BLKSIZ || off2 >= BLKSIZ) err++; blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); putdword(blk2); putword(off2); rel++; } else { err++; break; } } break; case IT_COND: for (i = 0; i < cnt; i++) { eid = getbyte(); putbyte(eid); if (eid == 0x00) { /* * 基本エントリ */ len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); blk2 = getdword(); off2 = getword(); if (off1 >= BLKSIZ || off2 >= BLKSIZ) err++; blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); putdword(blk2); putword(off2); rel++; } else if (eid == 0x80) { /* * 集団エントリ */ len = getbyte(); dum = getword(); num = getword(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); if (off1 >= BLKSIZ) err++; blk1 = reloc(blk1); if (blk1 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putword(dum); putword(num); putbytes(buf, len); putdword(blk1); putword(off1); rel++; } else if (eid == 0xc0) { /* * メンバ情報 */ blk1 = getdword(); off1 = getword(); if (off1 >= BLKSIZ) err++; blk1 = reloc(blk1); if (blk1 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putdword(blk1); putword(off1); rel++; } else { err++; break; } } break; case IT_ITEM: for (i = 0; i < cnt; i++) { eid = getbyte(); putbyte(eid); if (eid == 0x00) { /* * 基本エントリ */ len = getbyte(); getbytes(buf, len); blk1 = getdword(); off1 = getword(); blk2 = getdword(); off2 = getword(); if (off1 >= BLKSIZ || off2 >= BLKSIZ) err++; blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putbyte(len); putbytes(buf, len); putdword(blk1); putword(off1); putdword(blk2); putword(off2); rel++; } else if (eid == 0x80) { /* * 集団エントリ */ len = getbyte(); dum = getword(); num = getword(); getbytes(buf, len); putbyte(len); putword(dum); putword(num); putbytes(buf, len); } else if (eid == 0xc0) { /* * メンバ情報 */ blk1 = getdword(); off1 = getword(); blk2 = getdword(); off2 = getword(); if (off1 >= BLKSIZ || off2 >= BLKSIZ) err++; blk1 = reloc(blk1); blk2 = reloc(blk2); if (blk1 == 0L || blk2 == 0L) { errblk = cur_block(); erroff = cur_off(); ref++; } putdword(blk1); putword(off1); putdword(blk2); putword(off2); rel++; } else { err++; break; } } break; } nextblock: if (err) { if (tty) putc('\n', stderr); log("インデックス構造に不整合があります(ブロック=%lu)\n", cur_block()); return ERR; } if (get_error() > 0 || write_newblock() == ERR) { if (tty) putc('\n', stderr); log("ファイルの書き込み中にエラーが発生しました\n"); return ERR; } read_block(); } if (ref > 0) { if (tty) putc('\n', stderr); log("参照先のないインデックスがあります(個数=%ld, 最終位置=%lu:%d)\n", ref, errblk, erroff); } return OK; } int copydata(itemid, topblk, blks) int itemid; long topblk, blks; { int pc, npc; long n; if (tty) { pc = -1; putc('\r', stderr); } log("ID=%02X, 種別=データ, 開始ブロック=%ld, ブロック数=%ld\n", itemid, topblk, blks); reset_error(); n = cur_newblock(); while (blks--) { if (tty) { npc = (int)(n++ * 100 / totalblks); if (npc > pc) { fprintf(stderr, "\r処理中です(%d%%)", npc); fflush(stderr); pc = npc; } } getbytes(buf, BLKSIZ); putbytes(buf, BLKSIZ); if (get_error() > 0) { if (tty) putc('\n', stderr); log("ファイルの書き込み中にエラーが発生しました\n"); return ERR; } } return OK; }