/**********************************************************************
 
	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.

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




#define OPEN_FILESPACE

#include	"machine/include.h"
#include	"memory_debug.h"
#include	"pdb64.h"
#include	"change_endian.h"
#include	"filespace64.h"
#include	"utils.h"
#include	"favt64.h"

INTEGER64
fa_write64(int fd,void * d,U_INTEGER64 len);
U_INTEGER64
fs_raw_write64(PDB64 * p,void * d,int flags);
void change_endian_freelist64_to_net(PN64_FREELIST * f);
void change_endian_freelist64_to_host(PN64_FREELIST * f);
void free_freelist64(FREELIST64 * f);
void load_freelist64(PDB64 * p,PN64_FREELIST * f,U_INTEGER64 fofs);
void save_freelist64(PDB64 * p,PN64_FREELIST * f,U_INTEGER64 fofs);
FREELIST64 *
next_freelist64(PDB64 * p,FREELIST64 * f);
FREELIST64 *
insert_freelist64(PDB64 * p,FREELIST64 * f,U_INTEGER64 fofs,
			INTEGER64 size);
int delete_freelist64(U_INTEGER64 * retp,PDB64 * p,FREELIST64 * b);
void truncate_check64(PDB64 * p,U_INTEGER64 length);
int check_freelist64(PDB64 * p);
int check_filespace64(PDB64 * p);


void
check_pdb64(PDB64 * p)
{
	if ( p == 0 )
		return;
	if ( p->freelist_work == 0 )
		er_panic("check_pdb64");
}


INTEGER64
fa_write64(int fd,void * d,U_INTEGER64 len)
{
char * dp;
int er;
int ret;
int _s;
	ret = len;

	for ( dp = (char*)d ; len > 0 ; ) {
		if ( len > 0x10000 )
			_s = 0x10000;
		else	_s = len;
		er = u_write(fd,dp,_s);
		if ( er <= 0 )
			break;
		len -= er;
		dp += er;
	}
	if ( len == 0 )
		return ret;
	else	return -1;
}

INTEGER64
fa_write64_header(int fd,void * d,U_INTEGER64 len)
{
PN64_HEADER h;
PHYS_PN64_HEADER ph;
int h_size;
INTEGER64 ret;
	h = *(PN64_HEADER*)d;
	change_endian_header64(&h);

	ph.h16.type = h.type;
	if ( h.size < PHYS_SIZE16_LIMIT ) {
		h_size = sizeof(ph.h16);
		ph.h16.size = h.size - sizeof(h)
				+ h_size;
	}
	else if ( h.size < (INTEGER64)CONST_INT64(0x100000000) ) {
		h_size = sizeof(ph.h32);
		ph.h16.size = PHYS_SIZE32;
		ph.h32.size = h.size - sizeof(h) + h_size;
	}
	else {
		h_size = sizeof(ph.h64);
		ph.h16.size= PHYS_SIZE64;
		ph.h64.size = h.size - sizeof(h) + h_size;

if ( h_size != 12 )
er_panic("???");

	}

	change_endian_phys_header64_to_net(&ph);

	ret = fa_write64(fd,&ph,h_size);
	if ( ret < 0 )
		return ret;
	len -= sizeof(PN64_HEADER);
	if ( len )
		return ret + fa_write64(fd,((PN64_HEADER*)d)+1,len);
	else	return ret;
}



U_INTEGER64
fs_raw_write64(PDB64 * p,void * d,int flags)
{
PN64_HEADER * h;
PN64_HEADER hh;
U_INTEGER64 size;
#define DUMMY_SIZE 100
char dummy[DUMMY_SIZE];
int s;
int er,len;
U_INTEGER64 offset;

	offset = u_lseek64(p->fid,0,SEEK_END);
	h = d;
	hh = *h;
	change_endian_header64(&hh);
	size = hh.size;
	switch ( flags &(FSF_ONLYHEADER|FSF_RESERVE_SP) ) {
	case 0:
		fa_write64_header(p->fid,d,size);
		break;
	case FSF_ONLYHEADER:
		fa_write64_header(p->fid,d,sizeof(*h));
		break;
	case FSF_RESERVE_SP:
	case FSF_RESERVE_SP|FSF_ONLYHEADER:
		fa_write64_header(p->fid,d,sizeof(*h));
		for ( s = size - sizeof(*h) ; s > 0 ; ) {
			if ( s > DUMMY_SIZE )
				len = DUMMY_SIZE;
			else	len = s;
			er = fa_write64(p->fid,dummy,len);
			s -= er;
		}
		break;
	}
	return offset;
}

void
change_endian_freelist64_to_net(PN64_FREELIST * f)
{
	change_endian_header64(&f->h);
	change_endian(f->next);
}


void
change_endian_freelist64_to_host(PN64_FREELIST * f)
{
	change_endian_header64(&f->h);
	change_endian(f->next);
}

void *
get_file_record64(U_INTEGER64 * retp,PDB64 * p,short type,
	INTEGER64 max_size)
{
U_INTEGER64 fofs;
INTEGER64 er;
PN64_HEADER * h;
PHYS_PN64_HEADER ph;
unsigned short h16_size;
INTEGER64 size,_size;
INTEGER64 length;
int h_size;
int f;
char * ptr;
int _s;
INTEGER64 read_size;

	if ( retp ) {
		fofs = *retp;
		f = 0;
	}
	else {
		fofs = 0;
		f = 1;
	}
	length = u_lseek64(p->fid,0,SEEK_END);
	if ( length < 0 ) {
		return 0;
	}
	for ( ; ; ) {
		if ( fofs >= length ) {
			return 0;
		}
		er = u_lseek64(p->fid,fofs,SEEK_SET);
		if ( er < 0 )
			er_panic("get_file_record64(1)");
		er = u_read(p->fid,&ph,sizeof(PN_HEADER));

// ph.h16.type NET

		if ( er < sizeof(PN_HEADER) )
			er_panic("get_file_record64(2)");
		h16_size = ph.h16.size;
		change_endian(h16_size);
		if ( h16_size < sizeof(PN_HEADER) )
		  	er_panic("data error");
		switch ( h16_size ) {
		case PHYS_SIZE32:
			er = u_read(p->fid,&ph.h32.size,sizeof(int));
			if ( er < sizeof(int) )
				er_panic("get_file_record64(2)");
			change_endian_phys_header64_to_host(&ph);
// ph.h16.type HOST
			h_size = sizeof(ph.h32);
			size = ph.h32.size;
			break;
		case PHYS_SIZE64:
			er = u_read(p->fid,&ph.h64.size,
					sizeof(INTEGER64));
			if ( er < sizeof(INTEGER64) )
				er_panic("get_file_record64(2)");
			change_endian_phys_header64_to_host(&ph);
// ph.h16.type HOST
			h_size = sizeof(ph.h64);
			size = ph.h64.size;
			break;
		default:
			change_endian_phys_header64_to_host(&ph);
// ph.h16.type HOST
			h_size = sizeof(ph.h16);
			size = ph.h16.size;
			break;
		}
		if ( f == 0 && type <= 0 )
			break;
		if ( f && ph.h16.type == type )
			break;
		fofs += size;
		f = 1;
	}
	_size = size - h_size + sizeof(PN64_HEADER);
	if ( max_size && _size > max_size )
		read_size = max_size;
	else	read_size = _size;
	h = d_alloc(read_size);
	h->type = ph.h16.type;
//	change_endian(h->type);
	h->size = _size;
	change_endian_header64(h);
// h.type NET

	size = read_size - sizeof(*h);
	ptr = (char*)(h+1);
	for ( ; size > 0 ; ) {
		if ( size > 0x10000 )
			_s = 0x10000;
		else	_s = size;
		er = u_read(p->fid,h+1,_s);
		if ( er < _s )
			er_panic("get_file_record(3)");
		ptr += er;
		size -= er;
	}
	if ( retp )
		*retp = fofs;
	return (void*)h;
}



PDB64*
open_filespace64(char * filename,int oflags,int mode,
	int flags,int type,char * encoding)
{
PDB64 * p;
INTEGER64 length;
PN64_FILE_HEADER h;
PN64_FREELIST	f, * ff;
FREELIST64 * fp;
	p = open_pdb64(filename,oflags,mode,flags&PF_PDB_MASK);
	if ( p == 0 ) {
		return 0;
	}
	length = u_lseek64(p->fid,0,SEEK_END);
	if ( length == 0 ) {
		h.h.size = sizeof(h);
		h.h.type = PNT_FILE_HEADER;
		h.type = type;
		strcpy(h.version,PDB64_VERSION);
		if ( encoding == 0 )
			strcpy(h.encoding,"UTF-8");
		else	strcpy(h.encoding,encoding);
		h.linear = 0;
		h.linear_length = 0;
		change_endian_file_header64(&h);
		fs_raw_write64(p,&h,0);
		if ( flags & PF_USEFREELIST ) {
			f.h.size = sizeof(f);
			f.h.type = PNT_FREELIST_HEADER;
			f.next = 0;
			fp = d_alloc(sizeof(*fp));
			memcpy(&fp->f,&f,sizeof(f));
			fp->next = 0;
			fp->fofs = PHYS_SIZE(sizeof(h));
			change_endian_freelist64_to_net(&f);
			fs_raw_write64(p,&f,0);
			p->freelist_work = fp;
		}
	}
	else {
		ff = get_file_record64(0,p,PNT_FREELIST_HEADER,0);
		if ( ff ) {
			fp = d_alloc(sizeof(*fp));
			memcpy(&fp->f,ff,sizeof(*ff));
			fp->next = 0;
			fp->fofs = sizeof(h);
			d_f_ree(ff);
			change_endian_freelist64_to_host(&fp->f);
			p->freelist_work = fp;

		}
		else if ( PF_USEFREELIST & flags ) {
			close_pdb64(p);
			return 0;
		}
	}
	return p;
}

void
free_freelist64(FREELIST64 * f)
{
FREELIST64 * f2;
	for ( ; f ; ) {
		f2 = f->next;
		d_f_ree(f);
		f = f2;
	}
}


void
close_filespace64(PDB64 * p)
{
	if ( p->freelist_work )
		free_freelist64(p->freelist_work);
	p->freelist_work = 0;
	flush_favt64_cache(p);
	close_pdb64(p);
}

void
flush_filespace64(PDB64 * p)
{
	flush_favt64_cache(p);
}


void
load_freelist64(PDB64 * p,PN64_FREELIST * f,U_INTEGER64 fofs)
{
PN64_FREELIST * _f;

	_f = get_file_record64(&fofs,p,0,sizeof(PN64_FREELIST));
	change_endian_freelist64_to_host(_f);
	*f = *_f;
	d_f_ree(_f);
}

void
save_freelist64(PDB64 * p,PN64_FREELIST * f,U_INTEGER64 fofs)
{
int er;
PN64_FREELIST buf;
	buf = *f;
	change_endian_freelist64_to_net(&buf);
	u_lseek64(p->fid,fofs,SEEK_SET);
	er = fa_write64_header(p->fid,&buf,sizeof(buf));
	if ( er < 0 )
		er_panic("save_freelist");
}


FREELIST64 *
next_freelist64(PDB64 * p,FREELIST64 * f)
{
FREELIST64 * ret;
	if ( f->next )
		return f->next;
	if ( f->f.next == 0 )
		return 0;
	ret = d_alloc(sizeof(*ret));

	load_freelist64(p,&ret->f,f->f.next);

	if ( ret->f.h.type != PNT_FREELIST_HEADER &&
			ret->f.h.type != PNT_FREELIST_NODE )
		er_panic("next_freelist(2)");
	f->next = ret;
	ret->next = 0;
	ret->fofs = f->f.next;
	return ret;
}

FREELIST64 *
insert_freelist64(PDB64 * p,FREELIST64 * f,U_INTEGER64 fofs,
			INTEGER64 size)
{
FREELIST64 * ff;
	if ( size < sizeof(PN64_FREELIST) )
		return 0;
	ff = d_alloc(sizeof(*ff));
	ff->f.h.type = PNT_FREELIST_NODE;
	ff->f.h.size = size;
	ff->f.next = f->f.next;
	save_freelist64(p,&ff->f,fofs);
	ff->next = f->next;
	ff->fofs = fofs;

	f->next = ff;
	f->f.next = fofs;
	save_freelist64(p,&f->f,f->fofs);

	return ff;
}

int
delete_freelist64(U_INTEGER64 * retp,PDB64 * p,FREELIST64 * b)
{
U_INTEGER64 delete_fofs;
FREELIST64 * d;
PN64_FREELIST buf;
	if ( b->f.next == 0 )
		return -1;
	delete_fofs = b->f.next;
	if ( b->next ) {
		d = b->next;
		b->f.next = d->f.next;
		b->next = d->next;
		d_f_ree(d);
	}
	else {
		load_freelist64(p,&buf,delete_fofs);
		b->f.next = buf.next;
	}

	save_freelist64(p,&b->f,b->fofs);

	if ( retp )
		*retp = delete_fofs;
	return 0;
}


INTEGER64
alloc_filespace64(PDB64 * p,PN64_HEADER * h)
{
FREELIST64 * fp, * fp1;
INTEGER64 ret;
PN64_FREELIST buf;

check_freelist64(p);

	if ( h->size < sizeof(PN64_FREELIST) )
		er_panic("alloc_filespace sizeoerror(1)");
	fp = p->freelist_work;
	if ( fp == 0 )
		er_panic("alloc_filespace(1)");
	for ( ; ; ) {
		fp1 = next_freelist64(p,fp);
		if ( fp1 == 0 )
			goto nothing;
		if ( fp1->f.h.size == h->size )
			goto fit_ok;
		if ( PHYS_SIZE(fp1->f.h.size) > 
			PHYS_SIZE(h->size) + SHORTEST_FREELIST_SIZE )
			goto large_ok;
		fp = fp1;
	}
fit_ok:

	if ( delete_freelist64(&ret,p,fp) < 0 )
		er_panic("alloc_filespace(2)");
	buf.h = *h;
	save_freelist64(p,&buf,ret);

check_freelist64(p);

	return ret;
large_ok:

	ret = fp1->fofs;
	buf.h = *h;
	save_freelist64(p,&buf,ret);

	fp1->fofs += PHYS_SIZE(h->size);
	fp1->f.h.size = LOGI_SIZE(PHYS_SIZE(fp1->f.h.size) - PHYS_SIZE(h->size));
	save_freelist64(p,&fp1->f,fp1->fofs);

	fp->f.next = fp1->fofs;
	save_freelist64(p,&fp->f,fp->fofs);


check_freelist64(p);

	return ret;
nothing:

	buf.h = *h;
	change_endian_header64(&buf.h);

	ret = fs_raw_write64(p,&buf,FSF_RESERVE_SP|FSF_ONLYHEADER);


check_freelist64(p);

	return ret;
}

void
truncate_check64(PDB64 * p,U_INTEGER64 length)
{
FREELIST64 * fp, * fp1;
INTEGER64 fofs;

	fp = p->freelist_work;
	if ( fp == 0 )
		er_panic("truncate_check(1)");
	fp1 = next_freelist64(p,fp);
	if ( fp1 == 0 )
		return;
	for ( ; ; ) {
		if ( fp1->fofs + PHYS_SIZE(fp1->f.h.size) == length )
			break;
		fp = fp1;
		fp1 = next_freelist64(p,fp);
		if ( fp1 == 0 )
			return;
	}
	fofs = fp1->fofs;
	if ( delete_freelist64(0,p,fp) < 0 )
		er_panic("truncate_cache64(1)");
	ftruncate64(p->fid,fofs);
}

void
free_filespace64(PDB64 * p,U_INTEGER64 fofs)
{
PN64_FREELIST f;
FREELIST64 * fp,* fp1,* prev;
U_INTEGER64 length;

check_freelist64(p);

	if ( fofs == 0 )
		er_panic("free_filespace64");
	load_freelist64(p,&f,fofs);
	length = u_lseek64(p->fid,0,SEEK_END);
	if ( fofs + PHYS_SIZE(f.h.size) >= length ) {
		ftruncate64(p->fid,fofs);
		truncate_check64(p,fofs);

check_freelist64(p);

		return;
	}
	fp = p->freelist_work;
	if ( fp == 0 )
		er_panic("free_filespace(1)");
	fp1 = next_freelist64(p,fp);
	if ( fp1 == 0 )
		goto only_one;
	if ( fp1->fofs < fofs )
		goto large;
	prev = fp;
	fp = fp1;
	for ( ; ; prev = fp, fp = fp1 ) {
		fp1 = next_freelist64(p,fp);
		if ( fp1 == 0 )
			goto next_nothing;

		if ( fp1->fofs < fofs && fp->fofs > fofs )
			goto three_type;
	}
next_nothing:

	if ( fofs + PHYS_SIZE(f.h.size) == fp->fofs )
		goto stack_on;
	goto only_one;
three_type:

	if ( fofs + PHYS_SIZE(f.h.size) == fp->fofs ) {
		if ( fp1->fofs + PHYS_SIZE(fp1->f.h.size) == fofs )
			goto sandwitch;
		else	goto stack_on;
	}
	else if ( fp1->fofs + PHYS_SIZE(fp1->f.h.size) == fofs )
		goto hang_on;
	else	goto only_one;
large:

	if ( fp1->fofs + PHYS_SIZE(fp1->f.h.size) == fofs )
		goto hang_on;
	else if ( fp1->fofs + PHYS_SIZE(fp1->f.h.size) > fofs ) {
		fprintf(stderr,"=== %lli %lli / %lli %lli\n",
			fp1->fofs + PHYS_SIZE(fp1->f.h.size),fofs,
			fp1->f.h.size,PHYS_SIZE(fp1->f.h.size));
		er_panic("free_filespace(1-1)");
	}
	else {
		fp1 = fp;
		fp = p->freelist_work;
		goto only_one;
	}

only_one:

	insert_freelist64(p,fp,fofs,f.h.size);

check_freelist64(p);


	return;
hang_on:

	fp1->f.h.size = LOGI_SIZE(PHYS_SIZE(fp1->f.h.size) + PHYS_SIZE(f.h.size));
	save_freelist64(p,&fp1->f,fp1->fofs);

check_freelist64(p);


	return;
stack_on:

	fp->f.h.size = LOGI_SIZE(PHYS_SIZE(fp->f.h.size) + PHYS_SIZE(f.h.size));
	fp->fofs  = fofs;
	save_freelist64(p,&fp->f,fp->fofs);
	prev->f.next = fofs;
	save_freelist64(p,&prev->f,prev->fofs);

check_freelist64(p);


	return;
sandwitch:

	f.h.size = LOGI_SIZE(PHYS_SIZE(fp1->f.h.size) + PHYS_SIZE(fp->f.h.size)
			+ PHYS_SIZE(f.h.size));
	if ( delete_freelist64(0,p,prev) < 0 )
		er_panic("free_filespace64(1)");
	fp1->f.h.size = f.h.size;
	save_freelist64(p,&fp1->f,fp1->fofs);

check_freelist64(p);


	return;
}

int
check_freelist64(PDB64 * p)
{
FREELIST64 * fp;
U_INTEGER64 prev,header;
U_INTEGER64 length;

	fp = p->freelist_work;
	if ( fp == 0 )
		return -1;
	header = fp->fofs;
	length = u_lseek64(p->fid,0,SEEK_END);
	prev = 0;
	for ( ; fp ; prev = fp->fofs , fp = next_freelist64(p,fp) ) {
		if ( fp == 0 )
			break;
		if ( fp->next ) {
			if ( fp->f.next != fp->next->fofs ) {
				fprintf(stderr,
				"prv" I64_FORMAT " ofs" I64_FORMAT " typ%x siz" I64_FORMAT "\n",
					prev,
					fp->fofs,
					fp->f.h.type,
					fp->f.h.size);
				fprintf(stderr,
					"f.next " I64_FORMAT " next->fofs " I64_FORMAT "\n",
					fp->f.next,fp->next->fofs);
				fprintf(stderr,
					"fp %x %x\n",
					(int)fp,(int)fp->next);
				er_panic("check_freelist(-1)");
			}
		}
		if ( fp->fofs >= length ) {
			fprintf(stderr,"prv" I64_FORMAT " ofs" I64_FORMAT " typ%x siz" I64_FORMAT "\n",
				prev,fp->fofs,fp->f.h.type,fp->f.h.size);
			er_panic("check_freelist(0)");
		}
		if ( prev && fp->f.h.type != PNT_FREELIST_NODE ) {
			fprintf(stderr,"prv" I64_FORMAT " ofs" I64_FORMAT " typ%x siz" I64_FORMAT "\n",
				prev,fp->fofs,fp->f.h.type,fp->f.h.size);
			er_panic("check_freelist(1)");
		}
		if ( prev == 0 )
			continue;
		if ( prev == header )
			continue;
		if (  prev <= fp->fofs ) {
			fprintf(stderr,"prv" I64_FORMAT " ofs" I64_FORMAT " typ%x siz" I64_FORMAT "\n",
				prev,fp->fofs,fp->f.h.type,fp->f.h.size);
			er_panic("check_freelist(2)");
		}
		if ( fp->fofs + fp->f.h.size >= prev ) {
			fprintf(stderr,"prv" I64_FORMAT " ofs" I64_FORMAT " typ%x siz" I64_FORMAT "\n",
				prev,fp->fofs,fp->f.h.type,fp->f.h.size);
			er_panic("check_freelist(3)");
		}
	}
	return 0;
}


int
check_filespace64(PDB64 * p)
{
U_INTEGER64 fofs;
PHYS_PN64_HEADER h;
char * str;
U_INTEGER64 length;
int er;
unsigned short s16;
//INTEGER64 size;
PN64_HEADER hh;
	length = u_lseek64(p->fid,0,SEEK_END);
	fofs = 0;
	for ( ; ; ) {
		if ( fofs == 0 )
			return 0;
		if ( fofs > length ) {
			str = "broken last segment";
			goto err;
		}
		u_lseek64(p->fid,fofs,SEEK_SET);
		er = u_read(p->fid,&h,sizeof(PN_HEADER));
		if ( er < sizeof(PN_HEADER) ) {
			perror("cannot read");
			er_panic("check_filespace(1)");
		}
		s16 = h.h16.size;
		change_endian(s16);
		switch ( s16 ) {
		case PHYS_SIZE32:
			er = u_read(p->fid,&h.h16+1,
				sizeof(_PN32_HEADER)
				- sizeof(PN_HEADER));
			if ( er < sizeof(_PN32_HEADER)
					- sizeof(PN_HEADER) ) {
				perror("cannot read");
				er_panic("check_filespace(1)");
			}
			change_endian_phys_header64_to_host(&h);
			if ( h.h32.size < sizeof(_PN32_HEADER) ) {
				str = "too short segment (32)";
				goto err;
			}
			hh.type = h.h16.type;
			hh.size = h.h32.size;
			break;
		case PHYS_SIZE64:
			er = u_read(p->fid,&h.h16+1,
				sizeof(_PN64_HEADER)
				- sizeof(PN_HEADER));
			if ( er < sizeof(_PN64_HEADER)
					- sizeof(PN_HEADER) ) {
				perror("cannot read");
				er_panic("check_filespace(1)");
			}
			change_endian_phys_header64_to_host(&h);
			if ( h.h64.size < sizeof(_PN64_HEADER) ) {
				str = "too short segment (64)";
				goto err;
			}
			hh.type = h.h16.type;
			hh.size = h.h64.size;
			break;
		default:
			change_endian_phys_header64_to_host(&h);
			if ( s16 < sizeof(PN_HEADER) ) {
				str = "too short segment (16)";
				goto err;
			}
			hh.type = h.h16.type;
			hh.size = h.h16.size;
			break;
		}
		fofs += PHYS_SIZE(hh.size);
	}
err:

/*
	fprintf(stderr,"offset " I64_FORMAT " type %x size " I64_FORMAT "\n",
		fofs,
		hh.type,
		hh.size);
*/
	return 0;
}


