Move the LZW compression functions out of cache1d.cpp into their own object, klzw.cpp.

This eliminates the hackiness of libcache1d.so (now libkzlw.so) and CACHE1D_COMPRESS_ONLY.

git-svn-id: https://svn.eduke32.com/eduke32@7140 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
hendricks266 2018-11-05 07:28:07 +00:00
parent de5d358d32
commit fd175086a3
7 changed files with 411 additions and 362 deletions

View file

@ -165,6 +165,7 @@ engine_objs := \
rev.cpp \ rev.cpp \
baselayer.cpp \ baselayer.cpp \
cache1d.cpp \ cache1d.cpp \
klzw.cpp \
common.cpp \ common.cpp \
compat.cpp \ compat.cpp \
crc32.cpp \ crc32.cpp \
@ -211,6 +212,7 @@ engine_tools_objs := \
pragmas.cpp \ pragmas.cpp \
kplib.cpp \ kplib.cpp \
cache1d.cpp \ cache1d.cpp \
klzw.cpp \
crc32.cpp \ crc32.cpp \
colmatch.cpp \ colmatch.cpp \
lz4.cpp \ lz4.cpp \
@ -890,9 +892,9 @@ $(ebacktrace_dll): platform/Windows/src/backtrace.c
$(COMPILE_STATUS) $(COMPILE_STATUS)
$(RECIPE_IF) $(CC) $(CONLYFLAGS) -O2 -ggdb -shared -Wall -Wextra -static-libgcc -I$(engine_inc) -o $@ $^ -lbfd -liberty -limagehlp $(RECIPE_RESULT_COMPILE) $(RECIPE_IF) $(CC) $(CONLYFLAGS) -O2 -ggdb -shared -Wall -Wextra -static-libgcc -I$(engine_inc) -o $@ $^ -lbfd -liberty -limagehlp $(RECIPE_RESULT_COMPILE)
libcache1d$(DLLSUFFIX): $(engine_src)/cache1d.cpp libklzw$(DLLSUFFIX): $(engine_src)/klzw.cpp
$(COMPILE_STATUS) $(COMPILE_STATUS)
$(RECIPE_IF) $(COMPILER_C) -DCACHE1D_COMPRESS_ONLY -shared -fPIC $< -o $@ $(RECIPE_RESULT_COMPILE) $(RECIPE_IF) $(COMPILER_C) -shared -fPIC $< -o $@ $(RECIPE_RESULT_COMPILE)
# to debug the tools link phase, make a copy of this rule explicitly replacing % with the name of a tool, such as kextract # to debug the tools link phase, make a copy of this rule explicitly replacing % with the name of a tool, such as kextract
%$(EXESUFFIX): $(tools_obj)/%.$o $(foreach i,tools $(tools_deps),$(call expandobjs,$i)) %$(EXESUFFIX): $(tools_obj)/%.$o $(foreach i,tools $(tools_deps),$(call expandobjs,$i))

View file

@ -225,6 +225,7 @@
<ClCompile Include="..\..\source\build\src\hash.cpp" /> <ClCompile Include="..\..\source\build\src\hash.cpp" />
<ClCompile Include="..\..\source\build\src\hightile.cpp" /> <ClCompile Include="..\..\source\build\src\hightile.cpp" />
<ClCompile Include="..\..\source\build\src\jwzgles.c" /> <ClCompile Include="..\..\source\build\src\jwzgles.c" />
<ClCompile Include="..\..\source\build\src\klzw.cpp" />
<ClCompile Include="..\..\source\build\src\kplib.cpp" /> <ClCompile Include="..\..\source\build\src\kplib.cpp" />
<ClCompile Include="..\..\source\build\src\lunatic.cpp"> <ClCompile Include="..\..\source\build\src\lunatic.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -334,6 +335,7 @@
<ClInclude Include="..\..\source\build\include\hightile.h" /> <ClInclude Include="..\..\source\build\include\hightile.h" />
<ClInclude Include="..\..\source\build\include\jwzgles.h" /> <ClInclude Include="..\..\source\build\include\jwzgles.h" />
<ClInclude Include="..\..\source\build\include\jwzglesI.h" /> <ClInclude Include="..\..\source\build\include\jwzglesI.h" />
<ClInclude Include="..\..\source\build\include\klzw.h" />
<ClInclude Include="..\..\source\build\include\kplib.h" /> <ClInclude Include="..\..\source\build\include\kplib.h" />
<ClInclude Include="..\..\source\build\include\libdivide.h" /> <ClInclude Include="..\..\source\build\include\libdivide.h" />
<ClInclude Include="..\..\source\build\include\lz4.h" /> <ClInclude Include="..\..\source\build\include\lz4.h" />

