/**********************************************************************
 
	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	<fcntl.h>
#include	"change_endian.h"
#include	"pdb.h"
#include	"favt.h"
#include	"rcache.h"
#include	"filespace.h"
#include	"memory_debug.h"
#include	"resource.h"
#include	"recordlist.h"
#include	"resource.h"
#include	"stream.h"
#include	"rs_cache.h"
#include	"pri_level.h"

#define PURGE_FILE_ID_LIST 	10
#define RS_MIN_EXPIRE		120
#define RS_AVG_EXPIRE		(24*3600)
#define RS_MAX_EXPIRE		(30*24*3600)

typedef struct acc_pn_rs_cache_header {
	ACC_HEADER		h;
	PN_RS_CACHE_HEADER	d;
} ACC_PN_RS_CACHE_HEADER;

typedef struct acc_pn_rs_cache_data {
	ACC_HEADER		h;
	PN_RS_CACHE_DATA	d;
} ACC_PN_RS_CACHE_DATA;

typedef struct rsc_timer_index {
	unsigned int		fofs;
	unsigned int		timer;
} RSC_TIMER_INDEX;

typedef struct rs_convert_tbl {
	int		(*change_endian_to_host)();
	int		(*change_endian_to_net)();
	int		(*chain_to_host)(RECORD_LIST *);
	RESOURCE *	(*resource_to_host)(RECORD_LIST *,RS_BUF *);
	int		body_size;
} RS_CONVERT_TBL;


int change_endian_rs_res_status();
int change_endian_rs_res_status();
int change_endian_rs_coordinate_to_host();
int change_endian_rs_coordinate_to_net();
int change_endian_rs_pixel_map_r64_to_host();
int change_endian_rs_pixel_map_r64_to_net();
int change_endian_rs_draw_gb_to_host();
int change_endian_rs_draw_gb_to_net();
int change_endian_rs_res_map_to_host();
int change_endian_rs_res_map_to_net();
int change_endian_rs_bib_list_to_host();
int change_endian_rs_bib_list_to_net();
int change_endian_rs_note_to_host();
int change_endian_rs_note_to_net();
int change_endian_rs_clip_to_host();
int change_endian_rs_clip_to_net();
int change_endian_rs_map_to_host();
int change_endian_rs_map_to_net();
int change_endian_rs_info_scheme_to_host();
int change_endian_rs_info_scheme_to_net();
int change_endian_rs_triangle_to_host();
int change_endian_rs_triangle_to_net();
int change_endian_rs_map_point_list_to_host();
int change_endian_rs_map_point_list_to_net();
int change_endian_header_int();

int chain_string_all_to_host();
int chain_rs_coordinate_to_host();

RESOURCE * resource_rs_coordinate_to_host();
RESOURCE * resource_rs_pixel_map_r64_to_host();
RESOURCE * resource_rs_res_map_to_host();
RESOURCE * resource_rs_draw_gb_to_host();

RCACHE_BLK resource_cache;
ACC_PN_RS_CACHE_HEADER * rs_cache_header;
PDB * rs_p;
int max_rs_cache_counter = 10000;
int rs_rcache_flags;

RS_CONVERT_TBL rs_convert[] = {
	/* 0 */ {
		change_endian_header_int,
		change_endian_header_int,
		0,
		0
	},
	/* 1 */ {0,0,0,0,0},
	/* 2 */ {0,0,0,0,0},
	/* 3 */ {
		change_endian_rs_res_status,
		change_endian_rs_res_status,
		0,
		0,
		sizeof(PN_RS_RES_STATUS)
	},
	/* 4 */ {
		change_endian_rs_coordinate_to_host,
		change_endian_rs_coordinate_to_net,
		chain_rs_coordinate_to_host,
		resource_rs_coordinate_to_host,
		sizeof(PN_RS_COORDINATE)
	},
	/* 5 */ {
		change_endian_rs_pixel_map_r64_to_host,
		change_endian_rs_pixel_map_r64_to_net,
		chain_string_all_to_host,
		resource_rs_pixel_map_r64_to_host,
		sizeof(PN_RS_PIXEL_MAP_R64)
	},
	/* 6 */ {
		change_endian_rs_draw_gb_to_host,
		change_endian_rs_draw_gb_to_net,
		chain_string_all_to_host,
		resource_rs_draw_gb_to_host,
		sizeof(PN_RS_DRAW_GB)
	},
	/* 7 */ {
		change_endian_rs_res_map_to_host,
		change_endian_rs_res_map_to_net,
		chain_string_all_to_host,
		resource_rs_res_map_to_host,
		sizeof(PN_RS_RES_MAP)
	},
	/* 8 */ {
		change_endian_rs_bib_list_to_host,
		change_endian_rs_bib_list_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_BIB_LIST)
	},
	/* 9 */ {
		change_endian_rs_note_to_host,
		change_endian_rs_note_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_NOTE)
	},
	/* 10 */ {
		change_endian_rs_clip_to_host,
		change_endian_rs_clip_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_CLIP)
	},
	/* 11 */ {
		change_endian_rs_map_to_host,
		change_endian_rs_map_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_MAP)
	},
	/* 12 */ {
		change_endian_rs_info_scheme_to_host,
		change_endian_rs_info_scheme_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_INFO_SCHEME)
	},
	/* 13 */ {
		change_endian_rs_triangle_to_host,
		change_endian_rs_triangle_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_TRIANGLE)
	},
	/* 14 */ {
		change_endian_rs_map_point_list_to_host,
		change_endian_rs_map_point_list_to_net,
		chain_string_all_to_host,
		0,
		sizeof(PN_RS_MAP_POINT_LIST)
	}
};

int
change_endian_header_int(PN_HEADER * h)
{
	change_endian_header(h);
	return 0;
}

void
change_endian_rs_cache_header(PN_RS_CACHE_HEADER * d)
{
	change_endian_header(&d->h);
	change_endian_i(d->flags);
	change_endian_i(d->count);
	change_endian_i(d->url_tree);
	change_endian_i(d->timer_tree);
	change_endian_i(d->file_id);
}

int
change_endian_rs_cache_data_to_host(PN_RS_CACHE_DATA * d)
{
int i;
int len;
L_CHAR * ptr;
	change_endian_header(&d->h);
	change_endian_i(d->expire);
	change_endian_i(d->file_id);
	len = d->h.size - sizeof(PN_RS_CACHE_DATA);
	if ( len < 0 )
		return -1;
	ptr = (L_CHAR*)(d+1);
	for ( i = 0 ; i < len/sizeof(L_CHAR) ; i ++ , ptr ++ ) {
		change_endian_i(*ptr);
	}
	return 0;
}


int
change_endian_rs_cache_data_to_net(PN_RS_CACHE_DATA * d)
{
int i;
int len;
L_CHAR * ptr;
	len = d->h.size - sizeof(PN_RS_CACHE_DATA);
	if ( len < 0 )
		return -1;
	ptr = (L_CHAR*)(d+1);
	for ( i = 0 ; i < len/sizeof(L_CHAR) ; i ++ , ptr ++ ) {
		change_endian_i(*ptr);
	}
	change_endian_header(&d->h);
	change_endian_i(d->expire);
	change_endian_i(d->file_id);
	return 0;
}


int
chain_string_to_host(RECORD_LIST * r)
{
L_CHAR * str;
int len;
	str = r->ptr;
	len = l_strlen(str);
	set_recordlist_chain(r,r->ptr,(len+1)*sizeof(L_CHAR),0);
	r->ptr = ((L_CHAR*)r->ptr) + len + 1;
	return 0;
}

int
chain_string_all_to_host(RECORD_LIST * r)
{
	for ( ; check_recordlist_ptr(r) == 0 ; )
		chain_string_to_host(r);
	return 0;
}

int
chain_cid_to_host(RECORD_LIST * r)
{
int * cid;
int len;
	cid = r->ptr;
	len = cid[0];
	set_recordlist_chain(r,r->ptr,(len+1)*sizeof(int),0);
	r->ptr = ((int*)r->ptr) + len + 1;
	return 0;
}

int
change_endian_after_structure_string(void * st,int st_len)
{
PN_HEADER * h;
int len,i;
L_CHAR * ptr;
	h = (PN_HEADER*)st;
	if ( st_len > h->size )
		return -1;
	ptr = (L_CHAR*)(((char*)st)+st_len);
	len = (h->size - st_len)/sizeof(L_CHAR);
	for ( i = 0 ; i < len ; i ++ , ptr ++ )
		change_endian_i(*ptr);
	return 0;
}

int
change_endian_rs_res_status(PN_RS_RES_STATUS * st)
{
	change_endian_header(&st->pn_h);
	change_endian_i(st->type);
	return 0;
}

int
change_endian_rs_res_header(PN_RS_RES_HEADER * rs)
{
	change_endian_header(&rs->pn_h);
	change_endian_i(rs->type);
	change_endian_i(rs->flags);
	change_endian_i(rs->modify);
	change_endian_gb_rect(&rs->minrect);
	change_endian_f(rs->visible_resolution);
	return 0;
}

int
chain_rs_res_header_to_host(RECORD_LIST * r)
{
	/* URL entry */
	chain_string_to_host(r);
	/* URL target */
	chain_string_to_host(r);
	/* XL_SEXP * meta */
	chain_string_to_host(r);
	/* COORDINATE_UNIT cu.url */
	chain_string_to_host(r);
	/* COORDINATE_UNIT cu.system */
	chain_string_to_host(r);
	/* COORDINATE_UNIT cu.unit */
	chain_string_to_host(r);
	return 0;
}

int
change_endian_rs_bib_list_to_host(PN_RS_BIB_LIST * b)
{
	change_endian_header(&b->pn_h);
	change_endian_i(b->inherit);
	return change_endian_after_structure_string((void*)b,sizeof(*b));
}



int
change_endian_rs_bib_list_to_net(PN_RS_BIB_LIST * b)
{
	if ( change_endian_after_structure_string((void*)b,sizeof(*b)) < 0 )
		return -1;
	change_endian_header(&b->pn_h);
	change_endian_i(b->inherit);
	return 0;
}

