xref: /plan9-contrib/sys/src/cmd/gs/src/gxclmem.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gxclmem.c,v 1.5 2002/06/16 05:48:55 lpd Exp $ */
187dd7cddfSDavid du Colombier /* RAM-based command list implementation */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gserrors.h"
227dd7cddfSDavid du Colombier #include "gxclmem.h"
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier /*
257dd7cddfSDavid du Colombier  * Based on: memfile.c        Version: 1.4 3/21/95 14:59:33 by Ray Johnston.
267dd7cddfSDavid du Colombier  * Copyright assigned to Aladdin Enterprises.
277dd7cddfSDavid du Colombier  */
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /*****************************************************************************
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier    This package is more or less optimal for use by the clist routines, with
327dd7cddfSDavid du Colombier    a couple of the more likely to change "tuning" parameters given in the
337dd7cddfSDavid du Colombier    two macros below -- NEED_TO_COMPRESS and GET_NUM_RAW_BUFFERS. Usually
347dd7cddfSDavid du Colombier    the NEED_TO_COMPRESS decision will be deferred as long as possible based
357dd7cddfSDavid du Colombier    on some total system free RAM space remaining.
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier    The data structures are in "memfile.h", and the primary 'tuning' parameter
387dd7cddfSDavid du Colombier    is MEMFILE_DATA_SIZE. This should not be too small to keep the overhead
397dd7cddfSDavid du Colombier    ratio of the block structures to the clist data small. A value of 16384
407dd7cddfSDavid du Colombier    is probably in the ballpark.
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier    The concept is that a memory based "file" is created initially without
437dd7cddfSDavid du Colombier    compression, with index blocks every MEMFILE_DATA_SIZE of the file. The
447dd7cddfSDavid du Colombier    primary blocks (used by the memfile_fseek logic) for indexing into the
457dd7cddfSDavid du Colombier    file are called 'logical' (LOG_MEMFILE_BLK) and the data in stored in a
467dd7cddfSDavid du Colombier    different block called a 'physical' block (PHYS_MEMFILE_BLK). When the
477dd7cddfSDavid du Colombier    file is not yet compressed, indicated by (f->phys_curr==NULL), then there
487dd7cddfSDavid du Colombier    is one physical block for each logical block. The physical block also has
497dd7cddfSDavid du Colombier    the 'data_limit' set to NULL if the data is not compressed. Thus when a
507dd7cddfSDavid du Colombier    file is not compressed there is one physical block for each logical block.
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier COMPRESSION.
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier    When compression is triggered for a file then all of the blocks except
557dd7cddfSDavid du Colombier    the last are compressed.  Compression will result in a physical block
567dd7cddfSDavid du Colombier    that holds data for more than one logical block. Each logical block now
577dd7cddfSDavid du Colombier    points to the start of compressed data in a physical block with the
587dd7cddfSDavid du Colombier    'phys_pdata' pointer. The 'data_limit' pointer in the physical block is
597dd7cddfSDavid du Colombier    where the compression logic stopped storing data (as stream data
607dd7cddfSDavid du Colombier    compressors are allowed to do). The data for the logical block may span
617dd7cddfSDavid du Colombier    to the next physical block. Once physical blocks are compressed, they are
627dd7cddfSDavid du Colombier    chained together using the 'link' field.
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier    The 'f->phys_curr' points to the block being filled by compression, with
657dd7cddfSDavid du Colombier    the 'f->wt.ptr' pointing to the last byte filled in the block. These are
667dd7cddfSDavid du Colombier    used during subsequent compression when the last logical block of the
677dd7cddfSDavid du Colombier    file fills the physical block.
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier DECOMPRESSION.
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier    During reading the clist, if the logical block points to an uncompressed
727dd7cddfSDavid du Colombier    physical block, then 'memfile_get_pdata' simply sets the 'pdata' and the
737dd7cddfSDavid du Colombier    'pdata_end' pointers. If the logical block was compressed, then it may
747dd7cddfSDavid du Colombier    still be resident in a cache of decompression buffers. The number of these
757dd7cddfSDavid du Colombier    decompression buffers is not critical -- even one is enough, but having
767dd7cddfSDavid du Colombier    more may prevent decompressing blocks more than once (a cache_miss). The
777dd7cddfSDavid du Colombier    number of decompression buffers, called "raw" buffers, that are attempted
787dd7cddfSDavid du Colombier    to allocate can be changed with the GET_NUM_RAW_BUFFERS macro, but no
797dd7cddfSDavid du Colombier    error occurs if less than that number can be allocated.
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier    If the logical block still resides in a decompression cache buffer, then
827dd7cddfSDavid du Colombier    the 'raw_block' will identify the block. If the data for a logical block
837dd7cddfSDavid du Colombier    only exists in compressed form, then the "tail" of the list of decompression
847dd7cddfSDavid du Colombier    buffers is re-used, marking the 'raw_block' of the logical block that was
857dd7cddfSDavid du Colombier    previously associated with this data to NULL.
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier    Whichever raw decompression buffer is accessed is moved to the head of the
887dd7cddfSDavid du Colombier    decompression buffer list in order to keep the tail of the list as the
897dd7cddfSDavid du Colombier    "least recently used".
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier    There are some DEBUG global static variables used to count the number of
927dd7cddfSDavid du Colombier    cache hits "tot_cache_hits" and the number of times a logical block is
937dd7cddfSDavid du Colombier    decompressed "tot_cache_miss". Note that the actual number of cache miss
947dd7cddfSDavid du Colombier    events is 'f->log_length/MEMFILE_DATA_SIZE - tot_cache_miss' since we
957dd7cddfSDavid du Colombier    assume that every logical block must be decmpressed at least once.
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier    Empirical results so far indicate that if one cache raw buffer for every
987dd7cddfSDavid du Colombier    32 logical blocks, then the hit/miss ratio exceeds 99%. Of course, the
997dd7cddfSDavid du Colombier    number of raw buffers should be more than 1 if possible, and in many
1007dd7cddfSDavid du Colombier    implementations (single threaded), the memory usage does not increase
1017dd7cddfSDavid du Colombier    during the page output step so almost all of memory can be used for
1027dd7cddfSDavid du Colombier    these raw buffers to prevent the likelihood of a cache miss.
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier    Of course, this is dependent on reasonably efficient clist blocking
1057dd7cddfSDavid du Colombier    during writing which is dependent on the data and on the BufferSpace
1067dd7cddfSDavid du Colombier    value which determines the number of clist band data buffers available.
1077dd7cddfSDavid du Colombier    Empirical testing shows that the overall efficiency is best if the
1087dd7cddfSDavid du Colombier    BufferSpace value is 1,000,000 (as in the original Ghostscript source).
1097dd7cddfSDavid du Colombier    [Note: I expected to be able to use smaller buffer sizes for some cases,
1107dd7cddfSDavid du Colombier     but this resulted in a high level of thrashing...RJJ]
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier LIMITATIONS.
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier    The most serious limitation is caused by the way 'memfile_fwrite' decides
1157dd7cddfSDavid du Colombier    to free up and re-initialize a file. If memfile_fwrite is called after
1167dd7cddfSDavid du Colombier    a seek to any location except the start of the file, then an error is
1177dd7cddfSDavid du Colombier    issued since logic is not present to properly free up on a partial file.
1187dd7cddfSDavid du Colombier    This is not a problem as used by the 'clist' logic since rewind is used
1197dd7cddfSDavid du Colombier    to position to the start of a file when re-using it after an 'erasepage'.
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier    Since the 'clist' logic always traverses the clist using fseek's to ever
1227dd7cddfSDavid du Colombier    increasing locations, no optimizations of backward seeks was implemented.
1237dd7cddfSDavid du Colombier    This would be relatively easy with back chain links or bi-directional
1247dd7cddfSDavid du Colombier    "X-OR" pointer information to link the logical block chain. The rewind
1257dd7cddfSDavid du Colombier    function is optimal and moves directly to the start of the file.
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier ********************************************************************************/
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier /*
1307dd7cddfSDavid du Colombier    The need to compress should be conditional on the amount of available
1317dd7cddfSDavid du Colombier    memory, but we don't have a way to communicate this to these routines.
1327dd7cddfSDavid du Colombier    Instead, we simply start compressing when we've allocated more than
1337dd7cddfSDavid du Colombier    COMPRESSION_THRESHOLD amount of data.  The threshold should be at
1347dd7cddfSDavid du Colombier    least as large as the fixed overhead of the compressor plus the
1357dd7cddfSDavid du Colombier    decompressor, plus the expected compressed size of a block that size.
1367dd7cddfSDavid du Colombier  */
1377dd7cddfSDavid du Colombier private const long COMPRESSION_THRESHOLD = 300000;
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier #define NEED_TO_COMPRESS(f)\
1407dd7cddfSDavid du Colombier   ((f)->ok_to_compress && (f)->total_space > COMPRESSION_THRESHOLD)
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier    /* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8)    */
1437dd7cddfSDavid du Colombier #define GET_NUM_RAW_BUFFERS( f ) 					\
1447dd7cddfSDavid du Colombier 	 max(f->log_length/MEMFILE_DATA_SIZE/32, 8)
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier #define MALLOC(f, siz, cname)\
1477dd7cddfSDavid du Colombier   (void *)gs_alloc_bytes((f)->data_memory, siz, cname)
1487dd7cddfSDavid du Colombier #define FREE(f, obj, cname)\
1497dd7cddfSDavid du Colombier   (gs_free_object((f)->data_memory, obj, cname),\
1507dd7cddfSDavid du Colombier    (f)->total_space -= sizeof(*(obj)))
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier /* Structure descriptor for GC */
1537dd7cddfSDavid du Colombier private_st_MEMFILE();
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	/* forward references */
156*593dc095SDavid du Colombier private void memfile_free_mem(MEMFILE * f);
157*593dc095SDavid du Colombier private int memfile_init_empty(MEMFILE * f);
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier /************************************************/
1607dd7cddfSDavid du Colombier /*   #define DEBUG      /- force statistics -/  */
1617dd7cddfSDavid du Colombier /************************************************/
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier #ifdef DEBUG
1647dd7cddfSDavid du Colombier long tot_compressed;
1657dd7cddfSDavid du Colombier long tot_raw;
1667dd7cddfSDavid du Colombier long tot_cache_miss;
1677dd7cddfSDavid du Colombier long tot_cache_hits;
1687dd7cddfSDavid du Colombier long tot_swap_out;
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier /*
1717dd7cddfSDavid du Colombier    The following pointers are here only for helping with a dumb debugger
1727dd7cddfSDavid du Colombier    that can't inspect local variables!
1737dd7cddfSDavid du Colombier  */
1747dd7cddfSDavid du Colombier byte *decomp_wt_ptr0, *decomp_wt_limit0;
1757dd7cddfSDavid du Colombier const byte *decomp_rd_ptr0, *decomp_rd_limit0;
1767dd7cddfSDavid du Colombier byte *decomp_wt_ptr1, *decomp_wt_limit1;
1777dd7cddfSDavid du Colombier const byte *decomp_rd_ptr1, *decomp_rd_limit1;
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier #endif
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier /* ----------------------------- Memory Allocation --------------------- */
1827dd7cddfSDavid du Colombier void *	/* allocated memory's address, 0 if failure */
allocateWithReserve(MEMFILE * f,int sizeofBlock,int * return_code,const char * allocName,const char * errorMessage)1837dd7cddfSDavid du Colombier allocateWithReserve(
1847dd7cddfSDavid du Colombier          MEMFILE  *f,			/* file to allocate mem to */
1857dd7cddfSDavid du Colombier          int      sizeofBlock,		/* size of block to allocate */
1867dd7cddfSDavid du Colombier          int      *return_code,         /* RET 0 ok, -ve GS-style error, or +1 if OK but low memory */
1877dd7cddfSDavid du Colombier 	 const   char     *allocName,		/* name to allocate by */
1887dd7cddfSDavid du Colombier 	 const   char     *errorMessage         /* error message to print */
1897dd7cddfSDavid du Colombier )
1907dd7cddfSDavid du Colombier {
1917dd7cddfSDavid du Colombier     int code = 0;	/* assume success */
1927dd7cddfSDavid du Colombier     void *block = MALLOC(f, sizeofBlock, allocName);
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier     if (block == NULL) {
1957dd7cddfSDavid du Colombier 	/* Try to recover block from reserve */
1967dd7cddfSDavid du Colombier 	if (sizeofBlock == sizeof(LOG_MEMFILE_BLK)) {
1977dd7cddfSDavid du Colombier 	    if (f->reserveLogBlockCount > 0) {
1987dd7cddfSDavid du Colombier 		block = f->reserveLogBlockChain;
1997dd7cddfSDavid du Colombier 		f->reserveLogBlockChain = f->reserveLogBlockChain->link;
2007dd7cddfSDavid du Colombier 		--f->reserveLogBlockCount;
2017dd7cddfSDavid du Colombier 	    }
2027dd7cddfSDavid du Colombier 	} else if (sizeofBlock == sizeof(PHYS_MEMFILE_BLK) ||
2037dd7cddfSDavid du Colombier 		   sizeofBlock == sizeof(RAW_BUFFER)
2047dd7cddfSDavid du Colombier 		   ) {
2057dd7cddfSDavid du Colombier 	    if (f->reservePhysBlockCount > 0) {
2067dd7cddfSDavid du Colombier 		block = f->reservePhysBlockChain;
2077dd7cddfSDavid du Colombier 		f->reservePhysBlockChain = f->reservePhysBlockChain->link;
2087dd7cddfSDavid du Colombier 		--f->reservePhysBlockCount;
2097dd7cddfSDavid du Colombier 	    }
2107dd7cddfSDavid du Colombier 	}
2117dd7cddfSDavid du Colombier 	if (block != NULL)
2127dd7cddfSDavid du Colombier 	    code = 1;	/* successful, but allocated from reserve */
2137dd7cddfSDavid du Colombier     }
2147dd7cddfSDavid du Colombier     if (block != NULL)
2157dd7cddfSDavid du Colombier 	f->total_space += sizeofBlock;
2167dd7cddfSDavid du Colombier     else
2177dd7cddfSDavid du Colombier 	code = gs_note_error(gs_error_VMerror);
2187dd7cddfSDavid du Colombier     *return_code = code;
2197dd7cddfSDavid du Colombier     return block;
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier /* ---------------- Open/close/unlink ---------------- */
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier int
memfile_fopen(char fname[gp_file_name_sizeof],const char * fmode,clist_file_ptr * pf,gs_memory_t * mem,gs_memory_t * data_mem,bool ok_to_compress)2257dd7cddfSDavid du Colombier memfile_fopen(char fname[gp_file_name_sizeof], const char *fmode,
2267dd7cddfSDavid du Colombier 	      clist_file_ptr /*MEMFILE * */  * pf,
2277dd7cddfSDavid du Colombier 	      gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier     MEMFILE *f = 0;
2307dd7cddfSDavid du Colombier     int code = 0;
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier     /* We don't implement reopening an existing file. */
2337dd7cddfSDavid du Colombier     if (fname[0] != 0 || fmode[0] != 'w') {
2347dd7cddfSDavid du Colombier 	code = gs_note_error(gs_error_invalidfileaccess);
2357dd7cddfSDavid du Colombier 	goto finish;
2367dd7cddfSDavid du Colombier     }
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier     /* There is no need to set fname in this implementation, */
2397dd7cddfSDavid du Colombier     /* but we do it anyway. */
2407dd7cddfSDavid du Colombier     fname[0] = (ok_to_compress ? 'a' : 'b');
2417dd7cddfSDavid du Colombier     fname[1] = 0;
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier     f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
2447dd7cddfSDavid du Colombier 			"memfile_open_scratch(MEMFILE)");
2457dd7cddfSDavid du Colombier     if (f == NULL) {
2467dd7cddfSDavid du Colombier 	eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
2477dd7cddfSDavid du Colombier 	code = gs_note_error(gs_error_VMerror);
2487dd7cddfSDavid du Colombier 	goto finish;
2497dd7cddfSDavid du Colombier     }
2507dd7cddfSDavid du Colombier     f->memory = mem;
2517dd7cddfSDavid du Colombier     f->data_memory = data_mem;
2527dd7cddfSDavid du Colombier     /* init an empty file, BEFORE allocating de/compress state */
2537dd7cddfSDavid du Colombier     f->compress_state = 0;	/* make clean for GC, or alloc'n failure */
2547dd7cddfSDavid du Colombier     f->decompress_state = 0;
2557dd7cddfSDavid du Colombier     f->total_space = 0;
2567dd7cddfSDavid du Colombier     f->reservePhysBlockChain = NULL;
2577dd7cddfSDavid du Colombier     f->reservePhysBlockCount = 0;
2587dd7cddfSDavid du Colombier     f->reserveLogBlockChain = NULL;
2597dd7cddfSDavid du Colombier     f->reserveLogBlockCount = 0;
2607dd7cddfSDavid du Colombier     /* init an empty file           */
2617dd7cddfSDavid du Colombier     if ((code = memfile_init_empty(f)) < 0)
2627dd7cddfSDavid du Colombier 	goto finish;
2637dd7cddfSDavid du Colombier     if ((code = memfile_set_memory_warning(f, 0)) < 0)
2647dd7cddfSDavid du Colombier 	goto finish;
2657dd7cddfSDavid du Colombier     /*
2667dd7cddfSDavid du Colombier      * Disregard the ok_to_compress flag, since the size threshold gives us
2677dd7cddfSDavid du Colombier      * a much better criterion for deciding when compression is appropriate.
2687dd7cddfSDavid du Colombier      */
2697dd7cddfSDavid du Colombier     f->ok_to_compress = /*ok_to_compress */ true;
2707dd7cddfSDavid du Colombier     f->compress_state = 0;	/* make clean for GC */
2717dd7cddfSDavid du Colombier     f->decompress_state = 0;
2727dd7cddfSDavid du Colombier     if (f->ok_to_compress) {
2737dd7cddfSDavid du Colombier 	const stream_state *compress_proto = clist_compressor_state(NULL);
2747dd7cddfSDavid du Colombier 	const stream_state *decompress_proto = clist_decompressor_state(NULL);
2757dd7cddfSDavid du Colombier 	const stream_template *compress_template = compress_proto->template;
2767dd7cddfSDavid du Colombier 	const stream_template *decompress_template = decompress_proto->template;
2777dd7cddfSDavid du Colombier 
2787dd7cddfSDavid du Colombier 	f->compress_state =
2797dd7cddfSDavid du Colombier 	    gs_alloc_struct(mem, stream_state, compress_template->stype,
2807dd7cddfSDavid du Colombier 			    "memfile_open_scratch(compress_state)");
2817dd7cddfSDavid du Colombier 	f->decompress_state =
2827dd7cddfSDavid du Colombier 	    gs_alloc_struct(mem, stream_state, decompress_template->stype,
2837dd7cddfSDavid du Colombier 			    "memfile_open_scratch(decompress_state)");
2847dd7cddfSDavid du Colombier 	if (f->compress_state == 0 || f->decompress_state == 0) {
2857dd7cddfSDavid du Colombier 	    eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
2867dd7cddfSDavid du Colombier 	    code = gs_note_error(gs_error_VMerror);
2877dd7cddfSDavid du Colombier 	    goto finish;
2887dd7cddfSDavid du Colombier 	}
2897dd7cddfSDavid du Colombier 	memcpy(f->compress_state, compress_proto,
2907dd7cddfSDavid du Colombier 	       gs_struct_type_size(compress_template->stype));
2917dd7cddfSDavid du Colombier 	f->compress_state->memory = mem;
2927dd7cddfSDavid du Colombier 	memcpy(f->decompress_state, decompress_proto,
2937dd7cddfSDavid du Colombier 	       gs_struct_type_size(decompress_template->stype));
2947dd7cddfSDavid du Colombier 	f->decompress_state->memory = mem;
2957dd7cddfSDavid du Colombier 	if (compress_template->set_defaults)
2967dd7cddfSDavid du Colombier 	    (*compress_template->set_defaults) (f->compress_state);
2977dd7cddfSDavid du Colombier 	if (decompress_template->set_defaults)
2987dd7cddfSDavid du Colombier 	    (*decompress_template->set_defaults) (f->decompress_state);
2997dd7cddfSDavid du Colombier     }
3007dd7cddfSDavid du Colombier     f->total_space = 0;
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier #ifdef DEBUG
3037dd7cddfSDavid du Colombier     /* If this is the start, init some statistics.       */
3047dd7cddfSDavid du Colombier     /* Hack: we know the 'a' file is opened first. */
3057dd7cddfSDavid du Colombier     if (*fname == 'a') {
3067dd7cddfSDavid du Colombier 	tot_compressed = 0;
3077dd7cddfSDavid du Colombier 	tot_raw = 0;
3087dd7cddfSDavid du Colombier 	tot_cache_miss = 0;
3097dd7cddfSDavid du Colombier 	tot_cache_hits = 0;
3107dd7cddfSDavid du Colombier 	tot_swap_out = 0;
3117dd7cddfSDavid du Colombier     }
3127dd7cddfSDavid du Colombier #endif
3137dd7cddfSDavid du Colombier finish:
3147dd7cddfSDavid du Colombier     if (code < 0) {
3157dd7cddfSDavid du Colombier 	/* return failure, clean up memory before leaving */
3167dd7cddfSDavid du Colombier 	if (f != NULL)
3177dd7cddfSDavid du Colombier 	    memfile_fclose((clist_file_ptr)f, fname, true);
3187dd7cddfSDavid du Colombier     } else {
3197dd7cddfSDavid du Colombier       /* return success */
3207dd7cddfSDavid du Colombier       *pf = f;
3217dd7cddfSDavid du Colombier     }
3227dd7cddfSDavid du Colombier     return code;
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier int
memfile_fclose(clist_file_ptr cf,const char * fname,bool delete)3267dd7cddfSDavid du Colombier memfile_fclose(clist_file_ptr cf, const char *fname, bool delete)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier     MEMFILE *const f = (MEMFILE *)cf;
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier     /* We don't implement closing without deletion. */
3317dd7cddfSDavid du Colombier     if (!delete)
3327dd7cddfSDavid du Colombier 	return_error(gs_error_invalidfileaccess);
3337dd7cddfSDavid du Colombier     memfile_free_mem(f);
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier     /* Free reserve blocks; don't do it in memfile_free_mem because */
3367dd7cddfSDavid du Colombier     /* that routine gets called to reinit file */
3377dd7cddfSDavid du Colombier     while (f->reserveLogBlockChain != NULL) {
3387dd7cddfSDavid du Colombier 	LOG_MEMFILE_BLK *block = f->reserveLogBlockChain;
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	f->reserveLogBlockChain = block->link;
3417dd7cddfSDavid du Colombier 	FREE(f, block, "memfile_set_block_size");
3427dd7cddfSDavid du Colombier     }
3437dd7cddfSDavid du Colombier     while (f->reservePhysBlockChain != NULL) {
3447dd7cddfSDavid du Colombier 	PHYS_MEMFILE_BLK *block = f->reservePhysBlockChain;
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier 	f->reservePhysBlockChain = block->link;
3477dd7cddfSDavid du Colombier 	FREE(f, block, "memfile_set_block_size");
3487dd7cddfSDavid du Colombier     }
3497dd7cddfSDavid du Colombier 
3507dd7cddfSDavid du Colombier     /* deallocate de/compress state */
3517dd7cddfSDavid du Colombier     gs_free_object(f->memory, f->decompress_state,
3527dd7cddfSDavid du Colombier 		   "memfile_close_and_unlink(decompress_state)");
3537dd7cddfSDavid du Colombier     gs_free_object(f->memory, f->compress_state,
3547dd7cddfSDavid du Colombier 		   "memfile_close_and_unlink(compress_state)");
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier     /* deallocate the memfile object proper */
3577dd7cddfSDavid du Colombier     gs_free_object(f->memory, f, "memfile_close_and_unlink(MEMFILE)");
3587dd7cddfSDavid du Colombier     return 0;
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier 
3617dd7cddfSDavid du Colombier int
memfile_unlink(const char * fname)3627dd7cddfSDavid du Colombier memfile_unlink(const char *fname)
3637dd7cddfSDavid du Colombier {
3647dd7cddfSDavid du Colombier     /*
3657dd7cddfSDavid du Colombier      * Since we have no way to represent a memfile other than by the
3667dd7cddfSDavid du Colombier      * pointer, we don't (can't) implement unlinking.
3677dd7cddfSDavid du Colombier      */
3687dd7cddfSDavid du Colombier     return_error(gs_error_invalidfileaccess);
3697dd7cddfSDavid du Colombier }
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier /* ---------------- Writing ---------------- */
3727dd7cddfSDavid du Colombier 
3737dd7cddfSDavid du Colombier /* Pre-alloc enough reserve mem blox to guarantee a write of N bytes will succeed */
3747dd7cddfSDavid du Colombier int	/* returns 0 ok, gs_error_VMerror if insufficient */
memfile_set_memory_warning(clist_file_ptr cf,int bytes_left)3757dd7cddfSDavid du Colombier memfile_set_memory_warning(clist_file_ptr cf, int bytes_left)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier     MEMFILE *const f = (MEMFILE *)cf;
3787dd7cddfSDavid du Colombier     int code = 0;
3797dd7cddfSDavid du Colombier     /*
3807dd7cddfSDavid du Colombier      * Determine req'd memory block count from bytes_left.
3817dd7cddfSDavid du Colombier      * Allocate enough phys & log blocks to hold bytes_left
3827dd7cddfSDavid du Colombier      * + 1 phys blk for compress_log_blk + 1 phys blk for decompress.
3837dd7cddfSDavid du Colombier      */
3847dd7cddfSDavid du Colombier     int logNeeded =
3857dd7cddfSDavid du Colombier 	(bytes_left + MEMFILE_DATA_SIZE - 1) / MEMFILE_DATA_SIZE;
3867dd7cddfSDavid du Colombier     int physNeeded = logNeeded;
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier     if (bytes_left > 0)
3897dd7cddfSDavid du Colombier 	++physNeeded;
3907dd7cddfSDavid du Colombier     if (f->raw_head == NULL)
3917dd7cddfSDavid du Colombier 	++physNeeded;	/* have yet to allocate read buffers */
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier     /* Allocate or free memory depending on need */
3947dd7cddfSDavid du Colombier     while (logNeeded > f->reserveLogBlockCount) {
3957dd7cddfSDavid du Colombier 	LOG_MEMFILE_BLK *block =
3967dd7cddfSDavid du Colombier 	    MALLOC( f, sizeof(LOG_MEMFILE_BLK), "memfile_set_block_size" );
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier 	if (block == NULL) {
3997dd7cddfSDavid du Colombier 	    code = gs_note_error(gs_error_VMerror);
4007dd7cddfSDavid du Colombier 	    goto finish;
4017dd7cddfSDavid du Colombier 	}
4027dd7cddfSDavid du Colombier 	block->link = f->reserveLogBlockChain;
4037dd7cddfSDavid du Colombier 	f->reserveLogBlockChain = block;
4047dd7cddfSDavid du Colombier 	++f->reserveLogBlockCount;
4057dd7cddfSDavid du Colombier     }
4067dd7cddfSDavid du Colombier     while (logNeeded < f->reserveLogBlockCount) {
4077dd7cddfSDavid du Colombier 	LOG_MEMFILE_BLK *block = f->reserveLogBlockChain;
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier 	f->reserveLogBlockChain = block->link;
4107dd7cddfSDavid du Colombier 	FREE(f, block, "memfile_set_block_size");
4117dd7cddfSDavid du Colombier 	--f->reserveLogBlockCount;
4127dd7cddfSDavid du Colombier     }
4137dd7cddfSDavid du Colombier     while (physNeeded > f->reservePhysBlockCount) {
4147dd7cddfSDavid du Colombier 	PHYS_MEMFILE_BLK *block =
4157dd7cddfSDavid du Colombier 	    MALLOC( f,
4167dd7cddfSDavid du Colombier 		    max( sizeof(PHYS_MEMFILE_BLK), sizeof(RAW_BUFFER) ),
4177dd7cddfSDavid du Colombier 		    "memfile_set_block_size");
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier 	if (block == NULL) {
4207dd7cddfSDavid du Colombier 	    code = gs_note_error(gs_error_VMerror);
4217dd7cddfSDavid du Colombier 	    goto finish;
4227dd7cddfSDavid du Colombier 	}
4237dd7cddfSDavid du Colombier 	block->link = f->reservePhysBlockChain;
4247dd7cddfSDavid du Colombier 	f->reservePhysBlockChain = block;
4257dd7cddfSDavid du Colombier 	++f->reservePhysBlockCount;
4267dd7cddfSDavid du Colombier     }
4277dd7cddfSDavid du Colombier     while (physNeeded < f->reservePhysBlockCount) {
4287dd7cddfSDavid du Colombier 	PHYS_MEMFILE_BLK *block = f->reservePhysBlockChain;
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier 	f->reservePhysBlockChain = block->link;
4317dd7cddfSDavid du Colombier 	FREE(f, block, "memfile_set_block_size");
4327dd7cddfSDavid du Colombier 	--f->reservePhysBlockCount;
4337dd7cddfSDavid du Colombier     }
4347dd7cddfSDavid du Colombier     f->error_code = 0;	/* memfile_set_block_size is how user resets this */
4357dd7cddfSDavid du Colombier finish:
4367dd7cddfSDavid du Colombier     return code;
4377dd7cddfSDavid du Colombier }
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier private int
compress_log_blk(MEMFILE * f,LOG_MEMFILE_BLK * bp)4407dd7cddfSDavid du Colombier compress_log_blk(MEMFILE * f, LOG_MEMFILE_BLK * bp)
4417dd7cddfSDavid du Colombier {
4427dd7cddfSDavid du Colombier     int status;
4437dd7cddfSDavid du Colombier     int ecode = 0;		/* accumulate low-memory warnings */
4447dd7cddfSDavid du Colombier     int code;
4457dd7cddfSDavid du Colombier     long compressed_size;
4467dd7cddfSDavid du Colombier     byte *start_ptr;
4477dd7cddfSDavid du Colombier     PHYS_MEMFILE_BLK *newphys;
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier     /* compress this block */
4507dd7cddfSDavid du Colombier     f->rd.ptr = (const byte *)(bp->phys_blk->data) - 1;
4517dd7cddfSDavid du Colombier     f->rd.limit = f->rd.ptr + MEMFILE_DATA_SIZE;
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier     bp->phys_blk = f->phys_curr;
4547dd7cddfSDavid du Colombier     bp->phys_pdata = (char *)(f->wt.ptr) + 1;
4557dd7cddfSDavid du Colombier     if (f->compress_state->template->reinit != 0)
4567dd7cddfSDavid du Colombier 	(*f->compress_state->template->reinit)(f->compress_state);
4577dd7cddfSDavid du Colombier     compressed_size = 0;
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier     start_ptr = f->wt.ptr;
4607dd7cddfSDavid du Colombier     status = (*f->compress_state->template->process)(f->compress_state,
4617dd7cddfSDavid du Colombier 						     &(f->rd), &(f->wt), true);
4627dd7cddfSDavid du Colombier     bp->phys_blk->data_limit = (char *)(f->wt.ptr);
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier     if (status == 1) {		/* More output space needed (see strimpl.h) */
4657dd7cddfSDavid du Colombier 	/* allocate another physical block, then compress remainder       */
4667dd7cddfSDavid du Colombier 	compressed_size = f->wt.limit - start_ptr;
4677dd7cddfSDavid du Colombier 	newphys =
4687dd7cddfSDavid du Colombier 	    allocateWithReserve(f, sizeof(*newphys), &code, "memfile newphys",
4697dd7cddfSDavid du Colombier 			"compress_log_blk : MALLOC for 'newphys' failed\n");
4707dd7cddfSDavid du Colombier 	if (code < 0)
4717dd7cddfSDavid du Colombier 	    return code;
4727dd7cddfSDavid du Colombier 	ecode |= code;	/* accumulate any low-memory warnings */
4737dd7cddfSDavid du Colombier 	newphys->link = NULL;
4747dd7cddfSDavid du Colombier 	bp->phys_blk->link = newphys;
4757dd7cddfSDavid du Colombier 	f->phys_curr = newphys;
4767dd7cddfSDavid du Colombier 	f->wt.ptr = (byte *) (newphys->data) - 1;
4777dd7cddfSDavid du Colombier 	f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	start_ptr = f->wt.ptr;
4807dd7cddfSDavid du Colombier 	status =
4817dd7cddfSDavid du Colombier 	    (*f->compress_state->template->process)(f->compress_state,
4827dd7cddfSDavid du Colombier 						    &(f->rd), &(f->wt), true);
4837dd7cddfSDavid du Colombier 	if (status != 0) {
4847dd7cddfSDavid du Colombier 	    /*
4857dd7cddfSDavid du Colombier 	     * You'd think the above line is a bug, but in real life 1 src
4867dd7cddfSDavid du Colombier 	     * block never ends up getting split across 3 dest blocks.
4877dd7cddfSDavid du Colombier 	     */
4887dd7cddfSDavid du Colombier 	    /* CHANGE memfile_set_memory_warning if this assumption changes. */
4897dd7cddfSDavid du Colombier 	    eprintf("Compression required more than one full block!\n");
4907dd7cddfSDavid du Colombier 	    return_error(gs_error_Fatal);
4917dd7cddfSDavid du Colombier 	}
4927dd7cddfSDavid du Colombier 	newphys->data_limit = (char *)(f->wt.ptr);
4937dd7cddfSDavid du Colombier     }
4947dd7cddfSDavid du Colombier     compressed_size += f->wt.ptr - start_ptr;
4957dd7cddfSDavid du Colombier     if (compressed_size > MEMFILE_DATA_SIZE) {
4967dd7cddfSDavid du Colombier 	eprintf2("\nCompression didn't - raw=%d, compressed=%ld\n",
4977dd7cddfSDavid du Colombier 		 MEMFILE_DATA_SIZE, compressed_size);
4987dd7cddfSDavid du Colombier     }
4997dd7cddfSDavid du Colombier #ifdef DEBUG
5007dd7cddfSDavid du Colombier     tot_compressed += compressed_size;
5017dd7cddfSDavid du Colombier #endif
5027dd7cddfSDavid du Colombier     return (status < 0 ? gs_note_error(gs_error_ioerror) : ecode);
5037dd7cddfSDavid du Colombier }				/* end "compress_log_blk()"                                     */
5047dd7cddfSDavid du Colombier 
5057dd7cddfSDavid du Colombier /*      Internal (private) routine to handle end of logical block       */
5067dd7cddfSDavid du Colombier private int	/* ret 0 ok, -ve error, or +ve low-memory warning */
memfile_next_blk(MEMFILE * f)5077dd7cddfSDavid du Colombier memfile_next_blk(MEMFILE * f)
5087dd7cddfSDavid du Colombier {
5097dd7cddfSDavid du Colombier     LOG_MEMFILE_BLK *bp = f->log_curr_blk;
5107dd7cddfSDavid du Colombier     LOG_MEMFILE_BLK *newbp;
5117dd7cddfSDavid du Colombier     PHYS_MEMFILE_BLK *newphys, *oldphys;
5127dd7cddfSDavid du Colombier     int ecode = 0;		/* accumulate low-memory warnings */
5137dd7cddfSDavid du Colombier     int code;
5147dd7cddfSDavid du Colombier 
5157dd7cddfSDavid du Colombier     if (f->phys_curr == NULL) {	/* means NOT compressing                */
5167dd7cddfSDavid du Colombier 	/* allocate a new block                                           */
5177dd7cddfSDavid du Colombier 	newphys =
5187dd7cddfSDavid du Colombier 	    allocateWithReserve(f, sizeof(*newphys), &code, "memfile newphys",
5197dd7cddfSDavid du Colombier 			"memfile_next_blk: MALLOC 1 for 'newphys' failed\n");
5207dd7cddfSDavid du Colombier 	if (code < 0)
5217dd7cddfSDavid du Colombier 	    return code;
5227dd7cddfSDavid du Colombier 	ecode |= code;	/* accumulate low-mem warnings */
5237dd7cddfSDavid du Colombier 	newphys->link = NULL;
5247dd7cddfSDavid du Colombier 	newphys->data_limit = NULL;	/* raw                          */
5257dd7cddfSDavid du Colombier 
5267dd7cddfSDavid du Colombier 	newbp =
5277dd7cddfSDavid du Colombier 	    allocateWithReserve(f, sizeof(*newbp), &code, "memfile newbp",
5287dd7cddfSDavid du Colombier 			"memfile_next_blk: MALLOC 1 for 'newbp' failed\n");
5297dd7cddfSDavid du Colombier 	if (code < 0) {
5307dd7cddfSDavid du Colombier 	    FREE(f, newphys, "memfile newphys");
5317dd7cddfSDavid du Colombier 	    return code;
5327dd7cddfSDavid du Colombier 	}
5337dd7cddfSDavid du Colombier 	ecode |= code;	/* accumulate low-mem warnings */
5347dd7cddfSDavid du Colombier 	bp->link = newbp;
5357dd7cddfSDavid du Colombier 	newbp->link = NULL;
5367dd7cddfSDavid du Colombier 	newbp->raw_block = NULL;
5377dd7cddfSDavid du Colombier 	f->log_curr_blk = newbp;
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier 	/* check if need to start compressing                             */
5407dd7cddfSDavid du Colombier 	if (NEED_TO_COMPRESS(f)) {
5417dd7cddfSDavid du Colombier 	    if_debug0(':', "[:]Beginning compression\n");
5427dd7cddfSDavid du Colombier 	    /* compress the entire file up to this point                   */
5437dd7cddfSDavid du Colombier 	    if (!f->compressor_initialized) {
5447dd7cddfSDavid du Colombier 		int code = 0;
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier 		if (f->compress_state->template->init != 0)
5477dd7cddfSDavid du Colombier 		    code = (*f->compress_state->template->init) (f->compress_state);
5487dd7cddfSDavid du Colombier 		if (code < 0)
5497dd7cddfSDavid du Colombier 		    return_error(gs_error_VMerror);  /****** BOGUS ******/
5507dd7cddfSDavid du Colombier 		if (f->decompress_state->template->init != 0)
5517dd7cddfSDavid du Colombier 		    code = (*f->decompress_state->template->init)
5527dd7cddfSDavid du Colombier 			(f->decompress_state);
5537dd7cddfSDavid du Colombier 		if (code < 0)
5547dd7cddfSDavid du Colombier 		    return_error(gs_error_VMerror);  /****** BOGUS ******/
5557dd7cddfSDavid du Colombier 		f->compressor_initialized = true;
5567dd7cddfSDavid du Colombier 	    }
5577dd7cddfSDavid du Colombier 	    /* Write into the new physical block we just allocated,        */
5587dd7cddfSDavid du Colombier 	    /* replace it after the loop (after some blocks are freed)     */
5597dd7cddfSDavid du Colombier 	    f->phys_curr = newphys;
5607dd7cddfSDavid du Colombier 	    f->wt.ptr = (byte *) (newphys->data) - 1;
5617dd7cddfSDavid du Colombier 	    f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
5627dd7cddfSDavid du Colombier 	    bp = f->log_head;
5637dd7cddfSDavid du Colombier 	    while (bp != newbp) {	/* don't compress last block    */
5647dd7cddfSDavid du Colombier 		int code;
5657dd7cddfSDavid du Colombier 
5667dd7cddfSDavid du Colombier 		oldphys = bp->phys_blk;
5677dd7cddfSDavid du Colombier 		if ((code = compress_log_blk(f, bp)) < 0)
5687dd7cddfSDavid du Colombier 		    return code;
5697dd7cddfSDavid du Colombier 		ecode |= code;
5707dd7cddfSDavid du Colombier 		FREE(f, oldphys, "memfile_next_blk(oldphys)");
5717dd7cddfSDavid du Colombier 		bp = bp->link;
5727dd7cddfSDavid du Colombier 	    }			/* end while( ) compress loop                           */
5737dd7cddfSDavid du Colombier 	    /* Allocate a physical block for this (last) logical block     */
5747dd7cddfSDavid du Colombier 	    newphys =
5757dd7cddfSDavid du Colombier 		allocateWithReserve(f, sizeof(*newphys), &code,
5767dd7cddfSDavid du Colombier 			"memfile newphys",
5777dd7cddfSDavid du Colombier 			"memfile_next_blk: MALLOC 2 for 'newphys' failed\n");
5787dd7cddfSDavid du Colombier 	    if (code < 0)
5797dd7cddfSDavid du Colombier 		return code;
5807dd7cddfSDavid du Colombier 	    ecode |= code;	/* accumulate low-mem warnings */
5817dd7cddfSDavid du Colombier 	    newphys->link = NULL;
5827dd7cddfSDavid du Colombier 	    newphys->data_limit = NULL;		/* raw                  */
5837dd7cddfSDavid du Colombier 
5847dd7cddfSDavid du Colombier 	}			/* end convert file to compressed                                 */
5857dd7cddfSDavid du Colombier 	newbp->phys_blk = newphys;
5867dd7cddfSDavid du Colombier 	f->pdata = newphys->data;
5877dd7cddfSDavid du Colombier 	f->pdata_end = newphys->data + MEMFILE_DATA_SIZE;
5887dd7cddfSDavid du Colombier     }    /* end if NOT compressing                                 */
5897dd7cddfSDavid du Colombier     /* File IS being compressed                                       */
5907dd7cddfSDavid du Colombier     else {
5917dd7cddfSDavid du Colombier 	int code;
5927dd7cddfSDavid du Colombier 
5937dd7cddfSDavid du Colombier 	oldphys = bp->phys_blk;	/* save raw phys block ID               */
5947dd7cddfSDavid du Colombier 	/* compresses bp on phys list  */
5957dd7cddfSDavid du Colombier 	if ((code = compress_log_blk(f, bp)) < 0)
5967dd7cddfSDavid du Colombier 	    return code;
5977dd7cddfSDavid du Colombier 	ecode |= code;
5987dd7cddfSDavid du Colombier 	newbp =
5997dd7cddfSDavid du Colombier 	    allocateWithReserve(f, sizeof(*newbp), &code, "memfile newbp",
6007dd7cddfSDavid du Colombier 			"memfile_next_blk: MALLOC 2 for 'newbp' failed\n");
6017dd7cddfSDavid du Colombier 	if (code < 0)
6027dd7cddfSDavid du Colombier 	    return code;
6037dd7cddfSDavid du Colombier 	ecode |= code;
6047dd7cddfSDavid du Colombier 	bp->link = newbp;
6057dd7cddfSDavid du Colombier 	newbp->link = NULL;
6067dd7cddfSDavid du Colombier 	newbp->raw_block = NULL;
6077dd7cddfSDavid du Colombier 	/* Re-use the raw phys block for this new logical blk             */
6087dd7cddfSDavid du Colombier 	newbp->phys_blk = oldphys;
6097dd7cddfSDavid du Colombier 	f->pdata = oldphys->data;
6107dd7cddfSDavid du Colombier 	f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
6117dd7cddfSDavid du Colombier 	f->log_curr_blk = newbp;
6127dd7cddfSDavid du Colombier     }				/* end else (when we are compressing)                           */
6137dd7cddfSDavid du Colombier 
6147dd7cddfSDavid du Colombier     return (ecode);
6157dd7cddfSDavid du Colombier }
6167dd7cddfSDavid du Colombier 
6177dd7cddfSDavid du Colombier int	/* returns # of chars actually written */
memfile_fwrite_chars(const void * data,uint len,clist_file_ptr cf)6187dd7cddfSDavid du Colombier memfile_fwrite_chars(const void *data, uint len, clist_file_ptr cf)
6197dd7cddfSDavid du Colombier {
6207dd7cddfSDavid du Colombier     const char *str = (const char *)data;
6217dd7cddfSDavid du Colombier     MEMFILE *f = (MEMFILE *) cf;
6227dd7cddfSDavid du Colombier     uint count = len;
6237dd7cddfSDavid du Colombier     int ecode;
6247dd7cddfSDavid du Colombier 
6257dd7cddfSDavid du Colombier     /* check if we are writing to the start of the file.  If so, then    */
6267dd7cddfSDavid du Colombier     /* free the file memory and re-initialize it (frees memory)          */
6277dd7cddfSDavid du Colombier     if (f->log_curr_pos == 0) {
6287dd7cddfSDavid du Colombier 	int code;
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier 	memfile_free_mem(f);
6317dd7cddfSDavid du Colombier 	if ((code = memfile_init_empty(f)) < 0) {
6327dd7cddfSDavid du Colombier 	    f->error_code = code;
6337dd7cddfSDavid du Colombier 	    return 0;
6347dd7cddfSDavid du Colombier 	}
6357dd7cddfSDavid du Colombier     }
6367dd7cddfSDavid du Colombier     if (f->log_curr_blk->link != 0) {
6377dd7cddfSDavid du Colombier 	eprintf(" Write file truncate -- need to free physical blocks.\n");
6387dd7cddfSDavid du Colombier     }
6397dd7cddfSDavid du Colombier     while (count) {
6407dd7cddfSDavid du Colombier 	uint move_count = f->pdata_end - f->pdata;
6417dd7cddfSDavid du Colombier 
6427dd7cddfSDavid du Colombier 	if (move_count == 0) {
6437dd7cddfSDavid du Colombier 	    if ((ecode = memfile_next_blk(f)) != 0) {
6447dd7cddfSDavid du Colombier 		f->error_code = ecode;
6457dd7cddfSDavid du Colombier 		if (ecode < 0)
6467dd7cddfSDavid du Colombier 		    return 0;
6477dd7cddfSDavid du Colombier 	    }
6487dd7cddfSDavid du Colombier 	} else {
6497dd7cddfSDavid du Colombier 	    if (move_count > count)
6507dd7cddfSDavid du Colombier 		move_count = count;
6517dd7cddfSDavid du Colombier 	    memmove(f->pdata, str, move_count);
6527dd7cddfSDavid du Colombier 	    f->pdata += move_count;
6537dd7cddfSDavid du Colombier 	    str += move_count;
6547dd7cddfSDavid du Colombier 	    count -= move_count;
6557dd7cddfSDavid du Colombier 	}
6567dd7cddfSDavid du Colombier     }
6577dd7cddfSDavid du Colombier     f->log_curr_pos += len;
6587dd7cddfSDavid du Colombier     f->log_length = f->log_curr_pos;	/* truncate length to here      */
6597dd7cddfSDavid du Colombier #ifdef DEBUG
6607dd7cddfSDavid du Colombier     tot_raw += len;
6617dd7cddfSDavid du Colombier #endif
6627dd7cddfSDavid du Colombier     return (len);
6637dd7cddfSDavid du Colombier }
6647dd7cddfSDavid du Colombier 
6657dd7cddfSDavid du Colombier /*                                                                      */
6667dd7cddfSDavid du Colombier /*      Internal routine to set the f->pdata and f->pdata_end pointers  */
6677dd7cddfSDavid du Colombier /*      for the current logical block f->log_curr_blk                   */
6687dd7cddfSDavid du Colombier /*                                                                      */
6697dd7cddfSDavid du Colombier /*      If data only exists in compressed form, allocate a raw buffer   */
6707dd7cddfSDavid du Colombier /*      and decompress it.                                              */
6717dd7cddfSDavid du Colombier /*                                                                      */
6727dd7cddfSDavid du Colombier 
6737dd7cddfSDavid du Colombier private int
memfile_get_pdata(MEMFILE * f)6747dd7cddfSDavid du Colombier memfile_get_pdata(MEMFILE * f)
6757dd7cddfSDavid du Colombier {
6767dd7cddfSDavid du Colombier     int i, num_raw_buffers, status;
6777dd7cddfSDavid du Colombier     LOG_MEMFILE_BLK *bp = f->log_curr_blk;
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier     if (bp->phys_blk->data_limit == NULL) {
6807dd7cddfSDavid du Colombier 	/* Not compressed, return this data pointer                       */
6817dd7cddfSDavid du Colombier 	f->pdata = (bp->phys_blk)->data;
6827dd7cddfSDavid du Colombier 	i = f->log_curr_pos % MEMFILE_DATA_SIZE;	/* pos within block     */
6837dd7cddfSDavid du Colombier 	i = f->log_curr_pos - i;	/* base of block        */
6847dd7cddfSDavid du Colombier 	if (i + MEMFILE_DATA_SIZE > f->log_length)
6857dd7cddfSDavid du Colombier 	    f->pdata_end = f->pdata + f->log_length - i;
6867dd7cddfSDavid du Colombier 	else
6877dd7cddfSDavid du Colombier 	    f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
6887dd7cddfSDavid du Colombier     } else {
6897dd7cddfSDavid du Colombier 	/* data was compressed                                            */
6907dd7cddfSDavid du Colombier 	if (f->raw_head == NULL) {
6917dd7cddfSDavid du Colombier 	    /* need to allocate the raw buffer pool                        */
6927dd7cddfSDavid du Colombier 	    num_raw_buffers = GET_NUM_RAW_BUFFERS(f);
6937dd7cddfSDavid du Colombier 	    if (f->reservePhysBlockCount) {
6947dd7cddfSDavid du Colombier             /* HACK: allocate reserve block that's been reserved for
6957dd7cddfSDavid du Colombier 	     * decompression.  This buffer's block was pre-allocated to make
6967dd7cddfSDavid du Colombier 	     * sure we won't come up short here. Take from chain instead of
6977dd7cddfSDavid du Colombier 	     * allocateWithReserve() since this buf would just be wasted if
6987dd7cddfSDavid du Colombier 	     * allowed to remain preallocated. */
6997dd7cddfSDavid du Colombier 		f->raw_head = (RAW_BUFFER *)f->reservePhysBlockChain;
7007dd7cddfSDavid du Colombier 		f->reservePhysBlockChain = f->reservePhysBlockChain->link;
7017dd7cddfSDavid du Colombier 		--f->reservePhysBlockCount;
7027dd7cddfSDavid du Colombier 	    } else {
7037dd7cddfSDavid du Colombier 		int code;
7047dd7cddfSDavid du Colombier 
7057dd7cddfSDavid du Colombier 		f->raw_head =
7067dd7cddfSDavid du Colombier 		    allocateWithReserve(f, sizeof(*f->raw_head), &code,
7077dd7cddfSDavid du Colombier 					"memfile raw buffer",
7087dd7cddfSDavid du Colombier 			"memfile_get_pdata: MALLOC for 'raw_head' failed\n");
7097dd7cddfSDavid du Colombier 		if (code < 0)
7107dd7cddfSDavid du Colombier 		    return code;
7117dd7cddfSDavid du Colombier 	    }
7127dd7cddfSDavid du Colombier 	    f->raw_head->back = NULL;
7137dd7cddfSDavid du Colombier 	    f->raw_tail = f->raw_head;
7147dd7cddfSDavid du Colombier 	    f->raw_tail->log_blk = NULL;
7157dd7cddfSDavid du Colombier 	    for (i = 0; i < num_raw_buffers; i++) {
7167dd7cddfSDavid du Colombier 		f->raw_tail->fwd = (RAW_BUFFER *) MALLOC(f, sizeof(RAW_BUFFER),
7177dd7cddfSDavid du Colombier 						      "memfile raw buffer");
7187dd7cddfSDavid du Colombier 		/* if MALLOC fails, then just stop allocating            */
7197dd7cddfSDavid du Colombier 		if (!f->raw_tail->fwd)
7207dd7cddfSDavid du Colombier 		    break;
7217dd7cddfSDavid du Colombier 		f->total_space += sizeof(RAW_BUFFER);
7227dd7cddfSDavid du Colombier 		f->raw_tail->fwd->back = f->raw_tail;
7237dd7cddfSDavid du Colombier 		f->raw_tail = f->raw_tail->fwd;
7247dd7cddfSDavid du Colombier 		f->raw_tail->log_blk = NULL;
7257dd7cddfSDavid du Colombier 	    }
7267dd7cddfSDavid du Colombier 	    f->raw_tail->fwd = NULL;
7277dd7cddfSDavid du Colombier 	    num_raw_buffers = i + 1;	/* if MALLOC failed, then OK    */
7287dd7cddfSDavid du Colombier 	    if_debug1(':', "[:]Number of raw buffers allocated=%d\n",
7297dd7cddfSDavid du Colombier 		      num_raw_buffers);
7307dd7cddfSDavid du Colombier 	}			/* end allocating the raw buffer pool (first time only)           */
7317dd7cddfSDavid du Colombier 	if (bp->raw_block == NULL) {
7327dd7cddfSDavid du Colombier #ifdef DEBUG
7337dd7cddfSDavid du Colombier 	    tot_cache_miss++;	/* count every decompress       */
7347dd7cddfSDavid du Colombier #endif
7357dd7cddfSDavid du Colombier 	    /* find a raw buffer and decompress                            */
7367dd7cddfSDavid du Colombier 	    if (f->raw_tail->log_blk != NULL) {
7377dd7cddfSDavid du Colombier 		/* This block was in use, grab it                           */
7387dd7cddfSDavid du Colombier #ifdef DEBUG
7397dd7cddfSDavid du Colombier 		tot_swap_out++;
7407dd7cddfSDavid du Colombier #endif
7417dd7cddfSDavid du Colombier 		f->raw_tail->log_blk->raw_block = NULL;		/* data no longer here */
7427dd7cddfSDavid du Colombier 		f->raw_tail->log_blk = NULL;
7437dd7cddfSDavid du Colombier 	    }
7447dd7cddfSDavid du Colombier 	    /* Use the last raw block in the chain (the oldest)            */
7457dd7cddfSDavid du Colombier 	    f->raw_tail->back->fwd = NULL;	/* disconnect from tail */
7467dd7cddfSDavid du Colombier 	    f->raw_tail->fwd = f->raw_head;	/* new head             */
7477dd7cddfSDavid du Colombier 	    f->raw_head->back = f->raw_tail;
7487dd7cddfSDavid du Colombier 	    f->raw_tail = f->raw_tail->back;
7497dd7cddfSDavid du Colombier 	    f->raw_head = f->raw_head->back;
7507dd7cddfSDavid du Colombier 	    f->raw_head->back = NULL;
7517dd7cddfSDavid du Colombier 	    f->raw_head->log_blk = bp;
7527dd7cddfSDavid du Colombier 
7537dd7cddfSDavid du Colombier 	    /* Decompress the data into this raw block                     */
7547dd7cddfSDavid du Colombier 	    /* Initialize the decompressor                              */
7557dd7cddfSDavid du Colombier 	    if (f->decompress_state->template->reinit != 0)
7567dd7cddfSDavid du Colombier 		(*f->decompress_state->template->reinit) (f->decompress_state);
7577dd7cddfSDavid du Colombier 	    /* Set pointers and call the decompress routine             */
7587dd7cddfSDavid du Colombier 	    f->wt.ptr = (byte *) (f->raw_head->data) - 1;
7597dd7cddfSDavid du Colombier 	    f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
7607dd7cddfSDavid du Colombier 	    f->rd.ptr = (const byte *)(bp->phys_pdata) - 1;
7617dd7cddfSDavid du Colombier 	    f->rd.limit = (const byte *)bp->phys_blk->data_limit;
7627dd7cddfSDavid du Colombier #ifdef DEBUG
7637dd7cddfSDavid du Colombier 	    decomp_wt_ptr0 = f->wt.ptr;
7647dd7cddfSDavid du Colombier 	    decomp_wt_limit0 = f->wt.limit;
7657dd7cddfSDavid du Colombier 	    decomp_rd_ptr0 = f->rd.ptr;
7667dd7cddfSDavid du Colombier 	    decomp_rd_limit0 = f->rd.limit;
7677dd7cddfSDavid du Colombier #endif
7687dd7cddfSDavid du Colombier 	    status = (*f->decompress_state->template->process)
7697dd7cddfSDavid du Colombier 		(f->decompress_state, &(f->rd), &(f->wt), true);
7707dd7cddfSDavid du Colombier 	    if (status == 0) {	/* More input data needed */
7717dd7cddfSDavid du Colombier 		/* switch to next block and continue decompress             */
7727dd7cddfSDavid du Colombier 		int back_up = 0;	/* adjust pointer backwards     */
7737dd7cddfSDavid du Colombier 
7747dd7cddfSDavid du Colombier 		if (f->rd.ptr != f->rd.limit) {
7757dd7cddfSDavid du Colombier 		    /* transfer remainder bytes from the previous block      */
7767dd7cddfSDavid du Colombier 		    back_up = f->rd.limit - f->rd.ptr;
7777dd7cddfSDavid du Colombier 		    for (i = 0; i < back_up; i++)
7787dd7cddfSDavid du Colombier 			*(bp->phys_blk->link->data - back_up + i) = *++f->rd.ptr;
7797dd7cddfSDavid du Colombier 		}
7807dd7cddfSDavid du Colombier 		f->rd.ptr = (const byte *)bp->phys_blk->link->data - back_up - 1;
7817dd7cddfSDavid du Colombier 		f->rd.limit = (const byte *)bp->phys_blk->link->data_limit;
7827dd7cddfSDavid du Colombier #ifdef DEBUG
7837dd7cddfSDavid du Colombier 		decomp_wt_ptr1 = f->wt.ptr;
7847dd7cddfSDavid du Colombier 		decomp_wt_limit1 = f->wt.limit;
7857dd7cddfSDavid du Colombier 		decomp_rd_ptr1 = f->rd.ptr;
7867dd7cddfSDavid du Colombier 		decomp_rd_limit1 = f->rd.limit;
7877dd7cddfSDavid du Colombier #endif
7887dd7cddfSDavid du Colombier 		status = (*f->decompress_state->template->process)
7897dd7cddfSDavid du Colombier 		    (f->decompress_state, &(f->rd), &(f->wt), true);
7907dd7cddfSDavid du Colombier 		if (status == 0) {
7917dd7cddfSDavid du Colombier 		    eprintf("Decompression required more than one full block!\n");
7927dd7cddfSDavid du Colombier 		    return_error(gs_error_Fatal);
7937dd7cddfSDavid du Colombier 		}
7947dd7cddfSDavid du Colombier 	    }
7957dd7cddfSDavid du Colombier 	    bp->raw_block = f->raw_head;	/* point to raw block           */
7967dd7cddfSDavid du Colombier 	}
7977dd7cddfSDavid du Colombier 	/* end if( raw_block == NULL ) meaning need to decompress data    */
7987dd7cddfSDavid du Colombier 	else {
7997dd7cddfSDavid du Colombier 	    /* data exists in the raw data cache, if not raw_head, move it */
8007dd7cddfSDavid du Colombier 	    if (bp->raw_block != f->raw_head) {
8017dd7cddfSDavid du Colombier 		/*          move to raw_head                                */
8027dd7cddfSDavid du Colombier 		/*          prev.fwd = this.fwd                             */
8037dd7cddfSDavid du Colombier 		bp->raw_block->back->fwd = bp->raw_block->fwd;
8047dd7cddfSDavid du Colombier 		if (bp->raw_block->fwd != NULL)
8057dd7cddfSDavid du Colombier 		    /*               next.back = this.back                   */
8067dd7cddfSDavid du Colombier 		    bp->raw_block->fwd->back = bp->raw_block->back;
8077dd7cddfSDavid du Colombier 		else
8087dd7cddfSDavid du Colombier 		    f->raw_tail = bp->raw_block->back;	/* tail = prev        */
8097dd7cddfSDavid du Colombier 		f->raw_head->back = bp->raw_block;	/* head.back = this     */
8107dd7cddfSDavid du Colombier 		bp->raw_block->fwd = f->raw_head;	/* this.fwd = orig head */
8117dd7cddfSDavid du Colombier 		f->raw_head = bp->raw_block;	/* head = this          */
8127dd7cddfSDavid du Colombier 		f->raw_head->back = NULL;	/* this.back = NULL     */
8137dd7cddfSDavid du Colombier #ifdef DEBUG
8147dd7cddfSDavid du Colombier 		tot_cache_hits++;	/* counting here prevents repeats since */
8157dd7cddfSDavid du Colombier 		/* won't count if already at head       */
8167dd7cddfSDavid du Colombier #endif
8177dd7cddfSDavid du Colombier 	    }
8187dd7cddfSDavid du Colombier 	}
8197dd7cddfSDavid du Colombier 	f->pdata = bp->raw_block->data;
8207dd7cddfSDavid du Colombier 	f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
8217dd7cddfSDavid du Colombier 	/* NOTE: last block is never compressed, so a compressed block    */
8227dd7cddfSDavid du Colombier 	/*        is always full size.                                    */
8237dd7cddfSDavid du Colombier     }				/* end else (when data was compressed)                             */
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier     return (0);
8267dd7cddfSDavid du Colombier }
8277dd7cddfSDavid du Colombier 
8287dd7cddfSDavid du Colombier /* ---------------- Reading ---------------- */
8297dd7cddfSDavid du Colombier 
8307dd7cddfSDavid du Colombier int
memfile_fread_chars(void * data,uint len,clist_file_ptr cf)8317dd7cddfSDavid du Colombier memfile_fread_chars(void *data, uint len, clist_file_ptr cf)
8327dd7cddfSDavid du Colombier {
8337dd7cddfSDavid du Colombier     char *str = (char *)data;
8347dd7cddfSDavid du Colombier     MEMFILE *f = (MEMFILE *) cf;
8357dd7cddfSDavid du Colombier     uint count = len, num_read, move_count;
8367dd7cddfSDavid du Colombier 
8377dd7cddfSDavid du Colombier     num_read = f->log_length - f->log_curr_pos;
8387dd7cddfSDavid du Colombier     if (count > num_read)
8397dd7cddfSDavid du Colombier 	count = num_read;
8407dd7cddfSDavid du Colombier     num_read = count;
8417dd7cddfSDavid du Colombier 
8427dd7cddfSDavid du Colombier     while (count) {
8437dd7cddfSDavid du Colombier 	f->log_curr_pos++;	/* move into next byte */
8447dd7cddfSDavid du Colombier 	if (f->pdata == f->pdata_end) {
8457dd7cddfSDavid du Colombier 	    f->log_curr_blk = (f->log_curr_blk)->link;
8467dd7cddfSDavid du Colombier 	    memfile_get_pdata(f);
8477dd7cddfSDavid du Colombier 	}
8487dd7cddfSDavid du Colombier 	move_count = f->pdata_end - f->pdata;
8497dd7cddfSDavid du Colombier 	if (move_count > count)
8507dd7cddfSDavid du Colombier 	    move_count = count;
8517dd7cddfSDavid du Colombier 	f->log_curr_pos += move_count - 1;	/* new position         */
8527dd7cddfSDavid du Colombier 	memmove(str, f->pdata, move_count);
8537dd7cddfSDavid du Colombier 	str += move_count;
8547dd7cddfSDavid du Colombier 	f->pdata += move_count;
8557dd7cddfSDavid du Colombier 	count -= move_count;
8567dd7cddfSDavid du Colombier     }
8577dd7cddfSDavid du Colombier 
8587dd7cddfSDavid du Colombier     return (num_read);
8597dd7cddfSDavid du Colombier }
8607dd7cddfSDavid du Colombier 
8617dd7cddfSDavid du Colombier /* ---------------- Position/status ---------------- */
8627dd7cddfSDavid du Colombier 
8637dd7cddfSDavid du Colombier int
memfile_ferror_code(clist_file_ptr cf)8647dd7cddfSDavid du Colombier memfile_ferror_code(clist_file_ptr cf)
8657dd7cddfSDavid du Colombier {
8667dd7cddfSDavid du Colombier     return (((MEMFILE *) cf)->error_code);	/* errors stored here */
8677dd7cddfSDavid du Colombier }
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier long
memfile_ftell(clist_file_ptr cf)8707dd7cddfSDavid du Colombier memfile_ftell(clist_file_ptr cf)
8717dd7cddfSDavid du Colombier {
8727dd7cddfSDavid du Colombier     return (((MEMFILE *) cf)->log_curr_pos);
8737dd7cddfSDavid du Colombier }
8747dd7cddfSDavid du Colombier 
8757dd7cddfSDavid du Colombier void
memfile_rewind(clist_file_ptr cf,bool discard_data,const char * ignore_fname)8767dd7cddfSDavid du Colombier memfile_rewind(clist_file_ptr cf, bool discard_data, const char *ignore_fname)
8777dd7cddfSDavid du Colombier {
8787dd7cddfSDavid du Colombier     MEMFILE *f = (MEMFILE *) cf;
8797dd7cddfSDavid du Colombier 
8807dd7cddfSDavid du Colombier     if (discard_data) {
8817dd7cddfSDavid du Colombier 	memfile_free_mem(f);
8827dd7cddfSDavid du Colombier 	/* We have to call memfile_init_empty to preserve invariants. */
8837dd7cddfSDavid du Colombier 	memfile_init_empty(f);
8847dd7cddfSDavid du Colombier     } else {
8857dd7cddfSDavid du Colombier 	f->log_curr_blk = f->log_head;
8867dd7cddfSDavid du Colombier 	f->log_curr_pos = 0;
8877dd7cddfSDavid du Colombier 	memfile_get_pdata(f);
8887dd7cddfSDavid du Colombier     }
8897dd7cddfSDavid du Colombier }
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier int
memfile_fseek(clist_file_ptr cf,long offset,int mode,const char * ignore_fname)8927dd7cddfSDavid du Colombier memfile_fseek(clist_file_ptr cf, long offset, int mode, const char *ignore_fname)
8937dd7cddfSDavid du Colombier {
8947dd7cddfSDavid du Colombier     MEMFILE *f = (MEMFILE *) cf;
8957dd7cddfSDavid du Colombier     long i, block_num, new_pos;
8967dd7cddfSDavid du Colombier 
8977dd7cddfSDavid du Colombier     switch (mode) {
8987dd7cddfSDavid du Colombier 	case SEEK_SET:		/* offset from the beginning of the file */
8997dd7cddfSDavid du Colombier 	    new_pos = offset;
9007dd7cddfSDavid du Colombier 	    break;
9017dd7cddfSDavid du Colombier 
9027dd7cddfSDavid du Colombier 	case SEEK_CUR:		/* offset from the current position in the file */
9037dd7cddfSDavid du Colombier 	    new_pos = offset + f->log_curr_pos;
9047dd7cddfSDavid du Colombier 	    break;
9057dd7cddfSDavid du Colombier 
9067dd7cddfSDavid du Colombier 	case SEEK_END:		/* offset back from the end of the file */
9077dd7cddfSDavid du Colombier 	    new_pos = f->log_length - offset;
9087dd7cddfSDavid du Colombier 	    break;
9097dd7cddfSDavid du Colombier 
9107dd7cddfSDavid du Colombier 	default:
9117dd7cddfSDavid du Colombier 	    return (-1);
9127dd7cddfSDavid du Colombier     }
9137dd7cddfSDavid du Colombier     if (new_pos < 0 || new_pos > f->log_length)
9147dd7cddfSDavid du Colombier 	return -1;
9157dd7cddfSDavid du Colombier     if ((f->pdata == f->pdata_end) && (f->log_curr_blk->link != NULL)) {
9167dd7cddfSDavid du Colombier 	/* log_curr_blk is actually one block behind log_curr_pos         */
9177dd7cddfSDavid du Colombier 	f->log_curr_blk = f->log_curr_blk->link;
9187dd7cddfSDavid du Colombier     }
9197dd7cddfSDavid du Colombier     block_num = new_pos / MEMFILE_DATA_SIZE;
9207dd7cddfSDavid du Colombier     i = f->log_curr_pos / MEMFILE_DATA_SIZE;
9217dd7cddfSDavid du Colombier     if (block_num < i) {	/* if moving backwards, start at beginning */
9227dd7cddfSDavid du Colombier 	f->log_curr_blk = f->log_head;
9237dd7cddfSDavid du Colombier 	i = 0;
9247dd7cddfSDavid du Colombier     }
9257dd7cddfSDavid du Colombier     for (; i < block_num; i++) {
9267dd7cddfSDavid du Colombier 	f->log_curr_blk = f->log_curr_blk->link;
9277dd7cddfSDavid du Colombier     }
9287dd7cddfSDavid du Colombier     f->log_curr_pos = new_pos;
9297dd7cddfSDavid du Colombier     memfile_get_pdata(f);	/* pointers to start of block           */
9307dd7cddfSDavid du Colombier     f->pdata += new_pos - (block_num * MEMFILE_DATA_SIZE);
9317dd7cddfSDavid du Colombier 
9327dd7cddfSDavid du Colombier     return 0;			/* return "normal" status                       */
9337dd7cddfSDavid du Colombier }
9347dd7cddfSDavid du Colombier 
9357dd7cddfSDavid du Colombier /* ---------------- Internal routines ---------------- */
9367dd7cddfSDavid du Colombier 
9377dd7cddfSDavid du Colombier private void
memfile_free_mem(MEMFILE * f)9387dd7cddfSDavid du Colombier memfile_free_mem(MEMFILE * f)
9397dd7cddfSDavid du Colombier {
9407dd7cddfSDavid du Colombier     LOG_MEMFILE_BLK *bp, *tmpbp;
9417dd7cddfSDavid du Colombier 
9427dd7cddfSDavid du Colombier #ifdef DEBUG
9437dd7cddfSDavid du Colombier     /* output some diagnostics about the effectiveness                   */
9447dd7cddfSDavid du Colombier     if (tot_raw > 100) {
9457dd7cddfSDavid du Colombier 	if_debug2(':', "[:]tot_raw=%ld, tot_compressed=%ld\n",
9467dd7cddfSDavid du Colombier 		  tot_raw, tot_compressed);
9477dd7cddfSDavid du Colombier     }
9487dd7cddfSDavid du Colombier     if (tot_cache_hits != 0) {
9497dd7cddfSDavid du Colombier 	if_debug3(':', "[:]Cache hits=%ld, cache misses=%ld, swapouts=%ld\n",
9507dd7cddfSDavid du Colombier 		 tot_cache_hits,
9517dd7cddfSDavid du Colombier 		 tot_cache_miss - (f->log_length / MEMFILE_DATA_SIZE),
9527dd7cddfSDavid du Colombier 		 tot_swap_out);
9537dd7cddfSDavid du Colombier     }
9547dd7cddfSDavid du Colombier     tot_raw = 0;
9557dd7cddfSDavid du Colombier     tot_compressed = 0;
9567dd7cddfSDavid du Colombier     tot_cache_hits = 0;
9577dd7cddfSDavid du Colombier     tot_cache_miss = 0;
9587dd7cddfSDavid du Colombier     tot_swap_out = 0;
9597dd7cddfSDavid du Colombier #endif
9607dd7cddfSDavid du Colombier 
9617dd7cddfSDavid du Colombier     /* Free up memory that was allocated for the memfile              */
9627dd7cddfSDavid du Colombier     bp = f->log_head;
9637dd7cddfSDavid du Colombier 
9647dd7cddfSDavid du Colombier /******************************************************************
9657dd7cddfSDavid du Colombier  * The following was the original algorithm here.  This algorithm has a bug:
9667dd7cddfSDavid du Colombier  * the second loop references the physical blocks again after they have been
9677dd7cddfSDavid du Colombier  * freed.
9687dd7cddfSDavid du Colombier  ******************************************************************/
9697dd7cddfSDavid du Colombier 
9707dd7cddfSDavid du Colombier #if 0				/**************** *************** */
9717dd7cddfSDavid du Colombier 
9727dd7cddfSDavid du Colombier     if (bp != NULL) {
9737dd7cddfSDavid du Colombier 	/* Free the physical blocks that make up the compressed data      */
9747dd7cddfSDavid du Colombier 	PHYS_MEMFILE_BLK *pphys = (f->log_head)->phys_blk;
9757dd7cddfSDavid du Colombier 
9767dd7cddfSDavid du Colombier 	if (pphys->data_limit != NULL) {
9777dd7cddfSDavid du Colombier 	    /* the data was compressed, free the chain of blocks             */
9787dd7cddfSDavid du Colombier 	    while (pphys != NULL) {
9797dd7cddfSDavid du Colombier 		PHYS_MEMFILE_BLK *tmpphys = pphys->link;
9807dd7cddfSDavid du Colombier 
9817dd7cddfSDavid du Colombier 		FREE(f, pphys, "memfile_free_mem(pphys)");
9827dd7cddfSDavid du Colombier 		pphys = tmpphys;
9837dd7cddfSDavid du Colombier 	    }
9847dd7cddfSDavid du Colombier 	}
9857dd7cddfSDavid du Colombier     }
9867dd7cddfSDavid du Colombier     /* free the logical blocks                                        */
9877dd7cddfSDavid du Colombier     while (bp != NULL) {
9887dd7cddfSDavid du Colombier 	/* if this logical block was not compressed, free the phys_blk  */
9897dd7cddfSDavid du Colombier 	if (bp->phys_blk->data_limit == NULL) {
9907dd7cddfSDavid du Colombier 	    FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
9917dd7cddfSDavid du Colombier 	}
9927dd7cddfSDavid du Colombier 	tmpbp = bp->link;
9937dd7cddfSDavid du Colombier 	FREE(f, bp, "memfile_free_mem(log_blk)");
9947dd7cddfSDavid du Colombier 	bp = tmpbp;
9957dd7cddfSDavid du Colombier     }
9967dd7cddfSDavid du Colombier 
9977dd7cddfSDavid du Colombier #else /**************** *************** */
9987dd7cddfSDavid du Colombier # if 1				/**************** *************** */
9997dd7cddfSDavid du Colombier 
10007dd7cddfSDavid du Colombier /****************************************************************
10017dd7cddfSDavid du Colombier  * This algorithm is correct (we think).
10027dd7cddfSDavid du Colombier  ****************************************************************/
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier     if (bp != NULL) {
10057dd7cddfSDavid du Colombier 	/* Null out phys_blk pointers to compressed data. */
10067dd7cddfSDavid du Colombier 	PHYS_MEMFILE_BLK *pphys = bp->phys_blk;
10077dd7cddfSDavid du Colombier 
10087dd7cddfSDavid du Colombier 	{
10097dd7cddfSDavid du Colombier 	    for (tmpbp = bp; tmpbp != NULL; tmpbp = tmpbp->link)
10107dd7cddfSDavid du Colombier 		if (tmpbp->phys_blk->data_limit != NULL)
10117dd7cddfSDavid du Colombier 		    tmpbp->phys_blk = 0;
10127dd7cddfSDavid du Colombier 	}
10137dd7cddfSDavid du Colombier 	/* Free the physical blocks that make up the compressed data      */
10147dd7cddfSDavid du Colombier 	if (pphys->data_limit != NULL) {
10157dd7cddfSDavid du Colombier 	    /* the data was compressed, free the chain of blocks             */
10167dd7cddfSDavid du Colombier 	    while (pphys != NULL) {
10177dd7cddfSDavid du Colombier 		PHYS_MEMFILE_BLK *tmpphys = pphys->link;
10187dd7cddfSDavid du Colombier 
10197dd7cddfSDavid du Colombier 		FREE(f, pphys, "memfile_free_mem(pphys)");
10207dd7cddfSDavid du Colombier 		pphys = tmpphys;
10217dd7cddfSDavid du Colombier 	    }
10227dd7cddfSDavid du Colombier 	}
10237dd7cddfSDavid du Colombier     }
10247dd7cddfSDavid du Colombier     /* Now free the logical blocks, and any uncompressed physical blocks. */
10257dd7cddfSDavid du Colombier     while (bp != NULL) {
10267dd7cddfSDavid du Colombier 	if (bp->phys_blk != NULL) {
10277dd7cddfSDavid du Colombier 	    FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
10287dd7cddfSDavid du Colombier 	}
10297dd7cddfSDavid du Colombier 	tmpbp = bp->link;
10307dd7cddfSDavid du Colombier 	FREE(f, bp, "memfile_free_mem(log_blk)");
10317dd7cddfSDavid du Colombier 	bp = tmpbp;
10327dd7cddfSDavid du Colombier     }
10337dd7cddfSDavid du Colombier 
10347dd7cddfSDavid du Colombier /***********************************************************************
10357dd7cddfSDavid du Colombier  * This algorithm appears to be both simpler and free of the bug that
10367dd7cddfSDavid du Colombier  * occasionally causes the older one to reference freed blocks; but in
10377dd7cddfSDavid du Colombier  * fact it can miss blocks, because the very last compressed logical block
10387dd7cddfSDavid du Colombier  * can have spill into a second physical block, which is not referenced by
10397dd7cddfSDavid du Colombier  * any logical block.
10407dd7cddfSDavid du Colombier  ***********************************************************************/
10417dd7cddfSDavid du Colombier 
10427dd7cddfSDavid du Colombier # else				/**************** *************** */
10437dd7cddfSDavid du Colombier 
10447dd7cddfSDavid du Colombier     {
10457dd7cddfSDavid du Colombier 	PHYS_MEMFILE_BLK *prev_phys = 0;
10467dd7cddfSDavid du Colombier 
10477dd7cddfSDavid du Colombier 	while (bp != NULL) {
10487dd7cddfSDavid du Colombier 	    PHYS_MEMFILE_BLK *phys = bp->phys_blk;
10497dd7cddfSDavid du Colombier 
10507dd7cddfSDavid du Colombier 	    if (phys != prev_phys) {
10517dd7cddfSDavid du Colombier 		FREE(f, phys, "memfile_free_mem(phys_blk)");
10527dd7cddfSDavid du Colombier 		prev_phys = phys;
10537dd7cddfSDavid du Colombier 	    }
10547dd7cddfSDavid du Colombier 	    tmpbp = bp->link;
10557dd7cddfSDavid du Colombier 	    FREE(f, bp, "memfile_free_mem(log_blk)");
10567dd7cddfSDavid du Colombier 	    bp = tmpbp;
10577dd7cddfSDavid du Colombier 	}
10587dd7cddfSDavid du Colombier     }
10597dd7cddfSDavid du Colombier 
10607dd7cddfSDavid du Colombier # endif				/**************** *************** */
10617dd7cddfSDavid du Colombier #endif /**************** *************** */
10627dd7cddfSDavid du Colombier 
10637dd7cddfSDavid du Colombier     f->log_head = NULL;
10647dd7cddfSDavid du Colombier 
10657dd7cddfSDavid du Colombier     /* Free any internal compressor state. */
10667dd7cddfSDavid du Colombier     if (f->compressor_initialized) {
10677dd7cddfSDavid du Colombier 	if (f->decompress_state->template->release != 0)
10687dd7cddfSDavid du Colombier 	    (*f->decompress_state->template->release) (f->decompress_state);
10697dd7cddfSDavid du Colombier 	if (f->compress_state->template->release != 0)
10707dd7cddfSDavid du Colombier 	    (*f->compress_state->template->release) (f->compress_state);
10717dd7cddfSDavid du Colombier 	f->compressor_initialized = false;
10727dd7cddfSDavid du Colombier     }
10737dd7cddfSDavid du Colombier     /* free the raw buffers                                           */
10747dd7cddfSDavid du Colombier     while (f->raw_head != NULL) {
10757dd7cddfSDavid du Colombier 	RAW_BUFFER *tmpraw = f->raw_head->fwd;
10767dd7cddfSDavid du Colombier 
10777dd7cddfSDavid du Colombier 	FREE(f, f->raw_head, "memfile_free_mem(raw)");
10787dd7cddfSDavid du Colombier 	f->raw_head = tmpraw;
10797dd7cddfSDavid du Colombier     }
10807dd7cddfSDavid du Colombier }
10817dd7cddfSDavid du Colombier 
10827dd7cddfSDavid du Colombier private int
memfile_init_empty(MEMFILE * f)10837dd7cddfSDavid du Colombier memfile_init_empty(MEMFILE * f)
10847dd7cddfSDavid du Colombier {
10857dd7cddfSDavid du Colombier     PHYS_MEMFILE_BLK *pphys;
10867dd7cddfSDavid du Colombier     LOG_MEMFILE_BLK *plog;
10877dd7cddfSDavid du Colombier 
10887dd7cddfSDavid du Colombier    /* Zero out key fields so that allocation failure will be unwindable */
10897dd7cddfSDavid du Colombier     f->phys_curr = NULL; 	/* flag as file not compressed    	*/
10907dd7cddfSDavid du Colombier     f->log_head = NULL;
10917dd7cddfSDavid du Colombier     f->log_curr_blk = NULL;
10927dd7cddfSDavid du Colombier     f->log_curr_pos = 0;
10937dd7cddfSDavid du Colombier     f->log_length = 0;
10947dd7cddfSDavid du Colombier     f->raw_head = NULL;
10957dd7cddfSDavid du Colombier     f->compressor_initialized = false;
10967dd7cddfSDavid du Colombier     f->total_space = 0;
10977dd7cddfSDavid du Colombier 
10987dd7cddfSDavid du Colombier     /* File empty - get a physical mem block (includes the buffer area)  */
10997dd7cddfSDavid du Colombier     pphys = MALLOC(f, sizeof(*pphys), "memfile pphys");
11007dd7cddfSDavid du Colombier     if (!pphys) {
11017dd7cddfSDavid du Colombier 	eprintf("memfile_init_empty: MALLOC for 'pphys' failed\n");
11027dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
11037dd7cddfSDavid du Colombier     }
11047dd7cddfSDavid du Colombier     f->total_space += sizeof(*pphys);
11057dd7cddfSDavid du Colombier     pphys->data_limit = NULL;	/* raw data for now     */
11067dd7cddfSDavid du Colombier 
11077dd7cddfSDavid du Colombier    /* Get logical mem block to go with physical one */
11087dd7cddfSDavid du Colombier     plog = (LOG_MEMFILE_BLK *)MALLOC( f, sizeof(*plog), "memfile_init_empty" );
11097dd7cddfSDavid du Colombier     if (plog == NULL) {
11107dd7cddfSDavid du Colombier 	FREE(f, pphys, "memfile_init_empty");
11117dd7cddfSDavid du Colombier 	eprintf("memfile_init_empty: MALLOC for log_curr_blk failed\n");
11127dd7cddfSDavid du Colombier 	return_error(gs_error_VMerror);
11137dd7cddfSDavid du Colombier     }
11147dd7cddfSDavid du Colombier     f->total_space += sizeof(*plog);
11157dd7cddfSDavid du Colombier     f->log_head = f->log_curr_blk = plog;
11167dd7cddfSDavid du Colombier     f->log_curr_blk->link = NULL;
11177dd7cddfSDavid du Colombier     f->log_curr_blk->phys_blk = pphys;
11187dd7cddfSDavid du Colombier     f->log_curr_blk->phys_pdata = NULL;
11197dd7cddfSDavid du Colombier     f->log_curr_blk->raw_block = NULL;
11207dd7cddfSDavid du Colombier 
11217dd7cddfSDavid du Colombier     f->pdata = pphys->data;
11227dd7cddfSDavid du Colombier     f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
11237dd7cddfSDavid du Colombier 
11247dd7cddfSDavid du Colombier     f->error_code = 0;
11257dd7cddfSDavid du Colombier 
11267dd7cddfSDavid du Colombier     return 0;
11277dd7cddfSDavid du Colombier }
1128