void *
xx_read_filespace64(PDB64 * p,U_INTEGER64 fofs,char * __file,int __line)
{
ACC_PN64_HEADER * ah;
int er;
U_INTEGER64 size,_size;
PHYS_PN64_HEADER hh;
unsigned short s16;
int _s;
char * ptr;

	u_lseek64(p->fid,fofs,SEEK_SET);
	er = u_read(p->fid,&hh,sizeof(PN_HEADER));
	if ( er < sizeof(PN_HEADER) )
		goto err;
	s16 = hh.h16.size;
	change_endian(s16);
	switch ( s16 ) {
	case PHYS_SIZE32:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN32_HEADER) - sizeof(PN_HEADER));
		if ( er < sizeof(_PN32_HEADER) - sizeof(PN_HEADER) )
			goto err;
		change_endian(hh.h32.size);
		size = hh.h32.size;
		change_endian(hh.h32.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h32) + sizeof(PN64_HEADER);
		break;
	case PHYS_SIZE64:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN64_HEADER) - sizeof(PN_HEADER));
		if ( er < sizeof(_PN64_HEADER) - sizeof(PN_HEADER) )
			goto err;
		size = hh.h64.size;
		change_endian(size);
		_size = size - sizeof(hh.h64) + sizeof(PN64_HEADER);
		break;
	default:
		change_endian(hh.h16.size);
		size = hh.h16.size;
		change_endian(hh.h16.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h16) + sizeof(PN64_HEADER);
		break;
	}
	ah = xx_d_alloc(_size+sizeof(ACC_PN64_HEADER)-sizeof(PN64_HEADER),
			__file,__line);
	ah->a.fofs = fofs;
	ah->h.type = hh.h16.type;
	change_endian(ah->h.type);
	ah->h.size = _size;
	change_endian_header64(&ah->h);

	ptr = (char*)(ah+1);
	_size -= sizeof(PN64_HEADER);
	for ( ; _size ; ) {
		if ( _size > 0x10000 )
			_s = 0x10000;
		else	_s = _size;
		er = u_read(p->fid,ptr,_s);
		if ( er < _s ) {
			d_f_ree(ah);
			goto err;
		}
		ptr += er;
		_size -= er;
		
	}
	return ah;