int
change_endian_rs_note_to_host(PN_RS_NOTE * n)
{
	change_endian_header(&n->pn_h);
	change_endian_i(n->type);
	change_endian_i(n->fill_color);
	change_endian_i(n->line_color);
	return change_endian_after_structure_string((void*)n,sizeof(*n));
}


int
change_endian_rs_note_to_net(PN_RS_NOTE * n)
{
	if ( change_endian_after_structure_string((void*)n,sizeof(*n)) < 0 )
		return -1;
	change_endian_header(&n->pn_h);
	change_endian_i(n->type);
	change_endian_i(n->fill_color);
	change_endian_i(n->line_color);
	return 0;
}

int
change_endian_rs_pixel_map_r64_to_host(PN_RS_PIXEL_MAP_R64 * r)
{
int i;
	change_endian_rs_res_header(&r->h);
	change_endian_f(r->dpm);
	for ( i = 0 ; i < 32 ; i ++ ) {
		change_endian_i(r->width[i]);
		change_endian_i(r->height[i]);
	}
	change_endian_i(r->max_level);
	return change_endian_after_structure_string((void*)r,sizeof(*r));
}


int
change_endian_rs_pixel_map_r64_to_net(PN_RS_PIXEL_MAP_R64 * r)
{
int i;
	if ( change_endian_after_structure_string((void*)r,sizeof(*r)) < 0 )
		return -1;
	change_endian_rs_res_header(&r->h);
	change_endian_f(r->dpm);
	for ( i = 0 ; i < 32 ; i ++ ) {
		change_endian_i(r->width[i]);
		change_endian_i(r->height[i]);
	}
	change_endian_i(r->max_level);
	return 0;
}

int
change_endian_rs_coordinate_to_host(PN_RS_COORDINATE * c)
{
	change_endian_rs_res_header(&c->h);
	change_endian_i(c->flags);
	change_endian_i(c->geometory_type);
	change_endian_f(c->limit_resolution);
	change_endian_f(c->weight);
	return change_endian_after_structure_string((void*)c,sizeof(*c));
}

int
change_endian_rs_coordinate_to_net(PN_RS_COORDINATE * c)
{
	if ( change_endian_after_structure_string((void*)c,sizeof(*c)) < 0 )
		return -1;
	change_endian_rs_res_header(&c->h);
	change_endian_i(c->flags);
	change_endian_i(c->geometory_type);
	change_endian_f(c->limit_resolution);
	change_endian_f(c->weight);
	return 0;
}

int
chain_rs_coordinate_to_host(RECORD_LIST * r)
{
	chain_rs_res_header_to_host(r);
	/* L_CHAR * mode */
	chain_string_to_host(r);
	/* XL_SEXP * initial_cmd */
	chain_string_to_host(r);
	/* XL_SEXP * button_action */
	chain_string_to_host(r);
	/* int * cid */
	chain_cid_to_host(r);
	/* after */
	chain_string_all_to_host(r);
	return 0;
}

int
change_endian_rs_clip_to_host(PN_RS_CLIP * c)
{
	change_endian_header(c->pn_h);
	change_endian_s(c->type);
	change_endian_s(c->shape);
	switch ( c->shape ) {
	case CST_RECT:
		change_endian_gb_rect(&c->d.rect);
		break;
	default:
		break;
	}
	return 0;
}

int
change_endian_rs_clip_to_net(PN_RS_CLIP * c)
{
	switch ( c->shape ) {
	case CST_RECT:
		change_endian_gb_rect(&c->d.rect);
		break;
	default:
		break;
	}
	change_endian_header(c->pn_h);
	change_endian_s(c->type);
	change_endian_s(c->shape);
	return 0;
}

int
change_endian_rs_map_to_host(PN_RS_MAP * m)
{
	change_endian_header(&m->pn_h);
	change_endian_s(m->depth);
	change_endian_s(m->flags);
	change_endian_i(m->mod_time_org);
	change_endian_i(m->mod_time);
	change_endian_i(m->cindex_time);
	change_endian_gb_rect(&m->cindex_mr);
	return change_endian_after_structure_string((void*)m,sizeof(*m));
}


int
change_endian_rs_map_to_net(PN_RS_MAP * m)
{
	if ( change_endian_after_structure_string((void*)m,sizeof(*m)) < 0 )
		return -1;
	change_endian_header(&m->pn_h);
	change_endian_s(m->depth);
	change_endian_s(m->flags);
	change_endian_i(m->mod_time_org);
	change_endian_i(m->mod_time);
	change_endian_i(m->cindex_time);
	change_endian_gb_rect(&m->cindex_mr);
	return 0;
}

int
change_endian_rs_draw_gb_to_host(PN_RS_DRAW_GB * g)
{
int i;
	change_endian_rs_res_header(&g->h);
	change_endian_i(g->type);
	change_endian_s(g->level);
	change_endian_s(g->pdb_lock);
	change_endian_i(g->flags);
	change_endian_f(g->resolution);
	change_endian_gb_point(&g->matrix_ofs);
	for ( i = 0 ; i < g->level ; i ++ )
		change_endian_gb_point(&g->pitch_list[i]);
	change_endian_i(g->loop_no);
	change_endian_f(g->onmap_indicate_size);
	change_endian_s(g->hit_level);
	change_endian_s(g->hit_outofcircle);
	return change_endian_after_structure_string((void*)g,sizeof(*g));
}


int
change_endian_rs_draw_gb_to_net(PN_RS_DRAW_GB * g)
{
int i;
	if ( change_endian_after_structure_string((void*)g,sizeof(*g)) < 0 )
		return -1;
	for ( i = 0 ; i < g->level ; i ++ )
		change_endian_gb_point(&g->pitch_list[i]);
	change_endian_rs_res_header(&g->h);
	change_endian_i(g->type);
	change_endian_s(g->level);
	change_endian_s(g->pdb_lock);
	change_endian_i(g->flags);
	change_endian_f(g->resolution);
	change_endian_gb_point(&g->matrix_ofs);
	change_endian_i(g->loop_no);
	change_endian_f(g->onmap_indicate_size);
	change_endian_s(g->hit_level);
	change_endian_s(g->hit_outofcircle);
	return 0;
}

int
change_endian_rs_info_scheme_to_host(PN_RS_INFO_SCHEME * s)
{
	change_endian_header(&s->pn_h);
	change_endian_s(s->card_type);
	change_endian_s(s->onmap_type);
	return change_endian_after_structure_string((void*)s,sizeof(*s));
}

int
change_endian_rs_info_scheme_to_net(PN_RS_INFO_SCHEME * s)
{
	if ( change_endian_after_structure_string((void*)s,sizeof(*s)) < 0 )
		return -1;
	change_endian_header(&s->pn_h);
	change_endian_s(s->card_type);
	change_endian_s(s->onmap_type);
	return 0;
}

void
change_endian_rs_triangle_set(PN_RS_TRIANGLE_SET * s)
{
	change_endian_i(s->sts);
	change_endian_i(s->cnt);
	change_endian_affen2d(&s->a);
	change_endian_gb_rect(&s->minrect);
	change_endian_f(s->resolution_rate);
}

void
change_endian_rs_map_parameter_to_host(PN_RS_MAP_PARAMETER * p)
{
	change_endian_i(p->type);
	change_endian_f(p->resolution_rate);
	switch ( p->type ) {
	case MT_MOVE:
		change_endian_gb_point(&p->opt.ptr);
		break;
	case MT_ROTATE:
	case MT_LINEAR:
		change_endian_affen2d(&p->opt.affen);
		break;
	case MT_TRIANGLE:
		change_endian_rs_triangle_set(&p->opt.tri);
		break;
	default:
		break;
	}
}


void
change_endian_rs_map_parameter_to_net(PN_RS_MAP_PARAMETER * p)
{
	switch ( p->type ) {
	case MT_MOVE:
		change_endian_gb_point(&p->opt.ptr);
		break;
	case MT_ROTATE:
	case MT_LINEAR:
		change_endian_affen2d(&p->opt.affen);
		break;
	case MT_TRIANGLE:
		change_endian_rs_triangle_set(&p->opt.tri);
		break;
	default:
		break;
	}
	change_endian_i(p->type);
	change_endian_f(p->resolution_rate);
}

int
change_endian_rs_res_map_to_host(PN_RS_RES_MAP * m)
{
	change_endian_rs_res_header(&m->h);
	change_endian_rs_map_parameter_to_host(&m->param_forward);
	change_endian_rs_map_parameter_to_host(&m->param_reverse);
	return change_endian_after_structure_string((void*)m,sizeof(*m));
}


int
change_endian_rs_res_map_to_net(PN_RS_RES_MAP * m)
{
	if ( change_endian_after_structure_string((void*)m,sizeof(*m)) < 0 )
		return -1;
	change_endian_rs_res_header(&m->h);
	change_endian_rs_map_parameter_to_host(&m->param_forward);
	change_endian_rs_map_parameter_to_host(&m->param_reverse);
	return 0;
}


int
change_endian_rs_triangle_to_host(PN_RS_TRIANGLE * t)
{
int i;
	change_endian_header(&t->pn_h);
	for ( i = 0 ; i  < 3 ; i ++ )
		change_endian_gb_point(&t->ptp[i]);
	change_endian_affen2d(&t->a);
	change_endian_f(t->resolution_rate);
	change_endian_gb_rect(&t->minrect);
	return change_endian_after_structure_string((void*)t,sizeof(*t));
}


int
change_endian_rs_triangle_to_net(PN_RS_TRIANGLE * t)
{
int i;
	if (  change_endian_after_structure_string((void*)t,sizeof(*t)) < 0 )
		return -1;
	change_endian_header(&t->pn_h);
	for ( i = 0 ; i  < 3 ; i ++ )
		change_endian_gb_point(&(t->ptp[i]));
	change_endian_affen2d(&t->a);
	change_endian_f(t->resolution_rate);
	change_endian_gb_rect(&t->minrect);
	return 0;
}

