/**********************************************************************
 
	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	<stdio.h>
#include	<string.h>
#include	<fcntl.h>
#include	<errno.h>
#include	<sys/types.h>
#include	"r64.h"
#include	"r64_types.h"
#include	"machine/include.h"
#include	"u_file.h"

int
_r64_read(R64_FILE * f,int w,int h,int level)
{
R64_CACHE_ENT * ce;
unsigned int ofs1,ofs2;
int i,vol;
int er;
	if ( f->level_ofs[level] == 0 ) {
		r64_error = E_NOLEV;
		return -1;
	}
	if ( w < 0 || w >= f->level_w[level] ) {
		r64_error = E_OVER;
		return -1;
	}
	if ( h < 0 || h >= f->level_h[level] ) {
		r64_error = E_OVER;
		return -1;
	}
	if ( _new_ce(f) < 0 )
		return -1;
	ce = f->cache[0].next;
	ce->flags = 0;
	ce->level = level;
	ce->w_ofs = w - w%ENT_UNIT;
	ce->h_ofs = h - h%ENT_UNIT;
	if ( f->level_w[level] - ce->w_ofs >= ENT_UNIT )
		ce->w_len = ENT_UNIT;
	else	ce->w_len = f->level_w[level] - ce->w_ofs;
	if ( f->level_h[level] - ce->h_ofs >= ENT_UNIT )
		ce->h_len = ENT_UNIT;
	else	ce->h_len = f->level_h[level] - ce->h_ofs;
	ofs2 = u_lseek64(f->fd,0,SEEK_END);
	ofs1 = CH_OFS2_FILE(f,ce);

/*
printf("== over(%x) %i %i - %x %x\n",f,ce->w_ofs,ce->h_ofs,ofs1,ofs2);
*/
	if ( ofs1 >= ofs2 ) {
	broken:
		if ( f->fctl == O_RDONLY ) {
			r64_error = E_WRITE;
			return -1;
		}
		vol = UNIT_VOL(f);
		for ( i = 0 ; i < vol ; i += 3 )
			memcpy(&ce->buf[i],f->background,3);
		ce->flags |= EF_DIRTY;
	}
	else {
/*
printf("== O(%x) - %x\n",f,ofs1);
*/
		if ( u_lseek64(f->fd,ofs1,SEEK_SET) < 0 ) {
			r64_error = E_SYS;
			return -1;
		}
		vol = ENT_VOL(f,ce);
	retry:
		er = u_read(f->fd,ce->buf,vol);
		if ( er < vol ) {
			if ( errno == EAGAIN )
				goto retry;
			r64_error = E_SYS;
			return -1;
		}
/*
printf("0(%x) vol=%i %x (%x)\n",f,vol,ce->buf[192],ce);
*/
		if ( er != vol )
			goto broken;
	}
	return 0;
}