err:
	return 0;
}

void *
xx_read_filespace64_header
	(PDB64 * p,U_INTEGER64 fofs,char * __file,int __line)
{
ACC_PN64_HEADER * ah;
int er;
U_INTEGER64 size,_size;
PHYS_PN64_HEADER hh;
unsigned short s16;

	u_lseek64(p->fid,fofs,SEEK_SET);
	er = u_read(p->fid,&hh,sizeof(PN_HEADER));
	if ( er < sizeof(PN_HEADER) )
		goto err;
	s16 = hh.h16.size;
	change_endian(s16);
	switch ( s16 ) {
	case PHYS_SIZE32:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN32_HEADER) - sizeof(PN_HEADER));
		if ( er < sizeof(_PN32_HEADER) - sizeof(PN_HEADER) )
			goto err;
		change_endian(hh.h32.size);
		size = hh.h32.size;
		change_endian(hh.h32.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h32) + sizeof(PN64_HEADER);
		break;
	case PHYS_SIZE64:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN64_HEADER) - sizeof(PN_HEADER));
		if ( er < sizeof(_PN64_HEADER) - sizeof(PN_HEADER) )
			goto err;
		size = hh.h64.size;
		change_endian(size);
		_size = size - sizeof(hh.h64) + sizeof(PN64_HEADER);
		break;
	default:
		change_endian(hh.h16.size);
		size = hh.h16.size;
		change_endian(hh.h16.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h16) + sizeof(PN64_HEADER);
		break;
	}
	ah = xx_d_alloc(sizeof(ACC_PN64_HEADER),__file,__line);
	ah->a.fofs = fofs;
	ah->h.type = hh.h16.type;
	change_endian(ah->h.type);
	ah->h.size = _size;
	change_endian_header64(&ah->h);
	return ah;