int
change_endian_rs_map_point_list_to_host(PN_RS_MAP_POINT_LIST * p)
{
	change_endian_header(&p->pn_h);
	change_endian_gb_point(&p->src);
	change_endian_gb_point(&p->dest);
	return change_endian_after_structure_string((void*)p,sizeof(*p));
}


int
change_endian_rs_map_point_list_to_net(PN_RS_MAP_POINT_LIST * p)
{
	if ( change_endian_after_structure_string((void*)p,sizeof(*p)) < 0 )
		return -1;
	change_endian_header(&p->pn_h);
	change_endian_gb_point(&p->src);
	change_endian_gb_point(&p->dest);
	return 0;
}


int
change_endian_rs_to_host(RECORD_LIST * r)
{
int type;
PN_RS_RES_STATUS * s;
int ret,_ret;
RS_CONVERT_TBL * t;
	ret = 0;
	for ( ; r ; r = r->next ) {
		type = r->header.type;
		if ( PNT_GET_GROUP(type) != PNT_RS_CACHE_GROUP ) {
			ret = -1;
			continue;
		}
		t = &rs_convert[PNT_TYPE_MASK&type];
		if ( t->change_endian_to_host == 0 ) {
			ret = -1;
			continue;
		}
		if ( (*t->change_endian_to_host)(r->data) < 0 ) {
			ret = -1;
			continue;
		}
		if ( t->chain_to_host == 0 )
			continue;
		if ( r->header.size <= t->body_size )
			r->ptr = 0;
		else	r->ptr = ((char*)r->data) + t->body_size;
		if ( (*t->chain_to_host)(r) < 0 ) {
			ret = -1;
			continue;
		}
	}
	return ret;
}



int
change_endian_rs_to_net(RECORD_LIST * r)
{
int type;
PN_RS_RES_STATUS * s;
int ret,_ret;
RS_CONVERT_TBL * t;
	ret = 0;
	for ( ; r ; r = r->next ) {
		type = r->header.type;
		if ( PNT_GET_GROUP(type) != PNT_RS_CACHE_GROUP ) {
			ret = -1;
			continue;
		}
		t = &rs_convert[PNT_TYPE_MASK&type];
		if ( t->change_endian_to_net == 0 ) {
			ret = -1;
			continue;
		}
		if ( (*t->change_endian_to_net)(r->data) < 0 ) {
			ret = -1;
			continue;
		}
	}
	return ret;
}






void
rsc_timer_endian(RSC_TIMER_INDEX * ix)
{
	change_endian_i(ix->fofs);
	change_endian_i(ix->timer);
}

int
cmp_rsc_timer(RSC_TIMER_INDEX * ix1,RSC_TIMER_INDEX * ix2)
{
	if ( ix1->timer < ix2->timer )
		return -1;
	if ( ix1->timer > ix2->timer )
		return 1;
	if ( ix1->fofs < ix2->fofs )
		return -1;
	if ( ix1->fofs > ix2->fofs )
		return 1;
	return 0;
}

void
_purge_rs_cache_header()
{
ACC_PN_RS_CACHE_HEADER * h;
	if ( rs_p == 0 )
		return;
	if ( rs_cache_header == 0 )
		return;
	h = d_alloc(sizeof(ACC_PN_RS_CACHE_HEADER));
	*h = *rs_cache_header;
	change_endian_rs_cache_header(&h->d);
	write_filespace(rs_p,h);
	d_f_ree(h);
}


int
_new_rs_cache()
{
PDB * p;
L_CHAR * encoding;
ACC_PN_RS_CACHE_HEADER * h;
FAVT_ROOT * rt;
int ret;
	h = 0;
	encoding = l_string(std_cm,"UCS4");
	p = open_filespace(
		n_string(std_cm,resource_cache.path),
		O_CREAT|O_RDWR|O_TRUNC,0644,
		PF_USEFREELIST,FT_RT_CACHE,encoding,0,0);
	if ( p == 0 )
		return -1;
	ret = -1;
	h = d_alloc(sizeof(*h));
	h->h.fofs = 0;
	h->d.h.size = sizeof(h->d);
	h->d.h.type = PNT_RS_CACHE_HEADER;
	h->h.fofs = alloc_filespace(p,&h->d.h);
	strcpy(h->d.version,RS_CACHE_VERSION);
	h->d.flags = 0;
	h->d.count = 0;
	h->d.file_id = 1;
	rt = favt_alloc_root(p,FAT_RSC_URL,favt_string_endian);
	if ( rt == 0 ) {
		ret = -1;
		goto end;
	}
	h->d.url_tree = rt->h.fofs;
	rt = favt_alloc_root(p,FAT_RSC_TIMER,rsc_timer_endian);
	if ( rt == 0 ) {
		ret = -1;
		goto end;
	}
	h->d.timer_tree = rt->h.fofs;

	change_endian_rs_cache_header(&h->d);
	write_filespace(p,h);
	ret = 0;

	close_filespace(p);
end:
	if ( h )
		d_f_ree(h);
	return ret;
}

void
init_rs_cache()
{
}

L_CHAR *
get_filepath_from_file_id(int id,char * prefix)
{
char * f_path;
L_CHAR * ret;

	f_path = d_alloc(100);
	sprintf(f_path,"f%03i/f%03i/f%03i/f%03i%s",
		(id >> 24)&0x0ff,
		(id >> 16)&0x0ff,
		(id >> 8)&0x0ff,
		id & 0x0ff,
		prefix);

	ret = get_rcache_file_name(f_path);
	d_f_ree(f_path);
	if ( ret )
		mk_path(ret,0);
	return ret;
}

int
round_file_id(int fid)
{
	if ( fid < 0 )
		fid = fid & 0x7fffffff;
	if ( fid == 0 )
		fid = 1;
	return fid;
}

int
rs_exist_check(int fid)
{
L_CHAR * filepath;
int fd;
	filepath = get_filepath_from_file_id(fid,".inf");
	if ( filepath == 0 )
		return -1;
	fd = open(n_string(std_cm,filepath),O_RDONLY);
	if ( fd < 0 )
		return -1;
	close(fd);
	return 0;
}

typedef struct file_list {
	struct file_list * 	next;
	char * 			name;
} FILE_LIST;

FILE_LIST *
new_file_list(char * name,FILE_LIST * in)
{
FILE_LIST * ret;
	ret = d_alloc(sizeof(*ret));
	ret->next = in;
	ret->name = copy_str(name);
	return ret;
}

void
free_file_list(FILE_LIST * f)
{
FILE_LIST * f2;
	for ( ; f ; ) {
		f2 = f;
		f = f->next;
		d_f_ree(f2->name);
		d_f_ree(f2);
	}
}

void
clean_empty_dir(L_CHAR * dir)
{
DIR * dd;
struct dirent * d;
L_CHAR * dir_path, * file;
char * _file;
int i;

	dd = u_opendir(n_string(std_cm,dir));
	if ( dd == 0 )
		return;
	for ( ; ; ) {
		d = u_readdir(dd);
		if ( d == 0 )
			break;
		if ( d->d_name[0] == '.' )
			continue;
		closedir(dd);
		return;
	}
	closedir(dd);
	unlink(n_string(std_cm,dir));
	dir_path = ll_copy_str(dir);
	for ( i = l_strlen(dir)-1 ; i >= 0 && dir_path[i] != '/' ; i -- );
	if (  i > 0 ) {
		dir_path[i] = 0;
		clean_empty_dir(dir_path);
	}
	d_f_ree(dir_path);
	return;
}

void
_delete_rs_resource(int file_id)
{
L_CHAR * filepath;
L_CHAR * dir_path;
char * file;
int len;
DIR * dd;
struct dirent * d;
FILE_LIST * ff,* _f;
char * buf;

	filepath = get_filepath_from_file_id(file_id,"");
	if ( filepath == 0 )
		return;
	dir_path = ll_copy_str(filepath);
	len = l_strlen(dir_path);
	dir_path[len-5] = 0;
	file = ln_copy_str(std_cm,&dir_path[len-4]);
	dd = u_opendir(n_string(std_cm,dir_path));
	if ( dd == 0 )
		goto end1;
	ff = 0;
	for ( ; ; ) {
		d = u_readdir(dd);
		if ( d == 0 )
			break;
		if ( d->d_name[0] == '.' )
			continue;
		if ( memcmp(d->d_name,file,strlen(file)) )
			continue;
		ff = new_file_list(d->d_name,ff);
	}
	closedir(dd);
	len = strlen(n_string(std_cm,dir_path));
	for ( _f = ff ; _f ; _f = _f->next ) {
		buf = d_alloc(len + strlen(_f->name) + 10);
		sprintf(buf,"%s/%s",n_string(std_cm,dir_path),_f->name);
		unlink(buf);
		d_f_ree(buf);
	}
	clean_empty_dir(dir_path);
end2:
	free_file_list(ff);
end1:
	d_f_ree(dir_path);
	d_f_ree(filepath);
	return;
}

void
_open_rs_cache()
{
PN_RS_CACHE_HEADER * h;
unsigned int fofs;

retry:
	rs_p = open_filespace(
		n_string(std_cm,resource_cache.path),O_RDWR,
		0600,PF_USEFREELIST,FT_RT_CACHE,0,0,0);
	if ( rs_p ) {
		fofs = 0;
		h = get_file_record(&fofs,
			rs_p,PNT_RS_CACHE_HEADER);
		if ( h == 0 ) {
			close_filespace(rs_p);
			goto remake;
		}
		rs_cache_header = d_alloc(sizeof(*rs_cache_header));
		rs_cache_header->d = *h;
		rs_cache_header->h.fofs = fofs;
		d_f_ree(h);
		change_endian_rs_cache_header(&rs_cache_header->d);
		if ( (rs_cache_header->d.flags & RTC_F_WRITE) ||
				strcmp(rs_cache_header->d.version,
					RT_CACHE_VERSION) ) {
			close_filespace(rs_p);
			d_f_ree(rs_cache_header);
			rs_cache_header = 0;
			goto remake;
		}
	}
	else {
		goto remake;
	}
	resource_cache.err = RE_RUN;
	return;
remake:
	resource_cache.err = RE_DESTROY;
	return;
}


