diff options
Diffstat (limited to 'converter/other/fiasco/lib/bit-io.c')
-rw-r--r-- | converter/other/fiasco/lib/bit-io.c | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c new file mode 100644 index 00000000..364a1c05 --- /dev/null +++ b/converter/other/fiasco/lib/bit-io.c @@ -0,0 +1,327 @@ +/* + * bit-io.c: Buffered and bit oriented file I/O + * + * Written by: Ullrich Hafner + * + * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) + * Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de> + */ + +/* + * $Date: 2000/06/14 20:49:37 $ + * $Author: hafner $ + * $Revision: 5.1 $ + * $State: Exp $ + */ + +#define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + +#include "config.h" + +#include <string.h> +#if STDC_HEADERS +# include <stdlib.h> +#endif /* not STDC_HEADERS */ + +#include "macros.h" +#include "types.h" +#include "error.h" + +#include "misc.h" +#include "bit-io.h" + +/***************************************************************************** + + local constants + +*****************************************************************************/ + +static const unsigned BUFFER_SIZE = 16350; + +static const unsigned mask[] = {0x0001, 0x0002, 0x0004, 0x0008, + 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, + 0x1000, 0x2000, 0x4000, 0x8000}; + +/***************************************************************************** + + public code + +*****************************************************************************/ + +FILE * +open_file (const char *filename, const char *env_var, openmode_e mode) +/* + * Try to open file 'filename' with mode 'mode' (READ_ACCESS, WRITE_ACCESS). + * Scan the current directory first and then cycle through the + * path given in the environment variable 'env_var', if set. + * + * Return value: + * Pointer to open file on success, else NULL. + */ +{ + char *path; /* current path */ + FILE *fp; /* file pointer of I/O stream */ + char *ext_filename = NULL; /* full path of file */ + char *env_path = NULL; /* path given by 'env_var' */ + char const * const PATH_SEP = " ;:,"; /* path separation characters */ + char const * const DEFAULT_PATH = "."; /* default for output files */ + const char * const read_mode = "rb"; + const char * const write_mode = "wb"; + + + assert (mode == READ_ACCESS || mode == WRITE_ACCESS); + + /* + * First check for stdin or stdout + */ + if (filename == NULL || streq (filename, "-")) + { + if (mode == READ_ACCESS) + return stdin; + else + return stdout; + } + + /* + * Try to open 'readonly' file in the current directory + */ + if (mode == READ_ACCESS && (fp = fopen (filename, read_mode))) + return fp; + + if (mode == WRITE_ACCESS && strchr (filename, '/')) /* contains path */ + return fopen (filename, write_mode); + + /* + * Get value of environment variable 'env_var', if set + * else use DEFAULT_PATH ("./") + */ + if (env_var != NULL) + env_path = getenv (env_var); + if (env_path == NULL) + env_path = strdup (DEFAULT_PATH); + else + env_path = strdup (env_path); + + /* + * Try to open file in the directory given by the environment + * variable env_var - individual path components are separated by PATH_SEP + */ + path = strtok (env_path, PATH_SEP); + do + { + if (ext_filename) + Free (ext_filename); + ext_filename = Calloc (strlen (path) + strlen (filename) + 2, + sizeof (char)); + strcpy (ext_filename, path); + if (*(ext_filename + strlen (ext_filename) - 1) != '/') + strcat (ext_filename, "/"); + strcat (ext_filename, filename); + fp = fopen (ext_filename, mode == READ_ACCESS ? read_mode : write_mode); + } + while (fp == NULL && (path = strtok (NULL, PATH_SEP)) != NULL); + + Free (env_path); + + return fp; +} + +bitfile_t * +open_bitfile (const char *filename, const char *env_var, openmode_e mode) +/* + * Bitfile constructor: + * Try to open file 'filename' for buffered bit oriented access with mode + * 'mode'. Scan the current directory first and then cycle through the path + * given in the environment variable 'env_var', if set. + * + * Return value: + * Pointer to open bitfile on success, + * otherwise the program is terminated. + */ +{ + bitfile_t *bitfile = Calloc (1, sizeof (bitfile_t)); + + bitfile->file = open_file (filename, env_var, mode); + + if (bitfile->file == NULL) + file_error (filename); + + if (mode == READ_ACCESS) + { + bitfile->bytepos = 0; + bitfile->bitpos = 0; + bitfile->mode = mode; + bitfile->filename = filename ? strdup (filename) : strdup ("(stdin)"); + } + else if (mode == WRITE_ACCESS) + { + bitfile->bytepos = BUFFER_SIZE - 1; + bitfile->bitpos = 8; + bitfile->mode = mode; + bitfile->filename = filename ? strdup (filename) : strdup ("(stdout)"); + } + else + error ("Unknow file access mode '%d'.", mode); + + bitfile->bits_processed = 0; + bitfile->buffer = Calloc (BUFFER_SIZE, sizeof (byte_t)); + bitfile->ptr = bitfile->buffer; + + return bitfile; +} + +bool_t +get_bit (bitfile_t *bitfile) +/* + * Get one bit from the given stream 'bitfile'. + * + * Return value: + * 1 H bit + * 0 L bit + * + * Side effects: + * Buffer of 'bitfile' is modified accordingly. + */ +{ + assert (bitfile); + + if (!bitfile->bitpos--) /* use next byte ? */ + { + bitfile->ptr++; + if (!bitfile->bytepos--) /* no more bytes left in the buffer? */ + { + /* + * Fill buffer with new data + */ + int bytes = fread (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE, bitfile->file) - 1; + if (bytes < 0) /* Error or EOF */ + error ("Can't read next bit from bitfile %s.", bitfile->filename); + else + bitfile->bytepos = bytes; + + bitfile->ptr = bitfile->buffer; + } + bitfile->bitpos = 7; + } + + bitfile->bits_processed++; + + return *bitfile->ptr & mask [bitfile->bitpos] ? 1 : 0; +} + +unsigned int +get_bits (bitfile_t *bitfile, unsigned bits) +/* + * Get #'bits' bits from the given stream 'bitfile'. + * + * Return value: + * composed integer value + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + unsigned value = 0; /* input value */ + + while (bits--) + value = (unsigned) (value << 1) | get_bit (bitfile); + + return value; +} + +void +put_bit (bitfile_t *bitfile, unsigned value) +/* + * Put the bit 'value' to the bitfile buffer. + * The buffer is written to the file 'bitfile->file' if the number of + * buffer bytes exceeds 'BUFFER_SIZE'. + * + * No return value. + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + assert (bitfile); + + if (!bitfile->bitpos--) /* use next byte ? */ + { + bitfile->ptr++; + if (!bitfile->bytepos--) /* no more bytes left ? */ + { + /* + * Write buffer to disk and fill buffer with zeros + */ + if (fwrite (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE, bitfile->file) != BUFFER_SIZE) + error ("Can't write next bit of bitfile %s!", bitfile->filename); + memset (bitfile->buffer, 0, BUFFER_SIZE); + bitfile->bytepos = BUFFER_SIZE - 1; + bitfile->ptr = bitfile->buffer; + } + bitfile->bitpos = 7; + } + + if (value) + *bitfile->ptr |= mask [bitfile->bitpos]; + + bitfile->bits_processed++; +} + +void +put_bits (bitfile_t *bitfile, unsigned value, unsigned bits) +/* + * Put #'bits' bits of integer 'value' to the bitfile buffer 'bitfile'. + * + * No return value. + * + * Side effects: + * Buffer of 'bitfile' is modified. + */ +{ + while (bits--) + put_bit (bitfile, value & mask [bits]); +} + +void +close_bitfile (bitfile_t *bitfile) +/* + * Bitfile destructor: + * Close 'bitfile', if 'bitfile->mode' == WRITE_ACCESS write bit buffer + * to disk. + * + * No return value. + * + * Side effects: + * Structure 'bitfile' is discarded. + */ +{ + assert (bitfile); + + if (bitfile->mode == WRITE_ACCESS) + { + unsigned bytes = fwrite (bitfile->buffer, sizeof (byte_t), + BUFFER_SIZE - bitfile->bytepos, bitfile->file); + if (bytes != BUFFER_SIZE - bitfile->bytepos) + error ("Can't write remaining %d bytes of bitfile " + "(only %d bytes written)!", + BUFFER_SIZE - bitfile->bytepos, bytes); + } + fclose (bitfile->file); + Free (bitfile->buffer); + Free (bitfile->filename); + Free (bitfile); +} + +unsigned +bits_processed (const bitfile_t *bitfile) +/* + * Return value: + * Number of bits processed up to now + */ +{ + return bitfile->bits_processed; +} |