err:
	return 0;
}

int
write_filespace64(PDB64 * p,void * h)
{
ACC_PN64_HEADER * a;
U_INTEGER64 size;
	a = h;
	size = a->h.size;
	change_endian(size);
	u_lseek64(p->fid,a->a.fofs,SEEK_SET);
	return fa_write64_header(p->fid,&a->h,size);
}

void *
xx_read_filespace64f_header
	(PDB64 * p,U_INTEGER64 fofs,char * __file,int __line)
{
PN64_HEADER * ah;
int er;
U_INTEGER64 size,_size;
PHYS_PN64_HEADER hh;
unsigned short s16;

	u_lseek64(p->fid,fofs,SEEK_SET);
	er = u_read(p->fid,&hh,sizeof(PN_HEADER));
	if ( er < sizeof(PN_HEADER) )
		goto err;
	s16 = hh.h16.size;
	change_endian(s16);
	switch ( s16 ) {
	case PHYS_SIZE32:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN32_HEADER) - sizeof(PN_HEADER));
		if ( er < sizeof(_PN32_HEADER) - sizeof(PN_HEADER) )
			goto err;
		change_endian(hh.h32.size);
		size = hh.h32.size;
		change_endian(hh.h32.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h32) + sizeof(PN64_HEADER);
		break;
	case PHYS_SIZE64:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN64_HEADER) - sizeof(PN_HEADER));
		if ( er < sizeof(_PN64_HEADER) - sizeof(PN_HEADER) )
			goto err;
		size = hh.h64.size;
		change_endian(size);
		_size = size - sizeof(hh.h64) + sizeof(PN64_HEADER);
		break;
	default:
		change_endian(hh.h16.size);
		size = hh.h16.size;
		change_endian(hh.h16.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h16) + sizeof(PN64_HEADER);
		break;
	}
	ah = xx_d_alloc(sizeof(PN64_HEADER),__file,__line);
	ah->type = hh.h16.type;
	change_endian(ah->type);
	ah->size = _size;
	change_endian_header64(ah);
	return ah;