View file

@ -77,6 +77,9 @@
<ClCompile Include="..\..\source\build\src\jwzgles.c"> <ClCompile Include="..\..\source\build\src\jwzgles.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\source\build\src\klzw.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\build\src\kplib.cpp"> <ClCompile Include="..\..\source\build\src\kplib.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -274,6 +277,9 @@
<ClInclude Include="..\..\source\build\include\jwzglesI.h"> <ClInclude Include="..\..\source\build\include\jwzglesI.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\source\build\include\klzw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\build\include\kplib.h"> <ClInclude Include="..\..\source\build\include\kplib.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>

View file

@ -149,6 +149,7 @@ ENGINE_OBJS= \
$(ENGINE_OBJ)\animvpx.$o \ $(ENGINE_OBJ)\animvpx.$o \
$(ENGINE_OBJ)\baselayer.$o \ $(ENGINE_OBJ)\baselayer.$o \
$(ENGINE_OBJ)\cache1d.$o \ $(ENGINE_OBJ)\cache1d.$o \
$(ENGINE_OBJ)\klzw.$o \
$(ENGINE_OBJ)\common.$o \ $(ENGINE_OBJ)\common.$o \
$(ENGINE_OBJ)\compat.$o \ $(ENGINE_OBJ)\compat.$o \
$(ENGINE_OBJ)\crc32.$o \ $(ENGINE_OBJ)\crc32.$o \

View file

@ -0,0 +1,30 @@
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
// This file has been modified from Ken Silverman's original release
// by Jonathon Fowler (jf@jonof.id.au)
// by the EDuke32 team (development@voidpoint.com)
#ifndef klzw_h_
#define klzw_h_
#include "compat.h"
#ifdef __cplusplus
extern "C" {
#endif
// These two follow the argument order of the C functions "read" and "write":
// handle, buffer, length.
typedef int32_t (*klzw_readfunc)(intptr_t, void *, int32_t);
typedef void (*klzw_writefunc)(intptr_t, void const *, int32_t);
int32_t klzw_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f, klzw_readfunc readfunc);
void klzw_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f, klzw_writefunc writefunc);
#ifdef __cplusplus
}
#endif
#endif // klzw_h_

View file

