Files

130 lines
5.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*$Source: /usr/home/dhesi/zoo/RCS/io.c,v $*/
/*$Id: io.c,v 1.14 91/07/09 01:39:54 dhesi Exp $*/
/***********************************************************
io.c -- input/output (modified for in-memory I/O)
Adapted from Haruhiko Okumuras “ar” archiver.
This version feeds compressed bytes from a memory buffer
(via mem_getc()) and writes decompressed output to a buffer
(via mem_putc()), eliminating FILE* dependencies.
Modified for in-memory decompression by Natalia Portillo, 2025
***********************************************************/
#include <limits.h> // Provides CHAR_BIT for bit-width operations
#include "ar.h" // Archive format constants (e.g., CODE_BIT, NC)
#include "lh5.h" // Declarations for mem_getc(), mem_putc(), buffer state
#include "lzh.h" // LZH algorithm constants (e.g., BITBUFSIZ, DICSIZ)
//-----------------------------------------------------------------------------
// Global bit-I/O state
//-----------------------------------------------------------------------------
uint16_t bitbuf; // Accumulates bits shifted in from the input stream
int unpackable; // Unused in decompression here (was for encode error)
// Byte counters (optional diagnostics; not used to gate decompression)
size_t compsize; // Count of output bytes produced (for compression mode)
size_t origsize; // Count of input bytes consumed (for CRC in file I/O)
uint32_t subbitbuf; // Holds the last byte fetched; bits are consumed from here
int bitcount; // How many valid bits remain in subbitbuf
//-----------------------------------------------------------------------------
// fillbuf(n)
// Shift the global bitbuf left by n bits, then read in n new bits
// from the input buffer (in-memory) to replenish bitbuf.
//-----------------------------------------------------------------------------
void fillbuf(int n) /* Shift bitbuf n bits left, read n bits */
{
// Make room for n bits
bitbuf <<= n;
// While we still need more bits than we have in subbitbuf...
while(n > bitcount)
{
// Pull any remaining bits from subbitbuf into bitbuf
bitbuf |= subbitbuf << (n -= bitcount);
// Fetch the next compressed byte from input memory
{
int c = mem_getc(); // read one byte or 0 at EOF
subbitbuf = (c == EOF ? 0 : (uint8_t)c);
}
// Reset bitcount: a full new byte is available
bitcount = CHAR_BIT;
}
// Finally, consume the last n bits from subbitbuf into bitbuf
bitbuf |= subbitbuf >> (bitcount -= n);
}
//-----------------------------------------------------------------------------
// getbits(n)
// Return the next n bits from bitbuf (highest-order bits), then
// call fillbuf(n) to replace them. Useful for reading variable-length codes.
//-----------------------------------------------------------------------------
uint32_t getbits(int n)
{
uint32_t x = bitbuf >> (BITBUFSIZ - n); // extract top n bits
fillbuf(n); // replenish bitbuf for future reads
return x;
}
//-----------------------------------------------------------------------------
// putbits(n, x)
// Write the lowest n bits of x into the output buffer, packing them
// into bytes via subbitbuf/bitcount and sending full bytes out
// with mem_putc(). Used by the encoder; kept here for completeness.
//-----------------------------------------------------------------------------
void putbits(int n, uint32_t x) /* Write rightmost n bits of x */
{
// If we have enough room in subbitbuf, just pack the bits
if(n < bitcount) { subbitbuf |= x << (bitcount -= n); }
else
{
// Output the first full byte when subbitbuf fills
{
int w = (int)(subbitbuf | (x >> (n -= bitcount)));
mem_putc(w);
compsize++; // increment output counter (for compression)
}
// If remaining bits don't fill a full byte, stash them
if(n < CHAR_BIT) { subbitbuf = x << (bitcount = CHAR_BIT - n); }
else
{
// Otherwise, flush a second full byte
{
int w2 = (int)(x >> (n - CHAR_BIT));
mem_putc(w2);
compsize++;
}
// And stash any leftover bits beyond two bytes
subbitbuf = x << (bitcount = 2 * CHAR_BIT - n);
}
}
}
//-----------------------------------------------------------------------------
// init_getbits()
// Reset the bit-reader state so that fillbuf() will load fresh bits
// from the start of the input buffer.
//-----------------------------------------------------------------------------
void init_getbits()
{
bitbuf = 0; // clear accumulated bits
subbitbuf = 0; // no pending byte
bitcount = 0; // no bits available
fillbuf(BITBUFSIZ); // pre-load the bit buffer fully
}
//-----------------------------------------------------------------------------
// init_putbits()
// Reset the bit-writer state so subsequent putbits() calls start fresh.
//-----------------------------------------------------------------------------
void init_putbits()
{
bitcount = CHAR_BIT; // subbitbuf is empty but ready for CHAR_BIT bits
subbitbuf = 0; // clear any leftover byte data
}