void
_close_rs_cache()
{
	if ( rs_p == 0 )
		return;
	close_filespace(rs_p);
	rs_p = 0;
	d_f_ree(rs_cache_header);
	rs_cache_header = 0;
}

void
remake_rs_cache()
{
	local_lock_rcache(&resource_cache);
	if ( resource_cache.err != RE_DESTROY )
		goto end;
	wlock_rcache(&resource_cache);
	if ( resource_cache.err != RE_DESTROY )
		goto end;
	if ( rs_p )
		_close_rt_cache();
	if ( _new_rs_cache() < 0 ) {
		resource_cache.err = RE_STOP;
	}
	else {
		_open_rt_cache();
		if ( resource_cache.err == RE_DESTROY )
			resource_cache.err = RE_STOP;
	}
	resource_cache.err = RE_RUN;
end:
	unlock_rcache(&resource_cache);
}

unsigned int
get_rs_url(FAVT_NODE ** np,FAVT_ROOT * r,L_CHAR * url)
{
FAVT_NODE * n;
STRING_INDEX * ix;
int len;
	len = l_strlen(url);
	ix = d_alloc(STRING_IX_LENGTH_1(len));
	ix->fofs = 0;
	l_strcpy(ix->d,url);
	n = favt_search(r,root_node(r),ix,favt_cmp_string_1);
	d_f_ree(ix);
	if ( n == 0 )
		return 0;
	ix = n->data;
	if ( np )
		*np = n;
	return ix->fofs;
}


ACC_PN_RS_CACHE_DATA *
_search_rs_cache_entry(L_CHAR * url)
{
FAVT_ROOT * r;
unsigned int ix;
ACC_PN_RS_CACHE_DATA * ret;
	r = get_root(rs_p,rs_cache_header->d.url_tree,favt_string_endian);
	if ( r == 0 ) {
		resource_cache.err = RE_DESTROY;
		return 0;
	}
	ix = get_rs_url(0,r,url);
	if ( ix == 0 ) {
		return 0;
	}
	ret = read_filespace(rs_p,ix);
	change_endian_rs_cache_data_to_host(&ret->d);
	if ( ret->d.h.type != PNT_RS_CACHE_DATA )
		er_panic("_search_rs_cache_entry(1)");
	return ret;
}

int
_insert_rs_timer(unsigned int now,unsigned int data_ofs)
{
FAVT_ROOT * r;
RSC_TIMER_INDEX tix;
FAVT_NODE * n, * nn;

	r = get_root(rs_p,rs_cache_header->d.timer_tree,rsc_timer_endian);
	if ( r == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	tix.fofs = data_ofs;
	tix.timer = now;
	n = favt_alloc_node(r,&tix,sizeof(tix));
	if ( n == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	nn = favt_insert(r,&r->node,n,cmp_rsc_timer);
	if ( nn != n )
		er_panic("_new_rs_cache_entry(1)");
	return 0;
}

int
_delete_rs_timer(unsigned int now,unsigned int data_ofs)
{
FAVT_ROOT * r;
FAVT_NODE * n;
RSC_TIMER_INDEX tix;
	r = get_root(rs_p,rs_cache_header->d.timer_tree,rsc_timer_endian);
	if ( r == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	tix.fofs = data_ofs;
	tix.timer = now;
	n = favt_delete(r,&r->node,&tix,cmp_rsc_timer);
	if ( n == 0 )
		er_panic("_delete_rs_timer");
	favt_free_node(n);
	return 0;
}

int
_new_rs_cache_entry(L_CHAR * url,unsigned int expire)
{
ACC_PN_RS_CACHE_DATA * d;
int file_id;
int len,slen;
FAVT_ROOT * r;
STRING_INDEX * ix;
FAVT_NODE * n,* nn;
unsigned int data_ofs;
int inc;
	d = _search_rs_cache_entry(url);
	if ( d ) {
		d_f_ree(d);
		return -1;
	}
	file_id = rs_cache_header->d.file_id;
	inc = 1;
	for ( ; rs_exist_check(file_id) == 0 ; ) {
		file_id = round_file_id(file_id + inc);
		inc = inc<<1;
		if ( inc <= 0 )
			inc = 1;
	}
	rs_cache_header->d.file_id = round_file_id(file_id+1);
	rs_cache_header->d.count ++;
	_purge_rs_cache_header();

	len = (l_strlen(url)+1)*sizeof(L_CHAR);
	d = d_alloc(sizeof(ACC_PN_RS_CACHE_DATA) + len);
	d->d.file_id = file_id;
	d->d.expire = expire;
	d->d.h.type = PNT_RS_CACHE_DATA;
	d->d.h.size = sizeof(PN_RS_CACHE_DATA) + len;
	memcpy((&d->d)+1,url,len);

	data_ofs = d->h.fofs = alloc_filespace(rs_p,&d->d.h);
	change_endian_rs_cache_data_to_net(&d->d);
	write_filespace(rs_p,d);
	d_f_ree(d);

	r = get_root(rs_p,rs_cache_header->d.url_tree,favt_string_endian);
	if ( r == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	ix = d_alloc(STRING_IX_LENGTH_1(slen = l_strlen(url)));
	ix->fofs = data_ofs;
	l_strcpy(ix->d,url);
	n = favt_alloc_node(r,ix,STRING_IX_LENGTH_1(slen));
	if ( n == 0 ) {
		resource_cache.err = RE_DESTROY;
		d_f_ree(ix);
		return -1;
	}
	nn = favt_insert(r,&r->node,n,favt_cmp_string_1);
	if ( nn != n )
		er_panic("_new_rs_cache_entry");
	d_f_ree(ix);
	if ( _insert_rs_timer(expire,data_ofs) < 0 )
		return -1;
	return file_id;
}

int
_touch_rs_cache_entry(L_CHAR * url,unsigned int expire)
{
ACC_PN_RS_CACHE_DATA * d;
int ret;
	d = _search_rs_cache_entry(url);
	if ( d == 0 )
		return -1;
	ret = -1;
	if ( _delete_rs_timer(d->d.expire,d->h.fofs) < 0 )
		goto end;
	d->d.expire = expire;
	if ( _insert_rs_timer(d->d.expire,d->h.fofs) < 0 )
		goto end;
	change_endian_rs_cache_data_to_net(&d->d);
	write_filespace(rs_p,d);
	ret = 0;
end:
	d_f_ree(d);
	return ret;
}

int
_delete_rs_url(L_CHAR * url)
{
FAVT_ROOT * r;
FAVT_NODE * n;
STRING_INDEX * ix;
int len;
	r = get_root(rs_p,rs_cache_header->d.url_tree,favt_string_endian);
	if ( r == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	len = l_strlen(url);
	ix = d_alloc(STRING_IX_LENGTH_1(len));
	ix->fofs = 0;
	l_strcpy(ix->d,url);
	n = favt_delete(r,&r->node,ix,favt_cmp_string_1);
	d_f_ree(ix);
	if ( n == 0 )
		er_panic("delete"); 
	favt_free_node(n);
	return 0;

}

int
rs_purge_func(FAVT_NODE * a,FAVT_NODE ** n)
{
	*n = a;
	return 1;
}

int
__purge_rs_cache_data()
{
FAVT_ROOT * r;
RSC_TIMER_INDEX * ix;
unsigned int p_data;
ACC_PN_RS_CACHE_DATA * d;
FAVT_NODE * n;
int file_id;
	r = get_root(rs_p,rs_cache_header->d.timer_tree,rsc_timer_endian);
	if ( r == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	n = 0;
	favt_trace_from_small(r,root_node(r),rs_purge_func,&n);
	if ( n == 0 )
		return -1;
	ix = n->data;
	p_data = ix->fofs;
	d = read_filespace(rs_p,p_data);
	if ( d == 0 ) {
		resource_cache.err = RE_DESTROY;
		return -1;
	}
	change_endian_rs_cache_data_to_host(&d->d);
	file_id = d->d.file_id;
	_delete_rs_url((L_CHAR*)(&(d->d)+1));
	_delete_rs_timer(d->d.expire,d->h.fofs);
	free_filespace(rs_p,p_data);
	d_f_ree(d);
	rs_cache_header->d.count --;
	return file_id;
}


void
_purge_rs_cache_data(int * file_id_list)
{
int cnt;
	cnt = 0;
	for ( ; cnt < PURGE_FILE_ID_LIST &&
			rs_cache_header->d.count > max_rs_cache_counter ;
			cnt ++ )
		file_id_list[cnt] = __purge_rs_cache_data();
	file_id_list[cnt] = 0;
	_purge_rs_cache_header();
}


L_CHAR *
string_to_host(void * ptr)
{
L_CHAR * from;
	from = ptr;
	if ( from[0] == LCC_ERROR )
		return 0;
	return ll_copy_str(from);
}



int
coordinate_unit_to_host(COORDINATE_UNIT * cu,CHAIN_LIST ** _c)
{
CHAIN_LIST * c;
	c = *_c;
	*_c = 0;
	if ( c == 0 )
		return -1;
	cu->url = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		return -1;
	cu->system = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		return -1;
	cu->unit = string_to_host(c->ptr);
	*_c = c->next;
	return 0;
}

void
all_load(XL_SEXP * s)
{
	for ( ; get_type(s) == XLT_PAIR ; s = cdr(s) );
}


XL_SEXP *
get_xl_sexp_from_string(L_CHAR * str)
{
STREAM * s;
XL_SEXP * ret, * load;

	s = s_open_string_read(str,&int_cm,
		(l_strlen(str)+1)*sizeof(L_CHAR),
		1);
	ret = car(load = 
		init_parse(s,l_string(std_cm,"get_xl_sexp_from_string"),0));
	all_load(load);
	return ret;
}

int
set_rs_bib_list(RESOURCE * r,RECORD_LIST * lst)
{
PN_RS_BIB_LIST * b;
CHAIN_LIST * c;
L_CHAR * ns,* q, * type, * data;
BIB_LIST * bl;
	b = lst->data;
	c = lst->chain_head;
	if ( c == 0 )
		return -1;
	ns = c->ptr;
	c = c->next;
	if ( c == 0 )
		return -1;
	q = c->ptr;
	c = c->next;
	if ( c == 0 )
		return -1;
	type = c->ptr;
	c = c->next;
	if ( c == 0 )
		return -1;
	data = c->ptr;
	c = c->next;
	bl = d_alloc(sizeof(*bl));
	bl->data = string_to_host(data);
	bl->type = string_to_host(type);
	bl->qualifier = string_to_host(q);
	bl->namespace = string_to_host(ns);
	bl->inherit = b->inherit;
	r->h.bib = insert_bib_list(r->h.bib,bl);
	return 0;
}

int
set_rs_note(RESOURCE * r,RECORD_LIST * lst)
{
L_CHAR * img;
L_CHAR * data;
L_CHAR * url;
CHAIN_LIST * c;
PN_RS_NOTE * n;
	n = lst->data;
	c = lst->chain_head;
	if ( c == 0 )
		return -1;
	img = c->ptr;
	c = c->next;
	if ( c == 0 )
		return -1;
	data = c->ptr;
	c = c->next;
	if ( c == 0 )
		return -1;
	url = c->ptr;
	c = c->next;

	set_note(r,n->type,img,n->fill_color,n->line_color,data,url);
	return 0;
}

RESOURCE *
resource_rs_res_header(CHAIN_LIST ** _c,RECORD_LIST ** _lst)
{
PN_RS_RES_HEADER * rh;
CHAIN_LIST * c;
RESOURCE * ret;
URL u_entry,u_target;
RECORD_LIST * lst;
L_CHAR * f;
	lst = *_lst;
	ret = 0;
	rh = lst->data;
	c = lst->chain_head;
	if ( c == 0 )
		goto end1;
	get_url2(&u_entry,(L_CHAR*)c->ptr);
	c = c->next;
	if ( c == 0 )
		goto end2;
	get_url2(&u_target,(L_CHAR*)c->ptr);
	ret = new_resource_entry(rh->type,&u_entry);
	set_resource_target(ret,&u_target);
	ret->h.flags = (~(RF_COMPLETE|RF_FIX))&
				rh->flags |
			RF_CACHE;
	ret->h.modify = rh->modify;
	ret->h.minrect = rh->minrect;
	ret->h.visible_resolution = rh->visible_resolution;
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->h.meta = get_xl_sexp_from_string((L_CHAR*)c->ptr);
	c = c->next;
	if ( coordinate_unit_to_host(&ret->h.cu,&c) < 0 )
		goto err;
	lst = lst->next;
	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_BIB_LIST )
			break;
		if ( set_rs_bib_list(ret,lst) < 0 )
			goto err;
	}
	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_NOTE )
			break;
		if ( set_rs_note(ret,lst) < 0 )
			goto err;
	}
	setup_c_unit(
		&ret->h.cu,-1,f=ll_copy_str(get_url_str2(&ret->h.entry)),
		ret->h.meta,0);
	d_f_ree(f);
	goto end3;
err:
	free_resource_entry(ret);
	ret = 0;
end3:
	free_url(&u_target);
end2:
	free_url(&u_entry);
end1:
	*_lst = lst;
	*_c = c;
	return ret;
}

int
set_rs_clip(CLIP ** c_head,RECORD_LIST * lst)
{
CLIP * cp;
PN_RS_CLIP * cpp;
	cpp = lst->data;
	cp = d_alloc(sizeof(*cp));
	cp->type = cpp->type;
	cp->shape = cpp->shape;
	switch ( cpp->type ) {
	case CST_RECT:
		cp->d.rect = cpp->d.rect;
		break;
	default:
		er_panic("set_rs_clip");
	}

	cp->next = *c_head;
	*c_head = cp;
	return 0;
}

int
set_rs_map(RING_TYPE * ring,RECORD_LIST ** _lst,RESOURCE * dest)
{
MAP * m;
PN_RS_MAP * mp;
CHAIN_LIST * c;
RECORD_LIST * lst;
	lst = *_lst;
	mp = lst->data;
	c = lst->chain_head;

	m = d_alloc(sizeof(*m));
	m->depth = mp->depth;
	m->flags = mp->flags;
	m->mod_time_org = mp->mod_time_org;
	m->mod_time = mp->mod_time;
	m->cindex_time = mp->cindex_time;
	m->cindex_mr = mp->cindex_mr;
	m->clip = 0;
	m->dest = dest;
	m->src = 0;
	m->map_file = 0;

	if ( c == 0 )
		goto err;
	get_url2(&m->src_url,c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err1;
	get_url2(&m->dest_url,c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err2;
	get_url2(&m->map_url,c->ptr);
	c = c->next;

	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_CLIP )
			break;
		if ( set_rs_clip(&m->clip,lst) < 0 )
			goto err3;
	}
	INSERT_RING(R_PREV(RING_TYPE*,ring),&m->h);
	return 0;

err3:
	free_url(&m->map_url);
err2:
	free_url(&m->dest_url);
err1:
	free_url(&m->src_url);
err:
	free_clip(m->clip);
	d_f_ree(m);
	return -1;
}

RESOURCE *
resource_rs_coordinate_to_host(RECORD_LIST * lst)
{
RESOURCE * ret;
PN_RS_COORDINATE * cr;
CHAIN_LIST * c;
	cr = lst->data;
	ret = resource_rs_res_header(&c,&lst);
	if ( ret == 0 )
		return 0;
	ret->c.flags = cr->flags;
	ret->c.geometory_type = cr->geometory_type;
	ret->c.geometory_param = 0;/***/
	if ( ret->c.flags & CF_FIX_LIMIT_RESO )
		ret->c.limit_resolution = cr->limit_resolution;
	else	ret->c.limit_resolution = 0;
	ret->c.ov = search_overlay(&ret->h.entry);
	if ( ret->c.ov == 0 )
		ret->c.ov = &default_overlay;
	ret->c.weight = cr->weight;
	INIT_RING(&ret->c.map_children);
	INIT_RING(&ret->c.map_parents);
	if ( c == 0 )
		goto err;
	ret->c.mode = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.initial_cmd = get_xl_sexp_from_string(c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.button_action = get_xl_sexp_from_string(c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.cid = d_alloc(c->len);
	memcpy(ret->c.cid,c->ptr,c->len);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.body = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.body_pri = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.relation_master = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	ret->c.relation_slave = string_to_host(c->ptr);
	c = c->next;
	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_MAP )
			break;
		if ( set_rs_map(&ret->c.map_children,&lst,ret) < 0 )
			goto err;
	}
	if ( lst == 0 )
		goto err;
	if ( lst->header.type != PNT_RS_CACHE_NULL )
		goto err;
	lst = lst->next;
	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_CLIP )
			break;
		if ( set_rs_clip(&ret->c.clip,lst) < 0 )
			goto err;
	}
	return ret;
err:
	free_resource_entry(ret);
	return 0;	
}


