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