diff --git a/GNUmakefile b/GNUmakefile
index c81e4e559..d9ef931ad 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -165,6 +165,7 @@ engine_objs := \
rev.cpp \
baselayer.cpp \
cache1d.cpp \
+ klzw.cpp \
common.cpp \
compat.cpp \
crc32.cpp \
@@ -211,6 +212,7 @@ engine_tools_objs := \
pragmas.cpp \
kplib.cpp \
cache1d.cpp \
+ klzw.cpp \
crc32.cpp \
colmatch.cpp \
lz4.cpp \
@@ -890,9 +892,9 @@ $(ebacktrace_dll): platform/Windows/src/backtrace.c
$(COMPILE_STATUS)
$(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)
- $(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
%$(EXESUFFIX): $(tools_obj)/%.$o $(foreach i,tools $(tools_deps),$(call expandobjs,$i))
diff --git a/platform/Windows/build.vcxproj b/platform/Windows/build.vcxproj
index b55d1b9ae..da1b581a9 100644
--- a/platform/Windows/build.vcxproj
+++ b/platform/Windows/build.vcxproj
@@ -225,6 +225,7 @@
+
true
@@ -334,6 +335,7 @@
+
diff --git a/platform/Windows/build.vcxproj.filters b/platform/Windows/build.vcxproj.filters
index eab604702..36bb52b15 100644
--- a/platform/Windows/build.vcxproj.filters
+++ b/platform/Windows/build.vcxproj.filters
@@ -77,6 +77,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -274,6 +277,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/platform/Windows/msvc.mak b/platform/Windows/msvc.mak
index 7f844a3aa..e31809002 100644
--- a/platform/Windows/msvc.mak
+++ b/platform/Windows/msvc.mak
@@ -149,6 +149,7 @@ ENGINE_OBJS= \
$(ENGINE_OBJ)\animvpx.$o \
$(ENGINE_OBJ)\baselayer.$o \
$(ENGINE_OBJ)\cache1d.$o \
+ $(ENGINE_OBJ)\klzw.$o \
$(ENGINE_OBJ)\common.$o \
$(ENGINE_OBJ)\compat.$o \
$(ENGINE_OBJ)\crc32.$o \
diff --git a/source/build/include/klzw.h b/source/build/include/klzw.h
new file mode 100644
index 000000000..76939c185
--- /dev/null
+++ b/source/build/include/klzw.h
@@ -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_
diff --git a/source/build/src/cache1d.cpp b/source/build/src/cache1d.cpp
index 4c28fe409..d68402d9b 100644
--- a/source/build/src/cache1d.cpp
+++ b/source/build/src/cache1d.cpp
@@ -8,14 +8,6 @@
#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
// for FILENAME_CASE_CHECK
# define NEED_SHELLAPI_H
@@ -25,6 +17,7 @@
#include "pragmas.h"
#include "baselayer.h"
#include "lz4.h"
+#include "klzw.h"
#ifdef WITHKPLIB
#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)
{
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);
}
-#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= kgoal)
- {
- k = decompress_part(f, &kgoal);
- if (k) return -1;
- }
-
- uint32_t j = 0;
-
- if (dasizeof >= 4)
- {
- for (; j ARRAY_SSIZE(compressedDataStackBuf))
pCompressedData = (char *)Xaligned_alloc(16, leng);
- if (c1d_readfunc(fil, pCompressedData, leng) != leng)
+ if (kread(fil, pCompressedData, leng) != leng)
return -1;
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= 4)
- {
- for (; j 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)
{
- 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)
@@ -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 swleng = B_LITTLE32(leng);
- c1d_writefunc((intptr_t) fil, &swleng, 4);
- c1d_writefunc((intptr_t) fil, pCompressedData, leng);
+ Bfwrite(&swleng, sizeof(swleng), 1, fil);
+ Bfwrite(pCompressedData, leng, 1, fil);
if (pCompressedData != compressedDataStackBuf)
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=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:
- */
diff --git a/source/build/src/klzw.cpp b/source/build/src/klzw.cpp
new file mode 100644
index 000000000..ca385c75b
--- /dev/null
+++ b/source/build/src/klzw.cpp
@@ -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=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= x.kgoal)
+ {
+ k = decompress_part(&x);
+ if (k) return -1;
+ }
+
+ uint32_t j = 0;
+
+ if (dasizeof >= 4)
+ {
+ for (; jk, 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= 4)
+ {
+ for (; j LZWSIZE-dasizeof)
+ compress_part(&x);
+
+ ptr += dasizeof;
+ }
+
+ if (x.k > 0)
+ compress_part(&x);
+}