RESOURCE * 
resource_rs_pixel_map_r64_to_host(RECORD_LIST * lst)
{
RESOURCE * ret;
PN_RS_PIXEL_MAP_R64 * r64;
CHAIN_LIST * c;
int i;
	r64 = lst->data;
	ret = resource_rs_res_header(&c,&lst);
	if ( ret == 0 )
		return 0;
	ret->pr64.dpm = r64->dpm;
	ret->pr64.type = r64->type;
	for ( i = 0; i < 32 ; i ++ ) {
		ret->pr64.width[i] = r64->width[i];
		ret->pr64.height[i] = r64->height[i];
	}
	ret->pr64.max_level = r64->max_level;
	gv_new_luster_option(ret,ret->pr64.max_level);
	return ret;
}

int
set_rs_info_scheme(RESOURCE * r,RECORD_LIST * lst)
{
PN_RS_INFO_SCHEME * s;
L_CHAR * scheme, * card_style, * onmap_style;
CHAIN_LIST * c;
	s = lst->data;
	c = lst->chain_head;

	if ( c == 0 )
		return -1;
	scheme = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		return -1;
	card_style = string_to_host(c->ptr);
	c = c->next;
	if ( c == 0 )
		return -1;
	onmap_style = string_to_host(c->ptr);
	c = c->next;

	insert_scheme(&r->draw_gb.ischeme,
		scheme,
		s->card_type,
		s->onmap_type,
		card_style,
		onmap_style);
	return 0;
}

RESOURCE * 
resource_rs_draw_gb_to_host(RECORD_LIST * lst)
{
RESOURCE * ret;
PN_RS_DRAW_GB * g;
CHAIN_LIST * c;
int i;
extern void (*draw_gb_indicate_task)();
	g = lst->data;
	ret = resource_rs_res_header(&c,&lst);
	if ( ret == 0 )
		return 0;
	ret->draw_gb.level = g->level;
	ret->draw_gb.flags = g->flags;
	ret->draw_gb.type = g->type;
	ret->draw_gb.resolution = g->resolution;
	ret->draw_gb.matrix_ofs = g->matrix_ofs;
	ret->draw_gb.pitch_list
		= d_alloc(sizeof(GB_POINT)*g->level);
	for ( i = 0 ; i < g->level ; i ++ )
		ret->draw_gb.pitch_list[i] = g->pitch_list[i];
	ret->draw_gb.loop_no = g->loop_no;
	ret->draw_gb.onmap_indicate_size = g->onmap_indicate_size;
	ret->draw_gb.hit_level = g->hit_level;
	ret->draw_gb.hit_outofcircle = g->hit_outofcircle;
	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_INFO_SCHEME )
			break;
		if ( set_rs_info_scheme(ret,lst) < 0 )
			goto err;
	}
	new_vector_option2(ret,NR_NEW,ret->draw_gb.level);
	memset(&ret->draw_gb.ir_que,0,sizeof(SYS_QUEUE));
	if ( draw_gb_indicate_task ) {
		ret->draw_gb.ir_que.flags = QF_FIFO;
		ret->draw_gb.ir_que.gc_func = 0;
		ret->draw_gb.ir_que.gc_get = 0;
		ret->draw_gb.ir_que.key_func = draw_gb_indicate_task;
		ret->draw_gb.ir_que.pri = PRI_FETCH_STRONG;
		ret->draw_gb.ir_que.work = ret;
		setup_queue(&ret->draw_gb.ir_que);
	}
	return ret;