@ -8,14 +8,6 @@
#include "compat.h" #include "compat.h"
#ifdef CACHE1D_COMPRESS_ONLY
// Standalone libcache1d.so containing only the compression/decompression
// functions.
# define C1D_STATIC
#else
// cache1d.o for EDuke32
# define C1D_STATIC static
#ifdef _WIN32 #ifdef _WIN32
// for FILENAME_CASE_CHECK // for FILENAME_CASE_CHECK
# define NEED_SHELLAPI_H # define NEED_SHELLAPI_H
@ -25,6 +17,7 @@
#include "pragmas.h" #include "pragmas.h"
#include "baselayer.h" #include "baselayer.h"
#include "lz4.h" #include "lz4.h"
#include "klzw.h"
#ifdef WITHKPLIB #ifdef WITHKPLIB
#include "kplib.h" #include "kplib.h"
@ -1595,22 +1588,6 @@ failure:
} }
#endif // #ifdef CACHE1D_COMPRESS_ONLY / else
//Internal LZW variables
#define LZWSIZE 16384 //Watch out for shorts!
#define LZWSIZEPAD (LZWSIZE+(LZWSIZE>>4))
// lzwrawbuf LZWSIZE+1 (formerly): see (*) below
// XXX: lzwrawbuf size increased again :-/
static char lzwtmpbuf[LZWSIZEPAD], lzwrawbuf[LZWSIZEPAD], lzwcompbuf[LZWSIZEPAD];
static int16_t lzwbuf2[LZWSIZEPAD], lzwbuf3[LZWSIZEPAD];
static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf);
static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf);
#ifndef CACHE1D_COMPRESS_ONLY
static int32_t kdfread_func(intptr_t fil, void *outbuf, int32_t length) static int32_t kdfread_func(intptr_t fil, void *outbuf, int32_t length)
{ {
return kread((int32_t)fil, outbuf, length); return kread((int32_t)fil, outbuf, length);
@ -1620,89 +1597,11 @@ static void dfwrite_func(intptr_t fp, const void *inbuf, int32_t length)
{ {
Bfwrite(inbuf, length, 1, (BFILE *)fp); Bfwrite(inbuf, length, 1, (BFILE *)fp);
} }
#else
# define kdfread_func NULL
# define dfwrite_func NULL
#endif
// These two follow the argument order of the C functions "read" and "write":
// handle, buffer, length.
C1D_STATIC int32_t (*c1d_readfunc)(intptr_t, void *, int32_t) = kdfread_func;
C1D_STATIC void (*c1d_writefunc)(intptr_t, const void *, int32_t) = dfwrite_func;
////////// COMPRESSED READ //////////
static uint32_t decompress_part(intptr_t f, uint32_t *kgoalptr)
{
int16_t leng;
// Read compressed length first.
if (c1d_readfunc(f, &leng, 2) != 2)
return 1;
leng = B_LITTLE16(leng);
if (c1d_readfunc(f,lzwcompbuf, leng) != leng)
return 1;
*kgoalptr = lzwuncompress(lzwcompbuf, leng, lzwrawbuf);
return 0;
}
// Read from 'f' into 'buffer'.
C1D_STATIC int32_t c1d_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f)
{
char *ptr = (char *)buffer;
if (dasizeof > LZWSIZE)
{
count *= dasizeof;
dasizeof = 1;
}
uint32_t kgoal;
if (decompress_part(f, &kgoal))
return -1;
Bmemcpy(ptr, lzwrawbuf, (int32_t)dasizeof);
uint32_t k = (int32_t)dasizeof;
for (uint32_t i=1; i<count; i++)
{
if (k >= kgoal)
{
k = decompress_part(f, &kgoal);
if (k) return -1;
}
uint32_t j = 0;
if (dasizeof >= 4)
{
for (; j<dasizeof-4; j+=4)
{
ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255);
ptr[j+1+dasizeof] = ((ptr[j+1]+lzwrawbuf[j+1+k])&255);
ptr[j+2+dasizeof] = ((ptr[j+2]+lzwrawbuf[j+2+k])&255);
ptr[j+3+dasizeof] = ((ptr[j+3]+lzwrawbuf[j+3+k])&255);
}
}
for (; j<dasizeof; j++)
ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255);
k += dasizeof;
ptr += dasizeof;
}
return count;
}
int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil) int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil)
{ {
return c1d_read_compressed(buffer, dasizeof, count, (intptr_t)fil); return klzw_read_compressed(buffer, dasizeof, count, (intptr_t)fil, kdfread_func);
} }
// LZ4_COMPRESSION_ACCELERATION_VALUE can be tuned for performance/space trade-off // LZ4_COMPRESSION_ACCELERATION_VALUE can be tuned for performance/space trade-off
@ -1712,13 +1611,12 @@ int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil)
static char compressedDataStackBuf[131072]; static char compressedDataStackBuf[131072];
int32_t lz4CompressionLevel = LZ4_COMPRESSION_ACCELERATION_VALUE; int32_t lz4CompressionLevel = LZ4_COMPRESSION_ACCELERATION_VALUE;
int32_t kdfread_LZ4(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil) int32_t kdfread_LZ4(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil)
{ {
int32_t leng; int32_t leng;
// read compressed data length // read compressed data length
if (c1d_readfunc(fil, &leng, 4) != 4) if (kread(fil, &leng, sizeof(leng)) != sizeof(leng))
return -1; return -1;
leng = B_LITTLE32(leng); leng = B_LITTLE32(leng);
@ -1728,7 +1626,7 @@ int32_t kdfread_LZ4(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil)
if (leng > ARRAY_SSIZE(compressedDataStackBuf)) if (leng > ARRAY_SSIZE(compressedDataStackBuf))
pCompressedData = (char *)Xaligned_alloc(16, leng); pCompressedData = (char *)Xaligned_alloc(16, leng);
if (c1d_readfunc(fil, pCompressedData, leng) != leng) if (kread(fil, pCompressedData, leng) != leng)
return -1; return -1;
int32_t decompressedLength = LZ4_decompress_safe(pCompressedData, (char*) buffer, leng, dasizeof*count); int32_t decompressedLength = LZ4_decompress_safe(pCompressedData, (char*) buffer, leng, dasizeof*count);
@ -1740,68 +1638,9 @@ int32_t kdfread_LZ4(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil)
} }
////////// COMPRESSED WRITE //////////
static uint32_t compress_part(uint32_t k, intptr_t f)
{
const int16_t leng = (int16_t)lzwcompress(lzwrawbuf, k, lzwcompbuf);
const int16_t swleng = B_LITTLE16(leng);
c1d_writefunc(f, &swleng, 2);
c1d_writefunc(f, lzwcompbuf, leng);
return 0;
}
// Write from 'buffer' to 'f'.
C1D_STATIC void c1d_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f)
{
char const *ptr = (char const *)buffer;
if (dasizeof > LZWSIZE)
{
count *= dasizeof;
dasizeof = 1;
}
Bmemcpy(lzwrawbuf, ptr, (int32_t)dasizeof);
uint32_t k = dasizeof;
if (k > LZWSIZE-dasizeof)
k = compress_part(k, f);
for (uint32_t i=1; i<count; i++)
{
uint32_t j = 0;
if (dasizeof >= 4)
{
for (; j<dasizeof-4; j+=4)
{
lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255);
lzwrawbuf[j+1+k] = ((ptr[j+1+dasizeof]-ptr[j+1])&255);
lzwrawbuf[j+2+k] = ((ptr[j+2+dasizeof]-ptr[j+2])&255);
lzwrawbuf[j+3+k] = ((ptr[j+3+dasizeof]-ptr[j+3])&255);
}
}
for (; j<dasizeof; j++)
lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255);
k += dasizeof;
if (k > LZWSIZE-dasizeof)
k = compress_part(k, f);
ptr += dasizeof;
}
if (k > 0)
compress_part(k, f);
}
void dfwrite(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil) void dfwrite(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil)
{ {
c1d_write_compressed(buffer, dasizeof, count, (intptr_t)fil); klzw_write_compressed(buffer, dasizeof, count, (intptr_t)fil, dfwrite_func);
} }
void dfwrite_LZ4(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil) void dfwrite_LZ4(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil)
@ -1815,201 +1654,9 @@ void dfwrite_LZ4(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil
int32_t const leng = LZ4_compress_fast((const char*) buffer, pCompressedData, dasizeof*count, maxCompressedSize, lz4CompressionLevel); int32_t const leng = LZ4_compress_fast((const char*) buffer, pCompressedData, dasizeof*count, maxCompressedSize, lz4CompressionLevel);
int32_t const swleng = B_LITTLE32(leng); int32_t const swleng = B_LITTLE32(leng);
c1d_writefunc((intptr_t) fil, &swleng, 4); Bfwrite(&swleng, sizeof(swleng), 1, fil);
c1d_writefunc((intptr_t) fil, pCompressedData, leng); Bfwrite(pCompressedData, leng, 1, fil);
if (pCompressedData != compressedDataStackBuf) if (pCompressedData != compressedDataStackBuf)
Baligned_free(pCompressedData); Baligned_free(pCompressedData);
} }
////////// CORE COMPRESSION FUNCTIONS //////////
static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf)
{
int32_t i, addr, addrcnt, *intptr;
int32_t bytecnt1, bitcnt, numbits, oneupnumbits;
int16_t *shortptr;
int16_t *const lzwcodehead = lzwbuf2;
int16_t *const lzwcodenext = lzwbuf3;
for (i=255; i>=4; i-=4)
{
lzwtmpbuf[i] = i, lzwcodenext[i] = (i+1)&255;
lzwtmpbuf[i-1] = i-1, lzwcodenext[i-1] = (i) &255;
lzwtmpbuf[i-2] = i-2, lzwcodenext[i-2] = (i-1)&255;
lzwtmpbuf[i-3] = i-3, lzwcodenext[i-3] = (i-2)&255;
lzwcodehead[i] = lzwcodehead[i-1] = lzwcodehead[i-2] = lzwcodehead[i-3] = -1;
}
for (; i>=0; i--)
{
lzwtmpbuf[i] = i;
lzwcodenext[i] = (i+1)&255;
lzwcodehead[i] = -1;
}
Bmemset(lzwoutbuf, 0, 4+uncompleng+1);
// clearbuf(lzwoutbuf,((uncompleng+15)+3)>>2,0L);
addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3);
numbits = 8; oneupnumbits = (1<<8);
do
{
addr = lzwinbuf[bytecnt1];
do
{
int32_t newaddr;
if (++bytecnt1 == uncompleng)
break; // (*) see XXX below
if (lzwcodehead[addr] < 0)
{
lzwcodehead[addr] = addrcnt;
break;
}
newaddr = lzwcodehead[addr];
while (lzwtmpbuf[newaddr] != lzwinbuf[bytecnt1])
{
if (lzwcodenext[newaddr] < 0)
{
lzwcodenext[newaddr] = addrcnt;
break;
}
newaddr = lzwcodenext[newaddr];
}
if (lzwcodenext[newaddr] == addrcnt)
break;
addr = newaddr;
}
while (addr >= 0);
lzwtmpbuf[addrcnt] = lzwinbuf[bytecnt1]; // XXX: potential oob access of lzwinbuf via (*) above
lzwcodehead[addrcnt] = -1;
lzwcodenext[addrcnt] = -1;
intptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
intptr[0] |= B_LITTLE32(addr<<(bitcnt&7));
bitcnt += numbits;
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
bitcnt--;
addrcnt++;
if (addrcnt > oneupnumbits)
{ numbits++; oneupnumbits <<= 1; }
}
while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3)));
intptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
intptr[0] |= B_LITTLE32(addr<<(bitcnt&7));
bitcnt += numbits;
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
bitcnt--;
shortptr = (int16_t *)lzwoutbuf;
shortptr[0] = B_LITTLE16((int16_t)uncompleng);
if (((bitcnt+7)>>3) < uncompleng)
{
shortptr[1] = B_LITTLE16((int16_t)addrcnt);
return (bitcnt+7)>>3;
}
// Failed compressing, mark this in the stream.
shortptr[1] = 0;
for (i=0; i<uncompleng-4; i+=4)
{
lzwoutbuf[i+4] = lzwinbuf[i];
lzwoutbuf[i+5] = lzwinbuf[i+1];
lzwoutbuf[i+6] = lzwinbuf[i+2];
lzwoutbuf[i+7] = lzwinbuf[i+3];
}
for (; i<uncompleng; i++)
lzwoutbuf[i+4] = lzwinbuf[i];
return uncompleng+4;
}
static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf)
{
int32_t currstr, numbits, oneupnumbits;
int32_t i, bitcnt, outbytecnt;
const int16_t *const shortptr = (const int16_t *)lzwinbuf;
const int32_t strtot = B_LITTLE16(shortptr[1]);
const int32_t uncompleng = B_LITTLE16(shortptr[0]);
if (strtot == 0)
{
if (lzwoutbuf==lzwrawbuf && lzwinbuf==lzwcompbuf)
{
Bassert((compleng-4)+3+0u < sizeof(lzwrawbuf));
Bassert((compleng-4)+3+0u < sizeof(lzwcompbuf)-4);
}
Bmemcpy(lzwoutbuf, lzwinbuf+4, (compleng-4)+3);
return uncompleng;
}
for (i=255; i>=4; i-=4)
{
lzwbuf2[i] = lzwbuf3[i] = i;
lzwbuf2[i-1] = lzwbuf3[i-1] = i-1;
lzwbuf2[i-2] = lzwbuf3[i-2] = i-2;
lzwbuf2[i-3] = lzwbuf3[i-3] = i-3;
}
lzwbuf2[i] = lzwbuf3[i] = i;
lzwbuf2[i-1] = lzwbuf3[i-1] = i-1;
lzwbuf2[i-2] = lzwbuf3[i-2] = i-2;
currstr = 256; bitcnt = (4<<3); outbytecnt = 0;
numbits = 8; oneupnumbits = (1<<8);
do
{
const int32_t *const intptr = (const int32_t *)&lzwinbuf[bitcnt>>3];
int32_t dat = ((B_LITTLE32(intptr[0])>>(bitcnt&7)) & (oneupnumbits-1));
int32_t leng;
bitcnt += numbits;
if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1)))
{ dat &= ((oneupnumbits>>1)-1); bitcnt--; }
lzwbuf3[currstr] = dat;
for (leng=0; dat>=256; leng++,dat=lzwbuf3[dat])
lzwtmpbuf[leng] = lzwbuf2[dat];
lzwoutbuf[outbytecnt++] = dat;
for (i=leng-1; i>=4; i-=4, outbytecnt+=4)
{
lzwoutbuf[outbytecnt] = lzwtmpbuf[i];
lzwoutbuf[outbytecnt+1] = lzwtmpbuf[i-1];
lzwoutbuf[outbytecnt+2] = lzwtmpbuf[i-2];
lzwoutbuf[outbytecnt+3] = lzwtmpbuf[i-3];
}
for (; i>=0; i--)
lzwoutbuf[outbytecnt++] = lzwtmpbuf[i];
lzwbuf2[currstr-1] = dat; lzwbuf2[currstr] = dat;
currstr++;
if (currstr > oneupnumbits)
{ numbits++; oneupnumbits <<= 1; }
}
while (currstr < strtot);
return uncompleng;
}
/*
* vim:ts=4:sw=4:
*/