err:
	return 0;
}

void *
xx_read_filespace64f(PDB64 * p,U_INTEGER64 fofs,char * __file,int __line)
{
PN64_HEADER * ah;
int er;
U_INTEGER64 size,_size;
PHYS_PN64_HEADER hh;
unsigned short s16;
int _s;
char * ptr;
int err_code;

	u_lseek64(p->fid,fofs,SEEK_SET);
	er = u_read(p->fid,&hh,sizeof(PN_HEADER));
	err_code = 1;
	if ( er < sizeof(PN_HEADER) )
		goto err;
	s16 = hh.h16.size;
	change_endian(s16);
	switch ( s16 ) {
	case PHYS_SIZE32:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN32_HEADER) - sizeof(PN_HEADER));
		err_code = 2;
		if ( er < sizeof(_PN32_HEADER) - sizeof(PN_HEADER) )
			goto err;
		change_endian(hh.h32.size);
		size = hh.h32.size;
		change_endian(hh.h32.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h32) + sizeof(PN64_HEADER);
		break;
	case PHYS_SIZE64:
		er = u_read(p->fid,(&hh.h16)+1,
			sizeof(_PN64_HEADER) - sizeof(PN_HEADER));
		err_code = 3;
		if ( er < sizeof(_PN64_HEADER) - sizeof(PN_HEADER) )
			goto err;
		size = hh.h64.size;
		change_endian(size);
		_size = size - sizeof(hh.h64) + sizeof(PN64_HEADER);
		break;
	default:
		change_endian(hh.h16.size);
		size = hh.h16.size;
		change_endian(hh.h16.size);
		/*change_endian(size);*/
		_size = size - sizeof(hh.h16) + sizeof(PN64_HEADER);
		break;
	}
	ah = xx_d_alloc(_size,__file,__line);
	ah->type = hh.h16.type;
	change_endian(ah->type);
	ah->size = _size;
	change_endian_header64(ah);

	ptr = (char*)(ah+1);
	_size -= sizeof(PN64_HEADER);
	{
		int debug;
			debug = sizeof(PN64_HEADER);
	}

	for ( ; _size ; ) {
		if ( _size > 0x10000 )
			_s = 0x10000;
		else	
			_s = _size;

		{
			int debug1;
			debug1=errno;
			er = u_read(p->fid,ptr,_s);
			if ( er < _s ) {
				int en2;
				en2=errno;
				d_f_ree(ah);
				err_code = 4;
				goto err;
			}
		}

		ptr += er;
		_size -= er;
		
	}
	return ah;
err:

	return 0;
}

int
write_filespace64f(PDB64 * p,int fofs,void * h)
{
U_INTEGER64 size;
PN64_HEADER * a;
	a = h;
	size = a->size;
	change_endian(size);
	u_lseek64(p->fid,fofs,SEEK_SET);
	return fa_write64_header(p->fid,h,size);
}