err:
	free_resource_entry(ret);
	return 0;	
}

int
set_rs_map_point_list(RING_TYPE * ring,RECORD_LIST * lst)
{
PN_RS_MAP_POINT_LIST * mp;
CHAIN_LIST * c;
MAP_POINT_LIST * m;
	mp = lst->data;
	c = lst->chain_head;

	m = d_alloc(sizeof(*m));
	m->src = mp->src;
	m->dest = mp->dest;

	if ( c == 0 ) {
		d_f_ree(m);
		return -1;
	}
	m->tag = string_to_host(c->ptr);

	INSERT_RING(R_PREV(RING_TYPE*,ring),&m->h);
	return 0;
}

int
set_rs_triangle_set(TRIANGLE_SET * set,PN_RS_TRIANGLE_SET * pn_set)
{
	set->sts = pn_set->sts;
	set->cnt = pn_set->cnt;
	set->a = pn_set->a;
	set->minrect = pn_set->minrect;
	set->resolution_rate = pn_set->resolution_rate;
	set->tri_list = 0;
	return 0;
}

int
set_rs_map_parameter(MAP_PARAMETER * mp,PN_RS_MAP_PARAMETER * mpp)
{
	mp->type = mpp->type;
	mp->resolution_rate = mpp->resolution_rate;
	switch ( mp->type ) {
	case MT_MOVE:
		mp->opt.ptr = mpp->opt.ptr;
		break;
	case MT_ROTATE:
	case MT_LINEAR:
		mp->opt.affen = mpp->opt.affen;
		break;
	case MT_TRIANGLE:
		return set_rs_triangle_set(&mp->opt.tri,&mpp->opt.tri);
		break;
	default:
		er_panic("set_rs_map_parameter");
	}
	return 0;
}

TRIANGLE *
set_rs_triangle(TRIANGLE_SET * set,RING_TYPE * ring,RECORD_LIST * lst)
{
TRIANGLE * ret;
PN_RS_TRIANGLE * tp;
CHAIN_LIST * c;
int i;
MAP_POINT_LIST * mp;
	tp = lst->data;
	c = lst->chain_head;
	ret = d_alloc(sizeof(*ret));
	for ( i = 0 ; i < 3 ; i ++ )
		ret->ptp[i] = tp->ptp[i];
	ret->a = tp->a;
	ret->resolution_rate = tp->resolution_rate;
	ret->minrect = tp->minrect;
	ret->c = 0;

	for ( i = 0 ; i < 3 ; i ++ ) {
		if ( c == 0 )
			goto err;
		for ( mp = R_NEXT(MAP_POINT_LIST*,ring);
				(void*)ring != (void*)mp;
				mp = R_NEXT(MAP_POINT_LIST*,&mp->h) )
			if ( l_strcmp(mp->tag,c->ptr) == 0 )
				goto ok;
		goto err;
	ok:
		ret->ptl[i] = mp;
		c = c->next;
	}

	ret->next = set->tri_list;
	set->tri_list  = ret;

	return ret;
err:
	d_f_ree(ret);
	return ret;
}

RESOURCE *
resource_rs_res_map_to_host(RECORD_LIST * lst,RS_BUF * w)
{
RECORD_LIST * lst_1,*lst_2;
RESOURCE * ret;
PN_RS_RES_MAP * m;
CHAIN_LIST * c;
int i;
L_CHAR * url;
TRIANGLE * t1, * t2;
	m = lst->data;
	ret = resource_rs_res_header(&c,&lst);
	if ( ret == 0 )
		return 0;
	if ( c == 0 )
		goto err;
	get_url2(&ret->map.src,c->ptr);
	c = c->next;
	if ( c == 0 )
		goto err;
	get_url2(&ret->map.dest,c->ptr);
	c = c->next;
	coordinate_unit_to_host(&ret->map.cu_src,&c);
	coordinate_unit_to_host(&ret->map.cu_dest,&c);

	w->flags |= RSBF_MAP;
	INIT_RING(&ret->map.point_list);

	for ( ; lst ; lst = lst->next ) {
		if ( lst->header.type != PNT_RS_MAP_POINT_LIST )
			break;
		if ( set_rs_map_point_list(&ret->map.point_list,lst) < 0 )
			goto err;
	}
	set_rs_map_parameter(&ret->map.param_forward,&m->param_forward);
	set_rs_map_parameter(&ret->map.param_reverse,&m->param_reverse);
	for ( ; lst ;) {
		if ( lst->header.type != PNT_RS_TRIANGLE )
			break;
		lst_1 = lst;
		lst_2 = lst->next;
		if ( lst_2 == 0 )
			goto err;
		if ( lst_2->header.type != PNT_RS_TRIANGLE )
			goto err;
		t1 = set_rs_triangle(&ret->map.param_forward.opt.tri,
				&ret->map.point_list,
				lst_1);
		if ( t1 == 0 )
			goto err;
		t2 = set_rs_triangle(&ret->map.param_reverse.opt.tri,
				&ret->map.point_list,
				lst_2);
		if ( t2 == 0 )
			goto err;
		t1->c = t2;
		t2->c = t1;
		
		lst = lst_2->next;
	}
	return ret;
err:
	free_resource_entry(ret);
	return 0;	
}


RESOURCE *
_load_resource_from_cache(char * filename,RS_BUF * b)
{
RECORD_LIST * lst,* p;
RESOURCE * ret;
PN_RS_RES_STATUS * s;
RS_CONVERT_TBL * t;
	lst = read_recordlist(0,filename);
	if ( lst == 0 )
		return 0;
	if ( change_endian_rs_to_host(lst) < 0 ) {
		ret = 0;
		goto end;
	}
	p = lst;
	s = p->data;
	if ( strcmp(s->version,RS_CACHE_VERSION) ) {
		ret = 0;
		goto end;
	}
	if ( s->type != PNRS_T_RESOURCE ) {
		ret = 0;
		goto end;
	}
	p = p->next;
	if ( p == 0 ) {
		ret = 0;
		goto end;
	}
	t = &rs_convert[p->header.type&PNT_TYPE_MASK];
	if ( t->resource_to_host == 0 ) {
		ret = 0;
		goto end;
	}
	ret = (*t->resource_to_host)(p,b);
end:
	free_recordlist(lst);
	return ret;
}

RECORD_LIST **
_set_rs_res_status(RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_RES_STATUS * s;
	*p = tar = new_recordlist(PNT_RS_RES_STATUS,
		sizeof(*s));
	s = tar->data;
	strcpy(s->version,RS_CACHE_VERSION);
	s->type = PNRS_T_RESOURCE;
	return &tar->next;
}

void
_save_string_to_cache(RECORD_LIST * tar,L_CHAR * str,int flag)
{
static L_CHAR nl[2] = {LCC_ERROR,0};

	if ( str == 0 ) {
		set_recordlist_chain(tar,nl,2*sizeof(L_CHAR),0);
	}
	else {
		if ( flag == 1 )
			str = ll_copy_str(str);
		set_recordlist_chain(tar,str,
			(l_strlen(str)+1)*sizeof(L_CHAR),
			flag);
	}
}

void
_save_coordinate_unit_to_cache(RECORD_LIST * tar,COORDINATE_UNIT * cu)
{
	_save_string_to_cache(tar,cu->url,0);
	_save_string_to_cache(tar,cu->system,0);
	_save_string_to_cache(tar,cu->unit,0);
}

void
_save_xl_sexp_to_cache(RECORD_LIST * tar,XL_SEXP * s)
{
STREAM * st;
L_CHAR * ret;
	st = s_open_string_write(&int_cm);
	print_sexp(st,s,0);
	ret = s_get_l_string(st);
	_save_string_to_cache(tar,ret,1);
	s_close(st);
}

RECORD_LIST **
_save_rs_bib_list(BIB_LIST * bl,RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_BIB_LIST * b;
	*p = tar = new_recordlist(PNT_RS_BIB_LIST,sizeof(*b));
	b = tar->data;
	b->inherit = bl->inherit;
	_save_string_to_cache(tar,bl->namespace,0);
	_save_string_to_cache(tar,bl->qualifier,0);
	_save_string_to_cache(tar,bl->type,0);
	_save_string_to_cache(tar,bl->data,0);
	return &tar->next;
}

RECORD_LIST **
_save_rs_note(NOTE * n,RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_NOTE * np;
	*p = tar = new_recordlist(PNT_RS_NOTE,sizeof(*n));
	np = tar->data;
	np->type = n->type;
	np->fill_color = n->fill_color;
	np->line_color = n->line_color;
	_save_string_to_cache(tar,n->img,0);
	_save_string_to_cache(tar,n->data,0);
	_save_string_to_cache(tar,n->url,0);
	return &tar->next;
}


RECORD_LIST **
_save_res_header_to_cache(RECORD_LIST * tar,RECORD_LIST ** p,RESOURCE * r)
{
PN_RS_RES_HEADER * ph;
BIB_LIST * bl;
NOTE * n;
	ph = tar->data;
	ph->type = r->h.type;
	ph->flags = r->h.flags;
	ph->minrect = r->h.minrect;
	ph->modify = r->h.modify;
	ph->visible_resolution = r->h.visible_resolution;
	_save_string_to_cache(tar,get_url_str2(&r->h.entry),1);
	_save_string_to_cache(tar,get_url_str2(&r->h.target),1);
	_save_xl_sexp_to_cache(tar,r->h.meta);
	_save_coordinate_unit_to_cache(tar,&r->h.cu);
	for ( bl = r->h.bib ; bl ; bl = bl->next )
		p = _save_rs_bib_list(bl,p);
	for ( n = r->h.notes ; n ; n = n->next )
		p = _save_rs_note(n,p);
	return p;
}

