2025-08-26 01:02:06 +01:00
|
|
|
|
/*$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)
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
Adapted from Haruhiko Okumura’s “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
|
2025-08-26 01:02:06 +01:00
|
|
|
|
***********************************************************/
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
#include <limits.h> // Provides CHAR_BIT for bit-width operations
|
2025-08-26 01:02:06 +01:00
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
#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)
|
2025-08-26 01:02:06 +01:00
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// Global bit-I/O state
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-08-26 01:02:06 +01:00
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
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
|
2025-08-26 01:02:06 +01:00
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-08-26 01:02:06 +01:00
|
|
|
|
void fillbuf(int n) /* Shift bitbuf n bits left, read n bits */
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// Make room for n bits
|
2025-08-26 01:02:06 +01:00
|
|
|
|
bitbuf <<= n;
|
2025-08-26 02:06:19 +01:00
|
|
|
|
|
|
|
|
|
|
// While we still need more bits than we have in subbitbuf...
|
2025-08-26 01:02:06 +01:00
|
|
|
|
while(n > bitcount)
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// Pull any remaining bits from subbitbuf into bitbuf
|
2025-08-26 01:02:06 +01:00
|
|
|
|
bitbuf |= subbitbuf << (n -= bitcount);
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// Fetch the next compressed byte from input memory
|
2025-08-26 01:02:06 +01:00
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
int c = mem_getc(); // read one byte or 0 at EOF
|
2025-08-26 01:02:06 +01:00
|
|
|
|
subbitbuf = (c == EOF ? 0 : (uint8_t)c);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// Reset bitcount: a full new byte is available
|
2025-08-26 01:02:06 +01:00
|
|
|
|
bitcount = CHAR_BIT;
|
|
|
|
|
|
}
|
2025-08-26 02:06:19 +01:00
|
|
|
|
|
|
|
|
|
|
// Finally, consume the last n bits from subbitbuf into bitbuf
|
2025-08-26 01:02:06 +01:00
|
|
|
|
bitbuf |= subbitbuf >> (bitcount -= n);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-08-26 01:02:06 +01:00
|
|
|
|
uint32_t getbits(int n)
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
uint32_t x = bitbuf >> (BITBUFSIZ - n); // extract top n bits
|
|
|
|
|
|
fillbuf(n); // replenish bitbuf for future reads
|
2025-08-26 01:02:06 +01:00
|
|
|
|
return x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-08-26 01:02:06 +01:00
|
|
|
|
void putbits(int n, uint32_t x) /* Write rightmost n bits of x */
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// If we have enough room in subbitbuf, just pack the bits
|
2025-08-26 01:02:06 +01:00
|
|
|
|
if(n < bitcount) { subbitbuf |= x << (bitcount -= n); }
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// Output the first full byte when subbitbuf fills
|
2025-08-26 01:02:06 +01:00
|
|
|
|
{
|
|
|
|
|
|
int w = (int)(subbitbuf | (x >> (n -= bitcount)));
|
|
|
|
|
|
mem_putc(w);
|
2025-08-26 02:06:19 +01:00
|
|
|
|
compsize++; // increment output counter (for compression)
|
2025-08-26 01:02:06 +01:00
|
|
|
|
}
|
2025-08-26 02:06:19 +01:00
|
|
|
|
|
|
|
|
|
|
// If remaining bits don't fill a full byte, stash them
|
2025-08-26 01:02:06 +01:00
|
|
|
|
if(n < CHAR_BIT) { subbitbuf = x << (bitcount = CHAR_BIT - n); }
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// Otherwise, flush a second full byte
|
2025-08-26 01:02:06 +01:00
|
|
|
|
{
|
|
|
|
|
|
int w2 = (int)(x >> (n - CHAR_BIT));
|
|
|
|
|
|
mem_putc(w2);
|
|
|
|
|
|
compsize++;
|
|
|
|
|
|
}
|
2025-08-26 02:06:19 +01:00
|
|
|
|
// And stash any leftover bits beyond two bytes
|
2025-08-26 01:02:06 +01:00
|
|
|
|
subbitbuf = x << (bitcount = 2 * CHAR_BIT - n);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// init_getbits()
|
|
|
|
|
|
// Reset the bit-reader state so that fillbuf() will load fresh bits
|
|
|
|
|
|
// from the start of the input buffer.
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-08-26 01:02:06 +01:00
|
|
|
|
void init_getbits()
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
bitbuf = 0; // clear accumulated bits
|
|
|
|
|
|
subbitbuf = 0; // no pending byte
|
|
|
|
|
|
bitcount = 0; // no bits available
|
|
|
|
|
|
fillbuf(BITBUFSIZ); // pre-load the bit buffer fully
|
2025-08-26 01:02:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 02:06:19 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// init_putbits()
|
|
|
|
|
|
// Reset the bit-writer state so subsequent putbits() calls start fresh.
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-08-26 01:02:06 +01:00
|
|
|
|
void init_putbits()
|
|
|
|
|
|
{
|
2025-08-26 02:06:19 +01:00
|
|
|
|
bitcount = CHAR_BIT; // subbitbuf is empty but ready for CHAR_BIT bits
|
|
|
|
|
|
subbitbuf = 0; // clear any leftover byte data
|
2025-08-26 01:02:06 +01:00
|
|
|
|
}
|