SBSPSS/source/utils/lznp.cpp
2001-07-04 15:34:35 +00:00

94 lines
2.2 KiB
C++

/*
Program: unlznp.c
Author: Nick Pelling
Function: Decompresses an LZNP-compressed file
Note: Copyright (c) 1993-1994 Nick Pelling. All rights reserved.
*/
/*
Notes:
The basic procedure is:
(a) Read a control byte, and examine each bit in turn, LSB...MSB
(b) if bit is clear, copy a byte from input stream
(c) ...else read another byte in.
if >= 0x60, this means "copy a pair from nearby"
(d) ...else split it up into a length, and high 4 bits of offset
(e) read the low order 8 bits, and merge to form (-ve) offset
(f) if (offset == 0), then exit: this terminates decompression
(g) if length is maximum length, read superlength from next byte
(h) copy length bytes from (-ve) offset. Note: this may overlap!
(i) If no more bits in control byte, read another control byte
(j) Loop.
...and that's it.
*/
#include "lznp.h"
#define SMALLEST_LEN 2 /* smallest len usable at all */
#define MIN_LEN 3 /* smallest short length encodable */
#define MAX_LEN (MIN_LEN + 6-2) /* largest short length encodable */
#define MIN_SUPERLEN (MIN_LEN + 6-1) /* shortest long length encodable */
#define MAX_SUPERLEN (MIN_SUPERLEN + 254) /* largest long length encodable */
#define SUPERLEN_CODE (MIN_SUPERLEN - MIN_LEN) /* means "read superlength" */
typedef unsigned char UBYTE; /* just for convenience */
int LZNP_Decode(UBYTE *in, UBYTE *out)
{
int i, j;
unsigned int flags; /* now works with 16-bit ints */
UBYTE * OriginalOut=out;
for (flags=0;;)
{
if (((flags >>= 1) & 0xff00) == 0)
{
flags = (*in++) | 0xff00; /* uses higher byte cleverly */
} /* (to count eight) */
if (!(flags & 1))
{
*out++ = *in++;
}
else
{
i = *in++;
if (i >= 0x60)
{
i = 0x100 - i; /* i = copy offset */
j = SMALLEST_LEN; /* j = copy length */
}
else
{
j = i >> 4;
i = (i & 0x0F) << 8;
i |= *in++;
if (i == 0) /* offset of zero terminates LZNP data */
break;
if (j != SUPERLEN_CODE)
j += MIN_LEN;
else
j = MIN_SUPERLEN + (*in++);
}
for (i=-i,j++; --j; out++)
{
out[0] = out[i];
}
}
}
/* Return size */
return(out-OriginalOut);
}