/*
* bookinfo - 電子ブック/EPWING 書籍管理情報表示
*
* Written by Junn Ohta (ohta@src.ricoh.co.jp). Public Domain.
*/
char *progname = "bookinfo";
char *version = "1.0";
char *date = "1999/01/12";
char *author = "Junn Ohta (ohta@src.ricoh.co.jp)";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "epw.h"
#define MEGA 1048576L /* 1024 * 1024 */
#define NAME_LEN 28 /* 識別子名称表示幅 */
int verbose = FALSE;
long blkno;
uchr *bookfile;
int main();
void usage();
int bookinfo();
long estimate();
int nonzero();
ulng val();
uchr *hexstr();
uchr *jisstr();
uchr *idname();
int idmust();
int markdel();
uchr *bktype();
uchr *protinfo();
uchr *idxhndl();
uchr *dspvalid();
uchr *dsplist();
uchr *dspstyle();
uchr *idxinfo();
int
main(ac, av)
int ac;
char **av;
{
int ret;
ac--, av++;
while (ac > 0 && **av == '-') {
switch (av[0][1]) {
case 'v':
case 'V':
verbose = TRUE;
break;
case 'd':
case 'D':
if (markdel(&av[0][2]) == ERR)
usage();
break;
default:
usage();
}
ac--, av++;
}
if (ac < 1 || ac > 2)
usage();
bookfile = *av;
ac--, av++;
blkno = 1L;
if (ac == 1)
blkno = strtol(*av, NULL, 0);
ret = bookinfo(bookfile, blkno);
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 [-v] [-d<削除IDリスト>]", progname);
fprintf(stderr, " <書籍ファイル> [<情報ブロック番号>]\n\n");
fprintf(stderr, "オプション:\n");
fprintf(stderr, " -v: 複合検索管理情報を展開して表示する\n");
fprintf(stderr, " -d: 指定IDをサイズ計算でカウントしない\n");
exit(1);
}
int
bookinfo(bookfile, blkno)
char *bookfile;
long blkno;
{
int i, j, k, must, mark;
long size1, size2, cblks;
uchr tmp[32], tmp2[32], tmp3[32], tmp4[32];
INFO_T *infop;
ITEM_T *itemp;
CINFO_T *cinfop;
CENT_T *centp;
CITEM_T *citemp;
struct stat st;
if (open_book(bookfile) == ERR) {
fprintf(stderr, "%s: %s がオープンできません\n", progname, bookfile);
return ERR;
}
if ((infop = getinfo(blkno)) == NULL) {
fprintf(stderr, "%s: 書籍管理情報が取得できません\n", progname);
return ERR;
}
close_book();
printf("; 電子ブック/EPWING 書籍管理情報");
printf(" (generated by %s v%s)\n\n", progname, version);
printf("対象書籍ファイル = %s\n", bookfile);
printf("情報所在ブロック = %d\n", blkno);
printf("書籍構成要素数 = %d\n", infop->items);
printf("予備領域1(書籍種別/保護情報) = %sH\n",
hexstr(infop->resv1, tmp, RESV1_LEN));
printf(" 書籍種別: %s\n", bktype(infop->resv1));
printf(" 保護情報: %s\n", protinfo(infop->resv1));
printf("INDEX情報の取扱法 = %02XH (%s)\n",
infop->idxhndl, idxhndl(infop->idxhndl));
if (nonzero(infop->resv2, RESV2_LEN))
printf("予備領域2 = %sH\n", hexstr(infop->resv2, tmp, RESV2_LEN));
printf("\n");
printf(" ID 名称 ");
printf(" 先頭 サイズ INDEX情報 予備3/4\n");
itemp = infop->item;
for (i = 0; i < infop->items; i++) {
must = idmust(itemp->itemid);
mark = must? '*': ' ';
if (itemp->itemid != ID_CINFO) {
/*
* 複合検索以外
*/
printf("%c%02X %-*s %7lu%7lu %-9s %s/%s\n",
mark, itemp->itemid, NAME_LEN, idname(itemp->itemid),
itemp->topblk, itemp->blks, idxinfo(itemp),
hexstr(itemp->resv3, tmp, RESV3_LEN),
hexstr(itemp->resv4, tmp2, RESV4_LEN));
itemp++;
continue;
}
/*
* 複合検索
*/
cblks = itemp->blks;
cinfop = itemp->cinfo;
if (verbose) {
/*
* 複合検索管理情報を詳細表示
*/
printf("%c%02X 複合 %-*s %7lu%7lu %-9s %s/%s\n",
mark, ID_CINFO, CRESV1_LEN * 2,
nonzero(cinfop->cresv1, CRESV1_LEN)?
hexstr(cinfop->cresv1, tmp, CRESV1_LEN): (uchr *)"",
itemp->topblk, itemp->blks, idxinfo(itemp),
hexstr(itemp->resv3, tmp2, RESV3_LEN),
hexstr(itemp->resv4, tmp3, RESV4_LEN));
centp = cinfop->cent;
for (j = 0; j < cinfop->cents; j++) {
printf(" %3s%-*s %s\n",
(j < cinfop->cents - 1)? "|--": "'--",
CNAME_LEN, jisstr(centp->cname, tmp, CNAME_LEN),
hexstr(centp->cresv2, tmp2, CRESV2_LEN));
citemp = centp->citem;
for (k = 0; k < centp->citems; k++) {
printf(" %3s%c%02X %-*s %7lu%7lu %s/%s\n",
(j < cinfop->cents - 1)? "| ": " ",
mark, citemp->citemid,
NAME_LEN, idname(citemp->citemid),
citemp->ctopblk, citemp->cblks,
hexstr(citemp->cresv3, tmp, CRESV3_LEN),
hexstr(citemp->cresv4, tmp2, CRESV4_LEN));
cblks += citemp->cblks;
citemp++;
}
centp++;
}
} else {
/*
* 複合検索管理情報は合計サイズだけ表示
*/
centp = cinfop->cent;
for (j = 0; j < cinfop->cents; j++) {
citemp = centp->citem;
for (k = 0; k < centp->citems; k++) {
cblks += citemp->cblks;
citemp++;
}
centp++;
}
printf("%c%02X %-*s ***%7lu %-9s %s/%s\n",
mark, ID_CINFO, NAME_LEN, "複合検索",
cblks, idxinfo(itemp),
hexstr(itemp->resv3, tmp, RESV3_LEN),
hexstr(itemp->resv4, tmp2, RESV4_LEN));
}
itemp++;
}
printf("\n");
printf("表示方法の初期値情報:\n");
printf(" 有効無効フラグ = %02XH (%s)\n",
infop->dspvalid, dspvalid(infop->dspvalid));
printf(" 一覧表表示 = %02XH (%s)\n",
infop->dsplist, dsplist(infop->dsplist));
printf(" 本文表示法 = %02XH (%s)\n",
infop->dspstyle, dspstyle(infop->dspstyle));
if (nonzero(infop->resv5, RESV5_LEN))
printf(" 予備領域5 = %sH\n", hexstr(infop->resv5, tmp, RESV5_LEN));
if (nonzero(infop->resv6, RESV6_LEN))
printf(" 予備領域6 = %sH\n", hexstr(infop->resv6, tmp, RESV6_LEN));
printf("\n");
stat(bookfile, &st);
size1 = st.st_size;
size2 = estimate(infop, blkno);
printf("書籍ファイルサイズ = %3ldMB\n", (size1 + MEGA - 1) / MEGA);
printf("マーク部分のサイズ = %3ldMB\n", (size2 + MEGA - 1) / MEGA);
printf("\n");
freeinfo(infop);
return OK;
}
/*
* サイズ計算用のテーブル
*/
typedef struct slot_t {
dword topblk;
dword blks;
} SLOT_T;
long
estimate(infop, blkno)
INFO_T *infop;
long blkno;
{
int i, j, k, m, n, num, must;
long blks;
ITEM_T *itemp;
CINFO_T *cinfop;
CENT_T *centp;
CITEM_T *citemp;
SLOT_T *slot;
num = 1;
itemp = infop->item;
for (i = 0; i < infop->items; i++) {
must = idmust(itemp->itemid);
if (!must) {
itemp++;
continue;
}
num++;
if (itemp->itemid != ID_CINFO) {
itemp++;
continue;
}
cinfop = itemp->cinfo;
centp = cinfop->cent;
for (j = 0; j < cinfop->cents; j++) {
citemp = centp->citem;
for (k = 0; k < centp->citems; k++) {
num++;
citemp++;
}
centp++;
}
itemp++;
}
slot = (SLOT_T *)malloc(sizeof(SLOT_T) * num);
if (slot == NULL)
return 0L;
slot[0].topblk = blkno;
slot[0].blks = 1L;
n = 1;
itemp = infop->item;
for (i = 0; i < infop->items; i++) {
must = idmust(itemp->itemid);
if (!must) {
itemp++;
continue;
}
for (m = 0; m < n; m++) {
if (slot[m].topblk == itemp->topblk)
break;
}
if (m == n) {
slot[n].topblk = itemp->topblk;
slot[n].blks = itemp->blks;
n++;
}
if (itemp->itemid != ID_CINFO) {
itemp++;
continue;
}
cinfop = itemp->cinfo;
centp = cinfop->cent;
for (j = 0; j < cinfop->cents; j++) {
citemp = centp->citem;
for (k = 0; k < centp->citems; k++) {
for (m = 0; m < n; m++) {
if (slot[m].topblk == citemp->ctopblk)
break;
}
if (m == n) {
slot[n].topblk = citemp->ctopblk;
slot[n].blks = citemp->cblks;
n++;
}
citemp++;
}
centp++;
}
itemp++;
}
blks = 0L;
for (m = 0; m < n; m++)
blks += slot[m].blks;
free((char *)slot);
return blks * BLKSIZ;
}
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;
}
uchr *
hexstr(hex, buf, len)
uchr *hex, *buf;
int len;
{
uchr *p;
p = buf;
while (len--) {
*p++ = "0123456789ABCDEF"[*hex >> 4];
*p++ = "0123456789ABCDEF"[*hex & 0x0f];
hex++;
}
*p = '\0';
return buf;
}
uchr *
jisstr(p, buf, len)
uchr *p, *buf;
int len;
{
int c1, c2;
uchr *pend, *q;
pend = p + len;
while (pend >= p + 2 &&
(pend[-1] == '\0' && pend[-2] == '\0' ||
pend[-1] == 0x21 && pend[-2] == 0x21))
pend -= 2;
q = buf;
#ifdef EUC
while (p < pend)
*q++ = (*p++ | 0x80);
#endif
#ifdef SJIS
while (p < pend) {
c1 = *p++;
c2 = *p++;
if (c1 & 0x01) {
c2 += 0x1f;
if (c2 > 0x7e)
c2++;
} else {
c2 += 0x7e;
}
c1 = (c1 + 0xe1) >> 1;
if (c1 > 0x9f)
c1 += 0x40;
*q++ = c1;
*q++ = c2;
}
#endif
*q = '\0';
return buf;
}
/*
* 書籍構成要素識別子表
*/
typedef struct itype_t {
byte idmin;
byte idmax;
int must;
uchr *name;
} ITYPE_T;
ITYPE_T itypetbl[] = {
{ 0x00, 0x00, TRUE, "本文" },
{ 0x01, 0x01, TRUE, "メニュー" },
{ 0x02, 0x02, TRUE, "著作権表示" },
{ 0x03, 0x03, FALSE, "条件検索見出し" },
{ 0x04, 0x04, TRUE, "前方一致かな見出し" },
{ 0x05, 0x05, TRUE, "前方一致表記形見出し" },
{ 0x06, 0x06, TRUE, "後方一致かな見出し" },
{ 0x07, 0x07, TRUE, "後方一致表記形見出し" },
{ 0x08, 0x08, TRUE, "前方一致英字見出し" },
{ 0x09, 0x09, TRUE, "後方一致英字見出し" },
{ 0x0a, 0x0a, FALSE, "クロス検索見出し" },
{ 0x0b, 0x0b, FALSE, "項目番号見出し" },
{ 0x0d, 0x0d, FALSE, "項目別条件検索見出し" },
{ 0x0f, 0x0f, FALSE, "図版見出し" },
{ 0x20, 0x20, FALSE, "メニュー" },
{ 0x21, 0x21, FALSE, "著作権表示" },
{ 0x23, 0x23, FALSE, "著作権表示(1行表示用)" },
{ 0x24, 0x24, FALSE, "音声見出し" },
{ 0x30, 0x30, FALSE, "かなインデックス" },
{ 0x40, 0x40, FALSE, "英字インデックス" },
{ 0x50, 0x50, FALSE, "漢字インデックス" },
{ 0x60, 0x60, FALSE, "表記形インデックス" },
{ 0x70, 0x70, TRUE, "後方一致かなインデックス" },
{ 0x71, 0x71, TRUE, "後方一致表記形インデックス" },
{ 0x72, 0x72, TRUE, "後方一致英字インデックス" },
{ 0x80, 0x80, FALSE, "条件検索インデックス" },
{ 0x81, 0x81, FALSE, "クロス検索インデックス" },
{ 0x90, 0x90, TRUE, "前方一致かなインデックス" },
{ 0x91, 0x91, TRUE, "前方一致表記形インデックス" },
{ 0x92, 0x92, TRUE, "前方一致英字インデックス" },
{ 0xa0, 0xa0, FALSE, "項目番号インデックス" },
{ 0xa1, 0xa1, FALSE, "項目別条件検索インデックス" },
{ 0xb0, 0xb0, FALSE, "ページ検索インデックス" },
{ 0xb1, 0xb1, FALSE, "漢字インデックス" },
{ 0xd0, 0xd0, FALSE, "モノクロ図版" },
{ 0xd1, 0xd1, FALSE, "拡張モノクロ図版" },
{ 0xd2, 0xd2, FALSE, "カラー図版" },
{ 0xd8, 0xd8, FALSE, "PCM音声" },
{ 0xe0, 0xe0, FALSE, "色見本" },
{ 0xf0, 0xf0, FALSE, "暗証" },
{ 0xf1, 0xf1, TRUE, "外字(16×16ドット)" },
{ 0xf2, 0xf2, TRUE, "外字(8×16ドット)" },
{ 0xf3, 0xf3, TRUE, "外字(24×24ドット)" },
{ 0xf4, 0xf4, TRUE, "外字(12×24ドット)" },
{ 0xf5, 0xf5, TRUE, "外字(30×30ドット)" },
{ 0xf6, 0xf6, TRUE, "外字(15×30ドット)" },
{ 0xf7, 0xf7, TRUE, "外字(48×48ドット)" },
{ 0xf8, 0xf8, TRUE, "外字(24×48ドット)" },
{ 0xff, 0xff, FALSE, "複合検索管理情報" },
{ 0x00, 0x2f, FALSE, "その他のテキストデータ" },
{ 0x70, 0x7f, FALSE, "その他の後方一致インデックス" },
{ 0x80, 0x8f, FALSE, "その他の条件検索インデックス" },
{ 0x90, 0x9f, FALSE, "その他の前方一致インデックス" },
{ 0xa0, 0xbf, FALSE, "その他のインデックス" },
{ 0xd0, 0xdf, FALSE, "その他のマルチメディアデータ" }
};
uchr *
idname(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].name;
}
return "???";
}
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
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;
}
uchr *
bktype(str)
uchr *str;
{
switch (*str & 0xf0) {
case 0x00: return "国語辞典";
case 0x10: return "漢和辞典";
case 0x20: return "英和辞典";
case 0x30: return "和英辞典";
case 0x40: return "現代用語辞典";
case 0x50: return "百科事典";
case 0x60: return "一般書物";
case 0x70: return "類語辞典";
default: return "不明";
}
}
uchr *
protinfo(str)
uchr *str;
{
static uchr buf[160];
strcpy(buf, "表示");
strcat(buf, (str[1] & 0x01)? "禁止": "許可");
strcat(buf, ", 印刷");
strcat(buf, (str[1] & 0x02)? "禁止": "許可");
strcat(buf, ", テキスト引用");
strcat(buf, (str[1] & 0x04)? "禁止": "許可");
strcat(buf, ", 図版引用");
strcat(buf, (str[1] & 0x08)? "禁止": "許可");
strcat(buf, ",\n カラー図版引用");
strcat(buf, (str[1] & 0x10)? "許可" :"禁止");
strcat(buf, ", 動画引用");
strcat(buf, (str[1] & 0x20)? "許可" :"禁止");
strcat(buf, ", 大量引用");
strcat(buf, (str[1] & 0x80)? "許可" :"禁止");
return buf;
}
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;
}
uchr *
idxhndl(n)
int n;
{
switch (n) {
case 0x00: return "INDEX情報有効性に依存";
case 0x01: return "INDEX情報は無効";
case 0x02: return "INDEX情報は有効";
}
return "不明";
}
uchr *
dspvalid(n)
int n;
{
switch (n) {
case 0x00: return "初期値情報は無効";
case 0x01: return "初期値情報は有効";
}
return "不明";
}
uchr *
dsplist(n)
int n;
{
switch (n) {
case 0x00: return "直接本文表示";
case 0x01: return "一覧表を表示し、選択指示を受けて表示";
}
return "不明";
}
uchr *
dspstyle(n)
int n;
{
switch (n) {
case 0x00: return "検索結果を項目単位に連続して表示";
case 0x01: return "検索結果を先頭に本文を表示";
}
return "不明";
}
/*
* インデックス構成成分のデータ表現法
*/
#define I_KATA_MASK 0x00c00000L /* カタカナ */
#define I_KATA_HIRA 0x00000000L /* ひらがなに変換して記録(k) */
#define I_KATA_ASIS 0x00400000L /* そのまま記録(.) */
#define I_LCASE_MASK 0x00300000L /* 英小文字 */
#define I_LCASE_UCASE 0x00000000L /* 英大文字に変換して記録(a) */
#define I_LCASE_ASIS 0x00100000L /* そのまま記録(.) */
#define I_SYM_MASK 0x000c0000L /* 記号 */
#define I_SYM_DEL 0x00000000L /* 記号を削除して記録(s) */
#define I_SIM_ASIS 0x00040000L /* そのまま記録(.) */
#define I_CHOU_MASK 0x00030000L /* 長音 */
#define I_CHOU_BOIN 0x00000000L /* 直前の母音に変換して記録(c)*/
#define I_CHOU_ASIS 0x00010000L /* そのまま記録(.) */
#define I_CHOU_DEL 0x00020000L /* 長音を削除して記録(C) */
#define I_SOKU_MASK 0x0000c000L /* 促音 */
#define I_SOKU_LARGE 0x00000000L /* 大きな文字に変換して記録(t)*/
#define I_SOKU_ASIS 0x00004000L /* そのまま記録(.) */
#define I_YOU_MASK 0x00003000L /* 拗音 */
#define I_YOU_LARGE 0x00000000L /* 大きな文字に変換して記録(y)*/
#define I_YOU_ASIS 0x00001000L /* そのまま記録(.) */
#define I_GAI_MASK 0x00000c00L /* 外来語用小文字 */
#define I_GAI_LARGE 0x00000000L /* 大きな文字に変換して記録(g)*/
#define I_GAI_ASIS 0x00000400L /* そのまま記録(.) */
#define I_DAKU_MASK 0x00000300L /* 濁音 */
#define I_DAKU_SEI 0x00000000L /* 清音に変換して記録(d) */
#define I_DAKU_ASIS 0x00000100L /* そのまま記録(.) */
#define I_HAN_MASK 0x000000c0L /* 半濁音 */
#define I_HAN_SEI 0x00000000L /* 清音に変換して記録(h) */
#define I_HAN_ASIS 0x00000040L /* そのまま記録(.) */
#define I_RESV_MASK 0x0000003fL /* 予備領域 */
uchr *
idxinfo(item)
ITEM_T *item;
{
dword d;
static uchr buf[10];
if (item->idxvalid == 0x01)
return "";
d = item->idxinfo;
buf[0] = ((d & I_KATA_MASK ) == I_KATA_HIRA )? 'k': '.';
buf[1] = ((d & I_LCASE_MASK) == I_LCASE_UCASE)? 'a': '.';
buf[2] = ((d & I_SYM_MASK ) == I_SYM_DEL )? 's': '.';
buf[3] = ((d & I_CHOU_MASK ) == I_CHOU_BOIN )? 'c':
((d & I_CHOU_MASK ) == I_CHOU_DEL )? 'C': '.';
buf[4] = ((d & I_SOKU_MASK ) == I_SOKU_LARGE )? 't': '.';
buf[5] = ((d & I_YOU_MASK ) == I_YOU_LARGE )? 'y': '.';
buf[6] = ((d & I_GAI_MASK ) == I_GAI_LARGE )? 'g': '.';
buf[7] = ((d & I_DAKU_MASK ) == I_DAKU_SEI )? 'd': '.';
buf[8] = ((d & I_HAN_MASK ) == I_HAN_SEI )? 'h': '.';
buf[9] = '\0';
return buf;
}
syntax highlighted by Code2HTML, v. 0.9.1