/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#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 <varargs.h>
void
log(va_alist)
va_dcl
#else
#include <stdarg.h>
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;
}
syntax highlighted by Code2HTML, v. 0.9.1