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

#include <stdio.h>
#include <stdlib.h>
#include <string.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	wfd = -1;
static	int	werr = 0;
static	long	wblkno;
static	byte	wblkbuf[BLKSIZ];
static	byte	*wp, *wendp = &wblkbuf[BLKSIZ];

int
open_newbook(file)
uchr	*file;
{
    if (wfd != -1)
	close_book();
    if ((wfd = open(file, O_WRONLY|O_BINARY|O_CREAT|O_TRUNC, 0644)) < 0)
	return ERR;
    memset(wblkbuf, '\0', BLKSIZ);
    wp = wblkbuf;
    wblkno = 1L;
    werr = 0;
    return OK;
}

int
close_newbook()
{
    if (wfd == -1)
	return ERR;
    if (wp > wblkbuf)
	write_newblock();
    if (close(wfd) < 0)
	return ERR;
    return OK;
}

int
locate_newblock(blk)
long	blk;
{
    if (wfd == -1)
	return ERR;
    if (blk <= 0L)
	return ERR;
    if (wp > wblkbuf)
	write_newblock();
    if (lseek(wfd, (blk - 1L) * BLKSIZ, 0) < 0)
	return ERR;
    wp = wblkbuf;
    wblkno = blk;
    return OK;
}

int
write_newblock()
{
    if (wfd == -1)
	return ERR;
    if (write(wfd, (char *)wblkbuf, BLKSIZ) < BLKSIZ)
	return ERR;
    memset(wblkbuf, '\0', BLKSIZ);
    wp = wblkbuf;
    wblkno++;
    return OK;
}

long
cur_newblock()
{
    return wblkno;
}

int
cur_newoff()
{
    return wp - wblkbuf;
}

int
get_error()
{
    return werr;
}

void
reset_error()
{
    werr = 0;
}

int
putbyte(b)
byte	b;
{
    if (wp >= wendp) {
	if (write_newblock() == ERR)
	    werr++;
    }
    *wp++ = b;
    return OK;
}

int
putword(w)
word	w;
{
    putbyte(w >> 8);
    putbyte(w & 0xff);
    return OK;
}

int
putdword(d)
dword	d;
{
    putbyte(d >> 24);
    putbyte((d >> 16) & 0xff);
    putbyte((d >> 8) & 0xff);
    putbyte(d & 0xff);
    return OK;
}

int
putbcd(d, len)
dword	d;
int	len;
{
    int		i;
    dword	n;
    byte	*p, buf[10];

    p = buf;
    while (len--) {
	*p = (int)(d % 10L);
	d /= 10;
	*p |= (int)(d % 10L) << 4;
	d /= 10;
	p++;
    }
    while (p > buf) {
	putbyte(p[-1]);
	p--;
    }
    return OK;
}

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

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

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

    if (locate_newblock(blk) == ERR)
	return ERR;
    putword(infop->items);
    putbytes(infop->resv1, RESV1_LEN);
    putbyte(infop->idxhndl);
    putbytes(infop->resv2, RESV2_LEN);
    itemp = infop->item;
    for (i = 0; i < infop->items; i++) {
	putbyte(itemp->itemid);
	putbytes(itemp->resv3, RESV3_LEN);
	putdword(itemp->topblk);
	putdword(itemp->blks);
	putbyte(itemp->idxvalid);
	putbyte((itemp->idxinfo >> 16) & 0xff);
	putbyte((itemp->idxinfo >> 8) & 0xff);
	putbyte(itemp->idxinfo & 0xff);
	putbytes(itemp->resv4, RESV4_LEN);
	itemp++;
    }
    putbyte(infop->dspvalid);
    putbytes(infop->resv5, RESV5_LEN);
    putbyte(infop->dsplist);
    putbyte(infop->dspstyle);
    putbytes(infop->resv6, RESV6_LEN);
    if (write_newblock() == ERR)
	return ERR;

    itemp = infop->item;
    for (i = 0; i < infop->items; i++) {
	if (itemp->itemid != ID_CINFO) {
	    itemp++;
	    continue;
	}
	if (locate_newblock(itemp->topblk) == ERR)
	    return ERR;
	cinfop = itemp->cinfo;
	putword(cinfop->cents);
	putbytes(cinfop->cresv1, CRESV1_LEN);
	centp = cinfop->cent;
	for (j = 0; j < cinfop->cents; j++) {
	    putbyte(centp->citems);
	    putbytes(centp->cresv2, CRESV2_LEN);
	    putbytes(centp->cname, CNAME_LEN);
	    citemp = centp->citem;
	    for (k = 0; k < centp->citems; k++) {
		putbyte(citemp->citemid);
		putbytes(citemp->cresv3, CRESV3_LEN);
		putdword(citemp->ctopblk);
		putdword(citemp->cblks);
		putbytes(citemp->cresv4, CRESV4_LEN);
		citemp++;
	    }
	    centp++;
	}
	if (write_newblock() == ERR)
	    return ERR;
	itemp++;
    }
    return OK;
}