361
source/build/src/klzw.cpp Normal file
View file

@ -0,0 +1,361 @@
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
// This file has been modified from Ken Silverman's original release
// by Jonathon Fowler (jf@jonof.id.au)
// by the EDuke32 team (development@voidpoint.com)
#include "compat.h"
#include "klzw.h"
//Internal LZW variables
#define LZWSIZE 16384 //Watch out for shorts!
#define LZWSIZEPAD (LZWSIZE+(LZWSIZE>>4))
// lzwrawbuf LZWSIZE+1 (formerly): see (*) below
// XXX: lzwrawbuf size increased again :-/
static char lzwtmpbuf[LZWSIZEPAD], lzwrawbuf[LZWSIZEPAD], lzwcompbuf[LZWSIZEPAD];
static int16_t lzwbuf2[LZWSIZEPAD], lzwbuf3[LZWSIZEPAD];
////////// CORE COMPRESSION FUNCTIONS //////////
static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf)
{
int32_t i, addr, addrcnt, *intptr;
int32_t bytecnt1, bitcnt, numbits, oneupnumbits;
int16_t *shortptr;
int16_t *const lzwcodehead = lzwbuf2;
int16_t *const lzwcodenext = lzwbuf3;
for (i=255; i>=4; i-=4)
{
lzwtmpbuf[i] = i, lzwcodenext[i] = (i+1)&255;
lzwtmpbuf[i-1] = i-1, lzwcodenext[i-1] = (i) &255;
lzwtmpbuf[i-2] = i-2, lzwcodenext[i-2] = (i-1)&255;
lzwtmpbuf[i-3] = i-3, lzwcodenext[i-3] = (i-2)&255;
lzwcodehead[i] = lzwcodehead[i-1] = lzwcodehead[i-2] = lzwcodehead[i-3] = -1;
}
for (; i>=0; i--)
{
lzwtmpbuf[i] = i;
lzwcodenext[i] = (i+1)&255;
lzwcodehead[i] = -1;
}
Bmemset(lzwoutbuf, 0, 4+uncompleng+1);
// clearbuf(lzwoutbuf,((uncompleng+15)+3)>>2,0L);
addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3);
numbits = 8; oneupnumbits = (1<<8);
do
{
addr = lzwinbuf[bytecnt1];
do
{
int32_t newaddr;
if (++bytecnt1 == uncompleng)
break; // (*) see XXX below
if (lzwcodehead[addr] < 0)
{
lzwcodehead[addr] = addrcnt;
break;
}
newaddr = lzwcodehead[addr];
while (lzwtmpbuf[newaddr] != lzwinbuf[bytecnt1])
{
if (lzwcodenext[newaddr] < 0)
{
lzwcodenext[newaddr] = addrcnt;
break;
}
newaddr = lzwcodenext[newaddr];
}
if (lzwcodenext[newaddr] == addrcnt)
break;
addr = newaddr;
}
while (addr >= 0);
lzwtmpbuf[addrcnt] = lzwinbuf[bytecnt1]; // XXX: potential oob access of lzwinbuf via (*) above
lzwcodehead[addrcnt] = -1;
lzwcodenext[addrcnt] = -1;
intptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
intptr[0] |= B_LITTLE32(addr<<(bitcnt&7));
bitcnt += numbits;
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
bitcnt--;
addrcnt++;
if (addrcnt > oneupnumbits)
{ numbits++; oneupnumbits <<= 1; }
}
while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3)));
intptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
intptr[0] |= B_LITTLE32(addr<<(bitcnt&7));
bitcnt += numbits;
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
bitcnt--;
shortptr = (int16_t *)lzwoutbuf;
shortptr[0] = B_LITTLE16((int16_t)uncompleng);
if (((bitcnt+7)>>3) < uncompleng)
{
shortptr[1] = B_LITTLE16((int16_t)addrcnt);
return (bitcnt+7)>>3;
}
// Failed compressing, mark this in the stream.
shortptr[1] = 0;
for (i=0; i<uncompleng-4; i+=4)
{
lzwoutbuf[i+4] = lzwinbuf[i];
lzwoutbuf[i+5] = lzwinbuf[i+1];
lzwoutbuf[i+6] = lzwinbuf[i+2];
lzwoutbuf[i+7] = lzwinbuf[i+3];
}
for (; i<uncompleng; i++)
lzwoutbuf[i+4] = lzwinbuf[i];
return uncompleng+4;
}
static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf)
{
int32_t currstr, numbits, oneupnumbits;
int32_t i, bitcnt, outbytecnt;
const int16_t *const shortptr = (const int16_t *)lzwinbuf;
const int32_t strtot = B_LITTLE16(shortptr[1]);
const int32_t uncompleng = B_LITTLE16(shortptr[0]);
if (strtot == 0)
{
if (lzwoutbuf==lzwrawbuf && lzwinbuf==lzwcompbuf)
{
Bassert((compleng-4)+3+0u < sizeof(lzwrawbuf));
Bassert((compleng-4)+3+0u < sizeof(lzwcompbuf)-4);
}
Bmemcpy(lzwoutbuf, lzwinbuf+4, (compleng-4)+3);
return uncompleng;
}
for (i=255; i>=4; i-=4)
{
lzwbuf2[i] = lzwbuf3[i] = i;
lzwbuf2[i-1] = lzwbuf3[i-1] = i-1;
lzwbuf2[i-2] = lzwbuf3[i-2] = i-2;
lzwbuf2[i-3] = lzwbuf3[i-3] = i-3;
}
lzwbuf2[i] = lzwbuf3[i] = i;
lzwbuf2[i-1] = lzwbuf3[i-1] = i-1;
lzwbuf2[i-2] = lzwbuf3[i-2] = i-2;
currstr = 256; bitcnt = (4<<3); outbytecnt = 0;
numbits = 8; oneupnumbits = (1<<8);
do
{
const int32_t *const intptr = (const int32_t *)&lzwinbuf[bitcnt>>3];
int32_t dat = ((B_LITTLE32(intptr[0])>>(bitcnt&7)) & (oneupnumbits-1));
int32_t leng;
bitcnt += numbits;
if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1)))
{ dat &= ((oneupnumbits>>1)-1); bitcnt--; }
lzwbuf3[currstr] = dat;
for (leng=0; dat>=256; leng++,dat=lzwbuf3[dat])
lzwtmpbuf[leng] = lzwbuf2[dat];
lzwoutbuf[outbytecnt++] = dat;
for (i=leng-1; i>=4; i-=4, outbytecnt+=4)
{
lzwoutbuf[outbytecnt] = lzwtmpbuf[i];
lzwoutbuf[outbytecnt+1] = lzwtmpbuf[i-1];
lzwoutbuf[outbytecnt+2] = lzwtmpbuf[i-2];
lzwoutbuf[outbytecnt+3] = lzwtmpbuf[i-3];
}
for (; i>=0; i--)
lzwoutbuf[outbytecnt++] = lzwtmpbuf[i];
lzwbuf2[currstr-1] = dat; lzwbuf2[currstr] = dat;
currstr++;
if (currstr > oneupnumbits)
{ numbits++; oneupnumbits <<= 1; }
}
while (currstr < strtot);
return uncompleng;
}
////////// COMPRESSED READ //////////
struct decompress_info
{
klzw_readfunc readfunc;
intptr_t f;
uint32_t kgoal;
};
static uint32_t decompress_part(struct decompress_info * x)
{
intptr_t const f = x->f;
auto readfunc = x->readfunc;
// Read compressed length first.
int16_t leng;
if (readfunc(f, &leng, sizeof(leng)) != sizeof(leng))
return 1;
leng = B_LITTLE16(leng);
if (readfunc(f, lzwcompbuf, leng) != leng)
return 1;
x->kgoal = lzwuncompress(lzwcompbuf, leng, lzwrawbuf);
return 0;
}
// Read from 'f' into 'buffer'.
int32_t klzw_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f, klzw_readfunc readfunc)
{
char *ptr = (char *)buffer;
if (dasizeof > LZWSIZE)
{
count *= dasizeof;
dasizeof = 1;
}
struct decompress_info x;
x.readfunc = readfunc;
x.f = f;
if (decompress_part(&x))
return -1;
Bmemcpy(ptr, lzwrawbuf, (int32_t)dasizeof);
uint32_t k = (int32_t)dasizeof;
for (uint32_t i=1; i<count; i++)
{
if (k >= x.kgoal)
{
k = decompress_part(&x);
if (k) return -1;
}
uint32_t j = 0;
if (dasizeof >= 4)
{
for (; j<dasizeof-4; j+=4)
{
ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255);
ptr[j+1+dasizeof] = ((ptr[j+1]+lzwrawbuf[j+1+k])&255);
ptr[j+2+dasizeof] = ((ptr[j+2]+lzwrawbuf[j+2+k])&255);
ptr[j+3+dasizeof] = ((ptr[j+3]+lzwrawbuf[j+3+k])&255);
}
}
for (; j<dasizeof; j++)
ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255);
k += dasizeof;
ptr += dasizeof;
}
return count;
}
////////// COMPRESSED WRITE //////////
struct compress_info
{
klzw_writefunc writefunc;
intptr_t f;
uint32_t k;
};
static void compress_part(struct compress_info * x)
{
const int16_t leng = (int16_t)lzwcompress(lzwrawbuf, x->k, lzwcompbuf);
const int16_t swleng = B_LITTLE16(leng);
intptr_t const f = x->f;
auto writefunc = x->writefunc;
x->k = 0;
writefunc(f, &swleng, sizeof(swleng));
writefunc(f, lzwcompbuf, leng);
}
// Write from 'buffer' to 'f'.
void klzw_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f, klzw_writefunc writefunc)
{
char const *ptr = (char const *)buffer;
if (dasizeof > LZWSIZE)
{
count *= dasizeof;
dasizeof = 1;
}
Bmemcpy(lzwrawbuf, ptr, (int32_t)dasizeof);
struct compress_info x;
x.writefunc = writefunc;
x.f = f;
if ((x.k = dasizeof) > LZWSIZE-dasizeof)
compress_part(&x);
for (uint32_t i=1; i<count; i++)
{
uint32_t j = 0;
if (dasizeof >= 4)
{
for (; j<dasizeof-4; j+=4)
{
lzwrawbuf[j+x.k] = ((ptr[j+dasizeof]-ptr[j])&255);
lzwrawbuf[j+1+x.k] = ((ptr[j+1+dasizeof]-ptr[j+1])&255);
lzwrawbuf[j+2+x.k] = ((ptr[j+2+dasizeof]-ptr[j+2])&255);
lzwrawbuf[j+3+x.k] = ((ptr[j+3+dasizeof]-ptr[j+3])&255);
}
}
for (; j<dasizeof; j++)
lzwrawbuf[j+x.k] = ((ptr[j+dasizeof]-ptr[j])&255);
if ((x.k += dasizeof) > LZWSIZE-dasizeof)
compress_part(&x);
ptr += dasizeof;
}
if (x.k > 0)
compress_part(&x);
}