/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/


#include	<stdlib.h>
#include	<stdio.h>
#include	<fcntl.h>
#include	<errno.h>
#include	<sys/types.h>
#include	"r64.h"
#include	"r64_types.h"
#include	"change_endian.h"
#include	"machine/include.h"

int
get_cr_tbl_nos(CR_FILE * f)
{
unsigned int level_entry;
int w,h;
int ww,hh;
int i;	
	w = f->header.h.width;
	h = f->header.h.height;
	if ( w == 0 || h == 0 ) {
		r64_error = E_INVFILE;
		return -1;
	}
	level_entry = 0;
	for ( i = 0 ; i < LEVEL_OFS_LEN ; i ++ ) {
		f->level_entry[i] = level_entry;
		f->level_w[i] = w;
		f->level_h[i] = h;

		ww = w/f->header.rect_size;
		if ( w % f->header.rect_size )
			ww ++;
		hh = h/f->header.rect_size;
		if ( h % f->header.rect_size )
			hh ++;
		level_entry += ww*hh;
		w = (w>>1)+(w&1);
		h = (h>>1)+(h&1);
		if ( w <= 1 || h <= 1 )
			break;
	}
	f->header.cr_tbl_nos = level_entry;
	for ( ; i < LEVEL_OFS_LEN ; i ++ ) {
		f->level_entry[i] = -1;
		f->level_w[i] = 0;
		f->level_h[i] = 0;
	}
	return 0;
}


CR_FILE *
cr_open_file(
	char * filename,
	int ctl,
	int mode,
	int rect_size,
	int width,
	int height)
{
int fd;
CR_FILE * f;
int er;
int i;
CR_ENT * ce;
int dsize;
CR_TBL tbl;

retry:
	fd = open64(filename,ctl,mode);
	if ( fd < 0 ) {
		if ( errno == EAGAIN )
			goto retry;
		r64_error = E_SYS;
		return 0;
	}
	f = malloc(sizeof(*f));
	if ( f == 0 ) {
		r64_error = E_NOMEM;
		close(fd);
		return 0;
	}
	f->fd = fd;
	er = read(fd,(char*)&f->header,sizeof(CR_HEADER)) ;
	if ( er < 0 ) {
		r64_error = E_SYS;
		goto err0;
	}
	if ( er != sizeof(CR_HEADER) ) {
		if ( er == 0 && (ctl&(O_RDWR|O_RDONLY)) == O_RDWR ) {
			memcpy(f->header.h.preamble,"CR",3);
			f->header.h.type = 0;
			f->header.h.width = width;
			f->header.h.height = height;
			f->header.rect_size = rect_size;
			if ( get_cr_tbl_nos(f) < 0 )
				goto err0;
			change_endian_s(f->header.rect_size);
			change_endian_i(f->header.cr_tbl_nos);
			change_endian_s(f->header.h.height);
			change_endian_s(f->header.h.width);
			write(f->fd,(char*)&f->header,sizeof(f->header));
			change_endian_s(f->header.rect_size);
			change_endian_i(f->header.cr_tbl_nos);
			change_endian_s(f->header.h.height);
			change_endian_s(f->header.h.width);
			tbl.ofs = 0;
			tbl.type = 0;
			tbl.cal[0] = tbl.cal[1] = tbl.cal[2] = 0;
			tbl.size = 0;
			for ( i = 0 ; i < f->header.cr_tbl_nos ; i ++ )
				write(f->fd,(char*)&tbl,sizeof(tbl));
			f->write_ofs = lseek64(f->fd,0,SEEK_CUR);
		}
		else {
			r64_error = E_DFILE;
			goto err0;
		}
	}
	else {
		f->write_ofs = lseek64(f->fd,0,SEEK_END);
		change_endian_s(f->header.rect_size);
		change_endian_i(f->header.cr_tbl_nos);
		change_endian_s(f->header.h.height);
		change_endian_s(f->header.h.width);
	}
	if ( memcmp(f->header.h.preamble,"CR",3) ) {
		r64_error = E_INVFILE;
		goto err0;
	}
	f->header.h.type = 0;
	f->free_list = &f->cache[1];
	for ( i = 1 ; i < ENT_LEN ; i ++ ) {
		f->cache[i].b.buf = 0;
		if ( i+1 != ENT_LEN )
			f->cache[i].next = &f->cache[i+1];
		else	f->cache[i].next = 0;
	}
	f->cache[0].next = f->cache[0].prev = &f->cache[0];
	f->fctl = ctl&(O_RDONLY|O_RDWR);
	if ( get_cr_tbl_nos(f) < 0 )
		goto err1;
	return f;
err1:
err0:
	close(f->fd);
	free(f);
	return 0;
}
