diff -urN linux-2.2.5-e2c0.4.30/arch/alpha/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/alpha/defconfig --- linux-2.2.5-e2c0.4.30/arch/alpha/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/alpha/defconfig @@ -261,10 +261,12 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/arm/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/arm/defconfig --- linux-2.2.5-e2c0.4.30/arch/arm/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/arm/defconfig @@ -181,10 +181,12 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/i386/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/i386/defconfig --- linux-2.2.5-e2c0.4.30/arch/i386/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/i386/defconfig @@ -312,10 +312,12 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/m68k/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/m68k/defconfig --- linux-2.2.5-e2c0.4.30/arch/m68k/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/m68k/defconfig @@ -183,11 +183,13 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y CONFIG_EXT2_COMPR_X86_CODE=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/mips/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/mips/defconfig --- linux-2.2.5-e2c0.4.30/arch/mips/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/mips/defconfig @@ -271,11 +271,13 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y CONFIG_EXT2_COMPR_X86_CODE=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/ppc/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/ppc/defconfig --- linux-2.2.5-e2c0.4.30/arch/ppc/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/ppc/defconfig @@ -365,10 +365,12 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/sparc/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/sparc/defconfig --- linux-2.2.5-e2c0.4.30/arch/sparc/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/sparc/defconfig @@ -242,10 +242,12 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/arch/sparc64/defconfig linux-2.2.5-e2c0.4.30-lzrw/arch/sparc64/defconfig --- linux-2.2.5-e2c0.4.30/arch/sparc64/defconfig +++ linux-2.2.5-e2c0.4.30-lzrw/arch/sparc64/defconfig @@ -279,10 +279,12 @@ CONFIG_EXT2_COMPRESS=n CONFIG_EXT2_HAVE_LZO=y CONFIG_EXT2_HAVE_LZV1=y +# CONFIG_EXT2_HAVE_LZRW3A is not set CONFIG_EXT2_HAVE_GZIP=y CONFIG_EXT2_HAVE_BZIP2=y # CONFIG_EXT2_DEFAULT_COMPR_METHOD_NONE is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 is not set +# CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP1 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP3 is not set # CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP6 is not set diff -urN linux-2.2.5-e2c0.4.30/fs/Config.in linux-2.2.5-e2c0.4.30-lzrw/fs/Config.in --- linux-2.2.5-e2c0.4.30/fs/Config.in +++ linux-2.2.5-e2c0.4.30-lzrw/fs/Config.in @@ -55,6 +55,7 @@ if [ "$CONFIG_EXT2_COMPRESS" = "y" ]; then tristate ' LZO1X_1 algorithm' CONFIG_EXT2_HAVE_LZO tristate ' LZV1 algorithm' CONFIG_EXT2_HAVE_LZV1 + tristate ' LZRW3A algorithm (patented and thus deprecated; see help text)' CONFIG_EXT2_HAVE_LZRW3A tristate ' GZIP algorithm' CONFIG_EXT2_HAVE_GZIP tristate ' BZIP2 algorithm' CONFIG_EXT2_HAVE_BZIP2 # It would be nice if we could restrict the choice to the algorithms @@ -65,6 +66,7 @@ "defer CONFIG_EXT2_DEFAULT_COMPR_METHOD_DEFER \ LZO CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZO \ LZV1 CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZV1 \ + LZRW3A CONFIG_EXT2_DEFAULT_COMPR_METHOD_LZRW3A \ GZIP CONFIG_EXT2_DEFAULT_COMPR_METHOD_GZIP \ BZIP2 CONFIG_EXT2_DEFAULT_COMPR_METHOD_BZIP2" GZIP # N.B. Don't offer EXT2_NEVER_METH or any lossy algorithms for the diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/Makefile linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/Makefile --- linux-2.2.5-e2c0.4.30/fs/ext2/Makefile +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/Makefile @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... SUB_DIRS := -ALL_SUB_DIRS := bzip gzip lzo lzv +ALL_SUB_DIRS := bzip gzip lzo lzrw lzv MOD_LIST_NAME := E2C_MODULES ifeq ($(CONFIG_EXT2_COMPRESS),y) @@ -34,6 +34,14 @@ else ifeq ($(CONFIG_EXT2_HAVE_LZO),m) MOD_SUB_DIRS += lzo + endif +endif + +ifeq ($(CONFIG_EXT2_HAVE_LZRW3A),y) +SUB_DIRS += lzrw +else + ifeq ($(CONFIG_EXT2_HAVE_LZRW3A),m) + MOD_SUB_DIRS += lzrw endif endif diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/compress.c linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/compress.c --- linux-2.2.5-e2c0.4.30/fs/ext2/compress.c +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/compress.c @@ -101,7 +101,11 @@ {"lzv1", 0, ext2_iNONE, ext2_wNONE, ext2_rNONE}, #endif +#ifdef CONFIG_EXT2_HAVE_LZRW3A + {"lzrw3a", 1, ext2_iLZRW3A, ext2_wLZRW3A, ext2_rLZRW3A}, +#else {"lzrw3a", 0, ext2_iNONE, ext2_wNONE, ext2_rNONE}, +#endif #ifdef CONFIG_EXT2_HAVE_GZIP diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/Makefile linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/Makefile --- linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/Makefile +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/Makefile @@ -0,0 +1,23 @@ +# +# Makefile for the linux compression routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +O_TARGET := lzrw.o + +ifeq ($(CONFIG_EXT2_COMPR_X86_CODE),y) +O_OBJS := e2compr-lzrw3a.o rlzrw3a.o wlzrw3a.o +else +O_OBJS := e2compr-lzrw3a.o lzrw3a.o +endif + +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/e2compr-lzrw3a.c linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/e2compr-lzrw3a.c --- linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/e2compr-lzrw3a.c +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/e2compr-lzrw3a.c @@ -0,0 +1,72 @@ +#include +#include +#include + +#include "lzrw.h" + +#define U(X) ((unsigned long) X) +#define MEM_REQ (U(4096)*(U(sizeof(unsigned char *))) + (U(16))) + +extern int ext2_LZRW3A_compress(UBYTE *p_src_first, UBYTE *p_dst_first, + UBYTE *heap, int src_len, int p_dst_len); +extern int ext2_LZRW3A_decompress(UBYTE *p_src_first, UBYTE *p_dst, + UBYTE *heap, int src_len, int dst_len); + +size_t ext2_iLZRW3A(int action) +{ + switch (action) { + case EXT2_ALG_INIT_COMPRESS: + return MEM_REQ; + case EXT2_ALG_INIT_DECOMPRESS: + return MEM_REQ; + default: + return 0; + } +} + +size_t ext2_wLZRW3A (unsigned char *p_src_first, unsigned char *p_dst_first, + void *heap, size_t src_len, size_t p_dst_len, int xarg) +{ + int ret_code; + + MOD_INC_USE_COUNT; + ret_code = ext2_LZRW3A_compress(p_src_first, p_dst_first, heap, src_len, p_dst_len); + MOD_DEC_USE_COUNT; + return ret_code; +} + +size_t ext2_rLZRW3A (unsigned char *p_src_first, unsigned char *p_dst, + void *heap, size_t src_len, size_t dst_len, int xarg) +{ + int ret_code; + + MOD_INC_USE_COUNT; + ret_code = ext2_LZRW3A_decompress(p_src_first, p_dst, heap, src_len, dst_len); + MOD_DEC_USE_COUNT; + return ret_code; +} + +#ifdef MODULE + +int init_module(void) +{ + struct ext2_algorithm lzrw3a_alg; + + lzrw3a_alg.name = NULL; + lzrw3a_alg.avail = 1; + lzrw3a_alg.init = ext2_iLZRW3A; + lzrw3a_alg.compress = ext2_wLZRW3A; + lzrw3a_alg.decompress = ext2_rLZRW3A; + + return ext2_register_compression_module(EXT2_LZRW3A_ALG, + MEM_REQ, MEM_REQ, + &lzrw3a_alg); +} + +void cleanup_module(void) +{ + ext2_unregister_compression_module(EXT2_LZRW3A_ALG); +} + +#endif + diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/lzrw.h linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/lzrw.h --- linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/lzrw.h +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/lzrw.h @@ -0,0 +1,106 @@ +/* Author : Ross Williams. */ +/* Date : December 1989. */ +/* This header file and the C functions have been modified in order to */ +/* include them in the DouBle device driver by Jean-Marc Verbavatz, Feb 1994. */ +/* */ +/* This header file defines the interface to a set of lzrw functions */ +/* each member of which implements a particular data compression */ +/* algorithm. */ +/* */ +/* Normally in C programming, for each .H file, there is a corresponding .C */ +/* file that implements the functions promised in the .H file. */ +/* Here, there are many .C files corresponding to this header file. */ +/* Each comforming implementation file contains a single function */ +/* called that implements a single data compression */ +/* algorithm that conforms with the interface specified in this header file. */ +/* */ +/******************************************************************************/ +/* See the formal C definition later for a description of the parameters. */ +/* */ +/* Although compression algorithms usually compress data, there will always */ +/* be data that a given compressor will expand (this can be proven). */ +/* */ +/* Unfortunately, in general, the only way to tell if an algorithm will */ +/* expand a particular block of data is to run the algorithm on the data. */ +/* If the algorithm does not continuously monitor how many output bytes it */ +/* has written, it might write an output block far larger than the input */ +/* block before realizing that it has done so. */ +/* On the other hand, continuous checks on output length are inefficient. */ +/* */ +/* The problem does not arise for decompression. */ +/* */ +/******************************************************************************/ +/* Macro definitions and types that are likely to change between computers. */ +/* */ +#ifndef DONE_PORT /* Only do this if not previously done. */ + #ifndef TRUE + #define TRUE 1 + #define FALSE 0 + #endif + #ifndef UBYTE + #define UBYTE unsigned char /* Unsigned byte */ + #define UWORD unsigned short /* Unsigned word (2 bytes) */ + #define ULONG unsigned long /* Unsigned word (4 bytes) */ + #endif + + #define DONE_PORT /* Don't do all this again. */ + #define LOCAL static /* For non-exported routines. */ + #define EXPORT /* Signals exported function. */ + +#endif + +#if 0 +extern void *ext2_lzrw3a_htab; +#endif + +int rlzrw2( /* function for decompression algorithm. */ +UBYTE *src_adr, /* Address of input data. */ +UBYTE *dst_adr, /* Address of output data. */ +int src_len, /* Length of output data. */ +int dst_len /* Length of output data. */ +); + +void wlzrw2( /* function for compression algorithm. */ +UBYTE *src_adr, /* Address of input data. */ +int src_len, /* Length of input data. */ +UBYTE *dst_adr, /* Address of output data. */ +int *p_dst_len /* Pointer to a longword for */ + /* Length of output data. */ +); + +int rlzrw3( /* function for decompression algorithm. */ +UBYTE *src_adr, /* Address of input data. */ +UBYTE *dst_adr, /* Address of output data. */ +ULONG dst_len /* Length of output data. */ +); + +void wlzrw3( /* function for compression algorithm. */ +UBYTE *src_adr, /* Address of input data. */ +ULONG src_len, /* Length of input data. */ +UBYTE *dst_adr, /* Address of output data. */ +ULONG *p_dst_len /* Pointer to a longword where routine will write: */ + /* Length of output data. */ +); +/* + * NOTE: lzrw3 is not implemented in the DouBle driver version 0.2 + */ + +int rlzrw3a( /* function for decompression algorithm. */ +UBYTE *src_adr, /* Address of input data. */ +UBYTE *dst_adr, /* Address of output data. */ +int src_len, /* Length of input data. */ +int dst_len /* Length of output data. */ +); + +void wlzrw3a( /* function for compression algorithm. */ +UBYTE *src_adr, /* Address of input data. */ +int src_len, /* Length of input data. */ +UBYTE *dst_adr, /* Address of output data. */ +int *p_dst_len /* Pointer to a longword for */ + /* Length of output data. */ +); + +/******************************************************************************/ +/* End of LZRW.H */ +/******************************************************************************/ + diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/lzrw3a.c linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/lzrw3a.c --- linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/lzrw3a.c +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/lzrw3a.c @@ -0,0 +1,803 @@ +/*****************************************************************************/ +/* */ +/* LZRW3-A.C */ +/* */ +/*****************************************************************************/ +/* */ +/* Author : Ross Williams. */ +/* Date : 15-Jul-1991. */ +/* Release : 1. */ +/* */ +/*****************************************************************************/ +/* */ +/* This file contains an implementation of the LZRW3-A data compression */ +/* algorithm in the C programming language. */ +/* */ +/* The LZRW3-A algorithm has the following features: */ +/* */ +/* 1 Requires only 16K of memory (for both compression and decompression).*/ +/* 2 The compressor runs about two times faster than Unix compress's. */ +/* 3 The decompressor runs about three times faster than Unix compress's. */ +/* 4 Yields a few percent better compression than Unix compress for */ +/* most files. */ +/* 5 Allows you to dial up extra compression at a speed cost in the */ +/* compressor. The speed of the decompressor is not affected. */ +/* 6 Algorithm is deterministic. */ +/* 8 This implementation in C is in the public domain. */ +/* */ +/* (Timing tests for the speed comparison were performed on a Pyramid 9820.) */ +/* */ +/* LZRW3-A is LZRW3 with a deepened hash table. This simple change yields */ +/* about a 6% (absolute) improvement in compression. */ +/* */ +/* Here are the results of applying this code, compiled under THINK C 4.0 */ +/* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */ +/* */ +/* +----------------------------------------------------------------+ */ +/* | DATA COMPRESSION TEST | */ +/* | ===================== | */ +/* | Time of run : Mon 15-Jul-1991 05:29PM | */ +/* | Timing accuracy : One part in 100 | */ +/* | Context length : 262144 bytes (= 256.0000K) | */ +/* | Test suite : Calgary Corpus Suite | */ +/* | Files in suite : 14 | */ +/* | Algorithm : LZRW3-A | */ +/* | Note: All averages are calculated from the un-rounded values. | */ +/* +----------------------------------------------------------------+ */ +/* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */ +/* | ---------- ------ --- ------ ----- ---- ------- ------- | */ +/* | rpus:Bib.D 111261 1 49044 44.1 3.53 8.47 31.19 | */ +/* | us:Book1.D 768771 3 420464 54.7 4.38 7.27 30.07 | */ +/* | us:Book2.D 610856 3 277955 45.5 3.64 8.51 33.40 | */ +/* | rpus:Geo.D 102400 1 84218 82.2 6.58 4.23 15.04 | */ +/* | pus:News.D 377109 2 192880 51.1 4.09 7.08 25.89 | */ +/* | pus:Obj1.D 21504 1 12651 58.8 4.71 5.23 17.44 | */ +/* | pus:Obj2.D 246814 1 108044 43.8 3.50 8.01 28.11 | */ +/* | s:Paper1.D 53161 1 24526 46.1 3.69 8.11 30.24 | */ +/* | s:Paper2.D 82199 1 39483 48.0 3.84 8.11 32.04 | */ +/* | rpus:Pic.D 513216 2 111622 21.7 1.74 10.64 49.31 | */ +/* | us:Progc.D 39611 1 17923 45.2 3.62 8.06 29.01 | */ +/* | us:Progl.D 71646 1 24362 34.0 2.72 10.74 39.51 | */ +/* | us:Progp.D 49379 1 16805 34.0 2.72 10.64 37.58 | */ +/* | us:Trans.D 93695 1 30296 32.3 2.59 11.02 38.06 | */ +/* +----------------------------------------------------------------+ */ +/* | Average 224401 1 100733 45.8 3.67 8.29 31.21 | */ +/* +----------------------------------------------------------------+ */ +/* */ +/*****************************************************************************/ + +#include "lzrw.h" +/******************************************************************************/ + +/* + The following structure is returned by the "compress" function below when + the user asks the function to return identifying information. + The most important field in the record is the working memory field which + tells the calling program how much working memory should be passed to + "compress" when it is called to perform a compression or decompression. + LZRW3-A uses the same amount of memory during compression and + decompression. For more information on this structure see "lzrw.h". + The alignment fudge below really only needs to be 4 (but I play it safe!). + The id looks non-random, but it really was generated by coin tossing! + */ + +#define U(X) ((ULONG) X) +#define SIZE_P_BYTE (U(sizeof(UBYTE *))) +#define ALIGNMENT_FUDGE (U(16)) +#define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE ) + +/* + static struct compress_identity identity = + { + U(0x01B90B91), * Algorithm identification number. * + MEM_REQ, * Working memory (bytes) required. * + "LZRW3-A", * Name of algorithm. * + "1.0", * Version number of algorithm. * + "15-Jul-1990", * Date of algorithm. * + "Ross N. Williams", * Author of algorithm. * + "Renaissance Software", * Affiliation of author. * + }; +*/ + +/******************************************************************************/ +/* */ +/* BRIEF DESCRIPTION OF THE LZRW3-A ALGORITHM */ +/* ========================================== */ +/* Note: Before attempting to understand this algorithm, you should first */ +/* understand the LZRW3 algorithm from which this algorithm is derived. */ +/* */ +/* The LZRW3-A algorithm is identical to the LZRW3 algorithm except that the */ +/* hash table has been "deepened". The LZRW3 algorithm has a hash table of */ +/* 4096 pointers which point to strings in the buffer. LZRW3-A generalizes */ +/* this to 4096/(2^n) partitions each of which contains (2^n) pointers. */ +/* In LZRW3-A, the hash function hashes to a partition number. */ +/* */ +/* During the processing of each phrase, LZRW3 overwrites the pointer in the */ +/* position selected by the hash function. LZRW3-A overwrites one of the */ +/* pointers in the partition that was selected by the hash function. */ +/* */ +/* When searching for a match, LZRW3-A matches against all (2^n) strings */ +/* pointed to by the pointers in the target partition. */ +/* */ +/* Deep hash tables were used in early versions of LZRW1 in late 1989, but */ +/* were discarded in an effort to increase speed (which was the primary */ +/* requirement for LZRW1). They were revived for use in LZRW3-A in order to */ +/* produce an algorithm with compression performance competitive with Unix */ +/* compress. */ +/* */ +/* Until 14-Jul-1991, deep hash tables used in prototype LZRW* algorithms */ +/* used a queue discipline within each partition. Upon the arrival of a new */ +/* pointer, the pointers in the partition would be block copied back one */ +/* position (with the oldest pointer being overwritten) and the new pointer */ +/* being inserted in the space at the front (the youngest position). */ +/* This meant that pointers to the (2^n) most recent phrases corresponding to */ +/* each hash was kept. The only flaw in this system was the time-consuming */ +/* block copy operation which was cheap for shallow tables but expensive for */ +/* deep tables. */ +/* */ +/* The traditional solution to ring buffer block copy problems is to maintain */ +/* a cyclic counter which points to the "head" of the queue. However, this */ +/* would have required one counter to be stored for each partition and would */ +/* have been slightly messy. After some thought (on 14-Jul-1991) a better */ +/* solution was found. Instead of maintaining a counter for each partition, */ +/* LZRW3-A maintains a single counter for all partitions! This counter is */ +/* maintained in both the compressor and decompressor and means that the */ +/* algorithm (effectively) overwrites a RANDOM element of the partition to be */ +/* updated. The result was to increase the speed of the compressor and */ +/* decompressor, to make the decompressor's speed independent from whatever */ +/* depth was selected, and to impair compression by less than 1% absolute. */ +/* */ +/* Setting the depth is a speed/compression tradeoff. The table below gives */ +/* the tradeoff observed for a typical 50K text file on a Mac-SE. */ +/* Note: %Rem=Percentage Remaining (after compression). */ +/* */ +/* Depth %Rem CmpK/s DecK/s */ +/* 1 45.2 14.77 32.24 */ +/* 2 42.6 12.12 31.26 */ +/* 4 40.9 10.28 31.91 */ +/* 8 40.0 7.81 32.36 */ +/* 16 39.5 5.30 32.47 */ +/* 32 39.0 3.23 32.59 */ +/* */ +/* I have chosen a depth of 8 as the "default" depth for LZRW3-A. If you use */ +/* a depth different to this (e.g. 4), you should use the name LZRW3-A(4) to */ +/* indicate that a different depth is being used. LZRW3-A(8) is an acceptable */ +/* longhand for LZRW3-A. */ +/* */ +/* To change the depth, search for "HERE IT IS" in the rest of this file. */ +/* */ +/* +---+ */ +/* |___|4095 */ +/* |===| */ +/* +---------------------*_|<---+ /----+---\ */ +/* | |___| +---|Hash | */ +/* | 512 partitions |___| |Function| */ +/* | of 8 pointers |===| \--------/ */ +/* | each (or any |___|0 ^ */ +/* | a*b=4096) +---+ | */ +/* | Hash +-----+ */ +/* | Table | */ +/* | --- */ +/* v ^^^ */ +/* +-------------------------------------|----------------+ */ +/* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */ +/* +-------------------------------------|----------------+ */ +/* | |1......18| | */ +/* |<------- Lempel=History ------------>|<--Ziv-->| | */ +/* | (=bytes already processed) |<-Still to go-->| */ +/* |<-------------------- INPUT BLOCK ------------------->| */ +/* */ +/* */ +/******************************************************************************/ +/* */ +/* DEFINITION OF COMPRESSED FILE FORMAT */ +/* ==================================== */ +/* The file consists of zero */ +/* or more GROUPS, each of which represents one or more bytes. */ +/* * Each group consists of two bytes of CONTROL information followed by */ +/* sixteen ITEMs except for the last group which can contain from one */ +/* to sixteen items. */ +/* * An item can be either a LITERAL item or a COPY item. */ +/* * Each item corresponds to a bit in the control bytes. */ +/* * The first control byte corresponds to the first 8 items in the group */ +/* with bit 0 corresponding to the first item in the group and bit 7 to */ +/* the eighth item in the group. */ +/* * The second control byte corresponds to the second 8 items in the group */ +/* with bit 0 corresponding to the ninth item in the group and bit 7 to */ +/* the sixteenth item in the group. */ +/* * A zero bit in a control word means that the corresponding item is a */ +/* literal item. A one bit corresponds to a copy item. */ +/* * A literal item consists of a single byte which represents itself. */ +/* * A copy item consists of two bytes that represent from 3 to 18 bytes. */ +/* * The first byte in a copy item will be denoted C1. */ +/* * The second byte in a copy item will be denoted C2. */ +/* * Bits will be selected using square brackets. */ +/* For example: C1[0..3] is the low nibble of the first control byte. */ +/* of copy item C1. */ +/* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */ +/* in the range [3,18]. */ +/* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */ +/* is a number in the range [0,4095]. */ +/* * A copy item represents the sequence of bytes */ +/* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */ +/* text is the entire text of the uncompressed string. */ +/* POS is the index in the text of the character following the */ +/* string represented by all the items preceeding the item */ +/* being defined. */ +/* OFFSET is obtained from INDEX by looking up the hash table. */ +/* */ +/******************************************************************************/ + +/* When I first started to get concerned about the portability of my C code, */ +/* I switched over to using only macro defined types UBYTE, UWORD, ULONG and */ +/* one or two others. While, these are useful for most purposes, they impair */ +/* efficiency as, if I have a variable whose range will be [0,1000], I will */ +/* declare it as a UWORD. This will translate into (say) "short int" and */ +/* hence may be less efficient than just an "int" which represents the */ +/* natural size of the machine. Before releasing LZRW3-A, I realized this */ +/* mistake. Unfortunately, I can't access the ftp archive with my portability */ +/* header in it in time for this algorithm's release and so I am including an */ +/* extra definition. The definition UCARD stands for an unsigned (cardinal) */ +/* type that can hold values in the range [0,32767]. This is within the ANSI */ +/* range of a standard int or unsigned. No assumption about overflow of this */ +/* type is made in the code (i.e. all usages are within range and I do not */ +/* use the value -1 to detect the end of loops.). */ +/* You can use either "unsigned" or just "int" here depending on which is */ +/* more efficient in your environment (both the same probably). */ +#define UCARD unsigned + +/* The following constant defines the maximum length of an uncompressed item. */ +/* This definition must not be changed; its value is hardwired into the code. */ +/* The longest number of bytes that can be spanned by a single item is 18 */ +/* for the longest copy item. */ +#define MAX_RAW_ITEM (18) + +/* The following constant defines the maximum length of a compressed group. */ +/* This definition must not be changed; its value is hardwired into the code. */ +/* A compressed group consists of two control bytes followed by up to 16 */ +/* compressed items each of which can have a maximum length of two bytes. */ +#define MAX_CMP_GROUP (2+16*2) + +/* This constant defines the number of pointers in the hash table. The number */ +/* of partitions multiplied by the number of pointers in each partition must */ +/* multiply out to this value of 4096. In LZRW1, LZRW1-A, and LZRW2, this */ +/* table length value can be changed. However, in LZRW3-A (and LZRW3), the */ +/* table length cannot be changed because it is connected directly to the */ +/* coding scheme which is hardwired (the table index of a single pointer is */ +/* transmitted in the 12-bit index field). So don't change this constant! */ +#define HASH_TABLE_LENGTH (4096) + +/* HERE IT IS: THE PLACE TO CHANGE THE HASH TABLE DEPTH! */ +/* The following definition is the log_2 of the depth of the hash table. This */ +/* constant can be in the range [0,1,2,3,...,12]. Increasing the depth */ +/* increases compression at the expense of speed. However, you are not likely */ +/* to see much of a compression improvement (e.g. not more than 0.5%) above a */ +/* value of 6 and the algorithm will start to get very slow. See the table in */ +/* the earlier comments block for an idea of the trade-off involved. */ +/* Note: The parentheses are to avoid macro substitution funnies. */ +/* Note: The LZRW3-A default is a value of (3). */ +/* Note: If you end up choosing a value of 0, you should use LZRW3 instead. */ +/* Note: Changing the value of HASH_TABLE_DEPTH_BITS is the ONLY thing you */ +/* have to do to change the depth, so go ahead and recompile now! */ +/* Note: I have tested LZRW3-A for DEPTH_BITS=0,1,2,3,4 and a few other */ +/* values. However, I have not tested it for 12 as I can't wait that long! */ +#define HASH_TABLE_DEPTH_BITS (3) /* Must be in range [0,12]. */ + +/* The following definitions are all self-explanatory and follow from the */ +/* definition of HASH_TABLE_DEPTH_BITS and the hardwired requirement that the */ +/* hash table contain exactly 4096 pointers. */ +#define PARTITION_LENGTH_BITS (12-HASH_TABLE_DEPTH_BITS) +#define PARTITION_LENGTH (1<>4) & HASH_MASK) \ + << HASH_TABLE_DEPTH_BITS \ + ) + +#else +#define HASH(PTR) \ + ( \ + ( ((((*(PTR)<<3)^(*((PTR)+1)))<<3)^(*((PTR)+2))) & HASH_MASK) \ + << HASH_TABLE_DEPTH_BITS \ + ) +#endif + +/* Another operation that is performed more than once is the updating of the */ +/* hash table. Here two macros are defined to simplify update operations. */ +/* Updating consists of identifying and overwriting a pointer in a partition */ +/* with a newer pointer and then updating the global cycle value. */ +/* These macros accept the new pointer (NEWPTR) and either a pointer to */ +/* (P_BASE) or the index of (I_BASE) the zeroth (first, or base) pointer in */ +/* the partition that is to be updated. The macros use the 'cycle' variable */ +/* to locate and overwrite a pointer and then update the cycle value. */ +/* Note: Hardcoding 'cycle' in this macro is naughty (it should really be a */ +/* macro parameter), but I have done so because it neatens up the code. */ +#define UPDATE_P(P_BASE,NEWPTR) \ +{(P_BASE)[cycle++]=(NEWPTR); cycle&=DEPTH_MASK;} + +#define UPDATE_I(I_BASE,NEWPTR) \ +{hash[(I_BASE)+cycle++]=(NEWPTR); cycle&=DEPTH_MASK;} + +/* This constant supplies a legal (in-range) hash table index for use when */ +/* a legal-but-don't-care index is required. */ +#define ANY_HASH_INDEX (0) + +/******************************************************************************/ +#if 0 +void *ext2_lzrw3a_htab; +#endif + +EXPORT int ext2_LZRW3A_compress + (p_src_first,p_dst_first,heap,src_len,p_dst_len) +/* Input : Specify input block using p_src_first and src_len. */ +/* Input : Point p_dst_first to the start of the output zone (OZ). */ +/* Input : Point p_dst_len to a ULONG to receive the output length. */ +/* Input : Input block and output zone must not overlap. */ +/* Output : Length of output block written to *p_dst_len. */ +/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */ +/* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/ +/* Output : Upon completion *p_dst_len contains final size or 0 */ +UBYTE *p_src_first; +UBYTE *p_dst_first; +void *heap; +int src_len; +int p_dst_len; +{ + /* p_src and p_dst step through the source and destination blocks. */ + UBYTE const *p_src = p_src_first; + UBYTE *p_dst = p_dst_first; + + /* The following variables are never modified and are used in the */ + /* calculations that determine when the main loop terminates. */ + UBYTE const * const p_src_post = p_src_first + src_len; + UBYTE * const p_dst_post = p_dst_first + p_dst_len; + UBYTE const * const p_src_max1 = p_src_first + src_len - MAX_RAW_ITEM; + UBYTE const * const p_src_max16 = p_src_first + src_len - (MAX_RAW_ITEM * 16); + + /* The variables 'p_control' and 'control' are used to buffer control bits. */ + /* Before each group is processed, the next two bytes of the output block */ + /* are set aside for the control word for the group about to be processed. */ + /* 'p_control' is set to point to the first byte of that word. Meanwhile, */ + /* 'control' buffers the control bits being generated during the processing */ + /* of the group. Instead of having a counter to keep track of how many items */ + /* have been processed (=the number of bits in the control word), at the */ + /* start of each group, the top word of 'control' is filled with 1 bits. */ + /* As 'control' is shifted for each item, the 1 bits in the top word are */ + /* absorbed or destroyed. When they all run out (i.e. when the top word is */ + /* all zero bits, we know that we are at the end of a group. */ + #define TOPWORD 0xFFFF0000 + UBYTE *p_control; + ULONG control=TOPWORD; + + /* The variable 'hash' always points to the first element of the hash table. */ +#if 0 + UBYTE **hash= (UBYTE **) ext2_lzrw3a_htab; +#else + UBYTE **hash= (UBYTE **) heap; +#endif + + /* The following two variables represent the literal buffer. p_h1 points to */ + /* the partition (i.e. the zero'th (first) element of the partition) */ + /* corresponding to the youngest literal. p_h2 points to the partition */ + /* corresponding to the second youngest literal. */ + /* The value zero denotes an "empty" buffer value with p_h1=0 => p_h2=0. */ + UBYTE **p_h1=0; + UBYTE **p_h2=0; + + /* The following variable holds the current 'cycle' value. This value cycles */ + /* through the range [0,HASH_TABLE_DEPTH-1], being incremented every time */ + /* the hash table is updated. The value gives the within-partition number of */ + /* the next pointer to be overwritten. The decompressor maintains a cycle */ + /* value in synchrony. */ + UCARD cycle=0; + + /* Reserve the first two bytes of output as the control word for the first group. */ + /* Note: This is undone at the end if the input block is empty. */ + p_control = p_dst; + p_dst += 2; + + /* Initialize all elements of the hash table to point to a constant string. */ + /* Use of an unrolled loop speeds this up considerably. */ + /* These variables should really be declared "register", but I am worried */ + /* about the possibility that extra register declarations will tempt stupid */ + /* compilers to allocate all registers before they get to the innermostloop. */ + { + UCARD i; + UBYTE **p_h = hash; + #define ZH *p_h++=START_STRING_18 + for (i = 256; i--;) /* 256=HASH_TABLE_LENGTH/16. */ + {ZH;ZH;ZH;ZH; + ZH;ZH;ZH;ZH; + ZH;ZH;ZH;ZH; + ZH;ZH;ZH;ZH;} + #undef ZH + } + + /* The main loop processes either 1 or 16 items per iteration. As its */ + /* termination logic is complicated, I have opted for an infinite loop */ + /* structure containing 'break' and 'goto' statements. */ + while (TRUE) + {/* Begin main processing loop. */ + + /* Note: All the variables here except unroll should be defined within */ + /* the inner loop. Unfortunately the loop hasn't got a block. */ + UBYTE const *p_ziv = (void *) 0; /* Points to first byte of current Ziv. */ + UCARD unroll; /* Loop counter for unrolled inner loop. */ + UCARD index; /* Index of current partition. */ + UBYTE **p_h0; /* Pointer to current partition. */ + register UCARD d; /* Depth looping variable. */ + register UCARD bestlen; /* Holds the best length seen so far. */ + register UCARD bestpos; /* Holds number of best pointer seen so far. */ + + /* Test for overrun and jump to overrun code if necessary. */ + if (p_dst > p_dst_post) /* tbi: This looks wrong. Why not '>=' ? */ + goto overrun; + + /* The following cascade of if statements efficiently catches and deals */ + /* with varying degrees of closeness to the end of the input block. */ + /* When we get very close to the end, we stop updating the table and */ + /* code the remaining bytes as literals. This makes the code simpler. */ + unroll=16; + if (p_src>p_src_max16) + { + unroll=1; + if (p_src>p_src_max1) + { + if (p_src==p_src_post) + break; + else + {p_h0=&hash[ANY_HASH_INDEX]; /* Avoid undefined pointer. */ + goto literal;} + } + } + + /* This inner unrolled loop processes 'unroll' (whose value is either 1 */ + /* or 16) items. I have chosen to implement this loop with labels and */ + /* gotos to heighten the ease with which the loop may be implemented with */ + /* a single decrement and branch instruction in assembly language and */ + /* also because the labels act as highly readable place markers. */ + /* (Also because we jump into the loop for endgame literals (see above)). */ + + begin_unrolled_loop: + + p_ziv=p_src; + + /* To process the next phrase, we hash the next three bytes to obtain */ + /* an index to the zeroth (first) pointer in a target partition. We */ + /* get the pointer. */ + index=HASH(p_src); + p_h0=&hash[index]; + + /* This next part runs through the pointers in the partition matching */ + /* the bytes they point to in the Lempel with the bytes in the Ziv. */ + /* The length (bestlen) and within-partition pointer number (bestpos) */ + /* of the longest match so far is maintained and is the output of this */ + /* segment of code. The s[bestlen]==... is an optimization only. */ + bestlen=0; + bestpos=0; + for (d=0;dbestlen) + { + bestpos=d; + bestlen=len; + } + } + } + + /* The length of the longest match determines whether we code a */ + /* literal item or a copy item. */ + + if (bestlen<3) + { + /* Literal. */ + + /* Code the literal byte as itself and a zero control bit. */ + literal: *p_dst++=*p_src++; control&=0xFFFEFFFF; + + /* We have just coded a literal. If we had two pending ones, that */ + /* makes three and we can update the hash table. */ + if (p_h2!=0) + {UPDATE_P(p_h2, p_ziv - 2);} + + /* In any case, rotate the hash table pointers for next time. */ + p_h2=p_h1; + p_h1=p_h0; + + } + else + { + /* Copy */ + + /* To code a copy item, we construct a hash table index of the */ + /* winning pointer (index+=bestpos) and code it and the best length */ + /* into a 2 byte code word. Bump up p_src. */ + index+=bestpos; + *p_dst++=((index&0xF00)>>4)|(bestlen-3); + *p_dst++=index&0xFF; + p_src+=bestlen; + + /* As we have just coded three bytes, we are now in a position to */ + /* update the hash table with the literal bytes that were pending */ + /* upon the arrival of extra context bytes. */ + if (p_h1!=0) + { + if (p_h2!=0) + {UPDATE_P(p_h2,p_ziv-2); p_h2=0;} + UPDATE_P(p_h1,p_ziv-1); p_h1=0; + } + + /* In any case, we can update the hash table based on the current */ + /* position as we just coded at least three bytes in a copy items. */ + UPDATE_P(p_h0,p_ziv); + } + control>>=1; + + /* This loop is all set up for a decrement and jump instruction! */ + if (--unroll) goto begin_unrolled_loop; + + /* At this point it will nearly always be the end of a group in which */ + /* case, we have to do some control-word processing. However, near the */ + /* end of the input block, the inner unrolled loop is only executed once. */ + /* This necessitates the 'if' test. */ + if ((control&TOPWORD)==0) + { + /* Write the control word to the place we saved for it in the output. */ + *p_control++= control &0xFF; + *p_control = (control>>8) &0xFF; + + /* Reserve the next word in the output block for the control word */ + /* for the group about to be processed. */ + p_control=p_dst; p_dst+=2; + + /* Reset the control bits buffer. */ + control=TOPWORD; + } + + } /* End main processing loop. */ + + /* After the main processing loop has executed, all the input bytes have */ + /* been processed. However, the control word has still to be written to the */ + /* word reserved for it in the output at the start of the most recent group. */ + /* Before writing, the control word has to be shifted so that all the bits */ + /* are in the right place. The "empty" bit positions are filled with 1s */ + /* which partially fill the top word. */ + while(control&TOPWORD) control>>=1; + *p_control++= control &0xFF; + *p_control++=(control>>8) &0xFF; + + /* If the last group contained no items, delete the control word too. */ + if (p_control==p_dst) p_dst-=2; + + /* Write the length of the output block to the dst_len parameter and return. */ + return p_dst - p_dst_first; + + /* Jump here as soon as an overrun is detected. An overrun is defined to */ + /* have occurred if p_dst>p_dst_first+*p_dst_len as set by caller. */ + /* The algorithm checks for overruns at least at the end of each group */ + /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ + /* Once an overrun occurs, the only thing to do is to return an error */ + overrun: + return 0; +} + +/******************************************************************************/ + +#ifndef LZRW3A_ASM +EXPORT int ext2_LZRW3A_decompress + (p_src_first, p_dst, heap, src_len, dst_len) +/* Input : Specify input block using p_src_first. */ +/* Input : Point p_dst to the start of the output zone. */ +/* Input : dst_len contains output length */ +/* Input : Input block and output zone must not overlap. User knows */ +/* Input : upperbound on output block length from earlier compression. */ +/* Input : In any case, maximum expansion possible is nine times. */ +/* Input : src_len contains max input length */ +/* Output : Writes only in Mem[p_dst..p_dst+dst_len-1]. */ +UBYTE *p_src_first; +UBYTE *p_dst; +void *heap; +int src_len; +int dst_len; +{ + UBYTE *p_dst_first = p_dst; + + /* Byte pointers scan through the input and output blocks. */ + register UBYTE *p_src = p_src_first; + + /* The following two variables are never modified and are used to control */ + /* the main loop. */ + UBYTE * const p_dst_post = p_dst+dst_len; + UBYTE * const p_dst_max16 = p_dst+dst_len-MAX_RAW_ITEM*16; + + /* The hash table is the only resident of the working memory. The hash table */ + /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ + /* keep Macintoshes happy, it is longword aligned. */ +#if 0 + UBYTE **hash = (UBYTE **) ext2_lzrw3a_htab; +#else + UBYTE **hash = (UBYTE **) heap; +#endif + + /* The variable 'control' is used to buffer the control bits which appear in */ + /* groups of 16 bits (control words) at the start of each compressed group. */ + /* When each group is read, bit 16 of the register is set to one. Whenever */ + /* a new bit is needed, the register is shifted right. When the value of the */ + /* register becomes 1, we know that we have reached the end of a group. */ + /* Initializing the register to 1 thus instructs the code to follow that it */ + /* should read a new control word immediately. */ + register ULONG control=1; + + /* The value of 'literals' is always in the range 0..3. It is the number of */ + /* consecutive literal items just seen. We have to record this number so as */ + /* to know when to update the hash table. When literals gets to 3, there */ + /* have been three consecutive literals and we can update at the position of */ + /* the oldest of the three. */ + register UCARD literals=0; + + /* The following variable holds the current 'cycle' value. This value cycles */ + /* through the range [0,HASH_TABLE_DEPTH-1], being incremented every time */ + /* the hash table is updated. The value give the within-partition number of */ + /* the next pointer to be overwritten. The compressor maintains a cycle */ + /* value in synchrony. */ + UCARD cycle=0; + + /* Initialize all elements of the hash table to point to a constant string. */ + /* Use of an unrolled loop speeds this up considerably. */ + /* The comment about register declarations above similar code in the */ + /* compressor applies here too. */ + { + UCARD i; + UBYTE **p_h = hash; + + #define ZJ *p_h++=START_STRING_18 + for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ + {ZJ;ZJ;ZJ;ZJ; + ZJ;ZJ;ZJ;ZJ; + ZJ;ZJ;ZJ;ZJ; + ZJ;ZJ;ZJ;ZJ;} + #undef ZJ + } + + /* The outer loop processes either 1 or 16 items per iteration depending on */ + /* how close p_dst is to the end of the output block. */ + while (p_dst < p_dst_post && src_len >= 0) + {/* Start of outer loop */ + + register UCARD unroll; /* Counts unrolled loop executions. */ + + /* When 'control' has the value 1, it means that the 16 buffered control */ + /* bits that were read in at the start of the current group have all been */ + /* shifted out and that all that is left is the 1 bit that was injected */ + /* into bit 16 at the start of the current group. When we reach the end */ + /* of a group, we have to load a new control word and inject a new 1 bit. */ + if (control==1) + { + control=0x10000|*p_src++; + control|=(*p_src++)<<8; + src_len -= 2; + } + + /* If it is possible that we are within 16 groups from the end of the */ + /* input, execute the unrolled loop only once, else process a whole group */ + /* of 16 items by looping 16 times. */ + unroll= p_dst<=p_dst_max16 ? 16 : 1; + + /* This inner loop processes one phrase (item) per iteration. */ + while (unroll--) + { /* Begin unrolled inner loop. */ + + /* Process a literal or copy item depending on the next control bit. */ + if (control&1) + { + /* Copy item. */ + + register UBYTE *p; /* Points to place from which to copy. */ + register UCARD lenmt; /* Length of copy item minus three. */ + register UBYTE *p_ziv = p_dst; /* Pointer to start of current Ziv. */ + register UCARD index; /* Index of hash table copy pointer. */ + + /* Read and dismantle the copy word. Work out from where to copy. */ + lenmt=*p_src++; + index=((lenmt&0xF0)<<4)|*p_src++; + src_len -= 2; + p=hash[index]; + lenmt&=0xF; + + /* Now perform the copy using a half unrolled loop. */ + *p_dst++=*p++; + *p_dst++=*p++; + *p_dst++=*p++; + while (lenmt--) + *p_dst++=*p++; + + /* Because we have just received 3 or more bytes in a copy item */ + /* (whose bytes we have just installed in the output), we are now */ + /* in a position to flush all the pending literal hashings that had */ + /* been postponed for lack of bytes. */ + if (literals>0) + { + register UBYTE *r = p_ziv - literals;; + UPDATE_I(HASH(r),r); + if (literals==2) + {r++; UPDATE_I(HASH(r),r);} + literals=0; + } + + /* In any case, we can immediately update the hash table with the */ + /* current position. We don't need to do a HASH(...) to work out */ + /* where to put the pointer, as the compressor just told us!!! */ + UPDATE_I(index&(~DEPTH_MASK),p_ziv); + } + else + { + /* Literal item. */ + + /* Copy over the literal byte. */ + *p_dst++=*p_src++; + src_len--; + + /* If we now have three literals waiting to be hashed into the hash */ + /* table, we can do one of them now (because there are three). */ + if (++literals == 3) + {register UBYTE *p=p_dst-3; + UPDATE_I(HASH(p),p); literals=2;} + } + + /* Shift the control buffer so the next control bit is in bit 0. */ + control>>=1; + + } /* End unrolled inner loop. */ + + } /* End of outer loop */ + +#if 0 + if(src_len < 0) return 0; + return (p_src-p_src_first); +#else + return p_dst - p_dst_first; +#endif +} +#endif + +/******************************************************************************/ +/* End of LZRW3-A.C */ +/******************************************************************************/ diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/rlzrw3a.S linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/rlzrw3a.S --- linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/rlzrw3a.S +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/rlzrw3a.S @@ -0,0 +1,350 @@ +/* + * LZRW3A decompression written in assembly. + * + * Written by Antoine de Maricourt (dumesnil@etca.fr) + * 17 Mar 1995 + * + * NOTE: The use of this algorithm may be restricted by some + * patent. Please check if this is the case in your + * country before using it. As far as I know LZRW3A is + * patended in the USA. + * + * In order to be used, the compression routine (file lrzw3a.c) + * must be updated to use the following hash function : + * + * #define HASH(PTR) (\ + * (((((*(PTR)<<3)^(*((PTR)+1)))<<3)^(*((PTR)+2)))&HASH_MASK)\ + * << HASH_TABLE_DEPTH_BITS) + * + * The hash table depth is hardwired to 8. + * + * Interface : + * ----------- + * + * int rLZRW3A (char *ib, char *ob, int il, int ol); + * + * ib = input buffer (compressed data) + * ob = output buffer (uncompressed data) + * il = number of bytes in the input buffer + * ol = number of bytes to be uncompressed + * + * The routine may write more (i.e., ???) bytes than requested + * The returned value is the number of bytes written to output + * buffer. + * + * The algorithm and the coding method have been taken from + * file lzrw3a.c originaly written by Ross Williams. + * + * ----- + * Copyright (c) 1995 Antoine de Maricourt. Redistribution + * of this file is permitted under the GNU Public License. + */ + +#include + +#define A0 32 +#define A1 36 +#if 0 +#define A2 40 +#define A3 44 +#else +#define A2 44 +#define A3 48 +#endif +#define L0 + +#if 0 +#define HTAB SYMBOL_NAME(ext2_lzrw3a_htab) +#else +#define HTAB 40(%esp) +#endif + +#if 0 +.comm HTAB, 4 # hash table +#endif + +LC0: .ascii "123456789012345678\0" + + /* for i386 */ +#define bswap rol $16, + +/* + * Initialize the hash table. Some might want to do + * it with an unrolled loop. It would not be faster + * on my system. + */ + +#define InitTable() \ + movl HTAB, %edi; \ + movl $4096, %ecx; \ + movl $LC0, %eax; \ + rep; stosl + +#define CopyOneByte \ + movb (%esi), %dh; \ + movb %dh, 3(%edi) + +#define CopyByte(o1,o2) \ + movb o1(%esi), %dh; \ + movb %dh, o2(%edi) + +/* + * Update the hash key with the given byte. Note that + * the key is shifted after the xor, and not before. + * This will make it easier to add the cycle count. + */ + +#define UpdateHashKey \ + bswap %ebx; \ + xorb %dh, %bl; \ + andw $0x1ff, %bx; \ + shlw $3, %bx; \ + bswap %ebx + +/* + * Update the hashtable with the current position. The + * cycle count is incremented. + */ + +#define UpdateHashTable \ + andl $7, %edx; \ + bswap %ebx; \ + addw %bx, %dx; \ + movl %edi, (%ebp,%edx,4); \ + incb %dl; \ + bswap %ebx + +/* + * Copy a byte from the input buffer to the output + * and remember the value. This will be used instead + * of movsb when we need the value to update the hash + * key. + */ + +#define CopyLiteral \ + CopyOneByte; \ + incl %esi; \ + incl %edi; \ + UpdateHashKey + + .text + +ENTRY(ext2_LZRW3A_decompress) + pushl %ebp + pushl %edi + pushl %esi + pushl %ebx # be safe + pushl %ecx + pushl %edx + subl $4, %esp + + InitTable () + + movl A0(%esp), %esi # esi = input buffer + movl A1(%esp), %edi # edi = output buffer + subl $3, %edi + addl %esi, A2(%esp) # input limit + movl A3(%esp), %eax + addl %edi, %eax + movl %eax, A3(%esp) # output limit + subl $288, %eax + movl %eax, L0(%esp) + + /* + * eax = control word + * ebx = hash key (high) + literal count (bl) + loop count (bh) + * ecx = tmp data + * edx = cycle count (dl) + tmp data (dh) + * esi = source pointer + * edi = destination pointer + * ebp = hash table address + */ + + xorl %eax, %eax # we need a control word + movl %eax, %ebx # hash key is 0 + movl %eax, %edx # cycle is 0 + movl HTAB, %ebp # get pointer to hash table + movb $3, %bl + + /* + * Load a fresh control word if needed + */ + +L10: cmpl %esi, A2(%esp) # check for input overflow + jna L40 + + cmp $1, %eax + ja L11 + movb (%esi), %al + movb 1(%esi), %ah + lea 2(%esi), %esi + orl $0x10000, %eax + +L11: movb $16, %bh + cmpl L0(%esp), %edi + jbe L12 + movb $1, %bh + +L12: shrl $1, %eax + jc L20 # test control bit + + /* + * This is a literal + */ + + CopyLiteral + + decb %bl + jne L13 + UpdateHashTable + incb %bl + +L13: decb %bh # loop + jne L12 + + cmpl A3(%esp), %edi # check for output overflow + jb L10 # and continue + jmp L40 + + /* + * This is a copy item + */ + + + ALIGN +L20: + /* + * Load the index into ecx, and the len into dh + */ + + xorl %ecx, %ecx # clear high part of ecx + movb (%esi), %ch # load 4 high bits of index + movb 1(%esi), %cl # load 8 low bits of index + shrb $4, %ch # adjust index + + movl (%ebp,%ecx,4), %ecx # get pointer to item + xchg %ecx, %esi # put it into esi, save esi into ecx + + /* + * Copy first byte + */ + + CopyLiteral + decb %bl + jne L22 + UpdateHashTable + incb %bl + + /* + * Copy second byte + */ + +L22: CopyLiteral + decb %bl + jne L23 + UpdateHashTable + + /* + * Copy third byte + */ + +L23: CopyLiteral + UpdateHashTable # do not need to test bl. + movb $3, %bl + + /* + * Copy the remaining bytes + */ + + testb $1, (%ecx) + je L24 + CopyOneByte + incl %esi + incl %edi + +L24: testb $2, (%ecx) + je L25 + + CopyByte (0, 3) + CopyByte (1, 4) + + lea 2(%esi), %esi + lea 2(%edi), %edi + +L25: cmp %esi, %edi + ja L30 + + testb $4, (%ecx) + je L26 + + CopyByte (0, 3) + CopyByte (1, 4) + CopyByte (2, 5) + CopyByte (3, 6) + + lea 4(%esi), %esi + lea 4(%edi), %edi + +L26: testb $8, (%ecx) + je L27 + + CopyByte (0, 3) + CopyByte (1, 4) + CopyByte (2, 5) + CopyByte (3, 6) + CopyByte (4, 7) + CopyByte (5, 8) + CopyByte (6, 9) + CopyByte (7, 10) + + lea 8(%esi), %esi + lea 8(%edi), %edi + +L27: lea 2(%ecx), %esi # restore input pointer + + decb %bh # loop + jne L12 + + cmpl A3(%esp), %edi # check for output overflow + jb L10 # and continue + jmp L40 + + /* + * Copy the remaining bytes, but using movsl + * when we know the strings does not overlap. + */ + + ALIGN + +L30: lea 3(%edi), %edi + testb $4, (%ecx) + je L31 + movsl +L31: testb $8, (%ecx) + je L32 + movsl + movsl + +L32: lea -3(%edi), %edi + lea 2(%ecx), %esi # restore input pointer + decb %bh # loop + jne L12 + + cmpl A3(%esp), %edi # check for output overflow + jb L10 # and continue + + /* + * The end. + */ + +L40: lea 3(%edi), %eax + subl A1(%esp),%eax + + addl $4, %esp + popl %edx + popl %ecx + popl %ebx + popl %esi + popl %edi + popl %ebp + ret diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/wlzrw3a.c linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/wlzrw3a.c --- linux-2.2.5-e2c0.4.30/fs/ext2/lzrw/wlzrw3a.c +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/lzrw/wlzrw3a.c @@ -0,0 +1,784 @@ +/******************************************************************************/ +/* */ +/* LZRW3-A.C */ +/* */ +/******************************************************************************/ +/* */ +/* Author : Ross Williams. */ +/* Date : 15-Jul-1991. */ +/* Release : 1. */ +/* */ +/******************************************************************************/ +/* */ +/* This file contains an implementation of the LZRW3-A data compression */ +/* algorithm in the C programming language. */ +/* */ +/* The LZRW3-A algorithm has the following features: */ +/* */ +/* 1 Requires only 16K of memory (for both compression and decompression). */ +/* 2 The compressor runs about two times faster than Unix compress's. */ +/* 3 The decompressor runs about three times faster than Unix compress's. */ +/* 4 Yields a few percent better compression than Unix compress for */ +/* most files. */ +/* 5 Allows you to dial up extra compression at a speed cost in the */ +/* compressor. The speed of the decompressor is not affected. */ +/* 6 Algorithm is deterministic. */ +/* 8 This implementation in C is in the public domain. */ +/* */ +/* (Timing tests for the speed comparison were performed on a Pyramid 9820.) */ +/* */ +/* LZRW3-A is LZRW3 with a deepened hash table. This simple change yields */ +/* about a 6% (absolute) improvement in compression. */ +/* */ +/* Here are the results of applying this code, compiled under THINK C 4.0 */ +/* and running on a Mac-SE (8MHz 68000), to the standard calgary corpus. */ +/* */ +/* +----------------------------------------------------------------+ */ +/* | DATA COMPRESSION TEST | */ +/* | ===================== | */ +/* | Time of run : Mon 15-Jul-1991 05:29PM | */ +/* | Timing accuracy : One part in 100 | */ +/* | Context length : 262144 bytes (= 256.0000K) | */ +/* | Test suite : Calgary Corpus Suite | */ +/* | Files in suite : 14 | */ +/* | Algorithm : LZRW3-A | */ +/* | Note: All averages are calculated from the un-rounded values. | */ +/* +----------------------------------------------------------------+ */ +/* | File Name Length CxB ComLen %Remn Bits Com K/s Dec K/s | */ +/* | ---------- ------ --- ------ ----- ---- ------- ------- | */ +/* | rpus:Bib.D 111261 1 49044 44.1 3.53 8.47 31.19 | */ +/* | us:Book1.D 768771 3 420464 54.7 4.38 7.27 30.07 | */ +/* | us:Book2.D 610856 3 277955 45.5 3.64 8.51 33.40 | */ +/* | rpus:Geo.D 102400 1 84218 82.2 6.58 4.23 15.04 | */ +/* | pus:News.D 377109 2 192880 51.1 4.09 7.08 25.89 | */ +/* | pus:Obj1.D 21504 1 12651 58.8 4.71 5.23 17.44 | */ +/* | pus:Obj2.D 246814 1 108044 43.8 3.50 8.01 28.11 | */ +/* | s:Paper1.D 53161 1 24526 46.1 3.69 8.11 30.24 | */ +/* | s:Paper2.D 82199 1 39483 48.0 3.84 8.11 32.04 | */ +/* | rpus:Pic.D 513216 2 111622 21.7 1.74 10.64 49.31 | */ +/* | us:Progc.D 39611 1 17923 45.2 3.62 8.06 29.01 | */ +/* | us:Progl.D 71646 1 24362 34.0 2.72 10.74 39.51 | */ +/* | us:Progp.D 49379 1 16805 34.0 2.72 10.64 37.58 | */ +/* | us:Trans.D 93695 1 30296 32.3 2.59 11.02 38.06 | */ +/* +----------------------------------------------------------------+ */ +/* | Average 224401 1 100733 45.8 3.67 8.29 31.21 | */ +/* +----------------------------------------------------------------+ */ +/* */ +/******************************************************************************/ + +#include "lzrw.h" +/******************************************************************************/ + +/* The following structure is returned by the "compress" function below when */ +/* the user asks the function to return identifying information. */ +/* The most important field in the record is the working memory field which */ +/* tells the calling program how much working memory should be passed to */ +/* "compress" when it is called to perform a compression or decompression. */ +/* LZRW3-A uses the same amount of memory during compression and */ +/* decompression. For more information on this structure see "lzrw.h". */ +/* The alignment fudge below really only needs to be 4 (but I play it safe!). */ +/* The id looks non-random, but it really was generated by coin tossing! */ + +#define U(X) ((ULONG) X) +#define SIZE_P_BYTE (U(sizeof(UBYTE *))) +#define ALIGNMENT_FUDGE (U(16)) +#define MEM_REQ ( U(4096)*(SIZE_P_BYTE) + ALIGNMENT_FUDGE ) + +/*static struct compress_identity identity = +{ + U(0x01B90B91), * Algorithm identification number. * + MEM_REQ, * Working memory (bytes) required. * + "LZRW3-A", * Name of algorithm. * + "1.0", * Version number of algorithm. * + "15-Jul-1990", * Date of algorithm. * + "Ross N. Williams", * Author of algorithm. * + "Renaissance Software", * Affiliation of author. * +};*/ + +/******************************************************************************/ +/* */ +/* BRIEF DESCRIPTION OF THE LZRW3-A ALGORITHM */ +/* ========================================== */ +/* Note: Before attempting to understand this algorithm, you should first */ +/* understand the LZRW3 algorithm from which this algorithm is derived. */ +/* */ +/* The LZRW3-A algorithm is identical to the LZRW3 algorithm except that the */ +/* hash table has been "deepened". The LZRW3 algorithm has a hash table of */ +/* 4096 pointers which point to strings in the buffer. LZRW3-A generalizes */ +/* this to 4096/(2^n) partitions each of which contains (2^n) pointers. */ +/* In LZRW3-A, the hash function hashes to a partition number. */ +/* */ +/* During the processing of each phrase, LZRW3 overwrites the pointer in the */ +/* position selected by the hash function. LZRW3-A overwrites one of the */ +/* pointers in the partition that was selected by the hash function. */ +/* */ +/* When searching for a match, LZRW3-A matches against all (2^n) strings */ +/* pointed to by the pointers in the target partition. */ +/* */ +/* Deep hash tables were used in early versions of LZRW1 in late 1989, but */ +/* were discarded in an effort to increase speed (which was the primary */ +/* requirement for LZRW1). They were revived for use in LZRW3-A in order to */ +/* produce an algorithm with compression performance competitive with Unix */ +/* compress. */ +/* */ +/* Until 14-Jul-1991, deep hash tables used in prototype LZRW* algorithms */ +/* used a queue discipline within each partition. Upon the arrival of a new */ +/* pointer, the pointers in the partition would be block copied back one */ +/* position (with the oldest pointer being overwritten) and the new pointer */ +/* being inserted in the space at the front (the youngest position). */ +/* This meant that pointers to the (2^n) most recent phrases corresponding to */ +/* each hash was kept. The only flaw in this system was the time-consuming */ +/* block copy operation which was cheap for shallow tables but expensive for */ +/* deep tables. */ +/* */ +/* The traditional solution to ring buffer block copy problems is to maintain */ +/* a cyclic counter which points to the "head" of the queue. However, this */ +/* would have required one counter to be stored for each partition and would */ +/* have been slightly messy. After some thought (on 14-Jul-1991) a better */ +/* solution was found. Instead of maintaining a counter for each partition, */ +/* LZRW3-A maintains a single counter for all partitions! This counter is */ +/* maintained in both the compressor and decompressor and means that the */ +/* algorithm (effectively) overwrites a RANDOM element of the partition to be */ +/* updated. The result was to increase the speed of the compressor and */ +/* decompressor, to make the decompressor's speed independent from whatever */ +/* depth was selected, and to impair compression by less than 1% absolute. */ +/* */ +/* Setting the depth is a speed/compression tradeoff. The table below gives */ +/* the tradeoff observed for a typical 50K text file on a Mac-SE. */ +/* Note: %Rem=Percentage Remaining (after compression). */ +/* */ +/* Depth %Rem CmpK/s DecK/s */ +/* 1 45.2 14.77 32.24 */ +/* 2 42.6 12.12 31.26 */ +/* 4 40.9 10.28 31.91 */ +/* 8 40.0 7.81 32.36 */ +/* 16 39.5 5.30 32.47 */ +/* 32 39.0 3.23 32.59 */ +/* */ +/* I have chosen a depth of 8 as the "default" depth for LZRW3-A. If you use */ +/* a depth different to this (e.g. 4), you should use the name LZRW3-A(4) to */ +/* indicate that a different depth is being used. LZRW3-A(8) is an acceptable */ +/* longhand for LZRW3-A. */ +/* */ +/* To change the depth, search for "HERE IT IS" in the rest of this file. */ +/* */ +/* +---+ */ +/* |___|4095 */ +/* |===| */ +/* +---------------------*_|<---+ /----+---\ */ +/* | |___| +---|Hash | */ +/* | 512 partitions |___| |Function| */ +/* | of 8 pointers |===| \--------/ */ +/* | each (or any |___|0 ^ */ +/* | a*b=4096) +---+ | */ +/* | Hash +-----+ */ +/* | Table | */ +/* | --- */ +/* v ^^^ */ +/* +-------------------------------------|----------------+ */ +/* |||||||||||||||||||||||||||||||||||||||||||||||||||||||| */ +/* +-------------------------------------|----------------+ */ +/* | |1......18| | */ +/* |<------- Lempel=History ------------>|<--Ziv-->| | */ +/* | (=bytes already processed) |<-Still to go-->| */ +/* |<-------------------- INPUT BLOCK ------------------->| */ +/* */ +/* */ +/******************************************************************************/ +/* */ +/* DEFINITION OF COMPRESSED FILE FORMAT */ +/* ==================================== */ +/* The file consists of zero */ +/* or more GROUPS, each of which represents one or more bytes. */ +/* * Each group consists of two bytes of CONTROL information followed by */ +/* sixteen ITEMs except for the last group which can contain from one */ +/* to sixteen items. */ +/* * An item can be either a LITERAL item or a COPY item. */ +/* * Each item corresponds to a bit in the control bytes. */ +/* * The first control byte corresponds to the first 8 items in the group */ +/* with bit 0 corresponding to the first item in the group and bit 7 to */ +/* the eighth item in the group. */ +/* * The second control byte corresponds to the second 8 items in the group */ +/* with bit 0 corresponding to the ninth item in the group and bit 7 to */ +/* the sixteenth item in the group. */ +/* * A zero bit in a control word means that the corresponding item is a */ +/* literal item. A one bit corresponds to a copy item. */ +/* * A literal item consists of a single byte which represents itself. */ +/* * A copy item consists of two bytes that represent from 3 to 18 bytes. */ +/* * The first byte in a copy item will be denoted C1. */ +/* * The second byte in a copy item will be denoted C2. */ +/* * Bits will be selected using square brackets. */ +/* For example: C1[0..3] is the low nibble of the first control byte. */ +/* of copy item C1. */ +/* * The LENGTH of a copy item is defined to be C1[0..3]+3 which is a number */ +/* in the range [3,18]. */ +/* * The INDEX of a copy item is defined to be C1[4..7]*256+C2[0..8] which */ +/* is a number in the range [0,4095]. */ +/* * A copy item represents the sequence of bytes */ +/* text[POS-OFFSET..POS-OFFSET+LENGTH-1] where */ +/* text is the entire text of the uncompressed string. */ +/* POS is the index in the text of the character following the */ +/* string represented by all the items preceeding the item */ +/* being defined. */ +/* OFFSET is obtained from INDEX by looking up the hash table. */ +/* */ +/******************************************************************************/ + +/* When I first started to get concerned about the portability of my C code, */ +/* I switched over to using only macro defined types UBYTE, UWORD, ULONG and */ +/* one or two others. While, these are useful for most purposes, they impair */ +/* efficiency as, if I have a variable whose range will be [0,1000], I will */ +/* declare it as a UWORD. This will translate into (say) "short int" and */ +/* hence may be less efficient than just an "int" which represents the */ +/* natural size of the machine. Before releasing LZRW3-A, I realized this */ +/* mistake. Unfortunately, I can't access the ftp archive with my portability */ +/* header in it in time for this algorithm's release and so I am including an */ +/* extra definition. The definition UCARD stands for an unsigned (cardinal) */ +/* type that can hold values in the range [0,32767]. This is within the ANSI */ +/* range of a standard int or unsigned. No assumption about overflow of this */ +/* type is made in the code (i.e. all usages are within range and I do not */ +/* use the value -1 to detect the end of loops.). */ +/* You can use either "unsigned" or just "int" here depending on which is */ +/* more efficient in your environment (both the same probably). */ +#define UCARD unsigned + +/* The following constant defines the maximum length of an uncompressed item. */ +/* This definition must not be changed; its value is hardwired into the code. */ +/* The longest number of bytes that can be spanned by a single item is 18 */ +/* for the longest copy item. */ +#define MAX_RAW_ITEM (18) + +/* The following constant defines the maximum length of a compressed group. */ +/* This definition must not be changed; its value is hardwired into the code. */ +/* A compressed group consists of two control bytes followed by up to 16 */ +/* compressed items each of which can have a maximum length of two bytes. */ +#define MAX_CMP_GROUP (2+16*2) + +/* This constant defines the number of pointers in the hash table. The number */ +/* of partitions multiplied by the number of pointers in each partition must */ +/* multiply out to this value of 4096. In LZRW1, LZRW1-A, and LZRW2, this */ +/* table length value can be changed. However, in LZRW3-A (and LZRW3), the */ +/* table length cannot be changed because it is connected directly to the */ +/* coding scheme which is hardwired (the table index of a single pointer is */ +/* transmitted in the 12-bit index field). So don't change this constant! */ +#define HASH_TABLE_LENGTH (4096) + +/* HERE IT IS: THE PLACE TO CHANGE THE HASH TABLE DEPTH! */ +/* The following definition is the log_2 of the depth of the hash table. This */ +/* constant can be in the range [0,1,2,3,...,12]. Increasing the depth */ +/* increases compression at the expense of speed. However, you are not likely */ +/* to see much of a compression improvement (e.g. not more than 0.5%) above a */ +/* value of 6 and the algorithm will start to get very slow. See the table in */ +/* the earlier comments block for an idea of the trade-off involved. */ +/* Note: The parentheses are to avoid macro substitution funnies. */ +/* Note: The LZRW3-A default is a value of (3). */ +/* Note: If you end up choosing a value of 0, you should use LZRW3 instead. */ +/* Note: Changing the value of HASH_TABLE_DEPTH_BITS is the ONLY thing you */ +/* have to do to change the depth, so go ahead and recompile now! */ +/* Note: I have tested LZRW3-A for DEPTH_BITS=0,1,2,3,4 and a few other */ +/* values. However, I have not tested it for 12 as I can't wait that long! */ +#define HASH_TABLE_DEPTH_BITS (3) /* Must be in range [0,12]. */ + +/* The following definitions are all self-explanatory and follow from the */ +/* definition of HASH_TABLE_DEPTH_BITS and the hardwired requirement that the */ +/* hash table contain exactly 4096 pointers. */ +#define PARTITION_LENGTH_BITS (12-HASH_TABLE_DEPTH_BITS) +#define PARTITION_LENGTH (1<>4) & HASH_MASK) \ + << HASH_TABLE_DEPTH_BITS \ + ) + +#else +#define HASH(PTR) \ + ( \ + ( ((((*(PTR)<<3)^(*((PTR)+1)))<<3)^(*((PTR)+2))) & HASH_MASK) \ + << HASH_TABLE_DEPTH_BITS \ + ) +#endif + +/* Another operation that is performed more than once is the updating of the */ +/* hash table. Here two macros are defined to simplify update operations. */ +/* Updating consists of identifying and overwriting a pointer in a partition */ +/* with a newer pointer and then updating the global cycle value. */ +/* These macros accept the new pointer (NEWPTR) and either a pointer to */ +/* (P_BASE) or the index of (I_BASE) the zeroth (first, or base) pointer in */ +/* the partition that is to be updated. The macros use the 'cycle' variable */ +/* to locate and overwrite a pointer and then update the cycle value. */ +/* Note: Hardcoding 'cycle' in this macro is naughty (it should really be a */ +/* macro parameter), but I have done so because it neatens up the code. */ +#define UPDATE_P(P_BASE,NEWPTR) \ +{(P_BASE)[cycle++]=(NEWPTR); cycle&=DEPTH_MASK;} + +#define UPDATE_I(I_BASE,NEWPTR) \ +{hash[(I_BASE)+cycle++]=(NEWPTR); cycle&=DEPTH_MASK;} + +/* This constant supplies a legal (in-range) hash table index for use when */ +/* a legal-but-don't-care index is required. */ +#define ANY_HASH_INDEX (0) + +/******************************************************************************/ +#if 0 +void *ext2_lzrw3a_htab; +#endif + +EXPORT int ext2_LZRW3A_compress + (p_src_first,p_dst_first,heap,src_len,p_dst_len) +/* Input : Specify input block using p_src_first and src_len. */ +/* Input : Point p_dst_first to the start of the output zone (OZ). */ +/* Input : Point p_dst_len to a ULONG to receive the output length. */ +/* Input : Input block and output zone must not overlap. */ +/* Output : Length of output block written to *p_dst_len. */ +/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. May */ +/* Output : write in OZ=Mem[p_dst_first..p_dst_first+src_len+MAX_CMP_GROUP-1].*/ +/* Output : Upon completion *p_dst_len contains final size or 0 */ +UBYTE *p_src_first; +UBYTE *p_dst_first; +void *heap; +int src_len; +int p_dst_len; +{ + /* p_src and p_dst step through the source and destination blocks. */ + UBYTE *p_src = p_src_first; + UBYTE *p_dst = p_dst_first; + + /* The following variables are never modified and are used in the */ + /* calculations that determine when the main loop terminates. */ + UBYTE *p_src_post = p_src_first+src_len; + UBYTE *p_dst_post = p_dst_first+p_dst_len; + UBYTE *p_src_max1 = p_src_first+src_len-MAX_RAW_ITEM; + UBYTE *p_src_max16 = p_src_first+src_len-MAX_RAW_ITEM*16; + + /* The variables 'p_control' and 'control' are used to buffer control bits. */ + /* Before each group is processed, the next two bytes of the output block */ + /* are set aside for the control word for the group about to be processed. */ + /* 'p_control' is set to point to the first byte of that word. Meanwhile, */ + /* 'control' buffers the control bits being generated during the processing */ + /* of the group. Instead of having a counter to keep track of how many items */ + /* have been processed (=the number of bits in the control word), at the */ + /* start of each group, the top word of 'control' is filled with 1 bits. */ + /* As 'control' is shifted for each item, the 1 bits in the top word are */ + /* absorbed or destroyed. When they all run out (i.e. when the top word is */ + /* all zero bits, we know that we are at the end of a group. */ + #define TOPWORD 0xFFFF0000 + UBYTE *p_control; + ULONG control=TOPWORD; + + /* The variable 'hash' always points to the first element of the hash table. */ +#if 0 + UBYTE **hash= (UBYTE **) ext2_lzrw3a_htab; +#else + UBYTE **hash= (UBYTE **) heap; +#endif + + /* The following two variables represent the literal buffer. p_h1 points to */ + /* the partition (i.e. the zero'th (first) element of the partition) */ + /* corresponding to the youngest literal. p_h2 points to the partition */ + /* corresponding to the second youngest literal. */ + /* The value zero denotes an "empty" buffer value with p_h1=0 => p_h2=0. */ + UBYTE **p_h1=0; + UBYTE **p_h2=0; + + /* The following variable holds the current 'cycle' value. This value cycles */ + /* through the range [0,HASH_TABLE_DEPTH-1], being incremented every time */ + /* the hash table is updated. The value gives the within-partition number of */ + /* the next pointer to be overwritten. The decompressor maintains a cycle */ + /* value in synchrony. */ + UCARD cycle=0; + + /* Reserve the first word of output as the control word for the first group. */ + /* Note: This is undone at the end if the input block is empty. */ + p_control=p_dst; p_dst+=2; + + /* Initialize all elements of the hash table to point to a constant string. */ + /* Use of an unrolled loop speeds this up considerably. */ + /* These variables should really be declared "register", but I am worried */ + /* about the possibility that extra register declarations will tempt stupid */ + /* compilers to allocate all registers before they get to the innermostloop. */ + {UCARD i; UBYTE **p_h=hash; + #define ZH *p_h++=START_STRING_18 + for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ + {ZH;ZH;ZH;ZH; + ZH;ZH;ZH;ZH; + ZH;ZH;ZH;ZH; + ZH;ZH;ZH;ZH;} + } + + /* The main loop processes either 1 or 16 items per iteration. As its */ + /* termination logic is complicated, I have opted for an infinite loop */ + /* structure containing 'break' and 'goto' statements. */ + while (TRUE) + {/* Begin main processing loop. */ + + /* Note: All the variables here except unroll should be defined within */ + /* the inner loop. Unfortunately the loop hasn't got a block. */ + UBYTE *p_ziv; /* Points to first byte of current Ziv. */ + UCARD unroll; /* Loop counter for unrolled inner loop. */ + UCARD index; /* Index of current partition. */ + UBYTE **p_h0; /* Pointer to current partition. */ + register UCARD d; /* Depth looping variable. */ + register UCARD bestlen; /* Holds the best length seen so far. */ + register UCARD bestpos; /* Holds number of best pointer seen so far. */ + + /* Test for overrun and jump to overrun code if necessary. */ + if (p_dst>p_dst_post) + goto overrun; + + /* The following cascade of if statements efficiently catches and deals */ + /* with varying degrees of closeness to the end of the input block. */ + /* When we get very close to the end, we stop updating the table and */ + /* code the remaining bytes as literals. This makes the code simpler. */ + unroll=16; + if (p_src>p_src_max16) + { + unroll=1; + if (p_src>p_src_max1) + { + if (p_src==p_src_post) + break; + else + {p_h0=&hash[ANY_HASH_INDEX]; /* Avoid undefined pointer. */ + goto literal;} + } + } + + /* This inner unrolled loop processes 'unroll' (whose value is either 1 */ + /* or 16) items. I have chosen to implement this loop with labels and */ + /* gotos to heighten the ease with which the loop may be implemented with */ + /* a single decrement and branch instruction in assembly language and */ + /* also because the labels act as highly readable place markers. */ + /* (Also because we jump into the loop for endgame literals (see above)). */ + + begin_unrolled_loop: + + p_ziv=p_src; + + /* To process the next phrase, we hash the next three bytes to obtain */ + /* an index to the zeroth (first) pointer in a target partition. We */ + /* get the pointer. */ + index=HASH(p_src); + p_h0=&hash[index]; + + /* This next part runs through the pointers in the partition matching */ + /* the bytes they point to in the Lempel with the bytes in the Ziv. */ + /* The length (bestlen) and within-partition pointer number (bestpos) */ + /* of the longest match so far is maintained and is the output of this */ + /* segment of code. The s[bestlen]==... is an optimization only. */ + bestlen=0; + bestpos=0; + for (d=0;dbestlen) + { + bestpos=d; + bestlen=len; + } + } + } + + /* The length of the longest match determines whether we code a */ + /* literal item or a copy item. */ + + if (bestlen<3) + { + /* Literal. */ + + /* Code the literal byte as itself and a zero control bit. */ + literal: *p_dst++=*p_src++; control&=0xFFFEFFFF; + + /* We have just coded a literal. If we had two pending ones, that */ + /* makes three and we can update the hash table. */ + if (p_h2!=0) + {UPDATE_P(p_h2,p_ziv-2);} + + /* In any case, rotate the hash table pointers for next time. */ + p_h2=p_h1; p_h1=p_h0; + + } + else + { + /* Copy */ + + /* To code a copy item, we construct a hash table index of the */ + /* winning pointer (index+=bestpos) and code it and the best length */ + /* into a 2 byte code word. Bump up p_src. */ + index+=bestpos; + *p_dst++=((index&0xF00)>>4)|(bestlen-3); + *p_dst++=index&0xFF; + p_src+=bestlen; + + /* As we have just coded three bytes, we are now in a position to */ + /* update the hash table with the literal bytes that were pending */ + /* upon the arrival of extra context bytes. */ + if (p_h1!=0) + { + if (p_h2!=0) + {UPDATE_P(p_h2,p_ziv-2); p_h2=0;} + UPDATE_P(p_h1,p_ziv-1); p_h1=0; + } + + /* In any case, we can update the hash table based on the current */ + /* position as we just coded at least three bytes in a copy items. */ + UPDATE_P(p_h0,p_ziv); + } + control>>=1; + + /* This loop is all set up for a decrement and jump instruction! */ + if (--unroll) goto begin_unrolled_loop; + + /* At this point it will nearly always be the end of a group in which */ + /* case, we have to do some control-word processing. However, near the */ + /* end of the input block, the inner unrolled loop is only executed once. */ + /* This necessitates the 'if' test. */ + if ((control&TOPWORD)==0) + { + /* Write the control word to the place we saved for it in the output. */ + *p_control++= control &0xFF; + *p_control = (control>>8) &0xFF; + + /* Reserve the next word in the output block for the control word */ + /* for the group about to be processed. */ + p_control=p_dst; p_dst+=2; + + /* Reset the control bits buffer. */ + control=TOPWORD; + } + + } /* End main processing loop. */ + + /* After the main processing loop has executed, all the input bytes have */ + /* been processed. However, the control word has still to be written to the */ + /* word reserved for it in the output at the start of the most recent group. */ + /* Before writing, the control word has to be shifted so that all the bits */ + /* are in the right place. The "empty" bit positions are filled with 1s */ + /* which partially fill the top word. */ + while(control&TOPWORD) control>>=1; + *p_control++= control &0xFF; + *p_control++=(control>>8) &0xFF; + + /* If the last group contained no items, delete the control word too. */ + if (p_control==p_dst) p_dst-=2; + + /* Write the length of the output block to the dst_len parameter and return. */ + return p_dst-p_dst_first; + + /* Jump here as soon as an overrun is detected. An overrun is defined to */ + /* have occurred if p_dst>p_dst_first+*p_dst_len as set by caller. */ + /* The algorithm checks for overruns at least at the end of each group */ + /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ + /* Once an overrun occurs, the only thing to do is to return an error */ + overrun: + return 0; +} + +/******************************************************************************/ + +#if 0 +EXPORT int ext2_LZRW3A_decompress + (p_src_first, p_dst, src_len, dst_len) +/* Input : Specify input block using p_src_first. */ +/* Input : Point p_dst to the start of the output zone. */ +/* Input : dst_len contains output length */ +/* Input : Input block and output zone must not overlap. User knows */ +/* Input : upperbound on output block length from earlier compression. */ +/* Input : In any case, maximum expansion possible is nine times. */ +/* Input : src_len contains max input length */ +/* Output : Writes only in Mem[p_dst..p_dst+dst_len-1]. */ +UBYTE *p_src_first; +UBYTE *p_dst; +int src_len; +int dst_len; +{ + UBYTE *p_dst_first = p_dst; + + /* Byte pointers scan through the input and output blocks. */ + register UBYTE *p_src = p_src_first; + + /* The following two variables are never modified and are used to control */ + /* the main loop. */ + UBYTE *p_dst_post = p_dst+dst_len; + UBYTE *p_dst_max16 = p_dst+dst_len-MAX_RAW_ITEM*16; + + /* The hash table is the only resident of the working memory. The hash table */ + /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ + /* keep Macintoshes happy, it is longword aligned. */ + UBYTE **hash = (UBYTE **) ext2_lzrw3a_htab; + + /* The variable 'control' is used to buffer the control bits which appear in */ + /* groups of 16 bits (control words) at the start of each compressed group. */ + /* When each group is read, bit 16 of the register is set to one. Whenever */ + /* a new bit is needed, the register is shifted right. When the value of the */ + /* register becomes 1, we know that we have reached the end of a group. */ + /* Initializing the register to 1 thus instructs the code to follow that it */ + /* should read a new control word immediately. */ + register ULONG control=1; + + /* The value of 'literals' is always in the range 0..3. It is the number of */ + /* consecutive literal items just seen. We have to record this number so as */ + /* to know when to update the hash table. When literals gets to 3, there */ + /* have been three consecutive literals and we can update at the position of */ + /* the oldest of the three. */ + register UCARD literals=0; + + /* The following variable holds the current 'cycle' value. This value cycles */ + /* through the range [0,HASH_TABLE_DEPTH-1], being incremented every time */ + /* the hash table is updated. The value give the within-partition number of */ + /* the next pointer to be overwritten. The compressor maintains a cycle */ + /* value in synchrony. */ + UCARD cycle=0; + + /* Initialize all elements of the hash table to point to a constant string. */ + /* Use of an unrolled loop speeds this up considerably. */ + /* The comment about register declarations above similar code in the */ + /* compressor applies here too. */ + {UCARD i; UBYTE **p_h=hash; + #define ZJ *p_h++=START_STRING_18 + for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ + {ZJ;ZJ;ZJ;ZJ; + ZJ;ZJ;ZJ;ZJ; + ZJ;ZJ;ZJ;ZJ; + ZJ;ZJ;ZJ;ZJ;} + } + + /* The outer loop processes either 1 or 16 items per iteration depending on */ + /* how close p_dst is to the end of the output block. */ + while (p_dst < p_dst_post && src_len >= 0) + {/* Start of outer loop */ + + register UCARD unroll; /* Counts unrolled loop executions. */ + + /* When 'control' has the value 1, it means that the 16 buffered control */ + /* bits that were read in at the start of the current group have all been */ + /* shifted out and that all that is left is the 1 bit that was injected */ + /* into bit 16 at the start of the current group. When we reach the end */ + /* of a group, we have to load a new control word and inject a new 1 bit. */ + if (control==1) + { + control=0x10000|*p_src++; + control|=(*p_src++)<<8; + src_len -= 2; + } + + /* If it is possible that we are within 16 groups from the end of the */ + /* input, execute the unrolled loop only once, else process a whole group */ + /* of 16 items by looping 16 times. */ + unroll= p_dst<=p_dst_max16 ? 16 : 1; + + /* This inner loop processes one phrase (item) per iteration. */ + while (unroll--) + { /* Begin unrolled inner loop. */ + + /* Process a literal or copy item depending on the next control bit. */ + if (control&1) + { + /* Copy item. */ + + register UBYTE *p; /* Points to place from which to copy. */ + register UCARD lenmt; /* Length of copy item minus three. */ + register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */ + register UCARD index; /* Index of hash table copy pointer. */ + + /* Read and dismantle the copy word. Work out from where to copy. */ + lenmt=*p_src++; + index=((lenmt&0xF0)<<4)|*p_src++; + src_len -= 2; + p=hash[index]; + lenmt&=0xF; + + /* Now perform the copy using a half unrolled loop. */ + *p_dst++=*p++; + *p_dst++=*p++; + *p_dst++=*p++; + while (lenmt--) + *p_dst++=*p++; + + /* Because we have just received 3 or more bytes in a copy item */ + /* (whose bytes we have just installed in the output), we are now */ + /* in a position to flush all the pending literal hashings that had */ + /* been postponed for lack of bytes. */ + if (literals>0) + { + register UBYTE *r=p_ziv-literals;; + UPDATE_I(HASH(r),r); + if (literals==2) + {r++; UPDATE_I(HASH(r),r);} + literals=0; + } + + /* In any case, we can immediately update the hash table with the */ + /* current position. We don't need to do a HASH(...) to work out */ + /* where to put the pointer, as the compressor just told us!!! */ + UPDATE_I(index&(~DEPTH_MASK),p_ziv); + } + else + { + /* Literal item. */ + + /* Copy over the literal byte. */ + *p_dst++=*p_src++; + src_len--; + + /* If we now have three literals waiting to be hashed into the hash */ + /* table, we can do one of them now (because there are three). */ + if (++literals == 3) + {register UBYTE *p=p_dst-3; + UPDATE_I(HASH(p),p); literals=2;} + } + + /* Shift the control buffer so the next control bit is in bit 0. */ + control>>=1; + + } /* End unrolled inner loop. */ + + } /* End of outer loop */ + +#if 0 + if(src_len < 0) return 0; + return (p_src-p_src_first); +#else + return p_dst - p_dst_first; +#endif +} +#endif + +/******************************************************************************/ +/* End of LZRW3-A.C */ +/******************************************************************************/ diff -urN linux-2.2.5-e2c0.4.30/fs/ext2/new-method-howto.c linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/new-method-howto.c --- linux-2.2.5-e2c0.4.30/fs/ext2/new-method-howto.c +++ linux-2.2.5-e2c0.4.30-lzrw/fs/ext2/new-method-howto.c @@ -118,10 +118,9 @@ in fs/ext2/Makefile. Otherwise `mkdir fs/ext2/foo', and put a Makefile in it. If you - have .S files, lzrw/Makefile (see the separate LZRW patch on - ) is a - good starting point, otherwise gzip/Makefile. Add foo to the - definition of SUB_DIRS in fs/ext2/Makefile. + have .S files, lzrw/Makefile is a good starting point, otherwise + gzip/Makefile. Add foo to the definition of SUB_DIRS in + fs/ext2/Makefile. + Edit fs/Config.in. Search for `LZV' (there should be two such lines), duplicate each line, and change LZV to FOO. diff -urN linux-2.2.5-e2c0.4.30/include/linux/ext2_fs_c.h linux-2.2.5-e2c0.4.30-lzrw/include/linux/ext2_fs_c.h --- linux-2.2.5-e2c0.4.30/include/linux/ext2_fs_c.h +++ linux-2.2.5-e2c0.4.30-lzrw/include/linux/ext2_fs_c.h @@ -157,7 +157,11 @@ # else # define _ext2_lzv1_builtin 0 # endif -# define _ext2_lzrw3a_builtin 0 +# ifdef CONFIG_EXT2_HAVE_LZRW3A +# define _ext2_lzrw3a_builtin (1 << EXT2_LZRW3A_ALG) +# else +# define _ext2_lzrw3a_builtin 0 +# endif # ifdef CONFIG_EXT2_HAVE_GZIP # define _ext2_gzip_builtin (1 << EXT2_GZIP_ALG) # else @@ -179,7 +183,11 @@ # else # define _ext2_lzv1_module 0 # endif -# define _ext2_lzrw3a_module 0 +# ifdef CONFIG_EXT2_HAVE_LZRW3A_MODULE +# define _ext2_lzrw3a_module (1 << EXT2_LZRW3A_ALG) +# else +# define _ext2_lzrw3a_module 0 +# endif # ifdef CONFIG_EXT2_HAVE_GZIP_MODULE # define _ext2_gzip_module (1 << EXT2_GZIP_ALG) # else @@ -317,6 +325,7 @@ extern size_t ext2_iLZV1 (int); extern size_t ext2_iLZV2 (int); +extern size_t ext2_iLZRW3A (int); extern size_t ext2_iNONE (int); extern size_t ext2_iGZIP (int); extern size_t ext2_iBZIP2 (int); @@ -324,6 +333,7 @@ extern size_t ext2_wLZV1 (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_wLZV2 (__u8*, __u8*, void*, size_t, size_t, int); +extern size_t ext2_wLZRW3A (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_wNONE (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_wGZIP (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_wBZIP2 (__u8*, __u8*, void*, size_t, size_t, int); @@ -331,6 +341,7 @@ extern size_t ext2_rLZV1 (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_rLZV2 (__u8*, __u8*, void*, size_t, size_t, int); +extern size_t ext2_rLZRW3A (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_rNONE (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_rGZIP (__u8*, __u8*, void*, size_t, size_t, int); extern size_t ext2_rBZIP2 (__u8*, __u8*, void*, size_t, size_t, int);