void
_save_cid_to_cache(RECORD_LIST * tar,int * cid)
{
	set_recordlist_chain(tar,cid,(cid[0]+1)*sizeof(int),0);
}

RECORD_LIST **
_save_rs_clip(CLIP * cp,RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_CLIP * c;
	*p = tar = new_recordlist(PNT_RS_CLIP,sizeof(*c));
	c = tar->data;
	c->type = cp->type;
	c->shape = cp->shape;
	switch ( c->shape ) {
	case CST_RECT:
		c->d.rect = cp->d.rect;
		break;
	default:
		er_panic("_save_rs_clip");
	}
	return &tar->next;
}

RECORD_LIST **
_save_rs_map(MAP * mp,RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_MAP * m;
CLIP * c;
	*p = tar = new_recordlist(PNT_RS_MAP,sizeof(*m));
	p = &tar->next;
	m = tar->data;
	m->depth = mp->depth;
	m->flags = mp->flags;
	m->mod_time_org = mp->mod_time_org;
	m->mod_time = mp->mod_time;
	m->cindex_time = mp->cindex_time;
	m->cindex_mr = mp->cindex_mr;
	_save_string_to_cache(tar,get_url_str2(&mp->src_url),1);
	_save_string_to_cache(tar,get_url_str2(&mp->dest_url),1);
	_save_string_to_cache(tar,get_url_str2(&mp->map_url),1);
	for ( c = mp->clip ; c ; c = c->next )
		p = _save_rs_clip(c,p);
	return p;
}

RECORD_LIST **
_save_rs_null(RECORD_LIST ** p)
{
RECORD_LIST * tar;
	*p = tar = new_recordlist(PNT_RS_CACHE_NULL,sizeof(PN_HEADER));
	return &tar->next;
}

RECORD_LIST *
_save_coordinate_to_cache(RESOURCE * r)
{
RECORD_LIST * lst, ** p, * tar;
PN_RS_COORDINATE * c;
CLIP * cp;
MAP * mp;
int flags;
	if ( r->c.cid == 0 )
		return 0;
	flags = r->h.flags;
	lst = 0;
	p = &lst;
	p = _set_rs_res_status(p);
	*p = tar = new_recordlist(PNT_RS_COORDINATE,sizeof(*c));
	p = &tar->next;
	p = _save_res_header_to_cache(tar,p,r);
	c = tar->data;
	c->flags = r->c.flags;
	c->geometory_type = r->c.geometory_type;
	c->limit_resolution = r->c.limit_resolution;
	c->weight = r->c.weight;
	_save_string_to_cache(tar,r->c.mode,0);
	_save_xl_sexp_to_cache(tar,r->c.initial_cmd);
	_save_xl_sexp_to_cache(tar,r->c.button_action);
	_save_cid_to_cache(tar,r->c.cid);
	_save_string_to_cache(tar,r->c.body,0);
	_save_string_to_cache(tar,r->c.body_pri,0);
	_save_string_to_cache(tar,r->c.relation_master,0);
	_save_string_to_cache(tar,r->c.relation_slave,0);
	if ( flags & RF_LOAD_EXTEND ) {
		for ( mp = R_NEXT(MAP*,&r->c.map_children);
				mp != (MAP*)&r->c.map_children;
				mp = R_NEXT(MAP*,&mp->h) )
			p = _save_rs_map(mp,p);
	}
	p = _save_rs_null(p);
	for ( cp = r->c.clip ; cp ; cp = cp->next )
		p = _save_rs_clip(cp,p);
	return lst;
}

RECORD_LIST *
_save_pixel_map_r64_to_cache(RESOURCE * r)
{
RECORD_LIST * lst, ** p, * tar;
PN_RS_PIXEL_MAP_R64 * rp;
int i;
	lst = 0;
	p = &lst;
	p = _set_rs_res_status(p);
	*p = tar = new_recordlist(PNT_RS_PIXEL_MAP_R64,sizeof(*rp));
	p = &tar->next;
	p = _save_res_header_to_cache(tar,p,r);
	rp = tar->data;
	rp->dpm = r->pr64.dpm;
	rp->type = r->pr64.type;
	for ( i = 0 ; i < 32 ; i ++ ) {
		rp->width[i] = r->pr64.width[i];
		rp->height[i] = r->pr64.height[i];
	}
	rp->max_level = r->pr64.max_level;
	return lst;
}

RECORD_LIST **
_save_rs_info_scheme(INFO_SCHEME * is,RECORD_LIST** p)
{
RECORD_LIST * tar;
PN_RS_INFO_SCHEME * isp;
	*p = tar = new_recordlist(PNT_RS_INFO_SCHEME,sizeof(*isp));
	isp = tar->data;
	isp->card_type = is->card_type;
	isp->onmap_type = is->onmap_type;
	_save_string_to_cache(tar,is->scheme,0);
	_save_string_to_cache(tar,is->card_style,0);
	_save_string_to_cache(tar,is->onmap_style,0);
	return &tar->next;
}

RECORD_LIST *
_save_draw_gb_to_cache(RESOURCE * r)
{
RECORD_LIST * lst, ** p, * tar;
PN_RS_DRAW_GB* g;
int i;
INFO_SCHEME * is;
	lst = 0;
	p = &lst;
	p = _set_rs_res_status(p);
	*p = tar = new_recordlist(PNT_RS_DRAW_GB,sizeof(*g));
	p = &tar->next;
	p = _save_res_header_to_cache(tar,p,r);
	g = tar->data;
	g->type = r->draw_gb.type;
	g->level = r->draw_gb.level;
	g->pdb_lock = 0;
	g->flags = r->draw_gb.flags;
	g->resolution = r->draw_gb.resolution;
	g->matrix_ofs = r->draw_gb.matrix_ofs;
	for ( i = 0 ; i < r->draw_gb.level ; i ++ )
		g->pitch_list[i] = r->draw_gb.pitch_list[i];
	g->loop_no = r->draw_gb.loop_no;
	g->onmap_indicate_size = r->draw_gb.onmap_indicate_size;
	g->hit_level = r->draw_gb.hit_level;
	g->hit_outofcircle = r->draw_gb.hit_outofcircle;
	for ( is = r->draw_gb.ischeme ; is ; is = is->next )
		p = _save_rs_info_scheme(is,p);
	return lst;
}

void
_save_rs_triangle_set(
	PN_RS_TRIANGLE_SET * pn_set,
	TRIANGLE_SET * set)
{
	pn_set->sts = set->sts;
	pn_set->cnt = set->cnt;
	pn_set->a = set->a;
	pn_set->minrect = set->minrect;
	pn_set->resolution_rate = set->resolution_rate;
}

void
_save_rs_map_parameter(PN_RS_MAP_PARAMETER * pn_m,MAP_PARAMETER * m)
{
	pn_m->type = m->type;
	pn_m->resolution_rate = m->resolution_rate;
	switch ( pn_m->type ) {
	case MT_MOVE:
		pn_m->opt.ptr = m->opt.ptr;
		break;
	case MT_ROTATE:
	case MT_LINEAR:
		pn_m->opt.affen = m->opt.affen;
		break;
	case MT_TRIANGLE:
		_save_rs_triangle_set(&pn_m->opt.tri,&m->opt.tri);
		break;
	default:
		er_panic("_save_rs_map_parameter");
	}
}

RECORD_LIST **
_save_rs_map_point_list(MAP_POINT_LIST * mpl,RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_MAP_POINT_LIST * pn_mpl;
	*p = tar = new_recordlist(PNT_RS_MAP_POINT_LIST,sizeof(*pn_mpl));
	pn_mpl = tar->data;
	pn_mpl->src = mpl->src;
	pn_mpl->dest = mpl->dest;
	_save_string_to_cache(tar,mpl->tag,0);
	return &tar->next;
}

RECORD_LIST **
_save_rs_triangle(TRIANGLE * t,RECORD_LIST ** p)
{
RECORD_LIST * tar;
PN_RS_TRIANGLE * pn_t;
int i;
	*p = tar = new_recordlist(PNT_RS_TRIANGLE,sizeof(*pn_t));
	pn_t = tar->data;
	pn_t->a = t->a;
	pn_t->resolution_rate = t->resolution_rate;
	pn_t->minrect = t->minrect;
	for ( i = 0 ; i < 3 ; i ++ ) {
		pn_t->ptp[i] = t->ptp[i];
		_save_string_to_cache(tar,t->ptl[i]->tag,0);
	}
	return &tar->next;
}

RECORD_LIST *
_save_map_to_cache(RESOURCE * r)
{
RECORD_LIST * lst, ** p, * tar;
PN_RS_RES_MAP* rm;
int i;
MAP_POINT_LIST * mpl;
TRIANGLE * t;
	lst = 0;
	p = &lst;
	p = _set_rs_res_status(p);
	*p = tar = new_recordlist(PNT_RS_RES_MAP,sizeof(*rm));
	p = &tar->next;
	p = _save_res_header_to_cache(tar,p,r);
	rm = tar->data;

	_save_rs_map_parameter(&rm->param_forward,&r->map.param_forward);
	_save_rs_map_parameter(&rm->param_reverse,&r->map.param_reverse);

	_save_string_to_cache(tar,get_url_str2(&r->map.src),1);
	_save_string_to_cache(tar,get_url_str2(&r->map.dest),1);
	_save_coordinate_unit_to_cache(tar,&r->map.cu_src);
	_save_coordinate_unit_to_cache(tar,&r->map.cu_dest);

	for ( mpl = R_NEXT(MAP_POINT_LIST*,&r->map.point_list);
			mpl != (MAP_POINT_LIST*)&r->map.point_list;
			mpl = R_NEXT(MAP_POINT_LIST*,&mpl->h) )
		p = _save_rs_map_point_list(mpl,p);
	if ( r->map.param_forward.type == MT_TRIANGLE ) {
		for ( t = r->map.param_forward.opt.tri.tri_list ;
				t ; t = t->next ) {
			p = _save_rs_triangle(t,p);
			p = _save_rs_triangle(t->c,p);
		}
	}
	return lst;
}

