/*
 * bread.c - 電子ブック/EPWINGユーティリティー 書籍読み込みモジュール
 *
 *	Written by Junn Ohta (ohta@src.ricoh.co.jp). Public Domain.
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef MSDOS
#include <io.h>
#endif
#ifdef UNIX
#include <unistd.h>
#endif
#include "epw.h"

#ifndef O_BINARY
#define	O_BINARY	0
#endif

static	int	rfd = -1;
static	long	rblkno;
static	byte	rblkbuf[BLKSIZ];
static	byte	*rp, *rendp = &rblkbuf[BLKSIZ];

int
open_book(file)
uchr	*file;
{
    if (rfd != -1)
	close_book();
    if ((rfd = open(file, O_RDONLY|O_BINARY)) < 0)
	return ERR;
    rblkno = 0L;
    if (read_block() == ERR)
	return ERR;
    return OK;
}

int
close_book()
{
    if (rfd == -1)
	return ERR;
    if (close(rfd) < 0)
	return ERR;
    return OK;
}

int
locate_block(blk)
long	blk;
{
    if (rfd == -1)
	return ERR;
    if (blk <= 0L)
	return ERR;
    if (rblkno == blk) {
	rp = rblkbuf;
	return OK;
    }
    if (lseek(rfd, (blk - 1L) * BLKSIZ, 0) < 0)
	return ERR;
    if (read_block() == ERR)
	return ERR;
    rblkno = blk;
    return OK;
}

int
read_block()
{
    if (rfd == -1)
	return ERR;
    if (read(rfd, (char *)rblkbuf, BLKSIZ) < BLKSIZ)
	return ERR;
    rp = rblkbuf;
    rblkno++;
    return OK;
}

long
cur_block()
{
    return rblkno;
}

int
cur_off()
{
    return rp - rblkbuf;
}

byte
getbyte()
{
    if (rp >= rendp)
	read_block();
    return *rp++;
}

word
getword()
{
    word	w;

    w = getbyte() << 8;
    w += getbyte();
    return w;
}

dword
getdword()
{
    dword	d;

    d = (dword)getbyte() << 24;
    d += (dword)getbyte() << 16;
    d += (dword)getbyte() << 8;
    d += (dword)getbyte();
    return d;
}

long
getbcd(len)
int	len;
{
    int		err;
    byte	b1, b2;
    long	d;

    err = FALSE;
    d = 0L;
    while (len--) {
	b2 = getbyte();
	b1 = b2 >> 4;
	b2 &= 0x0f;
	if (b1 > 9 || b2 > 9)
	    err = TRUE;
	d = d * 100 + b1 * 10 + b2;
    }
    if (err)
	return -1L;
    return d;
}

byte *
getbytes(buf, len)
byte	*buf;
int	len;
{
    byte	*p;

    p = buf;
    while (len--)
	*p++ = getbyte();
    return buf;
}

INFO_T *
getinfo(blk)
long	blk;
{
    int		i, j, k;
    INFO_T	*infop;
    ITEM_T	*itemp;
    CINFO_T	*cinfop;
    CENT_T	*centp;
    CITEM_T	*citemp;

    if (locate_block(blk) == ERR)
	return NULL;
    infop = (INFO_T *)malloc(sizeof(INFO_T));
    if (infop == NULL)
	return NULL;
    infop->items = getword();
    getbytes(infop->resv1, RESV1_LEN);
    infop->idxhndl = getbyte();
    getbytes(infop->resv2, RESV2_LEN);
    infop->item = (ITEM_T *)malloc(sizeof(ITEM_T) * infop->items);
    if (infop->item == NULL)
	return NULL;
    itemp = infop->item;
    for (i = 0; i < infop->items; i++) {
	itemp->itemid = getbyte();
	getbytes(itemp->resv3, RESV3_LEN);
	itemp->topblk = getdword();
	itemp->blks = getdword();
	itemp->idxvalid = getbyte();
	itemp->idxinfo = getbyte() << 16;
	itemp->idxinfo += getbyte() << 8;
	itemp->idxinfo += getbyte();
	getbytes(itemp->resv4, RESV4_LEN);
	itemp->cinfo = NULL;
	itemp++;
    }
    infop->dspvalid = getbyte();
    getbytes(infop->resv5, RESV5_LEN);
    infop->dsplist = getbyte();
    infop->dspstyle = getbyte();
    getbytes(infop->resv6, RESV6_LEN);

    itemp = infop->item;
    for (i = 0; i < infop->items; i++) {
	if (itemp->itemid != ID_CINFO) {
	    itemp++;
	    continue;
	}
	if (locate_block(itemp->topblk) == ERR)
	    return NULL;
	itemp->cinfo = (CINFO_T *)malloc(sizeof(CINFO_T));
	if (itemp->cinfo == NULL)
	    return NULL;
	cinfop = itemp->cinfo;
	cinfop->cents = getword();
	getbytes(cinfop->cresv1, CRESV1_LEN);
	cinfop->cent = (CENT_T *)malloc(sizeof(CENT_T) * cinfop->cents);
	if (cinfop->cent == NULL)
	    return NULL;
	centp = cinfop->cent;
	for (j = 0; j < cinfop->cents; j++) {
	    centp->citems = getbyte();
	    getbytes(centp->cresv2, CRESV2_LEN);
	    getbytes(centp->cname, CNAME_LEN);
	    centp->citem = (CITEM_T *)malloc(sizeof(CITEM_T) * centp->citems);
	    if (centp->citem == NULL)
		return NULL;
	    citemp = centp->citem;
	    for (k = 0; k < centp->citems; k++) {
		citemp->citemid = getbyte();
		getbytes(citemp->cresv3, CRESV3_LEN);
		citemp->ctopblk = getdword();
		citemp->cblks = getdword();
		getbytes(citemp->cresv4, CRESV4_LEN);
		citemp++;
	    }
	    centp++;
	}
	itemp++;
    }
    return infop;
}

void
freeinfo(infop)
INFO_T	*infop;
{
    int		i, j;
    ITEM_T	*itemp;
    CINFO_T	*cinfop;
    CENT_T	*centp;

    itemp = infop->item;
    for (i = 0; i < infop->items; i++) {
	if (itemp->cinfo != NULL) {
	    cinfop = itemp->cinfo;
	    centp = cinfop->cent;
	    for (j = 0; j < cinfop->cents; j++) {
		free((char *)centp->citem);
		centp++;
	    }
	    free((char *)cinfop->cent);
	    free((char *)itemp->cinfo);
	}
	itemp++;
    }
    free((char *)infop->item);
    free((char *)infop);
}