int
_save_resource_to_cache(char * filename,RESOURCE * r,int mode)
{
RECORD_LIST * ret;
	switch ( r->h.type ) {
	case RT_COORDINATE:
		ret = _save_coordinate_to_cache(r);
		break;
	case RT_PIXEL_MAP_R64:
		ret = _save_pixel_map_r64_to_cache(r);
		break;
	case RT_DRAW_GB:
		ret = _save_draw_gb_to_cache(r);
		break;
	case RT_MAP:
		ret = _save_map_to_cache(r);
		break;
	default:
		er_panic("_save_resource_to_cache");
	}
	if ( ret == 0 )
		return -1;
	setup_recordlist(ret);
	if ( change_endian_rs_to_net(ret) < 0 )
		er_panic("save_resource_to_Cache(1)");
	write_recordlist(filename,ret,mode);
	free_recordlist(ret);
	return 0;
}


int
_get_rs_str(XL_SEXP ** retp,L_CHAR * filepath)
{
STREAM * st;
XL_SEXP * ret, * p, * load;
int _ret;
void gc_gb_sexp();
	st = s_open_file(n_string(std_cm,filepath),O_RDONLY);
	if ( st == 0 )
		return -1;
	s_set_cm(st,&int_cm);
	gc_push(0,0,"_get_rs_str");
	*retp = ret = car(load = init_parse(st,filepath,filepath));
	all_load(load);
	for ( p = ret ; ; p = cdr(p) ) {
		switch ( get_type(p) ) {
		case XLT_PAIR:
			continue;
		case XLT_ERROR:
			_ret = -1;
			break;
		default:
			_ret = 0;
			break;
		}
		break;
	}
	gc_pop(ret,gc_gb_sexp);
	return _ret;
}

int
_set_rs_str(L_CHAR * filepath,XL_SEXP * s)
{
STREAM * st;
	st = s_open_file(n_string(std_cm,filepath),O_CREAT|O_TRUNC|O_RDWR,0644);
	if ( st == 0 )
		return -1;
	s_set_cm(st,&int_cm);
	print_sexp(st,s,0);
	s_close(st);
	return 0;
}

int
_purge_rs_cache(L_CHAR * url)
{
FAVT_ROOT * r;
RSC_TIMER_INDEX * ix;
unsigned int p_data;
ACC_PN_RS_CACHE_DATA * d;
FAVT_NODE * n;
int file_id;
	d = _search_rs_cache_entry(url);
	if ( d == 0 )
		return -1;
	file_id = d->d.file_id;
	_delete_rs_url((L_CHAR*)((&d->d)+1));
	_delete_rs_timer(d->d.expire,d->h.fofs);
	free_filespace(rs_p,d->h.fofs);
	d_f_ree(d);
	rs_cache_header->d.count --;
	_purge_rs_cache_header();
	return file_id;
}

void
purge_rs_cache(L_CHAR * url)
{
int file_id;
L_CHAR * filepath;

retry:
	local_lock_rcache(&resource_cache);
	if ( resource_cache.err == 0 )
		goto idle;
	if ( resource_cache.err < 0 ) {
		unlock_rcache(&resource_cache);
		remake_rs_cache();
		if ( resource_cache.err < 0 )
			goto idle2;
		goto retry;
	}
	wlock_rcache(&resource_cache);
	if ( rs_p == 0 ) {
		_open_rs_cache();
		if ( resource_cache.err < 0 )
			goto idle;
	}


	file_id = _purge_rs_cache(url);
	if ( file_id < 0 )
		goto idle;
	unlock_rcache(&resource_cache);
	filepath = get_filepath_from_file_id(file_id,"");	
	wlock_rcache_path(filepath);
	_delete_rs_resource(file_id);
	unlock_rcache_path(filepath);
	d_f_ree(filepath);
	return;

idle:
	unlock_rcache(&resource_cache);
	remake_rs_cache();
idle2:
	return;
}

void
flush_rs_cache()
{

	local_lock_rcache(&resource_cache);
	_close_rs_cache();
	unlock_rcache(&resource_cache);
}

void
_disable_rs_cache()
{
	_close_rs_cache();
	resource_cache.err = RE_IDLE;
}

void
disable_rs_cache()
{
	local_lock_rcache(&resource_cache);
	_disable_rs_cache();
	rs_rcache_flags = 0;
	unlock_rcache(&resource_cache);
}

void
enable_rs_cache(int flags)
{
	local_lock_rcache(&resource_cache);
	if ( flags & (RCF_RESOURCE|RCF_RESOURCE_READ) )
		new_rcache_blk(&resource_cache,"resource.rch");
	else	_disable_rs_cache();
	rs_rcache_flags = flags;
	unlock_rcache(&resource_cache);
}

int
get_rs_resource_cache(RS_BUF * b,L_CHAR * url)
{
ACC_PN_RS_CACHE_DATA * d;
L_CHAR * filepath;
char * _f;
int del;
int rr;

	memset(b,0,sizeof(*b));
retry:
	del = 0;
	rr = -1;
	local_lock_rcache(&resource_cache);
	if ( (rs_rcache_flags & RCF_RESOURCE_READ) == 0 )
		goto idle;
	if ( resource_cache.err == 0 )
		goto idle;
	if ( resource_cache.err < 0 ) {
		unlock_rcache(&resource_cache);
		remake_rs_cache();
		if ( resource_cache.err < 0 )
			goto idle2;
		goto retry;
	}
	rlock_rcache(&resource_cache);
	if ( rs_p == 0 ) {
		_open_rs_cache();
		if ( resource_cache.err < 0 )
			goto idle;
	}

	d = _search_rs_cache_entry(url);
	if ( d == 0 ) {
		b->r = 0;
		rr = -1;
		goto idle;
	}
	if ( d->d.expire < get_xltime() ) {
		d_f_ree(d);
		unlock_rcache(&resource_cache);
		purge_rs_cache(url);
		b->r = 0;
		rr = -1;
	}
	else {
		filepath = get_filepath_from_file_id(d->d.file_id,".inf");
		rlock_rcache_path(filepath);
		unlock_rcache(&resource_cache);

		_f = ln_copy_str(std_cm,filepath);
		b->r = _load_resource_from_cache(_f,b);
		d_f_ree(_f);

		unlock_rcache_path(filepath);
		d_f_ree(filepath);
		if ( b->r == 0 ) {
			rr = -1;
		}
		else {
			filepath = get_filepath_from_file_id(d->d.file_id,
					".str");
			rlock_rcache_path(filepath);

			if ( _get_rs_str(&b->sexp,filepath) < 0 )
				b->sexp = 0;

			unlock_rcache_path(filepath);
			d_f_ree(filepath);
			rr = 0;
		}
		d_f_ree(d);
	}
	return rr;

idle:
	unlock_rcache(&resource_cache);
	remake_rs_cache();
idle2:
	return rr;
}

int
set_rs_resource_cache(RS_BUF * b)
{
ACC_PN_RS_CACHE_DATA * d;
L_CHAR * filepath;
char * _f;
int ret;
int file_id;
int file_id_list[PURGE_FILE_ID_LIST+1];
L_CHAR * url;
int i;
unsigned int expire,now;
int diff;
/*
printf("**** set_rs_resource_cache\n");
*/

	b->flags = 0;
retry:
	ret = -1;
	url = 0;
	file_id_list[0] = 0;
	local_lock_rcache(&resource_cache);
	if ( resource_cache.err == 0 )
		goto idle;
	if ( resource_cache.err < 0 ) {
		unlock_rcache(&resource_cache);
		remake_rs_cache();
		if ( resource_cache.err < 0 )
			goto idle2;
		goto retry;
	}
	rlock_rcache(&resource_cache);
	if ( rs_p == 0 ) {
		_open_rs_cache();
		if ( resource_cache.err < 0 )
			goto idle;
	}

	url = ll_copy_str(get_url_str2(&b->r->h.entry));

	now = get_xltime();
	if ( b->r->h.modify == 0 )
		expire = now + RS_AVG_EXPIRE;
	else {
		diff = now - b->r->h.modify;
		if ( diff < RS_MIN_EXPIRE )
			expire = now + RS_MIN_EXPIRE;
		else if ( diff > RS_MAX_EXPIRE )
			expire = now + RS_MAX_EXPIRE;
		else	expire = now + diff;
	}
	d = _search_rs_cache_entry(url);
	if ( d == 0 ) {
		file_id = _new_rs_cache_entry(url,expire);
		_purge_rs_cache_data(file_id_list);
	}
	else {
		_touch_rs_cache_entry(url,expire);
		file_id = d->d.file_id;
		d_f_ree(d);
	}
	filepath = get_filepath_from_file_id(file_id,".inf");

	wlock_rcache_path(filepath);
	unlock_rcache(&resource_cache);

	_f = ln_copy_str(std_cm,filepath);
	ret = _save_resource_to_cache(_f,b->r,0644);
	d_f_ree(_f);

	unlock_rcache_path(filepath);

	d_f_ree(filepath);

	if ( ret < 0 ) {
		goto err_end;
	}

	if ( b->sexp ) {
		filepath = get_filepath_from_file_id(file_id,".str");

		wlock_rcache_path(filepath);

		ret = _set_rs_str(filepath,b->sexp);

		unlock_rcache_path(filepath);

		d_f_ree(filepath);
	}

err_end:

	for ( i = 0 ; file_id_list[i] ; i ++ ) {
		filepath = get_filepath_from_file_id(file_id_list[i],"");
		wlock_rcache_path(filepath);
		_delete_rs_resource(file_id_list[i]);
		unlock_rcache_path(filepath);
		d_f_ree(filepath);
	}
	return ret;

idle:
	unlock_rcache(&resource_cache);
	remake_rs_cache();
idle2:
	return ret;
}

