summaryrefslogtreecommitdiffstats
path: root/openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2005-05-28 09:17:29 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2005-05-28 09:17:29 +0000
commit50af40000ac37ef921ebd46f6d641959503ee919 (patch)
tree823ff43388135467a5c7a60589acf62d173cedc4 /openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch
parent16530342e5f63527dc2e0c78dcaef4f4b68ceb48 (diff)
move package/linux into target/linux, use wbx' new kernel code. support building images with more than one kernel, split kernel module parts off of packages that use their own kernel modules (fuse, shfs, openswan). some cleanup in the image building process in target/. image builder is disabled for now, needs some fixing.
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@1085 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch')
-rw-r--r--openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch9119
1 files changed, 9119 insertions, 0 deletions
diff --git a/openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch b/openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch
new file mode 100644
index 000000000..56c5b3cbc
--- /dev/null
+++ b/openwrt/target/linux/linux-2.4/patches/005-jffs2_compression.patch
@@ -0,0 +1,9119 @@
+diff -Nur linux-mips-cvs/Documentation/Configure.help linux-mips/Documentation/Configure.help
+--- linux-mips-cvs/Documentation/Configure.help 2005-01-20 03:19:21.000000000 +0100
++++ linux-mips/Documentation/Configure.help 2005-02-07 05:08:35.000000000 +0100
+@@ -17528,6 +17528,32 @@
+ If reporting bugs, please try to have available a full dump of the
+ messages at debug level 1 while the misbehaviour was occurring.
+
++ARMLIB compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_ARMLIB
++ This enables ARMLIB support for BBC.
++
++LZO1X-* compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZO
++ This enables LZO1X-1 and LZO1X-999 support for BBC. (fast & good
++ compressor, beats ZLIB in everything)
++
++LZARI compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZARI
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional arithmetic coding (damn slow, but best compresor).
++
++LZHD compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZHD
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional dynamic Huffman coding (a little faster than LZARI, and
++ it's compression ratio is a little worse than LZARI's)
++
++LZSS compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZSS
++ This enables simple LempelZiv-Storer-Szymanski compression for BBC
++ (faster than LZHD, and, and has a not-so-good compression ratio,
++ was included just for testing)
++
+ JFFS stats available in /proc filesystem
+ CONFIG_JFFS_PROC_FS
+ Enabling this option will cause statistics from mounted JFFS file systems
+diff -Nur linux-mips-cvs/fs/Config.in linux-mips/fs/Config.in
+--- linux-mips-cvs/fs/Config.in 2004-11-19 01:28:47.000000000 +0100
++++ linux-mips/fs/Config.in 2005-02-07 05:08:34.000000000 +0100
+@@ -50,6 +50,12 @@
+ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
+ int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
+ fi
++dep_mbool ' ARMLIB compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_ARMLIB $CONFIG_JFFS2_FS
++dep_mbool ' LZO1X-* compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZO $CONFIG_JFFS2_FS
++dep_mbool ' LZARI compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZARI $CONFIG_JFFS2_FS
++dep_mbool ' LZHD compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZHD $CONFIG_JFFS2_FS
++dep_mbool ' LZSS compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZSS $CONFIG_JFFS2_FS
++
+ tristate 'Compressed ROM file system support' CONFIG_CRAMFS
+ bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
+ define_bool CONFIG_RAMFS y
+diff -Nur linux-mips-cvs/fs/jffs2/Config.in.bbc.inc linux-mips/fs/jffs2/Config.in.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Config.in.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Config.in.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,5 @@
++dep_mbool ' ARMLIB compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_ARMLIB $CONFIG_JFFS2_FS
++dep_mbool ' LZO1X-* compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZO $CONFIG_JFFS2_FS
++dep_mbool ' LZARI compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZARI $CONFIG_JFFS2_FS
++dep_mbool ' LZHD compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZHD $CONFIG_JFFS2_FS
++dep_mbool ' LZSS compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZSS $CONFIG_JFFS2_FS
+diff -Nur linux-mips-cvs/fs/jffs2/Configure.help.bbc.inc linux-mips/fs/jffs2/Configure.help.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Configure.help.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Configure.help.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,25 @@
++ARMLIB compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_ARMLIB
++ This enables ARMLIB support for BBC.
++
++LZO1X-* compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZO
++ This enables LZO1X-1 and LZO1X-999 support for BBC. (fast & good
++ compressor, beats ZLIB in everything)
++
++LZARI compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZARI
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional arithmetic coding (damn slow, but best compresor).
++
++LZHD compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZHD
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional dynamic Huffman coding (a little faster than LZARI, and
++ it's compression ratio is a little worse than LZARI's)
++
++LZSS compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZSS
++ This enables simple LempelZiv-Storer-Szymanski compression for BBC
++ (faster than LZHD, and, and has a not-so-good compression ratio,
++ was included just for testing)
+diff -Nur linux-mips-cvs/fs/jffs2/Kconfig.bbc.inc linux-mips/fs/jffs2/Kconfig.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Kconfig.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Kconfig.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,40 @@
++config JFFS2_BBC_ARMLIB
++ bool "ARMLIB compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables ARMLIB support for BBC.
++
++config JFFS2_BBC_LZO
++ bool "LZO1X-* compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables LZO1X-1 and LZO1X-999 support for BBC. (fast & good
++ compressor)
++
++config JFFS2_BBC_LZARI
++ bool "LZARI compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional arithmetic coding (damn slow, but best compresor).
++
++config JFFS2_BBC_LZHD
++ bool "LZHD compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional dynamic Huffman coding (a little faster than LZARI, and
++ it's compression ratio is a little worse than LZARI's)
++
++config JFFS2_BBC_LZSS
++ bool "LZSS compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables simple LempelZiv-Storer-Szymanski compression for BBC
++ (faster than LZHD, and, and has a not-so-good compression ratio,
++ was included just for testing)
+diff -Nur linux-mips-cvs/fs/jffs2/Makefile linux-mips/fs/jffs2/Makefile
+--- linux-mips-cvs/fs/jffs2/Makefile 2003-08-13 19:19:25.000000000 +0200
++++ linux-mips/fs/jffs2/Makefile 2005-02-07 05:08:34.000000000 +0100
+@@ -10,9 +10,23 @@
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+
+
++JFFS2_BBC_KERNEL_OBJS-y = jffs2_bbc_framework.o jffs2_bbc_fs.o
++
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_ARMLIB) += jffs2_bbc_armlib_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZO) += jffs2_bbc_lzo_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZSS) += jffs2_bbc_lzss_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZARI) += jffs2_bbc_lzari_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZHD) += jffs2_bbc_lzhd_comp.o
++
++JFFS2_BBC_KERNEL_OBJS := $(JFFS2_BBC_KERNEL_OBJS-y)
++
++JFFS2_BBC_MKFS_OBJS = jffs2_bbc_mkfs.o jffs2_bbc_framework.o jffs2_bbc_armlib_comp.o jffs2_bbc_lzo_comp.o\
++ jffs2_bbc_lzss_comp.o jffs2_bbc_lzari_comp.o jffs2_bbc_lzhd_comp.o
++
+ COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
+ compr_zlib.o
+ JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
++ $(JFFS2_BBC_KERNEL_OBJS) \
+ read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
+ symlink.o build.o erase.o background.o
+
+diff -Nur linux-mips-cvs/fs/jffs2/Makefile.bbc.inc linux-mips/fs/jffs2/Makefile.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Makefile.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Makefile.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,12 @@
++JFFS2_BBC_KERNEL_OBJS-y = jffs2_bbc_framework.o jffs2_bbc_fs.o
++
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_ARMLIB) += jffs2_bbc_armlib_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZO) += jffs2_bbc_lzo_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZSS) += jffs2_bbc_lzss_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZARI) += jffs2_bbc_lzari_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZHD) += jffs2_bbc_lzhd_comp.o
++
++JFFS2_BBC_KERNEL_OBJS := $(JFFS2_BBC_KERNEL_OBJS-y)
++
++JFFS2_BBC_MKFS_OBJS = jffs2_bbc_mkfs.o jffs2_bbc_framework.o jffs2_bbc_armlib_comp.o jffs2_bbc_lzo_comp.o\
++ jffs2_bbc_lzss_comp.o jffs2_bbc_lzari_comp.o jffs2_bbc_lzhd_comp.o
+diff -Nur linux-mips-cvs/fs/jffs2/compr_zlib.c linux-mips/fs/jffs2/compr_zlib.c
+--- linux-mips-cvs/fs/jffs2/compr_zlib.c 2003-01-11 18:53:17.000000000 +0100
++++ linux-mips/fs/jffs2/compr_zlib.c 2005-02-07 05:08:35.000000000 +0100
+@@ -85,7 +85,7 @@
+ vfree(inflate_workspace);
+ }
+
+-int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
++int jffs2_zlib_compress2(unsigned char *data_in, unsigned char *cpage_out,
+ __u32 *sourcelen, __u32 *dstlen)
+ {
+ z_stream strm;
+@@ -145,7 +145,7 @@
+ return 0;
+ }
+
+-void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
++void jffs2_zlib_decompress2(unsigned char *data_in, unsigned char *cpage_out,
+ __u32 srclen, __u32 destlen)
+ {
+ z_stream strm;
+@@ -175,3 +175,19 @@
+ zlib_inflateEnd(&strm);
+ up(&inflate_sem);
+ }
++
++extern int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 * sourcelen, __u32 * dstlen);
++extern void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
++
++int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
++ __u32 *sourcelen, __u32 *dstlen)
++{
++ return jffs2_zlib_compress(data_in,cpage_out,sourcelen,dstlen);
++}
++
++void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
++ __u32 srclen, __u32 destlen)
++{
++ jffs2_zlib_decompress(data_in,cpage_out,srclen,destlen);
++}
++
+diff -Nur linux-mips-cvs/fs/jffs2/file.c linux-mips/fs/jffs2/file.c
+--- linux-mips-cvs/fs/jffs2/file.c 2003-11-17 02:07:44.000000000 +0100
++++ linux-mips/fs/jffs2/file.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_framework.h" /**BBC**/
+ #include <linux/kernel.h>
+ #include <linux/mtd/compatmac.h> /* for min() */
+ #include <linux/slab.h>
+@@ -459,6 +460,7 @@
+
+ comprbuf = kmalloc(cdatalen, GFP_KERNEL);
+ if (comprbuf) {
++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
+ comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen);
+ }
+ if (comprtype == JFFS2_COMPR_NONE) {
+diff -Nur linux-mips-cvs/fs/jffs2/gc.c linux-mips/fs/jffs2/gc.c
+--- linux-mips-cvs/fs/jffs2/gc.c 2003-11-17 02:07:44.000000000 +0100
++++ linux-mips/fs/jffs2/gc.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_framework.h" /**BBC**/
+ #include <linux/kernel.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/slab.h>
+@@ -651,6 +652,7 @@
+ writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
+
+ if (comprbuf) {
++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
+ comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
+ }
+ if (comprtype) {
+diff -Nur linux-mips-cvs/fs/jffs2/hpatch linux-mips/fs/jffs2/hpatch
+--- linux-mips-cvs/fs/jffs2/hpatch 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/hpatch 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,191 @@
++#!/usr/bin/perl
++# A patch-like utility
++# Designed for patching different version of jffs2 with the same hpatch file
++#
++# Copyright (C) 2004, Ferenc Havasi
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License
++# as published by the Free Software Foundation; either version 2
++# of the License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++$filename_tmp1="file1.tmp";
++$filename_tmp2="file2.tmp";
++
++$filename_in="";
++$filename_out=$filename_tmp1;
++$filename_cnt=0;
++
++# Modes:
++# 0: expecting =
++# 1: normal_cmd
++# 2: skip until =
++# 3: expecting F (first state)
++$mode=3;
++
++%rules = ();
++
++sub file_end {
++ if (($mode!=2)&&($modified==1)) {
++ while (<SRC>) {
++ print DST $_;
++ }
++ close(SRC);
++ close(DST);
++ if ($cmd_name ne "") { $rules{"$cmd_name"}=1; }
++ $filename_result=$filename_out;
++ if ($filename_result ne $filename_in_save) {
++ open(RES,"<$filename_result") or die "Cannot open $filename_result.\n";
++ open(DST,">$filename_in_save") or die "Cannot open $filename_in_save.\n";
++ while (<RES>) {
++ print DST $_;
++ }
++ close(DST);
++ close(RES);
++ }
++ unlink($filename_tmp1) && unlink($filename_tmp2);
++ }
++ else {
++ close(SRC);
++ close(DST);
++ $filename_result=$filename_in;
++ if ($filename_result ne $filename_in_save) {
++ open(RES,"<$filename_result") or die "Cannot open $filename_result.\n";
++ open(DST,">$filename_in_save") or die "Cannot open $filename_in_save.\n";
++ while (<RES>) {
++ print DST $_;
++ }
++ close(DST);
++ close(RES);
++ }
++ unlink($filename_tmp1);
++ }
++ $modified=0;
++ foreach $rulename (keys %rules) {
++ if ($rules{"$rulename"}==0) { print(STDERR "On $filename_in_save error applying rule $rulename.\n"); }
++ }
++ %rules = ();
++}
++
++if ($#ARGV<0) {
++ print ("usage: hpatch hpatch_file\n");
++ exit;
++}
++
++open(CMD,"<$ARGV[0]") or die "Cannot open $ARGV[0].\n";
++$cmd_linenum=0;
++
++while (chomp($cmd_line=<CMD>)) {
++ $cmd_linenum++;
++ if ($cmd_line eq "") {next;}
++ #$cmd_line =~ s/\#.*//;
++ $cmd_line =~ s/\ *$//;
++ if ($cmd_line eq "") {next;}
++ if ($cmd_line =~ /^F(.*)/) {
++ $tmp_filename_in=$1;
++ if ($mode!=3) {
++ file_end();
++ }
++ $filename_in=$tmp_filename_in;
++ $filename_in_save=$filename_in;
++ open(SRC,"<$filename_in") or die "Cannot open $filename_in.\n";
++ open(DST,">$filename_out") or die "Cannot open $filename_out.\n";;
++ $modified=0;
++ $mode=0;
++ next;
++ }
++ if ($mode==3) {die "error: F expression expected in line $cmd_linenum\n";}
++ if ($cmd_line =~ /^=(.*)/) {
++ $tmp_cmd_name=$1;
++ if (($mode!=2)&&($modified==1)) {
++ while (<SRC>) {
++ print DST $_;
++ }
++ close(SRC);
++ close(DST);
++ if (($cmd_name ne "")) {$rules{"$cmd_name"}=1;};
++ $filename_cnt++;
++ if ($filename_cnt%2==1) {
++ $filename_in=$filename_tmp1;
++ $filename_out=$filename_tmp2;
++ }
++ else {
++ $filename_in=$filename_tmp2;
++ $filename_out=$filename_tmp1;
++ }
++ }
++ else {
++ close(SRC);
++ close(DST);
++ }
++ $mode=1;
++ $cmd_name=$tmp_cmd_name;
++ if (($cmd_name ne "")) {
++ if ($rules{"$cmd_name"}==1) {
++ $mode=2;
++ }
++ else {
++ $rules{"$cmd_name"}=0;
++ }
++ }
++ open(SRC,"<$filename_in") or die "Cannot open $filename_in.\n";
++ open(DST,">$filename_out") or die "Cannot open $filename_out.\n";
++ $modified=0;
++ next;
++ }
++ if ($mode == 0) {die "error: = expression expected in line $cmd_linenum\n";}
++ if ($mode == 2) {next;}
++ if ($cmd_line =~ /^!(.*)/) {
++ print "$1\n";
++ $modified=1;
++ next;
++ }
++ if ($cmd_line =~ /^\?(.*)/) {
++ $search_str=$1;
++ $found=0;
++ while (<SRC>) {
++ print DST $_;
++ if (index($_,$search_str)>=0) {$found=1; last;}
++ }
++ if ($found==0) { $mode=2; }
++ next;
++ }
++ if ($cmd_line =~ /^\+(.*)/) {
++ print DST "$1\n";
++ $modified=1;
++ next;
++ }
++ if ($cmd_line =~ /^\-(.*)/) {
++ $search_str=$1;
++ $found=0;
++ while (<SRC>) {
++ if (index($_,$search_str)>=0) {$saved_line=$_; $found=1; $modified=1; last;}
++ print DST $_;
++ }
++ if ($found==0) { $mode=2; }
++ next;
++ }
++ if ($cmd_line =~ /^i(.*)/) {
++ $filename_inc=$1;
++ open(INCSRC,"<$filename_inc") or die "Cannot open $filename_inc.\n";
++ while (<INCSRC>) {
++ print DST $_;
++ }
++ next;
++ }
++ if ($cmd_line =~ /^I/) {
++ print DST $saved_line;
++ next;
++ }
++}
++file_end();
++close(CMD);
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_armlib_comp.c linux-mips/fs/jffs2/jffs2_bbc_armlib_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_armlib_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_armlib_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,2224 @@
++/*
++ * JFFS2-BBC: armlib compressor plugin
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi & Tamas Gergely
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++#include "jffs2_bbc_framework.h"
++
++#ifdef __KERNEL__
++#include <linux/string.h>
++#else
++#include <string.h>
++#endif
++
++//ORIGIN: include/DataStructures/TypeDefs.h
++
++/*******************************************************************************
++* FILE: TypeDefs.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef TYPEDEFS_H
++#define TYPEDEFS_H
++
++#pragma pack(4)
++
++#ifndef bool
++#define bool char
++#define true 1
++#define false 0
++#endif
++
++#ifndef u8
++#define u8 unsigned char
++#endif
++#ifndef u16
++#define u16 unsigned short
++#endif
++#ifndef u32
++#define u32 unsigned long
++#endif
++#ifndef s8
++#define s8 signed char
++#endif
++#ifndef s16
++#define s16 signed short
++#endif
++#ifndef s32
++#define s32 signed long
++#endif
++
++typedef struct
++{
++ u32 capacity;
++ u32 size;
++ u32 alloc_size;
++ void *ptr;
++} vector;
++
++#define VECTOR_P_END(vct) ((void*)(((char*)((vct)->ptr)) + (vct)->size))
++#define VECTOR_S_END(vct) ((void*)(((char*)((vct).ptr)) + (vct).size))
++
++static void vector_clear(vector *);
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void vector_reset(vector *);
++static void vector_clr_ptr(vector *);
++static void vector_add_u8(vector *, u8);
++static void vector_add_u16(vector *, u16);
++static void vector_add_u32(vector *, u32);
++static void vector_add_s8(vector *, s8);
++static void vector_add_s16(vector *, s16);
++static void vector_add_s32(vector *, s32);
++static void vector_add_ptr(vector *, void *);
++static void vector_concat(vector *, vector *);
++#endif
++
++#endif
++
++//ORIGIN: include/DataStructures/DataTypes.h
++
++/*******************************************************************************
++* FILE: DataTypes.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef DATATYPES_H
++#define DATATYPES_H
++
++//#include "DataStructures/TypeDefs.h"
++
++typedef u16 THUMB_DataType;
++typedef u32 ARM_DataType;
++typedef u8 TokenType;
++typedef u8 PredictorType;
++typedef u8 *ProbDist;
++
++typedef vector RawData;
++typedef vector RawBlocks;
++typedef vector TokenStream;
++typedef vector TokenBlocks;
++typedef vector LatType;
++
++#define THUMB_DATA_LENGTH 16
++#define ARM_DATA_LENGTH 32
++#define TOKEN_LENGTH 8
++#define TOKEN_MAXVALUE 0xff
++#define PREDICTOR_LENGTH 8
++#define PREDICTOR_MAXVALUE 0xff
++
++#endif
++
++//ORIGIN: include/DataStructures/BitVector.h
++
++/*******************************************************************************
++* FILE: BitVector.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef BITVECTOR_H
++#define BITVECTOR_H
++
++//#include "DataStructures/TypeDefs.h"
++
++typedef vector BitBlocks;
++
++#pragma pack(4)
++
++typedef struct
++{
++ u32 freebits;
++ u32 capacity;
++ u32 size;
++ u8 *base;
++ u8 *ptr;
++} BitVector;
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void bitblocks_clear(BitBlocks *);
++static void bitvector_clear(BitVector *);
++static void bitvector_W_reset(BitVector *);
++static void bitvector_W_add0(BitVector *);
++static void bitvector_W_add1(BitVector *);
++static void bitvector_W_concat_b(BitVector *, BitVector *);
++static void bitvector_W_concat_v(BitVector *, vector *);
++static void bitvector_W_flush(BitVector *);
++static void bitvector_R_reset(BitVector *);
++static u8 bitvector_R_get1(BitVector *);
++static u8 bitvector_R_get8(BitVector *);
++#endif
++
++#define BITVECTOR_P_END(bv) ((void*)(((bv)->base)+((bv)->size)))
++#define BITVECTOR_S_END(bv) ((void*)( ((bv).base)+ ((bv).size)))
++#define BITVECTOR_SKIP(bv,num) ((bv)->ptr) += (num)
++
++#endif
++
++//ORIGIN: include/DataStructures/DecisionTree.h
++
++/*******************************************************************************
++* FILE: DecisionTree.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef DECISIONTREE_H
++#define DECISIONTREE_H
++
++//#include "DataStructures/DataTypes.h"
++
++#pragma pack(4)
++
++#define TREENODETYPE_NULLNODE 0
++#define TREENODETYPE_NODE_BINARY_EQ 1
++#define TREENODETYPE_LEAF_P 2
++#define TREENODETYPE_LEAF_C 3
++#define TREENODETYPE_NODE_BINARY_LT 5
++#define TREENODETYPE_IS_NODE(n) (((n) == TREENODETYPE_NODE_BINARY_EQ) || \
++ ((n) == TREENODETYPE_NODE_BINARY_LT))
++#define TREENODETYPE_IS_NODE_BINARY(n) (((n) == TREENODETYPE_NODE_BINARY_EQ) || \
++ ((n) == TREENODETYPE_NODE_BINARY_LT))
++
++#define TREENODETYPE_IS_LEAF(n) (((n) == TREENODETYPE_LEAF_P) || \
++ ((n) == TREENODETYPE_LEAF_C))
++
++
++#define TREE_SUBTREE_RELATION_LEFT_EQ !=
++#define TREE_SUBTREE_RELATION_RIGHT_EQ ==
++#define TREE_SUBTREE_RELATION_LEFT_LT <
++#define TREE_SUBTREE_RELATION_RIGHT_LT >=
++
++#define GET_NODE_PTR_TYPE(n) (((TreeNodeDummy*)(n))->type)
++
++typedef struct
++{
++ u8 type;
++} TreeNodeDummy;
++
++typedef struct
++{
++ u8 type; // [TREENODETYPE_NODE_BINARY]
++ u8 attribute;
++ PredictorType value;
++ void *left;
++ void *right;
++} TreeNodeBinary;
++
++typedef struct
++{
++ u8 type; // [TREENODETYPE_LEAF_P]
++ u16 pairs;
++ PredictorType *probabilities;
++} TreeLeafP;
++
++typedef struct
++{
++ u8 type; // [TREENODETYPE_LEAF_C]
++ PredictorType predicted_class;
++} TreeLeafC;
++
++typedef struct
++{
++ u32 high;
++ u32 low;
++ u32 max;
++} ProbabilityType;
++
++
++typedef struct
++{
++ void *root;
++ u16 number_of_classes;
++ u16 number_of_predictors;
++ PredictorType *predictor_max_values;
++} DecisionTree;
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void decisiontree_delete(DecisionTree *);
++static void decisiontree_get_probability_for_token(void *, PredictorType *, TokenType, ProbabilityType *);
++static TokenType decisiontree_get_token_for_range(void *, PredictorType *, u32, u32, ProbabilityType *);
++#endif
++
++#endif
++
++//ORIGIN: include/DataStructures/PredictorTable.h
++
++/*******************************************************************************
++* FILE: PredictorTable.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef PREDICTORTABLE_H
++#define PREDICTORTABLE_H
++
++//#include "DataStructures/TypeDefs.h"
++//#include "DataStructures/DataTypes.h"
++////#include "DataStructures/Filter.h"
++////#include "DataStructures/Converter.h"
++////#include "DataStructures/Manipulator.h"
++
++#define NUMBER_OF_PREDICTORS_ARM 17
++
++#ifndef __KERNEL__
++#define NUMBER_OF_PREDICTORS_TXT 2
++#else
++#undef TXT_TOKENS
++#endif // __KERNEL__
++
++#ifdef TXT_TOKENS
++#define NUMBER_OF_PREDICTORS NUMBER_OF_PREDICTORS_TXT
++#define predictortable_reset predictortable_resetTXT
++#define predictortable_update predictortable_updateTXT
++#define predictortable_minvalue predictortable_minvalueTXT
++#define predictortable_maxvalue predictortable_maxvalueTXT
++#else
++#define NUMBER_OF_PREDICTORS NUMBER_OF_PREDICTORS_ARM
++#define predictortable_reset predictortable_resetARM
++#define predictortable_update predictortable_updateARM
++#define predictortable_minvalue predictortable_minvalueARM
++#define predictortable_maxvalue predictortable_maxvalueARM
++#endif
++
++
++#pragma pack(4)
++
++typedef struct
++{
++ PredictorType *predictors;
++} PredictorTable;
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void predictortable_clear(PredictorTable *);
++static void predictortable_free(PredictorTable *);
++static void predictortable_resetARM(PredictorTable *);
++static void predictortable_updateARM(PredictorTable *, TokenType);
++static PredictorType predictortable_minvalueARM(PredictorTable *, u32);
++static PredictorType predictortable_maxvalueARM(PredictorTable *, u32);
++#endif
++
++#ifndef __KERNEL__
++/*
++static void predictortable_resetTXT(PredictorTable *);
++static void predictortable_updateTXT(PredictorTable *, TokenType);
++static PredictorType predictortable_minvalueTXT(PredictorTable *, u32);
++static PredictorType predictortable_maxvalueTXT(PredictorTable *, u32);
++*/
++#endif // __KERNEL__
++
++#endif
++
++//ORIGIN: include/DataStructures/ipack_model.h
++
++/*******************************************************************************
++* FILE: ipack_model.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef IPACK_MODEL_H
++#define IPACK_MODEL_H
++
++//#include "DataStructures/DataTypes.h"
++//#include "DataStructures/DecisionTree.h"
++//#include "DataStructures/PredictorTable.h"
++
++#define PROBABILITY_SHIFT 12
++#define PROBABILITY_MAX 0x00001000l
++
++#define NUMBER_OF_TOKENS_ARM 16
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION_ARM 8
++
++#ifndef __KERNEL__
++#define NUMBER_OF_TOKENS_TXT 256
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION_TXT 4
++#else
++#undef TXT_TOKENS
++#endif // __KERNEL__
++
++#ifdef TXT_TOKENS
++#define NUMBER_OF_TOKENS NUMBER_OF_TOKENS_TXT
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION NUMBER_OF_TOKENS_PER_INSTRUCTION_TXT
++#else
++#define NUMBER_OF_TOKENS NUMBER_OF_TOKENS_ARM
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION NUMBER_OF_TOKENS_PER_INSTRUCTION_ARM
++#endif
++
++#pragma pack(4)
++
++/*
++ Data structure of an internal node of the tree
++*/
++typedef struct
++{
++ PredictorType *attribute_ptr;
++ u32 value; // PredictorType
++ void *right_child_ptr;
++} ipack_treenodeBin;
++/*
++ Data structure of a leaf with probabilities
++*/
++typedef struct
++{
++ u16 probabilities[0]; // PredictorType[0]
++} ipack_treeleafP;
++/*
++ Data structure of a leaf with class prediction
++*/
++typedef struct
++{
++ PredictorType predicted_class; // PredictorType
++} ipack_treeleafC;
++/*
++ Possible data structures of a tree node
++*/
++typedef union
++{
++ ipack_treenodeBin nodeBin;
++ ipack_treeleafP leafP;
++ ipack_treeleafC leafC;
++} ipack_node_data;
++/*
++ Tree node
++*/
++typedef struct
++{
++ u32 type; // u8
++ ipack_node_data data; // ipack_node_data
++} ipack_nodetype;
++/*
++ Nullnode
++*/
++typedef struct
++{
++ u32 type;
++ u16 probabilities[NUMBER_OF_TOKENS];
++} ipack_nullnode;
++/*
++ Model for ipack project
++*/
++typedef struct
++{
++ char ID[4]; // char[4]
++ char block_sign[4]; // only the first 2 are used!
++ void *tree_root_ptr; // void*
++ void *tree_code; // generated ARM code
++ PredictorType *predictors_ptr; // PredictorType*
++ ipack_nullnode nullnode;
++} ipack_model_type;
++
++typedef struct
++{
++ u32 high;
++ u32 low;
++} ipack_probability_type;
++
++
++static void ipack_model_get_probability_for_token(ipack_nodetype *, TokenType, ipack_probability_type *);
++static TokenType ipack_model_get_token_for_range(ipack_nodetype *, u32, u32, ipack_probability_type *);
++/*void ipack_model_predictortable_reset (PredictorType*);
++void ipack_model_predictortable_update (PredictorType*, TokenType);*/
++
++#ifndef __KERNEL__
++/*static void ipack_model_printinfo(ipack_model_type *);
++static void ipack_dumpmodel(void *);*/
++#endif
++
++#endif
++
++//ORIGIN: include/Builders/PredictorGenerator.h
++
++/*******************************************************************************
++* FILE: PredictorGenerator.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef PREDICTORGENERATOR_H
++#define PREDICTORGENERATOR_H
++
++//#include "DataStructures.h"
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static PredictorTable *predictorgenerator_generate(void);
++#endif
++
++#endif
++
++//ORIGIN: include/Builders/Coder.h
++
++/*******************************************************************************
++* FILE: Coder.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef CODER_H
++#define CODER_H
++
++#define CODER_VALUEBITS 16
++#define CODER_VALUEMAX 0x00010000l
++#define CODER_VALUE3RD 0x0000c000l
++#define CODER_VALUEHLF 0x00008000l
++#define CODER_VALUE1ST 0x00004000l
++
++#endif
++
++//ORIGIN: DataStructures/src/TypeDefs.c
++
++/*******************************************************************************
++* FILE: TypeDefs.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/TypeDefs.h"
++#ifndef __KERNEL__
++#include <memory.h>
++#endif
++
++#define VECTOR_ALLOC_SIZE 0x00001000
++
++static void vector_clear(vector * vct)
++{
++ if (vct->ptr)
++ jffs2_bbc_free(vct->ptr);
++ vct->capacity = 0;
++ vct->size = 0;
++ vct->ptr = 0;
++}
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void vector_extend(vector * vct)
++{
++ void *tmp;
++ vct->capacity += vct->alloc_size;
++ tmp = jffs2_bbc_malloc(vct->capacity);
++ if (vct->ptr) {
++ memcpy(tmp, vct->ptr, vct->size);
++ jffs2_bbc_free(vct->ptr);
++ }
++ vct->ptr = tmp;
++}
++
++static void vector_reset(vector * vct)
++{
++ vct->capacity = 0;
++ vct->size = 0;
++ vct->alloc_size = VECTOR_ALLOC_SIZE;
++ vct->ptr = 0;
++}
++
++static void vector_clr_ptr(vector * vct)
++{
++ void **it;
++ void *end_it;
++ for (it = vct->ptr, end_it = (((char *) (vct->ptr)) + vct->size); it != end_it; it++) {
++ vector_clear(*it);
++ jffs2_bbc_free(*it);
++ }
++ if (vct->ptr)
++ jffs2_bbc_free(vct->ptr);
++ vct->capacity = 0;
++ vct->size = 0;
++ vct->ptr = 0;
++}
++
++static void vector_add_u8(vector * vct, u8 val)
++{
++ if ((vct->size) + sizeof(u8) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(u8 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(u8);
++};
++
++static void vector_add_u16(vector * vct, u16 val)
++{
++ if ((vct->size) + sizeof(u16) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(u16 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(u16);
++};
++
++static void vector_add_u32(vector * vct, u32 val)
++{
++ if ((vct->size) + sizeof(u32) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(u32 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(u32);
++};
++
++static void vector_add_s8(vector * vct, s8 val)
++{
++ if ((vct->size) + sizeof(s8) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(s8 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(s8);
++};
++
++static void vector_add_s16(vector * vct, s16 val)
++{
++ if ((vct->size) + sizeof(s16) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(s16 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(s16);
++};
++
++static void vector_add_s32(vector * vct, s32 val)
++{
++ if ((vct->size) + sizeof(s32) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(s32 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(s32);
++};
++
++static void vector_add_ptr(vector * vct, void *ptr)
++{
++ if ((vct->size) + sizeof(void *) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(void **) ((char *) (vct->ptr) + (vct->size)) = ptr;
++ vct->size += sizeof(void *);
++}
++
++static void vector_concat(vector * lhs, vector * rhs)
++{
++ void *tmp;
++ if (!(rhs->size)) {
++ return;
++ }
++ tmp = lhs->ptr;
++ lhs->capacity = (lhs->size) + (rhs->size);
++ lhs->ptr = jffs2_bbc_malloc(lhs->capacity);
++ if (tmp) {
++ memcpy(lhs->ptr, tmp, lhs->size);
++ jffs2_bbc_free(tmp);
++ }
++ memcpy((((u8 *) lhs->ptr) + lhs->size), rhs->ptr, rhs->size);
++ lhs->size += rhs->size;
++}
++
++#endif
++
++//ORIGIN: DataStructures/src/BitVector.c
++
++/*******************************************************************************
++* FILE: BitVector.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/BitVector.h"
++#ifndef __KERNEL__
++#include <memory.h>
++#endif
++
++#define VECTOR_ALLOC_SIZE 0x00001000
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++
++static void bitblocks_clear(BitBlocks * this)
++{
++ BitVector **it;
++ void *end_it;
++ for (it = this->ptr, end_it = VECTOR_P_END(this); it != end_it; it++) {
++ bitvector_clear(*it);
++ jffs2_bbc_free(*it);
++ }
++ jffs2_bbc_free(this->ptr);
++ this->ptr = 0;
++}
++
++static void bitvector_clear(BitVector * this)
++{
++ if (this->base) {
++ jffs2_bbc_free(this->base);
++ }
++ this->freebits = 0;
++ this->capacity = 0;
++ this->size = 0;
++ this->base = 0;
++ this->ptr = 0;
++}
++
++static void bitvector_W_reset(BitVector * this)
++{
++ this->freebits = 0;
++ this->capacity = 0;
++ this->size = 0;
++ this->base = 0;
++ this->ptr = 0;
++}
++
++static void bitvector_W_add0(BitVector * this)
++{
++ if (!(this->freebits)) {
++ if (this->size == this->capacity) {
++ void *tmp = this->base;
++ this->capacity += VECTOR_ALLOC_SIZE;
++ this->base = jffs2_bbc_malloc(this->capacity);
++ this->ptr = ((u8 *) (this->base)) + this->size;
++ memcpy(this->base, tmp, this->size);
++ jffs2_bbc_free(tmp);
++ }
++ else {
++ this->ptr++;
++ }
++ this->size++;
++ this->freebits = 7;
++ *(this->ptr) = 0x00;
++ }
++ else {
++ this->freebits--;
++ (*(this->ptr)) <<= 1;
++ }
++}
++
++static void bitvector_W_add1(BitVector * this)
++{
++ if (!(this->freebits)) {
++ if (this->size == this->capacity) {
++ void *tmp = this->base;
++ this->capacity += VECTOR_ALLOC_SIZE;
++ this->base = jffs2_bbc_malloc(this->capacity);
++ this->ptr = ((u8 *) (this->base)) + this->size;
++ memcpy(this->base, tmp, this->size);
++ jffs2_bbc_free(tmp);
++ }
++ else {
++ this->ptr++;
++ }
++ this->size++;
++ this->freebits = 7;
++ *(this->ptr) = 0x01;
++ }
++ else {
++ this->freebits--;
++ (*(this->ptr)) <<= 1;
++ (*(this->ptr)) |= 0x01;
++ }
++}
++
++static void bitvector_W_concat_b(BitVector * lhs, BitVector * rhs)
++{
++ void *tmp;
++ if (!(rhs->size)) {
++ return;
++ }
++ tmp = lhs->base;
++ lhs->capacity = ((((lhs->size) + (rhs->size) - 1) / VECTOR_ALLOC_SIZE) + 1) * VECTOR_ALLOC_SIZE;
++ lhs->base = jffs2_bbc_malloc(lhs->capacity);
++ if (tmp) {
++ memcpy(lhs->base, tmp, lhs->size);
++ jffs2_bbc_free(tmp);
++ }
++ memcpy((((u8 *) (lhs->base)) + lhs->size), rhs->base, rhs->size);
++ lhs->freebits = 0;
++ lhs->size += rhs->size;
++ lhs->ptr = ((u8 *) (lhs->base)) + lhs->size;
++}
++
++static void bitvector_W_concat_v(BitVector * lhs, vector * rhs)
++{
++ void *tmp;
++ if (!(rhs->size)) {
++ return;
++ }
++ tmp = lhs->base;
++ lhs->capacity = ((((lhs->size) + (rhs->size) - 1) / VECTOR_ALLOC_SIZE) + 1) * VECTOR_ALLOC_SIZE;
++ lhs->base = jffs2_bbc_malloc(lhs->capacity);
++ if (tmp) {
++ memcpy(lhs->base, tmp, lhs->size);
++ jffs2_bbc_free(tmp);
++ }
++ memcpy((((u8 *) (lhs->base)) + lhs->size), rhs->ptr, rhs->size);
++ lhs->freebits = 0;
++ lhs->size += rhs->size;
++ lhs->ptr = ((u8 *) (lhs->base)) + lhs->size;
++}
++
++static void bitvector_W_flush(BitVector * this)
++{
++ (*(this->ptr)) <<= this->freebits;
++ this->freebits = 0;
++}
++
++static void bitvector_R_reset(BitVector * this)
++{
++ this->freebits = 7;
++ this->ptr = this->base;
++}
++
++static u8 bitvector_R_get1(BitVector * this)
++{
++ u8 tmp = ((*(this->ptr)) >> this->freebits) & 0x01;
++ if (!(this->freebits)) {
++ this->freebits = 7;
++ this->ptr++;
++ }
++ else {
++ this->freebits--;
++ }
++ return tmp;
++}
++
++static u8 bitvector_R_get8(BitVector * this)
++{
++ u8 tmp = (*(this->ptr));
++ this->ptr++;
++ return tmp;
++}
++
++#endif
++
++//ORIGIN: DataStructures/src/DecisionTree.c
++
++/*******************************************************************************
++* FILE: DecisionTree.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/DecisionTree.h"
++
++static void decisiontree_delete_node(void *root)
++{
++ u8 tmp = GET_NODE_PTR_TYPE(root);
++ if (TREENODETYPE_IS_NODE_BINARY(tmp)) {
++ decisiontree_delete_node(((TreeNodeBinary *) root)->left);
++ decisiontree_delete_node(((TreeNodeBinary *) root)->right);
++ }
++ else if ((tmp) == TREENODETYPE_LEAF_P) {
++ if (((TreeLeafP *) root)->probabilities) {
++ jffs2_bbc_free(((TreeLeafP *) root)->probabilities);
++ }
++ }
++ else if ((tmp) == TREENODETYPE_LEAF_C) {
++ }
++ jffs2_bbc_free(root);
++}
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++
++static void decisiontree_delete(DecisionTree * dt)
++{
++ decisiontree_delete_node(dt->root);
++ jffs2_bbc_free(dt->predictor_max_values);
++}
++
++static void decisiontree_get_probability_for_token(void *root, PredictorType * preds, TokenType token, ProbabilityType * prob)
++{
++ void *tmp = root;
++ while (TREENODETYPE_IS_NODE(((TreeNodeBinary *) tmp)->type)) {
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_EQ((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_LT((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++ prob->max = 0;
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_P) {
++ u32 i;
++ u32 lngth = ((TreeLeafP *) tmp)->pairs << 1;
++ for (i = 0; i < lngth;) {
++ TokenType at = ((TreeLeafP *) tmp)->probabilities[i++];
++ TokenType av = ((TreeLeafP *) tmp)->probabilities[i++];
++ if (token > at)
++ prob->low += av;
++ if (token >= at)
++ prob->high += av;
++ prob->max += av;
++ }
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_C) {
++ if (((TreeLeafC *) tmp)->predicted_class == token) {
++ prob->high = TOKEN_MAXVALUE;
++ prob->max = TOKEN_MAXVALUE;
++ }
++ }
++}
++
++static TokenType decisiontree_get_token_for_range(void *root, PredictorType * preds, u32 value, u32 range, ProbabilityType * prob)
++{
++ void *tmp = root;
++ TokenType token = 0;
++ while (TREENODETYPE_IS_NODE(((TreeNodeBinary *) tmp)->type)) {
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_EQ((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_LT((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++ prob->max = 0;
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_P) {
++ u32 i;
++ u32 norm;
++ TokenType at = 0;
++ TokenType av;
++ u32 lngth = ((TreeLeafP *) tmp)->pairs << 1;
++ for (i = 0; i < lngth;) {
++ i++;
++ prob->max += ((TreeLeafP *) tmp)->probabilities[i++];
++ }
++ norm = (value * prob->max - 1) / range;
++ for (i = 0; prob->high <= norm;) {
++ at = ((TreeLeafP *) tmp)->probabilities[i++];
++ av = ((TreeLeafP *) tmp)->probabilities[i++];
++ prob->high += av;
++ if (prob->high <= norm)
++ prob->low += av;
++ }
++ token = at;
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_C) {
++ token = ((TreeLeafC *) tmp)->predicted_class;
++ prob->high = TOKEN_MAXVALUE;
++ prob->max = TOKEN_MAXVALUE;
++ }
++ return token;
++}
++#endif
++
++//ORIGIN: DataStructures/src/PredictorTable.c
++
++/*******************************************************************************
++* FILE: PredictorTable.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/PredictorTable.h"
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++
++static void predictortable_clear(PredictorTable * table)
++{
++ table->predictors = 0;
++}
++
++static void predictortable_free(PredictorTable * table)
++{
++ if (table->predictors) {
++ jffs2_bbc_free(table->predictors);
++ table->predictors = 0;
++ }
++}
++
++static void predictortable_resetARM(PredictorTable * table)
++{
++ register PredictorType *ptr = table->predictors;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS_ARM;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++}
++
++static void predictortable_updateARM(PredictorTable * table, TokenType token)
++{
++ register PredictorType *ptr = table->predictors;
++ register u32 ndx = ptr[0] + 1;
++ ptr[ndx + 8] = ptr[ndx];
++ ptr[ndx] = token;
++ if (ndx == 8) {
++ ptr[0] = 0;
++ }
++ else {
++ ++ptr[0];
++ }
++}
++
++static PredictorType predictortable_minvalueARM(PredictorTable * table, u32 index)
++{
++ return 0;
++}
++
++static PredictorType predictortable_maxvalueARM(PredictorTable * table, u32 index)
++{
++ if (index == 0) {
++ return 7;
++ }
++ else {
++ return 15;
++ }
++}
++
++#endif
++
++#ifndef __KERNEL__
++
++/*static void predictortable_resetTXT(PredictorTable * table)
++{
++ register PredictorType *ptr = table->predictors;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS_TXT;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++}
++
++static void predictortable_updateTXT(PredictorTable * table, TokenType token)
++{ //TODO: modify
++ register PredictorType *ptr = table->predictors;
++// register u32 ndx;
++ ptr[0] = token;
++ if ((('a' <= token) && (token <= 'z')) || (('A' <= token) && (token <= 'Z'))) {
++ ++(ptr[1]);
++ }
++ else {
++ ptr[1] = 0;
++ }
++}
++
++static PredictorType predictortable_minvalueTXT(PredictorTable * table, u32 index)
++{
++ return 0;
++}
++
++static PredictorType predictortable_maxvalueTXT(PredictorTable * table, u32 index)
++{ //TODO: modify
++ return 254;
++}*/
++
++#endif // __KERNEL__
++
++//ORIGIN: DataStructures/src/ipack_model.c
++
++/*******************************************************************************
++* FILE: ipack_model.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "DataStructures/ipack_model.h"
++//#include "measuredef.h"
++//#include "ipack_common.h"
++
++#ifdef __MEASURE_TIME_MODEL_GETPROB
++#define __MT_P_MAX 256
++#define __MT_P_DIV 128
++#define __MT_P_MIN 0
++#endif
++
++static void ipack_model_get_probability_for_token(ipack_nodetype * tmp, TokenType token, ipack_probability_type * prob)
++{
++// register ipack_nodetype* tmp = model->tree_root_ptr;
++// register ipack_nodetype* tmp = root;
++ while (TREENODETYPE_IS_NODE(tmp->type)) {
++ if (tmp->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_EQ tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ else if (tmp->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_LT tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++// prob->max = 0;
++ if (tmp->type == TREENODETYPE_LEAF_P) {
++ if (token) {
++ prob->low = tmp->data.leafP.probabilities[token - 1];
++ }
++ prob->high = tmp->data.leafP.probabilities[token];
++// prob->max = tmp->data.leafP.probabilities[15];
++ }
++ else if (tmp->type == TREENODETYPE_LEAF_C) {
++ if (tmp->data.leafC.predicted_class == token) {
++ prob->high = TOKEN_MAXVALUE;
++// prob->max = TOKEN_MAXVALUE;
++ }
++ }
++}
++
++#ifndef IPACK_ARM_ASM
++
++//return ipack_model_get_token_for_range2(tmp,value,range,prob);
++
++static TokenType ipack_model_get_token_for_range(ipack_nodetype * tmp, u32 value, u32 range, ipack_probability_type * prob)
++{
++// register ipack_nodetype* tmp = model->tree_root_ptr;
++// register ipack_nodetype* tmp = root;
++ register TokenType token = 0;
++ while (TREENODETYPE_IS_NODE(tmp->type)) {
++ if (tmp->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_EQ tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ else if (tmp->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_LT tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++// prob->max = 0;
++ if (tmp->type == TREENODETYPE_LEAF_P) {
++ u32 i;
++ u32 norm;
++// prob->max = tmp->data.leafP.probabilities[15];
++/* norm = (value * prob->max -1)/range;
++ for(i = 0; i < 15; ++i) {
++ if(tmp->data.leafP.probabilities[i] > norm) {
++ break;
++ }
++ }*/
++ norm = ((value << PROBABILITY_SHIFT) - 1);
++ for (i = 0; i < NUMBER_OF_TOKENS; ++i) {
++ if (range * tmp->data.leafP.probabilities[i] > norm) {
++ break;
++ }
++ }
++ token = (TokenType) i;
++ prob->high = tmp->data.leafP.probabilities[i];
++ if (token) {
++ prob->low = tmp->data.leafP.probabilities[token - 1];
++ }
++ }
++ else if (tmp->type == TREENODETYPE_LEAF_C) {
++ token = tmp->data.leafC.predicted_class;
++ prob->high = PROBABILITY_MAX;
++// prob->max = PROBABILITY_MAX;
++ }
++ return token;
++}
++#endif
++/*
++void ipack_model_predictortable_reset(PredictorType* ptr)
++{
++// register PredictorType* ptr = model->predictors_ptr;
++// register PredictorType* ptr = preds;
++ register PredictorType* end = ptr + NUMBER_OF_PREDICTORS;
++ while(ptr < end) {
++ *(ptr++) = 0;
++ }
++}
++
++void ipack_model_predictortable_update(PredictorType* ptr, TokenType token)
++{
++// register PredictorType* ptr = model->predictors_ptr;
++// register PredictorType* ptr = preds;
++ register u32 ndx = ptr[0] + 1;
++ ptr[ndx + 8] = ptr[ndx];
++ ptr[ndx] = token;
++ if(ndx == 8) {
++ ptr[0] = 0;
++ } else {
++ ++ ptr[0];
++ }
++}*/
++/****************************************************************************/
++
++#ifndef __KERNEL__
++static void ipack_model_countpreds(void *ptr, ipack_nodetype * node, double *table, double val)
++{
++ if ((node->type == TREENODETYPE_NODE_BINARY_EQ) || (node->type == TREENODETYPE_NODE_BINARY_LT)) {
++ table[(u32) (node->data.nodeBin.attribute_ptr) - (u32) (ptr)] += val;
++ ipack_model_countpreds(ptr, (void *) (((u8 *) (node)) + sizeof(node->type) + sizeof(ipack_treenodeBin)), table, val / 2);
++ ipack_model_countpreds(ptr, node->data.nodeBin.right_child_ptr, table, val / 2);
++ }
++ else {
++ }
++}
++
++/*static void ipack_model_printinfo(ipack_model_type * model)
++{
++ double *prcnt = jffs2_bbc_malloc(sizeof(double) * NUMBER_OF_PREDICTORS);
++ u32 i;
++ for (i = 0; i < NUMBER_OF_PREDICTORS; i++) {
++ prcnt[i] = 0.0;
++ }
++ ipack_model_countpreds(model->predictors_ptr, model->tree_root_ptr, prcnt, 100);
++ for (i = 0; i < NUMBER_OF_PREDICTORS; i++) {
++ jffs2_bbc_print3(" p[%3d] = %10.6lf\n", (int) i, prcnt[i]);
++ }
++ jffs2_bbc_free(prcnt);
++}*/
++
++static void ipack_dumpnode(unsigned char **ptr, FILE * file, char *prefs)
++{
++ switch (*((*ptr)++)) {
++ u32 i;
++ u32 j;
++ u32 x;
++ u32 y;
++ case TREENODETYPE_NODE_BINARY_EQ:
++ x = *((*ptr)++);
++ y = *((*ptr)++);
++ fprintf(file, "%s+->\tBinary node: P[%u] equals %u\n", prefs, (unsigned int)x, (unsigned int)y);
++ for (j = 0; j < 4096 && prefs[j]; ++j);
++ prefs[j] = '\t';
++ prefs[++j] = '|';
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j--] = 0;
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j] = 0;
++ break;
++ case TREENODETYPE_NODE_BINARY_LT:
++ x = *((*ptr)++);
++ y = *((*ptr)++);
++ fprintf(file, "%s+->\tBinary node: P[%u] greater than %u\n", prefs, (unsigned int)x, (unsigned int)y);
++ for (j = 0; j < 4096 && prefs[j]; ++j);
++ prefs[j] = '\t';
++ prefs[++j] = '|';
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j--] = 0;
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j] = 0;
++ break;
++ case TREENODETYPE_LEAF_P:
++ x = *((*ptr)++);
++ fprintf(file, "%s+->\tLeaf: %u pairs\n", prefs, (unsigned int)x);
++ (*ptr) += (x << 1);
++ break;
++ case TREENODETYPE_LEAF_C:
++ x = *((*ptr)++);
++ fprintf(file, "%s+->\tLeaf: class %u\n", prefs, (unsigned int)x);
++ break;
++ default:
++ fprintf(file, "%s+->\tLeaf: nullnode\n", prefs);
++ }
++}
++
++/*static void ipack_dumpmodel(void *model)
++{
++ unsigned char *tmp_ptr = model;
++ FILE *file;
++ char C[4096];
++ if ((file = fopen("DUMPED_MODEL", "wa"))) {
++ int i;
++ for (i = 0; i < 4096; C[i++] = 0);
++ tmp_ptr += 8;
++ tmp_ptr += sizeof(u32);
++ ipack_dumpnode(&tmp_ptr, file, C);
++ fclose(file);
++ }
++}*/
++
++#endif
++
++//ORIGIN: Builders/src/PredictorGenerator.c
++
++/*******************************************************************************
++* FILE: PredictorGenerator.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "Builders/PredictorGenerator.h"
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static PredictorTable *predictorgenerator_generate( /*PredictorGeneratorSettings* settings */ )
++{
++ PredictorTable *ptr = jffs2_bbc_malloc(sizeof(PredictorTable));
++ predictortable_clear(ptr);
++ ptr->predictors = jffs2_bbc_malloc(NUMBER_OF_PREDICTORS * sizeof(PredictorType));
++ return ptr;
++}
++#endif
++
++//ORIGIN: Builders/src/ipack_armlib_compressor.c
++
++/*******************************************************************************
++* FILE: ipack_armlim_compressor.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures.h"
++//#include "Builders/PredictorGenerator.h"
++//#include "Builders/Tokenizer.h"
++//#include "Builders/Coder.h"
++
++#define EC_NO_ERROR 0
++#define EC_NOT_IPMF_FILE -1
++#define EC_NOT_IPMF_MODEL -2
++#define EC_NOT_HG_BLOCK -3
++#define EC_WRONG_INPUT_LENGTH -501
++#define EC_CODER_WRONG_PROBABILITY 1
++#define EC_CODER_WRONG_RANGE 2
++#define EC_BUFFER_OVERFLOW 501
++#define EC_BUFFER_UNDERFLOW 502
++#define EC_UNKNOWN_TOKEN_TYPE 1001
++#define EC_UNKNOWN_FILTER 1002
++#define EC_UNKNOWN_CONVERTER 1003
++#define EC_UNKNOWN_MANIPULATOR 1004
++
++/*******************************************************************************
++
++ COMPRESSOR INIT FUNCTIONS
++
++*******************************************************************************/
++
++#define ROUND_UP_TO_DWORD(val) ( ( (val) + 3 ) & 0xfffffffc )
++
++#ifndef __KERNEL__
++int ipack_glb_endian_X;
++#endif
++
++static int ipack_compressor_init_tree(unsigned char **ptr, ipack_model_type * model, ipack_nodetype * node, void *nullnode)
++{
++ int retval = 0;
++ node->type = *((*ptr)++);
++ switch (node->type) {
++ u32 i;
++ u32 j;
++ u32 lngth;
++ u32 tmpret;
++ TokenType at;
++ u16 av;
++ case TREENODETYPE_NODE_BINARY_EQ:
++ case TREENODETYPE_NODE_BINARY_LT:
++ node->data.nodeBin.attribute_ptr = (model->predictors_ptr) + (*((*ptr)++));
++ node->data.nodeBin.value = *((*ptr)++);
++ retval = sizeof(node->data.nodeBin);
++ retval += ipack_compressor_init_tree(ptr, model, (void *) ROUND_UP_TO_DWORD(((u32) node) + sizeof(node->type) + sizeof(node->data.nodeBin)), nullnode);
++ node->data.nodeBin.right_child_ptr = (void *) ROUND_UP_TO_DWORD(((u32) node) + retval + sizeof(node->type));
++ retval += ipack_compressor_init_tree(ptr, model, node->data.nodeBin.right_child_ptr, nullnode);
++ break;
++ case TREENODETYPE_LEAF_P:
++ lngth = *((*ptr)++);
++ av = 0;
++ for (i = 0, j = 0; i < lngth; ++i) {
++ at = *((*ptr)++);
++ while (j < at) {
++ node->data.leafP.probabilities[j++] = av;
++ }
++ av += *((*ptr)++);
++ }
++ while (j < NUMBER_OF_TOKENS) {
++ node->data.leafP.probabilities[j++] = av;
++ }
++ for (i = 0; i < NUMBER_OF_TOKENS; ++i) {
++ node->data.leafP.probabilities[i] = ((node->data.leafP.probabilities[i] << PROBABILITY_SHIFT) / node->data.leafP.probabilities[NUMBER_OF_TOKENS - 1]);
++ }
++ retval = ROUND_UP_TO_DWORD(NUMBER_OF_TOKENS * sizeof(u16));
++ break;
++ case TREENODETYPE_LEAF_C:
++ node->data.leafC.predicted_class = *((*ptr)++);
++ retval = sizeof(node->data.leafC);
++ retval = ROUND_UP_TO_DWORD(retval);
++ break;
++ default:
++ return 0;
++ }
++ return retval + sizeof(node->type);
++}
++
++#define IPACK_TREE_CONVERT_REPLACE 0
++#define IPACK_TREE_CONVERT_KEEP 1
++
++static void *ipack_tree_to_code(ipack_model_type * model, int *code_size);
++
++static int ipack_armlib_convert_tree_to_code(ipack_model_type * model_img, int mode)
++{
++#ifdef IPACK_TREE_TO_CODE
++ int tree_size;
++
++ model_img->tree_code = ipack_tree_to_code(model_img, &tree_size);
++ jffs2_bbc_print2("Convertation done. Code size=%d\n", tree_size);
++ if (mode == IPACK_TREE_CONVERT_REPLACE) {
++ jffs2_bbc_print1("Freeing original tree.\n");
++ jffs2_bbc_free(model_img->tree_root_ptr);
++ model_img->tree_root_ptr = NULL;
++ }
++#endif
++ return 0;
++}
++
++
++static int ipack_armlib_compressor_init(void **model)
++{
++ int retval = EC_NO_ERROR;
++ unsigned char *tmp_ptr = *model;
++ u32 i;
++ ipack_model_type *model_img;
++ char tmp_c[2];
++
++ if (*(tmp_ptr++) != 'i') {
++ return EC_NOT_IPMF_FILE;
++ }
++ else if (*(tmp_ptr++) != 'P') {
++ return EC_NOT_IPMF_FILE;
++ }
++ else if (*(tmp_ptr++) != 'M') {
++ return EC_NOT_IPMF_FILE;
++ }
++ else if (*(tmp_ptr++) != 'F') {
++ return EC_NOT_IPMF_FILE;
++ }
++ tmp_c[0] = *(tmp_ptr++);
++ tmp_c[1] = *(tmp_ptr++);
++ tmp_ptr += 2;
++
++ //model_img = jffs2_bbc_malloc(*((u32*)tmp_ptr));
++ model_img = jffs2_bbc_malloc(sizeof(ipack_model_type) + ROUND_UP_TO_DWORD(NUMBER_OF_PREDICTORS));
++ model_img->tree_root_ptr = jffs2_bbc_malloc(*((u32 *) tmp_ptr)); //it is smaller a little but, but...
++
++ tmp_ptr += sizeof(u32);
++
++ model_img->ID[0] = 'i';
++ model_img->ID[1] = 'P';
++ model_img->ID[2] = 'M';
++ model_img->ID[3] = 'F';
++
++ model_img->block_sign[0] = tmp_c[0];
++ model_img->block_sign[1] = tmp_c[1];
++
++ model_img->nullnode.type = TREENODETYPE_LEAF_P;
++ for (i = 0; i < NUMBER_OF_TOKENS; ++i) {
++ model_img->nullnode.probabilities[i] = 0;
++ }
++ model_img->predictors_ptr = (void *) (((u32) model_img) + sizeof(ipack_model_type));
++ //model_img->tree_root_ptr = (void*)ROUND_UP_TO_DWORD(((u32)(model_img->predictors_ptr)) + NUMBER_OF_PREDICTORS);//ALIGN
++
++ ipack_compressor_init_tree(&tmp_ptr, model_img, model_img->tree_root_ptr, &(model_img->nullnode));
++
++#ifdef IPACK_TREE_TO_CODE
++#ifdef IPACK_AUTO_TREE_TO_CODE
++ jffs2_bbc_print1("Automatically converting tree to ARM code...\n");
++ ipack_armlib_convert_tree_to_code(model_img, IPACK_TREE_CONVERT_REPLACE);
++#else
++ model_img->tree_code = NULL;
++#endif
++#else
++ model_img->tree_code = NULL;
++#endif
++
++ jffs2_bbc_free(*model);
++ *model = model_img;
++ return retval;
++}
++
++/*******************************************************************************
++
++ COMPRESSOR DEINIT FUNCTIONS
++
++*******************************************************************************/
++
++
++/* Descructor of compressor (model will be freed with jffs2_bbc_free() after it)*/
++static void ipack_armlib_compressor_deinit(void)
++{
++}
++
++/*******************************************************************************
++
++ COMPRESS FUNCTIONS
++
++*******************************************************************************/
++
++static int writebits0(unsigned char **dest, u8 * freebits, u32 * opposite, unsigned char *end)
++{
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x00;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ while (*opposite) {
++ --(*opposite);
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x01;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ (**dest) |= 0x01;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ return 0;
++}
++
++static int writebits1(unsigned char **dest, u8 * freebits, u32 * opposite, unsigned char *end)
++{
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x01;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ (**dest) |= 0x01;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ while (*opposite) {
++ --(*opposite);
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x00;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ return 0;
++}
++
++
++
++
++/* Compress block
++ * *dstlen bytes are allocated.
++ * if it is not enough write *sourcelen over to the processed amount of data
++ * returns non zero if fails
++ */
++static int ipack_armlib_compress(void *model, unsigned char *input, unsigned char *output, unsigned long *sourcelen, unsigned long *dstlen)
++{
++ register u32 coder_high = CODER_VALUEMAX - 1;
++ register u32 coder_low = 0;
++ u32 coder_opbits = 0;
++ u8 bitvector_freebits = 8;
++ unsigned char *bitvector_ptr = output;
++ unsigned char *bitvector_end = output + (*dstlen - 1);
++ ARM_DataType *tmpp;
++ TokenStream tmpv;
++ TokenType *it;
++ void *end_it;
++
++ ipack_nodetype *treeroot = ((ipack_model_type *) model)->tree_root_ptr;
++ PredictorType *predctrs = ((ipack_model_type *) model)->predictors_ptr;
++
++#ifdef IPACK_TREE_TO_CODE
++ void (*treefunc) (ipack_nodetype *, TokenType, ipack_probability_type *);
++
++ treefunc = ((ipack_model_type *) model)->tree_code;
++ if (treefunc != NULL)
++ treefunc += 4;
++#endif
++
++ if ((*sourcelen % 4) != 0) {
++ return EC_WRONG_INPUT_LENGTH;
++ }
++ if (*dstlen <= 4) {
++ return EC_BUFFER_OVERFLOW;
++ }
++
++ if (((ipack_model_type *) model)->ID[0] != 'i') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[1] != 'P') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[2] != 'M') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[3] != 'F') {
++ return EC_NOT_IPMF_MODEL;
++ }
++#ifdef TXT_TOKENS
++ tmpv.capacity = (*sourcelen);
++#else
++ tmpv.capacity = (*sourcelen) << 1;
++#endif
++ tmpv.size = tmpv.capacity;
++ tmpv.ptr = jffs2_bbc_malloc(tmpv.size);
++ it = tmpv.ptr;
++
++#ifndef __KERNEL__
++ if (ipack_glb_endian_X) {
++ for (tmpp = (void *) input; (u32) tmpp < (u32) (input + *sourcelen); ++tmpp) {
++#ifdef TXT_TOKENS
++ *(it++) = (u8) ((*tmpp & 0xff000000) >> 24);
++ *(it++) = (u8) ((*tmpp & 0x00ff0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0x0000ff00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x000000ff));
++#else
++ *(it++) = (u8) ((*tmpp & 0x0000f000) >> 12);
++ *(it++) = (u8) ((*tmpp & 0x0000000f));
++ *(it++) = (u8) ((*tmpp & 0xf0000000) >> 28);
++ *(it++) = (u8) ((*tmpp & 0x000f0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0x00000f00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x00f00000) >> 20);
++ *(it++) = (u8) ((*tmpp & 0x0f000000) >> 24);
++ *(it++) = (u8) ((*tmpp & 0x000000f0) >> 4);
++#endif //TXT_TOKENS
++ }
++ }
++ else {
++#endif
++ for (tmpp = (void *) input; (u32) tmpp < (u32) (input + *sourcelen); ++tmpp) {
++#ifdef TXT_TOKENS
++ *(it++) = (u8) ((*tmpp & 0x000000ff));
++ *(it++) = (u8) ((*tmpp & 0x0000ff00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x00ff0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0xff000000) >> 24);
++#else
++ *(it++) = (u8) ((*tmpp & 0x00f00000) >> 20);
++ *(it++) = (u8) ((*tmpp & 0x0f000000) >> 24);
++ *(it++) = (u8) ((*tmpp & 0x000000f0) >> 4);
++ *(it++) = (u8) ((*tmpp & 0x00000f00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x000f0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0x0000f000) >> 12);
++ *(it++) = (u8) ((*tmpp & 0x0000000f));
++ *(it++) = (u8) ((*tmpp & 0xf0000000) >> 28);
++#endif //TXT_TOKENS
++ }
++#ifndef __KERNEL__
++ }
++#endif
++/*
++ ENCODE
++*/
++ { //predictor reset
++ register PredictorType *ptr = predctrs;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++ }
++
++ //*(bitvector_ptr++) = 'H';
++ //*(bitvector_ptr++) = 'G';
++ *(bitvector_ptr++) = ((ipack_model_type *) model)->block_sign[0];
++ *(bitvector_ptr++) = ((ipack_model_type *) model)->block_sign[1];
++
++ *(bitvector_ptr++) = (unsigned char) (((*sourcelen) >> 8) & 0xff);
++ *(bitvector_ptr++) = (unsigned char) ((*sourcelen) & 0xff);
++ for (it = tmpv.ptr, end_it = VECTOR_S_END(tmpv); it != end_it; ++it) {
++ ipack_probability_type prob;
++ u32 range;
++
++#ifdef IPACK_TREE_TO_CODE
++ if (treefunc != NULL)
++ (*treefunc) (treeroot, *it, &prob);
++ else
++ ipack_model_get_probability_for_token(treeroot, *it, &prob);
++#else
++ ipack_model_get_probability_for_token(treeroot, *it, &prob);
++#endif
++
++ if (prob.high == prob.low) {
++ vector_clear(&tmpv);
++ return EC_CODER_WRONG_PROBABILITY;
++ }
++ range = coder_high - coder_low + 1;
++ coder_high = coder_low + ((range * prob.high) >> PROBABILITY_SHIFT) - 1;
++ coder_low += ((range * prob.low) >> PROBABILITY_SHIFT);
++ for (;;) {
++ if (coder_high < CODER_VALUEHLF) {
++ if (writebits0(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ vector_clear(&tmpv);
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ else if (coder_low >= CODER_VALUEHLF) {
++ if (writebits1(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ vector_clear(&tmpv);
++ return EC_BUFFER_OVERFLOW;
++ }
++ coder_high -= CODER_VALUEHLF;
++ coder_low -= CODER_VALUEHLF;
++ }
++ else if ((CODER_VALUE1ST <= coder_low) && (coder_high < CODER_VALUE3RD)) {
++ ++coder_opbits;
++ coder_high -= CODER_VALUE1ST;
++ coder_low -= CODER_VALUE1ST;
++ }
++ else {
++ break;
++ }
++ coder_high <<= 1;
++ ++coder_high;
++ coder_low <<= 1;
++ if (coder_high < coder_low) {
++ vector_clear(&tmpv);
++ return EC_CODER_WRONG_RANGE;
++ }
++ }
++ {
++#ifdef TXT_TOKENS
++// register u32 ndx;
++ predctrs[0] = *it;
++ if ((('a' <= *it) && (*it <= 'z')) || (('A' <= *it) && (*it <= 'Z'))) {
++ ++(predctrs[1]);
++ }
++ else {
++ predctrs[1] = 0;
++ }
++#else
++ register u32 ndx = predctrs[0] + 1;
++ predctrs[ndx + 8] = predctrs[ndx];
++ predctrs[ndx] = *it;
++ if (ndx == 8) {
++ predctrs[0] = 0;
++ }
++ else {
++ ++predctrs[0];
++ }
++#endif
++ }
++
++ }
++ vector_clear(&tmpv);
++ ++coder_opbits;
++ if (coder_low < CODER_VALUE1ST) {
++ if (writebits0(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ else {
++ if (writebits1(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ (*(bitvector_ptr)) <<= bitvector_freebits;
++ *dstlen = ((u32) bitvector_ptr - (u32) output + 1);
++ return EC_NO_ERROR;
++}
++
++/*******************************************************************************
++
++ DECOMPRESS FUNCTIONS
++
++*******************************************************************************/
++
++typedef struct
++{
++ u32 high;
++ u32 low;
++ u32 value;
++ u32 overread;
++} ipack_decompressor_values;
++
++typedef struct
++{
++ u8 freebits;
++ unsigned char *ptr;
++ unsigned char *end;
++} ipack_decompressor_bitvector;
++
++static u8 ipack_bitvector_R_get1(ipack_decompressor_bitvector * bv)
++{
++ u8 tmp;
++ if (bv->ptr == bv->end) {
++ bv->freebits = 0;
++ return 0;
++ }
++ tmp = (*(bv->ptr) >> bv->freebits) & 0x01;
++ if (!(bv->freebits)) {
++ bv->freebits = 7;
++ ++(bv->ptr);
++ }
++ else {
++ --(bv->freebits);
++ }
++ return tmp;
++}
++
++/* Decompress block
++ * returns non zero if fails
++ */
++static int ipack_armlib_decompress(void *model, unsigned char *input, unsigned char *output, unsigned long sourcelen, unsigned long dstlen)
++{
++ ARM_DataType *data;
++ register u32 coder_high = CODER_VALUEMAX - 1;
++ register u32 coder_low = 0;
++ register u32 coder_value = 0;
++ u32 coder_overread = 0;
++ ipack_decompressor_bitvector bitvector;
++ u32 lngth;
++ u32 i;
++ u32 cntbytes;
++ TokenType tkns[8];
++ TokenType *tptr;
++
++ ipack_nodetype *treeroot = ((ipack_model_type *) model)->tree_root_ptr;
++ PredictorType *predctrs = ((ipack_model_type *) model)->predictors_ptr;
++
++#ifdef IPACK_TREE_TO_CODE
++ TokenType(*treefunc) (ipack_nodetype *, u32, u32, ipack_probability_type *);
++
++ treefunc = ((ipack_model_type *) model)->tree_code;
++#endif
++
++
++ if (((ipack_model_type *) model)->ID[0] != 'i') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[1] != 'P') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[2] != 'M') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[3] != 'F') {
++ return EC_NOT_IPMF_MODEL;
++ }
++
++ bitvector.freebits = 7;
++ bitvector.ptr = input;
++ bitvector.end = input + sourcelen;
++
++ /*if(*(bitvector.ptr++) != 'H') {
++ return EC_NOT_HG_BLOCK;
++ } else if(*(bitvector.ptr++) != 'G') {
++ return EC_NOT_HG_BLOCK;
++ } */
++ bitvector.ptr++;
++ bitvector.ptr++;
++
++ data = (void *) output;
++ cntbytes = *(bitvector.ptr++);
++ cntbytes <<= 8;
++ cntbytes += *(bitvector.ptr++);
++
++ { //predictor reset
++ register PredictorType *ptr = predctrs;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++ }
++ for (i = 0; i < CODER_VALUEBITS; ++i) {
++ coder_value <<= 1;
++ coder_value += ipack_bitvector_R_get1(&bitvector);
++ }
++ lngth = dstlen >> 2;
++ if (lngth > (cntbytes >> 2)) {
++ lngth = cntbytes >> 2;
++ }
++ for (i = 0; (i < lngth); ++i) {
++ TokenType itoken;
++ u32 j;
++ tptr = tkns;
++ for (j = 0; j < NUMBER_OF_TOKENS_PER_INSTRUCTION; ++j) {
++ ipack_probability_type prob;
++ u32 range = coder_high - coder_low + 1;
++
++#ifdef IPACK_TREE_TO_CODE
++ if (treefunc != NULL)
++ itoken = (*treefunc) (treeroot, coder_value - coder_low + 1, range, &prob);
++ else
++#endif
++ itoken = ipack_model_get_token_for_range(treeroot, coder_value - coder_low + 1, range, &prob);
++
++
++ if (prob.high == prob.low) {
++ return EC_CODER_WRONG_PROBABILITY;
++ }
++ coder_high = coder_low + ((range * prob.high) >> PROBABILITY_SHIFT) - 1;
++ coder_low += ((range * prob.low) >> PROBABILITY_SHIFT);
++ for (;;) {
++ if (coder_high < CODER_VALUEHLF) {
++ }
++ else if (CODER_VALUEHLF <= coder_low) {
++ coder_value -= CODER_VALUEHLF;
++ coder_high -= CODER_VALUEHLF;
++ coder_low -= CODER_VALUEHLF;
++ }
++ else if ((CODER_VALUE1ST <= coder_low) && (coder_high < CODER_VALUE3RD)) {
++ coder_value -= CODER_VALUE1ST;
++ coder_high -= CODER_VALUE1ST;
++ coder_low -= CODER_VALUE1ST;
++ }
++ else {
++ break;
++ }
++ coder_low <<= 1;
++ coder_high <<= 1;
++ ++(coder_high);
++ coder_value <<= 1;
++ if (bitvector.ptr == bitvector.end) {
++ bitvector.freebits = 0;
++ }
++ coder_value += ((*(bitvector.ptr) >> bitvector.freebits) & 0x01);
++ if (bitvector.freebits) {
++ --bitvector.freebits;
++ }
++ else {
++ bitvector.freebits = 7;
++ ++bitvector.ptr;
++ }
++ if (coder_high < coder_low) {
++ return EC_CODER_WRONG_RANGE;
++ }
++ if ((bitvector.ptr == bitvector.end) && !(bitvector.freebits)) {
++ if ((coder_overread++) > CODER_VALUEBITS) {
++ return EC_BUFFER_UNDERFLOW;
++ }
++ }
++ }
++ {
++#ifdef TXT_TOKENS
++// register u32 ndx;
++ predctrs[0] = itoken;
++ if ((('a' <= itoken) && (itoken <= 'z')) || (('A' <= itoken) && (itoken <= 'Z'))) {
++ ++(predctrs[1]);
++ }
++ else {
++ predctrs[1] = 0;
++ }
++
++#else
++ register u32 ndx = predctrs[0] + 1;
++ predctrs[ndx + 8] = predctrs[ndx];
++ predctrs[ndx] = itoken;
++ if (ndx == 8) {
++ predctrs[0] = 0;
++ }
++ else {
++ ++predctrs[0];
++ }
++#endif
++ }
++
++ (*(tptr++)) = itoken;
++ }
++ tptr = tkns;
++#ifndef __KERNEL__
++ if (ipack_glb_endian_X) {
++#ifdef TXT_TOKENS
++ (*data) = ((*tptr) << 24);
++ ++tptr;
++ (*data) |= ((*tptr) << 16);
++ ++tptr;
++ (*data) |= ((*tptr) << 8);
++ ++tptr;
++ (*data) |= (*tptr);
++ ++data;
++#else
++ (*data) = (((*tptr) & 0xf) << 12);
++ ++tptr;
++ (*data) |= ((*tptr) & 0xf);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 28);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 16);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 8);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 20);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 24);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 4);
++ ++data;
++#endif
++ }
++ else {
++#endif
++#ifdef TXT_TOKENS
++ (*data) = (*tptr);
++ ++tptr;
++ (*data) |= ((*tptr) << 8);
++ ++tptr;
++ (*data) |= ((*tptr) << 16);
++ ++tptr;
++ (*data) |= ((*tptr) << 24);
++ ++data;
++#else
++ (*data) = (((*tptr) & 0xf) << 20);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 24);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 4);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 8);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 16);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 12);
++ ++tptr;
++ (*data) |= ((*tptr) & 0xf);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 28);
++ ++data;
++#endif
++#ifndef __KERNEL__
++ }
++#endif
++ }
++ return EC_NO_ERROR;
++}
++
++static int ipack_armlib_estimate(void *model, unsigned char *input, unsigned long sourcelen, unsigned long *dstlen, unsigned long *readtime, unsigned long *writetime)
++{
++ int i, tmp, tmp2, max, maxi;
++ int cnt_cond[] = { 0, 0, 0, 0 };
++ int cnt_inst[] = { 0, 0, 0, 0 };
++
++ // TODO: make a more precise estimation!!!
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 6;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 2;
++
++ if (sourcelen % 4 != 0) {
++ *dstlen = sourcelen;
++ return 0;
++ }
++ for (i = 0; i < sourcelen; i++, input++) {
++ tmp2 = tmp = *input;
++ tmp = ((tmp) & 0xf0) >> 4;
++ tmp2 = tmp2 & 0xf;
++ if (tmp == 14)
++ cnt_cond[i % 4]++;
++ if ((tmp2 == 2) || (tmp2 == 3))
++ cnt_inst[i % 4]++;
++ }
++ maxi = -1;
++ max = -1;
++ for (i = 0; i < 4; i++)
++ if (max < cnt_cond[i]) {
++ max = cnt_cond[i];
++ maxi = i;
++ }
++ /*jffs2_bbc_print("armlib_EST: %d/%d : %d/%d %d/%d %d/%d %d/%d",
++ cnt_cond[maxi],cnt_inst[maxi],
++ cnt_cond[0],cnt_inst[0],
++ cnt_cond[1],cnt_inst[1],
++ cnt_cond[2],cnt_inst[2],
++ cnt_cond[3],cnt_inst[3]); */
++
++ if (cnt_cond[maxi] < (sourcelen >> 4)) {
++ *dstlen = sourcelen;
++ }
++ else {
++ *dstlen = sourcelen / 3;
++ }
++
++ return 0;
++}
++
++static char *ipack_armlib_proc_info(void);
++static int ipack_armlib_proc_command(char *command);
++static void ipack_armlib_destroy_model(void **model);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_armlib = {
++ "armlib",
++ 0x464d5069,
++ {0, 0, 0, 0},
++ NULL, // init
++ ipack_armlib_compressor_init, // init_model
++ ipack_armlib_destroy_model, // destroy_model
++ ipack_armlib_compressor_deinit, // deinit
++ ipack_armlib_compress,
++ ipack_armlib_estimate,
++ ipack_armlib_decompress,
++ ipack_armlib_proc_info,
++ ipack_armlib_proc_command
++};
++
++
++static char *ipack_armlib_proc_info()
++{
++#ifdef IPACK_TREE_TO_CODE
++#ifdef IPACK_AUTO_TREE_TO_CODE
++ return "automatic tree to code conversion";
++#else
++ return "manual tree to code conversion possibility";
++#endif
++#else
++ return "tree in memory version";
++#endif
++}
++
++static int ipack_armlib_proc_command(char *command)
++{
++ struct jffs2_bbc_model_list_node *model;
++ ipack_model_type *armlib_model;
++
++ if ((*command == 'g') || (*command == 'G')) {
++ jffs2_bbc_print1("Converting tree(s) to ARM code... (keeping original)\n");
++ model = jffs2_bbc_armlib.models;
++ if (model == NULL)
++ jffs2_bbc_print1("no model found!\n");
++ while (model != NULL) {
++ armlib_model = model->model;
++ if (armlib_model == NULL) {
++ jffs2_bbc_print1("Error: NULL model!\n");
++ }
++ else {
++ ipack_armlib_convert_tree_to_code(armlib_model, IPACK_TREE_CONVERT_KEEP);
++ }
++ model = model->next_compr_model;
++ }
++ }
++ else if ((*command == 'r') || (*command == 'R')) {
++ jffs2_bbc_print1("Converting tree(s) to ARM code... (deleting original)\n");
++ model = jffs2_bbc_armlib.models;
++ if (model == NULL)
++ jffs2_bbc_print1("no model found!\n");
++ while (model != NULL) {
++ armlib_model = model->model;
++ if (armlib_model == NULL) {
++ jffs2_bbc_print1("Error: NULL model!\n");
++ }
++ else {
++ //armlib_model->tree_code = ipack_tree_to_code(armlib_model, &tree_size);
++ //jffs2_bbc_print("Convertation done. Code size=%d\n",tree_size);
++ ipack_armlib_convert_tree_to_code(armlib_model, IPACK_TREE_CONVERT_REPLACE);
++ }
++ model = model->next_compr_model;
++ }
++ }
++ else if ((*command == 'c') || (*command == 'C')) {
++ jffs2_bbc_print1("Deleting ARM representation of the tree(s)...\n");
++ model = jffs2_bbc_armlib.models;
++ if (model == NULL)
++ jffs2_bbc_print1("no model found!\n");
++ while (model != NULL) {
++ armlib_model = model->model;
++ if (armlib_model == NULL) {
++ jffs2_bbc_print1("Error: NULL model!\n");
++ }
++ else {
++ if (armlib_model->tree_code == NULL) {
++ jffs2_bbc_print1("already deleted.\n");
++ }
++ else {
++ if (armlib_model->tree_root_ptr == NULL) {
++ jffs2_bbc_print1("cannot delete this ARM tree - original tree has deleted\n");
++ }
++ else {
++ jffs2_bbc_print1("deleting...");
++ jffs2_bbc_free(armlib_model->tree_code);
++ armlib_model->tree_code = NULL;
++ jffs2_bbc_print1("done.\n");
++ }
++ }
++ }
++ model = model->next_compr_model;
++ }
++ }
++ else if (*command == '?') {
++ jffs2_bbc_print1("ARMLIB commands:\n");
++ jffs2_bbc_print1(" g: convert TREEs to ARM code and keep the original\n");
++ jffs2_bbc_print1(" r: convert TREEs to ARM code and remove the original\n");
++ jffs2_bbc_print1(" c: delete the original TREEs - if there is any\n");
++ }
++ else {
++ jffs2_bbc_print1("Unknown command.\n");
++ }
++ return 0;
++}
++
++static void ipack_armlib_destroy_model(void **model)
++{
++ ipack_model_type *model_img;
++
++ model_img = *model;
++ if (model_img == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: armlib: NULL model at destoying model!\n");
++ return;
++ }
++ if (model_img->tree_code != NULL) {
++ //jffs2_bbc_print1("jffs2.bbc: armlib: debug: freeing code...\n");
++ jffs2_bbc_free(model_img->tree_code);
++ model_img->tree_code = NULL;
++ }
++ if (model_img->tree_root_ptr != NULL) {
++ //jffs2_bbc_print1("jffs2.bbc: armlib: debug: freeing tree...\n");
++ jffs2_bbc_free(model_img->tree_root_ptr);
++ model_img->tree_root_ptr = NULL;
++ }
++
++ jffs2_bbc_free(model_img);
++ *model = NULL;
++}
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_armlib_init(int mode)
++{
++ if (jffs2_bbc_register_compressor(&jffs2_bbc_armlib) == 0)
++ return &jffs2_bbc_armlib;
++ else
++ return NULL;
++}
++
++void jffs2_bbc_armlib_deinit(void)
++{
++ jffs2_bbc_unregister_compressor(&jffs2_bbc_armlib);
++}
++
++/*END OF ARMLIB*/
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.c linux-mips/fs/jffs2/jffs2_bbc_framework.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_framework.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,1324 @@
++/*
++ * JFFS2-BBC: Compression Framework
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++/* USE JFFS2_BBC_STANDALONE define if you don't want to compile without JFFS2 */
++
++//#define DEBUG_COMPRESSORS
++//#define DEBUG_SHOW_BLOCK_SIZES
++
++#define JFFS2_BBC_STAT_BUFF_SIZE 8000
++
++#ifndef __KERNEL__
++
++#include <stdio.h>
++#include <malloc.h>
++typedef unsigned long uint32_t;
++
++#else
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#endif
++
++#define JFFS2_BBC_ZLIB_BLOCK_SIGN_0 (120)
++#define JFFS2_BBC_ZLIB_BLOCK_SIGN_1 (94)
++
++#define JFFS2_BBC_DUMMY_BLOCKSIGN_0 (0x54)
++#define JFFS2_BBC_DUMMY_BLOCKSIGN_1 (0x01)
++
++#ifndef NULL
++#define NULL ((void*)(0))
++#endif
++
++#include "jffs2_bbc_framework.h"
++
++/*********************************************************************
++ * Global data *
++ *********************************************************************/
++
++static int jffs2_bbc_compression_mode = JFFS2_BBC_ZLIB_MODE;
++static struct jffs2_bbc_compressor_type *jffs2_bbc_manual_compressor = NULL;
++static struct jffs2_bbc_compressor_type *jffs2_bbc_compressors = NULL;
++static struct jffs2_bbc_model_list_node *jffs2_bbc_model_list = NULL;
++static void *last_sb = NULL; /* previously activated sb */
++
++/*********************************************************************
++ * Compressor initialization *
++ *********************************************************************/
++
++#ifndef JFFS2_BBC_STANDALONE
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_ARMLIB)
++struct jffs2_bbc_compressor_type *jffs2_bbc_armlib_init(void);
++void jffs2_bbc_armlib_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZO)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzo_init(void);
++void jffs2_bbc_lzo_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZSS)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzss_init(void);
++void jffs2_bbc_lzss_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZARI)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzari_init(void);
++void jffs2_bbc_lzari_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZHD)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzhd_init(void);
++void jffs2_bbc_lzhd_deinit(void);
++#endif
++
++void jffs2_bbc_compressor_init()
++{
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_ARMLIB)
++ jffs2_bbc_armlib_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZO)
++ jffs2_bbc_lzo_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZSS)
++ jffs2_bbc_lzss_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZARI)
++ jffs2_bbc_lzari_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZHD)
++ jffs2_bbc_lzhd_init();
++#endif
++}
++
++void jffs2_bbc_compressor_deinit()
++{
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZHD)
++ jffs2_bbc_lzhd_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZARI)
++ jffs2_bbc_lzari_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZSS)
++ jffs2_bbc_lzss_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZO)
++ jffs2_bbc_lzo_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_ARMLIB)
++ jffs2_bbc_armlib_deinit();
++#endif
++}
++
++#endif
++
++#ifndef JFFS2_BBC_STANDALONE
++
++/*********************************************************************
++ * ZLIB COMPRESSOR *
++ *********************************************************************/
++
++extern int jffs2_zlib_compress2(unsigned char *data_in, unsigned char *cpage_out, uint32_t * sourcelen, uint32_t * dstlen);
++extern void jffs2_zlib_decompress2(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
++
++static int jffs2_bbc_zlib_compress(void *model, unsigned char *input, unsigned char *output, unsigned long *sourcelen, unsigned long *dstlen)
++{
++ return jffs2_zlib_compress2(input, output, sourcelen, dstlen);
++}
++
++static int jffs2_bbc_zlib_decompress(void *model, unsigned char *input, unsigned char *output, unsigned long sourcelen, unsigned long dstlen)
++{
++ jffs2_zlib_decompress2(input, output, sourcelen, dstlen);
++ return 0;
++}
++
++static int jffs2_bbc_zlib_estimate(void *model, unsigned char *input, unsigned long sourcelen, unsigned long *dstlen, unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 65 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME;
++ return 0;
++}
++
++static struct jffs2_bbc_compressor_type jffs2_bbc_zlib = {
++ "zlib",
++ 0,
++ {JFFS2_BBC_ZLIB_BLOCK_SIGN_0, JFFS2_BBC_ZLIB_BLOCK_SIGN_1, 0, 0},
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ jffs2_bbc_zlib_compress,
++ jffs2_bbc_zlib_estimate,
++ jffs2_bbc_zlib_decompress,
++ NULL,
++ NULL,
++ 1
++};
++
++static struct jffs2_bbc_compressor_type *jffs2_bbc_original_compressor = &jffs2_bbc_zlib;
++
++#endif
++
++/*********************************************************************
++ * Compression mode handling *
++ *********************************************************************/
++
++int jffs2_bbc_get_compression_mode(void)
++{
++ return jffs2_bbc_compression_mode;
++}
++
++void jffs2_bbc_set_compression_mode(int mode)
++{
++ jffs2_bbc_compression_mode = mode;
++}
++
++void jffs2_bbc_set_manual_compressor(struct jffs2_bbc_compressor_type *c)
++{
++ jffs2_bbc_manual_compressor = c;
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_MANUAL_MODE);
++}
++
++int jffs2_bbc_set_manual_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++ int i;
++
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ jffs2_bbc_set_manual_compressor(l);
++ return 0;
++ }
++ else if (name[i] == 0)
++ i = 1000;
++ else if (name[i] != l->name[i])
++ i = 1000;
++ }
++ l = l->next;
++ }
++ jffs2_bbc_set_manual_compressor(NULL);
++ return 1;
++}
++
++static struct jffs2_bbc_compressor_type *jffs2_bbc_get_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++ int i;
++
++#ifndef JFFS2_BBC_STANDALONE
++ l = jffs2_bbc_original_compressor;
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ return l;
++ }
++ else if (name[i] == 0)
++ i = 1000;
++ else if (name[i] != l->name[i])
++ i = 1000;
++ }
++#endif
++
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ return l;
++ }
++ else if (name[i] == 0)
++ i = 1000;
++ else if (name[i] != l->name[i])
++ i = 1000;
++ }
++ l = l->next;
++ }
++
++ return NULL;
++}
++
++int jffs2_bbc_disable_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++
++ l = jffs2_bbc_get_compressor_by_name(name);
++ if (l == NULL) return 1;
++ l->enabled = 0;
++ return 0;
++}
++
++int jffs2_bbc_enable_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++
++ l = jffs2_bbc_get_compressor_by_name(name);
++ if (l == NULL) return 1;
++ l->enabled = 1;
++ return 0;
++}
++
++void jffs2_bbc_compressor_command_by_name(char *name_and_command)
++{
++ struct jffs2_bbc_compressor_type *l;
++ int i;
++
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ if (name_and_command[i] != ':') {
++ jffs2_bbc_print1("jffs2.bbc: ':' missing after compressor name\n");
++ }
++ else {
++ if (l->proc_command != NULL)
++ l->proc_command(name_and_command + i + 1);
++ }
++ i = 1000;
++ return;
++ }
++ else if (name_and_command[i] == 0) {
++ i = 1000;
++ }
++ else if (name_and_command[i] != l->name[i]) {
++ i = 1000;
++ }
++ }
++ l = l->next;
++ }
++}
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_manual_compressor(void)
++{
++ if (jffs2_bbc_get_compression_mode() != JFFS2_BBC_MANUAL_MODE) {
++ jffs2_bbc_manual_compressor = NULL;
++ }
++ return jffs2_bbc_manual_compressor;
++}
++
++/*********************************************************************
++ * Compressor handling *
++ *********************************************************************/
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_compressor_list(void)
++{
++ return jffs2_bbc_compressors;
++}
++
++struct jffs2_bbc_model_list_node *jffs2_bbc_get_model_list(void)
++{
++ return jffs2_bbc_model_list;
++}
++
++int jffs2_bbc_register_compressor(struct jffs2_bbc_compressor_type *c)
++{
++ struct jffs2_bbc_compressor_type *l;
++ struct jffs2_bbc_model_list_node *l2;
++ int model_found = 0;
++
++ l = jffs2_bbc_compressors;
++ /* Check for confilcts */
++ while (l != NULL) {
++ c->name[15] = 0;
++ /*if (strcmp(c->name,l->name)==0) {
++ jffs2_bbc_print1("jffs2.bbc: compressor is already loaded.");
++ return -1;
++ } */
++ if ((l->model_file_sign == c->model_file_sign) && (c->model_file_sign != 0)) {
++ jffs2_bbc_print1("jffs2.bbc: already used model file sign. fail.");
++ return -1;
++ }
++ l = l->next;
++ }
++ /* Search and initialize model */
++ c->models = NULL;
++ c->mounted = 0;
++ if (c->init != NULL) {
++ if (c->init() != 0) {
++ jffs2_bbc_print2("jffs2.bbc: cannot initialize compressor %s.\n", c->name);
++ return -1;
++ }
++ }
++ if (c->model_file_sign != 0) {
++ l2 = jffs2_bbc_model_list;
++ while (1) {
++ if (l2 == NULL)
++ break;
++ if (c->model_file_sign == l2->sign) {
++ if (l2->compressor != NULL) {
++ jffs2_bbc_print2("jffs2.bbc: register for %s: BUG, model file already reserved!!!!\n", c->name);
++ }
++ else {
++ if (c->init_model(&(l2->model)) != 0) {
++ jffs2_bbc_print2("jffs2.bbc: cannot initialize compressor %s for a model", c->name);
++ }
++ else {
++ l2->compressor = c;
++ l2->next_compr_model = c->models;
++ c->models = l2;
++ c->mounted++;
++ model_found++;
++ }
++ }
++ }
++ l2 = l2->next_model;
++ }
++ /*if (model_found==0) {
++ jffs2_bbc_print2("jffs2.bbc: no macthing model file found for %s at this time (maybe later)\n",c->name);
++ } */
++ }
++ /* Insert to the end of the compressor list */
++ c->enabled = 1;
++ c->buffer = NULL;
++ c->buffer_size = 0;
++ c->stat_compr_orig = c->stat_compr_new = c->stat_decompr = 0;
++ c->next = NULL;
++ if (jffs2_bbc_compressors == NULL) {
++ jffs2_bbc_compressors = c;
++ }
++ else {
++ l = jffs2_bbc_compressors;
++ while (l->next != NULL)
++ l = l->next;
++ l->next = c;
++ }
++ return 0;
++}
++
++int jffs2_bbc_unregister_compressor(struct jffs2_bbc_compressor_type *c)
++{
++ struct jffs2_bbc_compressor_type *l;
++ struct jffs2_bbc_model_list_node *l2;
++
++ if (c->mounted != 0) {
++ jffs2_bbc_print1("jffs2.bbc: Compressor is in use. Sorry.");
++ return -1;
++ }
++ if (jffs2_bbc_compressors == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: unregister: empty list.");
++ return -1;
++ }
++ else if (jffs2_bbc_compressors == c) {
++ if (c->deinit != NULL)
++ c->deinit();
++ jffs2_bbc_compressors = c->next;
++ }
++ else {
++ l = jffs2_bbc_compressors;
++ while (l->next != c) {
++ if (l->next == NULL) {
++ jffs2_bbc_print2("jffs2.bbc: unregister: cannot find compressor %s in the list.", c->name);
++ return -1;
++ }
++ l = l->next;
++ }
++ if (c->deinit != NULL)
++ c->deinit();
++ l->next = c->next;
++ }
++ if (c->buffer != NULL) {
++ jffs2_bbc_free(c->buffer);
++ c->buffer = NULL;
++ c->buffer_size = 0;
++ }
++
++ l2 = jffs2_bbc_model_list;
++ while (l2 != NULL) {
++ if (l2->compressor == c) {
++ jffs2_bbc_print1("jffs2.bbc: unregister: BUG: model found!!!");
++ l2->compressor = NULL;
++ l2->next_compr_model = NULL;
++ }
++ l2 = l2->next_model;
++ }
++
++ return 0;
++}
++
++int jffs2_bbc_model_new(void *sb, int i_num, void *model)
++{
++ struct jffs2_bbc_model_list_node *node;
++ struct jffs2_bbc_compressor_type *l;
++ char block_sign[2];
++
++ int sign;
++
++ /* check for conflicts... */
++ sign = *((int *) model);
++ block_sign[0] = *(((char *) model) + 4);
++ block_sign[1] = *(((char *) model) + 5);
++ node = jffs2_bbc_model_list;
++ while (node != NULL) {
++ if ((node->block_sign[0] == block_sign[0]) && (node->block_sign[1] == block_sign[1]) && (node->sb == sb)) {
++ //jffs2_bbc_print2("jffs2.bbc: model_new: model conflict (inode=%d)!\n",i_num);
++ return -1;
++ }
++ node = node->next_model;
++ }
++
++ /* insertion */
++ node = jffs2_bbc_malloc_small((long)sizeof(struct jffs2_bbc_model_list_node));
++ node->sb = sb;
++ node->model = model;
++ node->sign = *((int *) model);
++ node->block_sign[0] = *(((char *) model) + 4);
++ node->block_sign[1] = *(((char *) model) + 5);
++ node->inode = i_num;
++ node->next_model = jffs2_bbc_model_list;
++ node->compressor = NULL;
++ node->stat_decompr = 0;
++ node->next_compr_model = NULL;
++ jffs2_bbc_model_list = node;
++
++ /* search for matching compressor */
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ if (l->model_file_sign == sign) {
++ //jffs2_bbc_print2("jffs2.bbc: compressor for model found: %s ",l->name);
++ if (l->init_model(&(node->model)) != 0) {
++ jffs2_bbc_print1("jffs2.bbc: cannot initialize compressor for a model");
++ }
++ else {
++ l->mounted++;
++ node->compressor = l;
++ node->next_compr_model = l->models;
++ l->models = node;
++ }
++ break;
++ }
++ l = l->next;
++ }
++ return 0;
++}
++
++static void jffs2_bbc_model_del_from_compressor(struct jffs2_bbc_model_list_node *node)
++{
++ struct jffs2_bbc_model_list_node *l;
++
++ if (node->model != NULL) {
++ if (node->compressor != NULL) {
++ if (node->compressor->destroy_model == NULL) {
++ jffs2_bbc_free(node->model);
++ node->model = NULL;
++ }
++ else {
++ node->compressor->destroy_model(&(node->model));
++ if (node->model != NULL)
++ jffs2_bbc_print1("jffs2.bbc: warning: not NULL model after destroying!\n");
++ }
++ }
++ }
++
++ if (node->compressor == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_del_from_compressor: no compressor!\n");
++ return;
++ }
++ l = node->compressor->models;
++ if (l == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_del_from_compressor error, models=NULL!\n");
++ return;
++ }
++ if (l == node) {
++ node->compressor->models = node->next_compr_model;
++ node->compressor->mounted--;
++ return;
++ }
++ while (1) {
++ if (l->next_compr_model == node) {
++ l->next_compr_model = node->next_compr_model;
++ node->compressor->mounted--;
++ return;
++ }
++ l = l->next_compr_model;
++ if (l == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_del_from_compressor: not found\n");
++ return;
++ }
++ }
++}
++
++void jffs2_bbc_model_del(void *sb)
++{
++ struct jffs2_bbc_model_list_node *l, *l2;
++
++ l = jffs2_bbc_model_list;
++ if (l == NULL)
++ return;
++ if (l->sb == sb) {
++ jffs2_bbc_model_list = l->next_model;
++ jffs2_bbc_model_del_from_compressor(l);
++ jffs2_bbc_free_small(l);
++ jffs2_bbc_model_del(sb);
++ return;
++ }
++ while (1) {
++ if (l->next_model == NULL) {
++ break;
++ }
++ if (l->next_model->sb == sb) {
++ l2 = l->next_model;
++ l->next_model = l->next_model->next_model;
++ jffs2_bbc_model_del_from_compressor(l2);
++ jffs2_bbc_free_small(l2);
++ jffs2_bbc_model_del(sb);
++ return;
++ }
++ l = l->next_model;
++ }
++ last_sb = NULL;
++}
++
++void jffs2_bbc_model_set_act_sb(void *sb)
++{
++ last_sb = sb;
++}
++
++void *jffs2_bbc_model_get_act_sb(void)
++{
++ return last_sb;
++}
++
++void *jffs2_bbc_model_get_newest(struct jffs2_bbc_compressor_type *compressor)
++{
++ struct jffs2_bbc_model_list_node *m, *best_m;
++ int max_sign, sign;
++
++ if (compressor == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_get: NULL!!\n");
++ return NULL;
++ }
++
++ best_m = NULL;
++ max_sign = -1;
++ m = compressor->models;
++ while (m != NULL) {
++ if (m->sb == last_sb) {
++ sign = (int) (m->block_sign[0]) * 256 + (int) (m->block_sign[1]);
++ if (sign > max_sign) {
++ max_sign = sign;
++ best_m = m;
++ }
++ }
++ m = m->next_compr_model;
++ }
++ if (best_m != NULL)
++ return best_m->model;
++ else
++ return NULL;
++}
++
++/*********************************************************************
++ * Statistics *
++ *********************************************************************/
++
++static char *jffs2_bbc_stat_buff = NULL;
++
++char *jffs2_bbc_get_model_stats(void)
++{
++ char *b;
++ struct jffs2_bbc_model_list_node *m;
++ struct jffs2_bbc_compressor_type *c;
++
++ if (jffs2_bbc_stat_buff == NULL)
++ jffs2_bbc_stat_buff = jffs2_bbc_malloc(8000);
++
++ b = jffs2_bbc_stat_buff;
++
++ b += sprintf(b, "Loaded compressors:");
++ c = jffs2_bbc_compressors;
++ while (c != NULL) {
++ b += sprintf(b, "\n %s (%d) ", c->name, c->enabled);
++ if (c->model_file_sign != 0) {
++ b += sprintf(b, "m_sign=%d ", c->model_file_sign);
++ b += sprintf(b, "models=");
++ m = c->models;
++ while (m != NULL) {
++ b += sprintf(b, "(inode=%d)", m->inode);
++ m = m->next_compr_model;
++ }
++ }
++ else {
++ b += sprintf(b, "b_sign=(%d,%d) nomodel", (int) (c->block_sign[0]), (int) (c->block_sign[1]));
++ }
++ if (c->proc_info != NULL) {
++ b += sprintf(b, "\n %s", c->proc_info());
++ }
++ c = c->next;
++ }
++
++ m = jffs2_bbc_model_list;
++
++ if (m == NULL) {
++ b += sprintf(b, "\nPresent models: NONE\n");
++ }
++ else {
++ b += sprintf(b, "\nPresent models:\n");
++ while (m != NULL) {
++ b += sprintf(b, " b_sign=(%d,%d),inode=%d,decompr=%d", (int) (m->block_sign[0]), (int) (m->block_sign[1]), m->inode, m->stat_decompr);
++ if (m->compressor == NULL)
++ b += sprintf(b, ",compressor=NULL\n");
++ else
++ b += sprintf(b, ",compressor=%s\n", m->compressor->name);
++ m = m->next_model;
++ }
++ }
++
++ return jffs2_bbc_stat_buff;
++}
++
++/*********************************************************************
++ * Memory handling, debug *
++ *********************************************************************/
++
++static int jffs2_bbc_mem_counter = 0;
++
++#ifdef __KERNEL__
++
++void *jffs2_bbc_malloc(long size)
++{
++ void *addr = vmalloc(size);
++ if (addr != NULL)
++ jffs2_bbc_mem_counter++;
++ else {
++ jffs2_bbc_print2("DEBUG: not enough memory (%ld)\n", size);
++ }
++ return addr;
++}
++
++void jffs2_bbc_free(void *addr)
++{
++ jffs2_bbc_mem_counter--;
++ vfree(addr);
++}
++
++void *jffs2_bbc_malloc_small(long size)
++{
++ void *addr;
++ addr = kmalloc(size, 0);
++ if (addr != NULL)
++ jffs2_bbc_mem_counter++;
++ return addr;
++}
++
++void jffs2_bbc_free_small(void *addr)
++{
++ jffs2_bbc_mem_counter--;
++ kfree(addr);
++}
++
++#else
++
++void *jffs2_bbc_malloc(long size)
++{
++ void *addr = malloc(size);
++ if (addr != NULL)
++ jffs2_bbc_mem_counter++;
++ return addr;
++}
++
++void jffs2_bbc_free(void *addr)
++{
++ jffs2_bbc_mem_counter--;
++ free(addr);
++}
++
++void *jffs2_bbc_malloc_small(long size)
++{
++ return jffs2_bbc_malloc(size);
++}
++
++void jffs2_bbc_free_small(void *addr)
++{
++ jffs2_bbc_free(addr);
++}
++
++#endif
++
++int jffs2_bbc_test_memory_counter(int verbose)
++{
++ if (verbose > 0) {
++ jffs2_bbc_print2("jffs2.bbc: mem_counter=%d!\n", jffs2_bbc_mem_counter);
++ }
++ return jffs2_bbc_mem_counter;
++}
++
++int jffs2_bbc_get_memory_counter(void)
++{
++ return jffs2_bbc_mem_counter;
++}
++
++static char mem_stat[200];
++
++char *jffs2_bbc_get_mem_stats(void)
++{
++ sprintf(mem_stat, "Memcounter=%d\n", jffs2_bbc_mem_counter);
++ return mem_stat;
++}
++
++void jffs2_bbc_print_flush(void)
++{
++#ifdef __KERNEL__
++ return;
++#else
++ fflush(stdout);
++ fflush(stderr);
++#endif
++}
++
++/*********************************************************************
++ * FRAMEWORK - ZLIB REPLACEMENT *
++ *********************************************************************/
++
++#ifndef JFFS2_BBC_STANDALONE
++
++/* Temorary buffers */
++static char stat_str[JFFS2_BBC_STAT_BUFF_SIZE];
++static int tmp_buffer_size = 0;
++static char *tmp_buffer = NULL;
++
++/* Statistic - used by /proc/jffs2_bbc and mkfs.jffs2 */
++char *jffs2_bbc_get_compr_stats(void)
++{
++ struct jffs2_bbc_compressor_type *l;
++ char *s = stat_str;
++
++ s += sprintf(s, "Compression statistics:\n");
++ l = jffs2_bbc_original_compressor;
++ //s += sprintf(s, " zlib: compr=%d/%d decompr=%d\n", stat_zlib_compr_new, stat_zlib_compr_orig, stat_zlib_decompr);
++ s += sprintf(s, " %s: compr=%d/%d decompr=%d\n", l->name, l->stat_compr_new, l->stat_compr_orig, l->stat_decompr);
++ l = jffs2_bbc_get_compressor_list();
++ while (l != NULL) {
++ s += sprintf(s, " %s: compr=%d/%d decompr=%d\n", l->name, l->stat_compr_new, l->stat_compr_orig, l->stat_decompr);
++ l = l->next;
++ }
++ return stat_str;
++}
++
++static void jffs2_bbc_buffer_fill(unsigned char *buff, int size)
++{
++ for (; size > 0; size--, buff++)
++ *buff = 255;
++}
++
++
++static int jffs2_bbc_update_compr_buf(unsigned long size)
++{
++ struct jffs2_bbc_compressor_type *l;
++
++ if (size < 5000)
++ size = 5000;
++ if (tmp_buffer == NULL) {
++ tmp_buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(tmp_buffer, size);
++ tmp_buffer_size = size;
++ }
++ else if (tmp_buffer_size < size) {
++ jffs2_bbc_free(tmp_buffer);
++ tmp_buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(tmp_buffer, size);
++ tmp_buffer_size = size;
++ }
++ l = jffs2_bbc_get_compressor_list();
++ while (l != NULL) {
++ if (l->buffer == NULL) {
++ l->buffer_size = size;
++ l->buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(l->buffer, size);
++ }
++ else if (l->buffer_size < size) {
++ jffs2_bbc_free(l->buffer);
++ l->buffer_size = size;
++ l->buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(l->buffer, size);
++ }
++ l = l->next;
++ }
++ return 0;
++}
++
++#ifdef DEBUG_COMPRESSORS
++
++static unsigned char *debug_tmp_buff = NULL;
++static long debug_orig_srclen = -1;
++static long debug_orig_dstlen = -1;
++static int debug_mem_counter = -1;
++
++
++void debug_before_compress(struct jffs2_bbc_compressor_type *c, void *model, unsigned char *input, unsigned char *output, long *sourcelen, long *dstlen)
++{
++
++ debug_orig_srclen = *sourcelen; // for buffer overflow test
++ debug_orig_dstlen = *dstlen; // for buffer overflow test
++ output[debug_orig_dstlen + 1] = 255;
++
++ debug_mem_counter = jffs2_bbc_get_memory_counter(); // for memory guard
++}
++
++void debug_after_compress(struct jffs2_bbc_compressor_type *c, int back, void *model, unsigned char *input, unsigned char *output, long *sourcelen, long *dstlen)
++{
++ long dst_len = *dstlen;
++ long src_len = *sourcelen;
++ int i;
++
++ // Memory guard
++ if (debug_mem_counter != jffs2_bbc_get_memory_counter()) {
++ jffs2_bbc_print4("!!!!!!!! %s error: possible COMPRESSOR MEMORY LEAK: %d->%d\n", c->name, debug_mem_counter, jffs2_bbc_get_memory_counter());
++ debug_mem_counter = jffs2_bbc_get_memory_counter();
++ }
++
++ // Buffer overflow test
++ if (output[debug_orig_dstlen + 1] != 255) {
++ jffs2_bbc_print7("!!!!!!!! %s error: BUFFER OVERFLOW !!!!!!!!!!!! b[%d]=%d (srclen=%d dstlen=%d, back=%d)\n", c->name, (int) (debug_orig_dstlen + 1), (int) (output[debug_orig_dstlen + 1]), (int) (debug_orig_srclen), (int) (*dstlen), back);
++ }
++
++ // Decompression check
++ if (back == 0) {
++ if (debug_tmp_buff == NULL)
++ debug_tmp_buff = jffs2_bbc_malloc(17000);
++ for (i = 0; i < src_len; i++) debug_tmp_buff[i] = 0xf6;
++ c->decompress(model, output, debug_tmp_buff, dst_len, src_len);
++ // Memory guard for decompressor
++ if (debug_mem_counter != jffs2_bbc_get_memory_counter()) {
++ jffs2_bbc_print4("!!!!!!!! %s error: possible DECOMPRESSOR MEMORY LEAK: %d->%d\n", c->name, debug_mem_counter, jffs2_bbc_get_memory_counter());
++ debug_mem_counter = jffs2_bbc_get_memory_counter();
++ }
++
++ for (i = 0; i < src_len; i++)
++ if (input[i] != debug_tmp_buff[i]) {
++ jffs2_bbc_print7("!!!!!!!! %s error: BLOCK DECOMPRESSED BADLY (first bad: %d in %d: %d!=%d (compressed size=%d)) !!!!!!!!!!!!\n", c->name, i, src_len, (int)input[i], (int)debug_tmp_buff[i], dst_len);
++ break;
++ }
++ return;
++ }
++
++ // Return value test
++ //jffs2_bbc_print3("!!!!!!!! %s error: %d !!!!!!!!!!!!\n", c->name, back);
++}
++
++#endif
++
++int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t * sourcelen, uint32_t * dstlen)
++{
++ struct jffs2_bbc_compressor_type *c;
++ int back, back_zlib, mode, min, i, i2;
++ long tmp = 0, tmp_read_time = 1000, tmp_write_time = 1000, orig_src, orig_dest, src, dest;
++ struct jffs2_bbc_model_list_node *m;
++ void *sb;
++ unsigned char *tmp_p = NULL;
++
++ sb = jffs2_bbc_model_get_act_sb();
++
++ orig_src = *sourcelen;
++ orig_dest = *dstlen;
++
++ mode = jffs2_bbc_get_compression_mode();
++
++ if (mode == JFFS2_BBC_DUMMY_MODE) {
++ i=0; i2=0;
++ if (*dstlen>2) {
++ cpage_out[i++]=JFFS2_BBC_DUMMY_BLOCKSIGN_0;
++ cpage_out[i++]=JFFS2_BBC_DUMMY_BLOCKSIGN_1;
++ i2=i;
++ }
++ for (;((i < *dstlen) && (i < (*sourcelen)+i2));i++) {
++ cpage_out[i] = data_in[i-i2];
++ }
++ *sourcelen=i-i2;
++ *dstlen=i;
++ return 0;
++ }
++
++ if (mode == JFFS2_BBC_ZLIB_MODE) {
++ /*if (!jffs2_bbc_original_compressor->enabled) {
++ jffs2_bbc_print2("jffs2.bbc: WARNING: ZLIB mode but %s disabled! Enabling for this procedure...\n",jffs2_bbc_original_compressor->name);
++ }*/
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++ }
++
++ jffs2_bbc_update_compr_buf(orig_dest);
++
++ if (mode == JFFS2_BBC_SIZE_MODE) {
++ // Testing all compressors
++ if (!jffs2_bbc_original_compressor->enabled) {
++ min = -1;
++ }
++ else {
++ back_zlib = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ min = *dstlen;
++ }
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ c->buffer_cnt = -1;
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->model_file_sign == 0) {
++ src = orig_src;
++ dest = orig_dest;
++#ifdef DEBUG_COMPRESSORS
++ debug_before_compress(c, NULL, data_in, c->buffer, &src, &dest);
++#endif
++ back = c->compress(NULL, data_in, c->buffer, &src, &dest);
++#ifdef DEBUG_COMPRESSORS
++ debug_after_compress(c, back, NULL, data_in, c->buffer, &src, &dest);
++#endif
++ if (back == 0) {
++ c->buffer_cnt = dest;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ }
++ else {
++ m = c->models;
++ while (m != NULL) {
++ src = orig_src;
++ dest = orig_dest;
++ if (m->sb == sb) {
++ if (c->buffer_cnt == -1) {
++#ifdef DEBUG_COMPRESSORS
++ debug_before_compress(c, m->model, data_in, c->buffer, (long *) (&src), (long *) (&dest));
++#endif
++ back = c->compress(m->model, data_in, c->buffer, (long *) (&src), (long *) (&dest));
++#ifdef DEBUG_COMPRESSORS
++ debug_after_compress(c, back, m->model, data_in, c->buffer, (long *) (&src), (long *) (&dest));
++#endif
++ if (back == 0) {
++ c->buffer_cnt = dest;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ }
++ else {
++#ifdef DEBUG_COMPRESSORS
++ debug_before_compress(c, m->model, data_in, tmp_buffer, &src, &dest);
++#endif
++ back = c->compress(m->model, data_in, tmp_buffer, &src, &dest);
++#ifdef DEBUG_COMPRESSORS
++ debug_after_compress(c, back, m->model, data_in, tmp_buffer, &src, &dest);
++#endif
++ if (back == 0) {
++ if (c->buffer_cnt > dest) {
++ c->buffer_cnt = dest;
++ tmp_p = c->buffer;
++ c->buffer = tmp_buffer;
++ tmp_buffer = tmp_p;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ }
++ }
++ }
++ m = m->next_compr_model;
++ }
++ }
++ c = c->next;
++ }
++ //Finding the best and copy its result
++
++#ifdef DEBUG_SHOW_BLOCK_SIZES
++ jffs2_bbc_print1("\n");
++ if (jffs2_bbc_original_compressor->enabled) {
++ if (min == *dstlen) {
++ jffs2_bbc_print3("%s:%d* ", jffs2_bbc_original_compressor->name, (int) (*dstlen));
++ }
++ else {
++ jffs2_bbc_print3("%s:%d ", jffs2_bbc_original_compressor->name, (int) (*dstlen));
++ }
++ }
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->buffer_cnt == min)
++ jffs2_bbc_print3("%s:%d* ", c->name, c->buffer_cnt);
++ else
++ jffs2_bbc_print3("%s:%d ", c->name, c->buffer_cnt);
++ c = c->next;
++ }
++#endif
++
++ if (min == -1) {
++ return -1; // none of compressors work (maybe too short output buffer)
++ }
++
++ if (jffs2_bbc_original_compressor->enabled) {
++ if (min == *dstlen) {
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back_zlib;
++ }
++ }
++
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->buffer_cnt == min) {
++ *dstlen = c->buffer_cnt;
++ *sourcelen = orig_src;
++ for (i = 0; i < *dstlen; i++) {
++ cpage_out[i] = c->buffer[i];
++ }
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ return 0;
++ }
++ c = c->next;
++ }
++ jffs2_bbc_print1("jffs2.bbc: compr (full): BUG!!!\n");
++ return 0;
++ }
++
++ if ((mode == JFFS2_BBC_FASTR_MODE)||(mode == JFFS2_BBC_FASTW_MODE)||(mode == JFFS2_BBC_FASTS_MODE)) {
++ // Estimating all compressors
++ if (jffs2_bbc_original_compressor->enabled) {
++ back = jffs2_bbc_original_compressor->estimate(NULL, data_in, *sourcelen, &tmp, &tmp_read_time, &tmp_write_time);
++ }
++ else {
++ tmp = -1;
++ tmp_read_time = -1;
++ tmp_write_time = -1;
++ }
++ if (mode == JFFS2_BBC_FASTR_MODE) tmp = tmp_read_time;
++ if (mode == JFFS2_BBC_FASTW_MODE) tmp = tmp_write_time;
++ min = tmp;
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ src = orig_src;
++ dest = orig_dest;
++ c->buffer_cnt = -1;
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if ((c->model_file_sign == 0) || (jffs2_bbc_model_get_newest(c) != NULL)) {
++ back = c->estimate(jffs2_bbc_model_get_newest(c), data_in, src, &dest, &tmp_read_time, &tmp_write_time);
++ if (mode == JFFS2_BBC_FASTR_MODE) dest = tmp_read_time;
++ if (mode == JFFS2_BBC_FASTW_MODE) dest = tmp_write_time;
++ if (back == 0) {
++ c->buffer_cnt = dest;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ else {
++ c->buffer_cnt = -1;
++ }
++ }
++ c = c->next;
++ }
++ // Finding the best and compress with it
++ if (min == -1) {
++ return -1;
++ }
++ if (jffs2_bbc_original_compressor->enabled) {
++ if (min == tmp) {
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++ }
++ }
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->buffer_cnt == min) {
++ back = c->compress(jffs2_bbc_model_get_newest(c), data_in, cpage_out, (unsigned long*)sourcelen, (unsigned long*)dstlen);
++ if ((back == 0) && (*dstlen < orig_dest) && (*dstlen > 4)) {
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ }
++ else { // fallback will always be available
++ *sourcelen = orig_src;
++ *dstlen = orig_dest;
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++ }
++ return 0;
++ }
++ c = c->next;
++ }
++ jffs2_bbc_print1("jffs2.bbc: compress (fastX mode): BUG!!!\n");
++ return 0;
++ }
++
++ if (mode == JFFS2_BBC_MANUAL_MODE) {
++ c = jffs2_bbc_get_manual_compressor();
++ if (c != NULL) {
++ if (c->model_file_sign == 0) {
++ src = orig_src;
++ dest = orig_dest;
++ back = c->compress(NULL, data_in, cpage_out, &src, &dest);
++ if (back == 0) {
++ *dstlen = dest;
++ *sourcelen = src;
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ return 0;
++ }
++ }
++ else {
++ c->buffer_cnt = -1;
++ m = c->models;
++ min = -1;
++ while (m != NULL) {
++ src = orig_src;
++ dest = orig_dest;
++ if (m->sb == sb) {
++ if (min == -1) {
++ back = c->compress(m->model, data_in, cpage_out, (unsigned long*)sourcelen, (unsigned long*)dstlen);
++ if ((back == 0) && (*dstlen < orig_dest) && (*dstlen > 4)) {
++ min = dest;
++ tmp_p = cpage_out;
++ }
++ }
++ else {
++ back = c->compress(m->model, data_in, tmp_buffer, &src, &dest);
++ if ((back == 0) && (dest < orig_dest) && (dest > 4)) {
++ if (c->buffer_cnt > dest) {
++ if (min > dest) {
++ min = dest;
++ tmp_p = tmp_buffer;
++ }
++ }
++ }
++ }
++ }
++ m = m->next_compr_model;
++ }
++ if (min != -1) {
++ if (tmp_p != cpage_out) {
++ for (i = 0; i < min; i++)
++ cpage_out[i] = tmp_p[i];
++ *sourcelen = orig_src;
++ *dstlen = min;
++ }
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ return 0;
++ }
++ }
++ }
++ /*else {
++ jffs2_bbc_print1("iPack: manual mode without selected compressor!\n");
++ } */
++
++ /*if (!jffs2_bbc_original_compressor->enabled) {
++ jffs2_bbc_print2("jffs2.bbc: WARNING: %s must be enabled! Enabling for this procedure...\n",jffs2_bbc_original_compressor->name);
++ }*/
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++
++
++ }
++
++ jffs2_bbc_print1("jffs2.bbc: compress: unimlemented compress mode!!!\n");
++ return 0;
++}
++
++void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen)
++{
++ struct jffs2_bbc_model_list_node *m;
++ struct jffs2_bbc_compressor_type *c;
++ char d[2];
++ void *sb;
++ int i;
++
++ /* If the input too small... */
++ if (destlen<=2) {
++ cpage_out[0]=data_in[0];
++ if (destlen==2) cpage_out[1]=data_in[1];
++ return;
++ }
++
++ sb = jffs2_bbc_model_get_act_sb();
++ d[0] = *(data_in);
++ d[1] = *(data_in + 1);
++
++ d[0] &= 0x7f; // Variants support...
++
++ /* Search for model based decompressors... */
++ m = jffs2_bbc_get_model_list();
++ while (m != NULL) {
++ if ((d[0] == m->block_sign[0]) && (d[1] == m->block_sign[1]) && (sb == m->sb)) {
++ if (m->compressor == NULL) {
++ jffs2_bbc_print3("jffs2.bbc: decompressor for block_sign (%d,%d) not loaded!\n", (int) (d[0]), (int) (d[1]));
++ }
++ else {
++ m->compressor->decompress(m->model, data_in, cpage_out, srclen, destlen);
++ m->compressor->stat_decompr++;
++ m->stat_decompr++;
++ }
++ return;
++ }
++ m = m->next_model;
++ }
++ /* Is it ZLIB? */
++ if ((((int) d[0]) == (int)(jffs2_bbc_original_compressor->block_sign[0])) && (((int) d[1]) == (int)(jffs2_bbc_original_compressor->block_sign[1]))) {
++ jffs2_bbc_original_compressor->decompress(NULL, data_in, cpage_out, srclen, destlen);
++ jffs2_bbc_original_compressor->stat_decompr++;
++ return;
++ }
++ /* Search for non model based decompressors... */
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->model_file_sign == 0) {
++ if (((int) (d[0]) == (int) (c->block_sign[0])) && ((int) (d[1]) == (int) (c->block_sign[1]))) {
++ c->decompress(NULL, data_in, cpage_out, srclen, destlen);
++ c->stat_decompr++;
++ return;
++ }
++ }
++ c = c->next;
++ }
++ /* Is it DUMMY? */
++ if ((((int) d[0]) == JFFS2_BBC_DUMMY_BLOCKSIGN_0) && (((int) d[1]) == JFFS2_BBC_DUMMY_BLOCKSIGN_1)) {
++ for (i=0;i<destlen;i++) {
++ cpage_out[i]=data_in[i+2];
++ }
++ return;
++ }
++ /* No matching decompressor found... */
++ jffs2_bbc_print4("jffs2.bbc: cannot find model for decompress: bsign=(%d,%d),sb=%d. Using zlib.\n", (int) d[0], (int) d[1], (int) sb);
++ jffs2_bbc_original_compressor->decompress(NULL, data_in, cpage_out, srclen, destlen);
++ jffs2_bbc_original_compressor->stat_decompr++;
++}
++
++#endif
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.h linux-mips/fs/jffs2/jffs2_bbc_framework.h
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_framework.h 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,202 @@
++/*
++ * JFFS2-BBC: Compression Framework - headers
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++#ifndef __JFFS2_BBC_FRAMEWORK_H__
++
++#define __JFFS2_BBC_FRAMEWORK_H__
++
++#define JFFS2_BBC_VERSION "0.54.3"
++
++#define JFFS2_BBC_CONFIG_FILE "bbc.conf"
++
++/*********************************************************************
++ * Compression mode handling *
++ *********************************************************************/
++
++#define JFFS2_BBC_ZLIB_MODE 1
++#define JFFS2_BBC_SIZE_MODE 2
++#define JFFS2_BBC_FASTR_MODE 3
++#define JFFS2_BBC_FASTW_MODE 4
++#define JFFS2_BBC_FASTS_MODE 5
++#define JFFS2_BBC_MANUAL_MODE 6
++#define JFFS2_BBC_DUMMY_MODE 7
++
++int jffs2_bbc_get_compression_mode(void);
++void jffs2_bbc_set_compression_mode(int mode);
++
++/*********************************************************************
++ * Read/write speed unit *
++ * everything is relative to the speed of zlib *
++ * bigger number means slower speed! *
++ *********************************************************************/
++
++#define JFFS2_BBC_ZLIB_READ_TIME 10000
++#define JFFS2_BBC_ZLIB_WRITE_TIME 10000
++
++/*********************************************************************
++ * Compressor handling *
++ *********************************************************************/
++
++struct jffs2_bbc_compressor_type
++{
++ char name[16];
++ int model_file_sign; /* 0 for no model file needed */
++ char block_sign[4]; /* only nomodel compressors, and only the first 2 _bytes are used! */
++ int (*init)(void);
++ int (*init_model)(void **model);
++ void (*destroy_model)(void **model);
++ void (*deinit)(void);
++ /* Compress block
++ * *dstlen bytes are allocated.
++ * if it is not enough write *sourcelen over to the processed amount of data
++ * returns non zero if fails
++ */
++ int (*compress)(void *model, unsigned char *input, unsigned char *output, unsigned long *sourcelen, unsigned long *dstlen);
++ int (*estimate)(void *model, unsigned char *input, unsigned long sourcelen,
++ unsigned long *dstlen, unsigned long *readtime, unsigned long *writetime);
++ /* Decompress block
++ * returns non zero if fails
++ */
++ int (*decompress)(void *model, unsigned char *input, unsigned char *output, unsigned long sourcelen, unsigned long dstlen);
++ char *(*proc_info)(void);
++ int (*proc_command)(char *command);
++ int enabled; /* filled by BBC */
++ int mounted; /* filled by BBC */
++ void *models; /* filled by BBC */
++ char *buffer; /* filled by BBC */
++ int buffer_size; /* filled by BBC */
++ int buffer_cnt; /* filled by BBC */
++ int buffer_tmp; /* filled by BBC */
++ int stat_compr_orig; /* filled by BBC */
++ int stat_compr_new; /* filled by BBC */
++ int stat_decompr; /* filled by BBC */
++ struct jffs2_bbc_compressor_type *next; /* filled by BBC */
++};
++
++/* It sets the compression mode to JFFS2_BBC_MANUAL_MODE */
++
++void jffs2_bbc_set_manual_compressor(struct jffs2_bbc_compressor_type *c); /* NULL = ZLIB */
++int jffs2_bbc_set_manual_compressor_by_name(char *name);
++int jffs2_bbc_disable_compressor_by_name(char *name);
++int jffs2_bbc_enable_compressor_by_name(char *name);
++void jffs2_bbc_compressor_command_by_name(char *name_and_command);
++
++/* If the compression mode is JFFS2_BCC_MANUAL_MODE the manually setted
++ compressor can be get using it. Otherwise it returns with NULL. */
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_manual_compressor(void);
++
++struct jffs2_bbc_model_list_node
++{
++ void *sb; /* FS idendifier (JFFS2_SB_INFO(sb) at this moment) */
++ void *model; /* model data */
++ int sign; /* sign of the model (first 4 bytes) */
++ char block_sign[4]; /* block sign - only the first 2 bytes are used! */
++ int inode; /* inode number of the model file */
++ int stat_decompr;
++ struct jffs2_bbc_compressor_type *compressor;
++ struct jffs2_bbc_model_list_node *next_model;
++ struct jffs2_bbc_model_list_node *next_compr_model;
++};
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_compressor_list(void);
++struct jffs2_bbc_model_list_node *jffs2_bbc_get_model_list(void);
++
++int jffs2_bbc_register_compressor(struct jffs2_bbc_compressor_type *c);
++int jffs2_bbc_unregister_compressor(struct jffs2_bbc_compressor_type *c);
++
++int jffs2_bbc_model_new(void *sb, int i_num, void *model);
++void jffs2_bbc_model_del(void *sb);
++void jffs2_bbc_model_set_act_sb(void *sb);
++void *jffs2_bbc_model_get_act_sb(void);
++void *jffs2_bbc_model_get_newest(struct jffs2_bbc_compressor_type *compressor);
++
++/*********************************************************************
++ * Compressor init function *
++ *********************************************************************/
++
++void jffs2_bbc_compressor_init(void);
++void jffs2_bbc_compressor_deinit(void);
++
++/*********************************************************************
++ * Statistics *
++ *********************************************************************/
++
++char *jffs2_bbc_get_compr_stats(void);
++char *jffs2_bbc_get_model_stats(void);
++
++/*********************************************************************
++ * Other *
++ *********************************************************************/
++
++
++void jffs2_bbc_print_flush(void);
++
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#define jffs2_bbc_print1(a) printk(a)
++#define jffs2_bbc_print2(a,b) printk(a,b)
++#define jffs2_bbc_print3(a,b,c) printk(a,b,c)
++#define jffs2_bbc_print4(a,b,c,d) printk(a,b,c,d)
++#define jffs2_bbc_print5(a,b,c,d,e) printk(a,b,c,d,e)
++#define jffs2_bbc_print6(a,b,c,d,e,f) printk(a,b,c,d,e,f)
++#define jffs2_bbc_print7(a,b,c,d,e,f,g) printk(a,b,c,d,e,f,g)
++#define jffs2_bbc_print8(a,b,c,d,e,f,g,h) printk(a,b,c,d,e,f,g,h)
++#define jffs2_bbc_print9(a,b,c,d,e,f,g,h,i) printk(a,b,c,d,e,f,g,h,i)
++#else
++#include <stdio.h>
++#define jffs2_bbc_print1(a) fprintf(stderr,a)
++#define jffs2_bbc_print2(a,b) fprintf(stderr,a,b)
++#define jffs2_bbc_print3(a,b,c) fprintf(stderr,a,b,c)
++#define jffs2_bbc_print4(a,b,c,d) fprintf(stderr,a,b,c,d)
++#define jffs2_bbc_print5(a,b,c,d,e) fprintf(stderr,a,b,c,d,e)
++#define jffs2_bbc_print6(a,b,c,d,e,f) fprintf(stderr,a,b,c,d,e,f)
++#define jffs2_bbc_print7(a,b,c,d,e,f,g) fprintf(stderr,a,b,c,d,e,f,g)
++#define jffs2_bbc_print8(a,b,c,d,e,f,g,h) fprintf(stderr,a,b,c,d,e,f,g,h)
++#define jffs2_bbc_print9(a,b,c,d,e,f,g,h,i) fprintf(stderr,a,b,c,d,e,f,g,h,i)
++#endif
++
++/* Handle endianness */
++#ifndef __KERNEL__
++
++#define ENDIAN_HOST_AND_TARGET_SAME 0
++#define ENDIAN_HOST_AND_TARGET_DIFFERENT 1
++
++extern int jffs2_bbc_glb_endian_X;
++
++#endif
++
++/* Allocating more than one page (tip. 4096 byte) */
++void *jffs2_bbc_malloc(long size);
++void jffs2_bbc_free(void *addr);
++
++/* Allocating less than one page (tip. 4096 byte) */
++void *jffs2_bbc_malloc_small(long size);
++void jffs2_bbc_free_small(void *addr);
++
++/* Memory guarding */
++int jffs2_bbc_test_memory_counter(int verbose);
++char *jffs2_bbc_get_mem_stats(void);
++int jffs2_bbc_get_memory_counter(void);
++
++#endif
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.c linux-mips/fs/jffs2/jffs2_bbc_fs.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_fs.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,331 @@
++/*
++ * JFFS2-BBC: File System Extension for Linux Kernel
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/jffs2.h>
++#include <linux/proc_fs.h>
++#include <linux/version.h>
++
++#include "nodelist.h"
++
++#include "jffs2_bbc_framework.h"
++
++struct jffs2_bbc_fs_sb_list {
++ struct super_block *sb;
++ struct jffs2_bbc_fs_sb_list *next;
++};
++
++static struct jffs2_bbc_fs_sb_list *sb_list = NULL;
++
++void jffs2_bbc_proc_init(void);
++void jffs2_bbc_proc_deinit(void);
++
++void jffs2_bbc_load_model(void *sb_par) {
++ struct jffs2_sb_info *c;
++ //struct jffs2_inode_info *f;
++ struct dentry *config_dentry,*model_dentry;
++ struct qstr config_name,model_name;
++ struct file *config_file,*model_file;
++ char *buff=NULL,*model_buff;
++ int config_size,model_size;
++ int i,prev_i;
++ struct super_block *sb;
++ struct jffs2_bbc_fs_sb_list *sb_l;
++
++ sb = sb_par;
++ sb_l = jffs2_bbc_malloc_small(sizeof(struct jffs2_bbc_fs_sb_list));
++ sb_l->sb = sb;
++ sb_l->next = sb_list;
++ sb_list = sb_l;
++ config_name.name = JFFS2_BBC_CONFIG_FILE;
++ config_name.len = strlen(config_name.name);
++ config_name.hash = full_name_hash(config_name.name,config_name.len);
++ config_dentry = d_alloc(sb->s_root,&config_name);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,config_dentry);
++#else
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,config_dentry,NULL);
++#endif
++
++ if (config_dentry->d_inode != NULL) {
++ config_size = config_dentry->d_inode->i_size;
++ //printk("config_file_size=%d\n",config_size);
++ if (config_size > 0) {
++ buff = jffs2_bbc_malloc(config_size+1);
++ config_file = dentry_open(config_dentry,NULL,O_RDONLY);
++ kernel_read(config_file,0,buff,config_size);
++ buff[config_size] = 0;
++ for (prev_i = i = 0 ; i < config_size+1 ; i++) {
++ if (buff[i] == '\n') buff[i]=0;
++ if (buff[i] == 0) {
++ if (prev_i != i) {
++ if ((buff[prev_i] == '-') && (buff[prev_i+1] == 0)) break;
++ printk("reading model file %s... ",buff+prev_i);
++ model_name.name = buff+prev_i;
++ model_name.len = strlen(buff+prev_i);
++ model_name.hash = full_name_hash(model_name.name,model_name.len);
++ model_dentry = d_alloc(sb->s_root,&model_name);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,model_dentry);
++#else
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,model_dentry,NULL);
++#endif
++ if (model_dentry->d_inode != NULL) {
++ c = JFFS2_SB_INFO(model_dentry->d_inode->i_sb);
++ //f = JFFS2_INODE_INFO(model_dentry->d_inode);
++ model_size = model_dentry->d_inode->i_size;
++ model_buff = jffs2_bbc_malloc(model_size);
++ model_file = dentry_open(model_dentry,NULL,O_RDONLY);
++ kernel_read(model_file,0,model_buff,model_size);
++ if (jffs2_bbc_model_new(c,model_dentry->d_inode->i_ino,model_buff) != 0) {
++ printk("already loaded.\n");
++ jffs2_bbc_free(model_buff);
++ }
++ else {
++ printk("done (%d bytes readed from inode %d).\n",model_size,(int)(model_dentry->d_inode->i_ino));
++ }
++ }
++ else {
++ printk("not found.\n");
++ }
++ dput(model_dentry);
++ }
++ prev_i = i+1;
++ }
++ }
++ }
++ }
++ dput(config_dentry);
++ if (buff != NULL) jffs2_bbc_free(buff);
++}
++
++void jffs2_bbc_unload_model(void *sb_par)
++{
++ struct jffs2_sb_info *c;
++ struct super_block *sb = sb_par;
++ struct jffs2_bbc_fs_sb_list *sb_l,*sb_l2;
++ int done = 0;
++
++ c = JFFS2_SB_INFO(sb);
++ jffs2_bbc_model_del(c);
++ if (sb_list == NULL) printk("jffs2.bbc: error! NULL sb list!\n");
++ else {
++ if (sb_list->sb == sb) {
++ jffs2_bbc_free_small(sb_list);
++ sb_list = NULL;
++ done = 1;
++ }
++ else {
++ sb_l = sb_list;
++ while (sb_l->next != NULL) {
++ if (sb_l->next->sb == sb) {
++ sb_l2 = sb_l->next->next;
++ jffs2_bbc_free_small(sb_l->next);
++ sb_l->next = sb_l2;
++ done = 1;
++ }
++ sb_l = sb_l->next;
++ }
++
++ }
++ if (done == 0) {
++ printk("jffs2.bbc: cannot delete sb from sblist!\n");
++ }
++ }
++}
++
++static int jffs2_bbc_get_mounted(void) {
++ struct jffs2_bbc_fs_sb_list *sb_l;
++ int num = 0;
++
++ sb_l = sb_list;
++ while (sb_l != NULL) {
++ num++;
++ sb_l = sb_l->next;
++ }
++ return num;
++
++}
++
++int jffs2_bbc_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data)
++{
++ int len = 0, mode;
++
++ mode = jffs2_bbc_get_compression_mode();
++ len += sprintf(buf + len, "BBC version: %s\n", JFFS2_BBC_VERSION);
++ len += sprintf(buf+len,"Mounted jffs2 filesystems: %d\n",jffs2_bbc_get_mounted());
++ //len += sprintf(buf+len,"actual model file inode: %d\n",jffs2_bbc_model_get_inum());
++ len += sprintf(buf + len, "Compression mode: ");
++ if (mode == JFFS2_BBC_ZLIB_MODE)
++ len += sprintf(buf + len, "ZLIB mode");
++ else if (mode == JFFS2_BBC_SIZE_MODE)
++ len += sprintf(buf + len, "SIZE mode");
++ else if (mode == JFFS2_BBC_FASTR_MODE)
++ len += sprintf(buf + len, "FASTR mode");
++ else if (mode == JFFS2_BBC_FASTW_MODE)
++ len += sprintf(buf + len, "FASTW mode");
++ else if (mode == JFFS2_BBC_FASTS_MODE)
++ len += sprintf(buf + len, "FASTS mode");
++ else if (mode == JFFS2_BBC_DUMMY_MODE)
++ len += sprintf(buf + len, "DUMMY mode");
++ else if (mode == JFFS2_BBC_MANUAL_MODE) {
++ len += sprintf(buf + len, "MANUAL mode (");
++ if (jffs2_bbc_get_manual_compressor() != NULL)
++ len += sprintf(buf + len, "%s)", jffs2_bbc_get_manual_compressor()->name);
++ else
++ len += sprintf(buf + len, "ZLIB)");
++ }
++ else
++ len += sprintf(buf + len, "unknown mode");
++ len += sprintf(buf + len, "\n");
++ len += sprintf(buf + len, "%s", jffs2_bbc_get_compr_stats());
++ len += sprintf(buf + len, "%s", jffs2_bbc_get_model_stats());
++ len += sprintf(buf + len, "%s", jffs2_bbc_get_mem_stats());
++ *eof = 1;
++ return len;
++}
++
++int jffs2_bbc_proc_write(struct file *file, const char *buffer_orig, unsigned long count, void *data)
++{
++ char *buffer;
++ int i;
++ struct jffs2_bbc_fs_sb_list *sb_l;
++
++ if (buffer_orig == NULL) return 0;
++
++ buffer = jffs2_bbc_malloc(count+2);
++ for (i=0;i<count;i++) buffer[i]=buffer_orig[i];
++ buffer[count] = 0;
++ if ((*buffer == 'z') || (*buffer == 'Z')) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_ZLIB_MODE);
++ jffs2_bbc_print1("jffs2.bbc: ZLIB compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if ((*buffer == 's') || (*buffer == 'S')) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_SIZE_MODE);
++ jffs2_bbc_print1("jffs2.bbc: SIZE compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if ((*buffer == 'd') || (*buffer == 'D')) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_DUMMY_MODE);
++ jffs2_bbc_print1("jffs2.bbc: DUMMY compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == 'm') || (*buffer == 'M')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_print1("jffs2.bbc: activating MANUAL mode.\n");
++ jffs2_bbc_set_manual_compressor_by_name(buffer + 2);
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == '0')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_print1("jffs2.bbc: disabling a compressor... ");
++ if (jffs2_bbc_disable_compressor_by_name(buffer + 2) == 0) {
++ jffs2_bbc_print1("done.\n");
++ }
++ else {
++ jffs2_bbc_print1("not found.\n");
++ }
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == '1')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_print1("jffs2.bbc: enabling a compressor... ");
++ if (jffs2_bbc_enable_compressor_by_name(buffer + 2) == 0) {
++ jffs2_bbc_print1("done.\n");
++ }
++ else {
++ jffs2_bbc_print1("not found.\n");
++ }
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == 'c') || (*buffer == 'C')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_compressor_command_by_name(buffer + 2);
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if ((*buffer == 'r') || (*buffer == 'R')) {
++ jffs2_bbc_print1("jffs2.bbc: reloading model files:\n");
++ sb_l = sb_list;
++ while (sb_l != NULL) {
++ jffs2_bbc_unload_model(sb_l->sb);
++ jffs2_bbc_load_model(sb_l->sb);
++ sb_l = sb_l->next;
++ }
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((buffer[0] == 'f') || (buffer[0] == 'F'))&&((buffer[1] == 'r') || (buffer[1] == 'R'))) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_FASTR_MODE);
++ jffs2_bbc_print1("jffs2.bbc: FASTR compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((buffer[0] == 'f') || (buffer[0] == 'F'))&&((buffer[1] == 'w') || (buffer[1] == 'W'))) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_FASTW_MODE);
++ jffs2_bbc_print1("jffs2.bbc: FASTW compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((buffer[0] == 'f') || (buffer[0] == 'F'))&&((buffer[1] == 's') || (buffer[1] == 'S'))) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_FASTS_MODE);
++ jffs2_bbc_print1("jffs2.bbc: FASTS compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++
++ jffs2_bbc_print1("jffs2.bbc: unkown command. Valid commands are:\n"
++ " z = switch to ZLIB compression mode\n"
++ " s = switch to SIZE compression mode\n"
++ " d = switch to DUMMY compression mode\n"
++ " fr = switch to FASTR compression mode\n"
++ " fw = switch to FASTW compression mode\n"
++ " fs = switch to FASTS compression mode\n"
++ " r = reread model files from actual file system\n"
++ " m:compressor_name = switch to MANUAL compression mode\n"
++ " 0:compressor_name = disable a compressor\n"
++ " 1:compressor_name = enable a compressor\n"
++ " c:compressor_name:command = enable a compressor\n");
++ jffs2_bbc_free(buffer);
++ return count;
++}
++
++void jffs2_bbc_proc_init()
++{
++ struct proc_dir_entry *res = create_proc_entry("jffs2_bbc", 0, NULL);
++ jffs2_bbc_compressor_init();
++ if (res) {
++ res->read_proc = jffs2_bbc_proc_read;
++ res->write_proc = jffs2_bbc_proc_write;
++ }
++}
++
++void jffs2_bbc_proc_deinit()
++{
++ jffs2_bbc_compressor_deinit();
++ remove_proc_entry("jffs2_bbc", NULL);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.h linux-mips/fs/jffs2/jffs2_bbc_fs.h
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_fs.h 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * JFFS2 BBC: File System Extension for Linux Kernel - headers
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++extern int jffs2_bbc_inode_not_found;
++
++void jffs2_bbc_load_model(void *sb);
++void jffs2_bbc_unload_model(void *sb);
++
++void jffs2_bbc_proc_init(void);
++void jffs2_bbc_proc_deinit(void);
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzari_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzari_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzari_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzari_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,788 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzari_comp.c -- Lempel-Ziv-Arithmetic coding compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the LZARI source included in LDS (lossless datacompression sources)
++ Block-compression and bitstream modifications by Patrik Kluba
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++Original copyright follows:
++
++**************************************************************
++ LZARI.C -- A Data Compression Program
++ (tab = 4 spaces)
++**************************************************************
++ 4/7/1989 Haruhiko Okumura
++ Use, distribute, and modify this program freely.
++ Please send me your improved versions.
++ PC-VAN SCIENCE
++ NIFTY-Serve PAF01022
++ CompuServe 74050,1022
++**************************************************************
++
++LZARI.C (c)1989 by Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
++All rights reserved. Permission granted for non-commercial use.
++
++*/
++
++/*
++
++ 2004-02-18 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Removed unused variables and fixed no return value
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++
++*/
++
++/* lzari.c */
++
++#define N 4096 /* size of ring buffer */
++#define F 60 /* upper limit for match_length */
++#define THRESHOLD 2 /* encode string into position and length
++ if match_length is greater than this */
++#define NIL N /* index for root of binary search trees */
++
++static unsigned char
++ text_buf[N + F - 1]; /* ring buffer of size N,
++ with extra F-1 bytes to facilitate string comparison */
++static unsigned long match_position, match_length, /* of longest match. These are
++ set by the InsertNode() procedure. */
++ lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
++ parents -- These constitute binary search trees. */
++
++static void InitTree(void) /* Initialize trees */
++{
++ unsigned long i;
++
++ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
++ left children of node i. These nodes need not be initialized.
++ Also, dad[i] is the parent of node i. These are initialized to
++ NIL (= N), which stands for 'not used.'
++ For i = 0 to 255, rson[N + i + 1] is the root of the tree
++ for strings that begin with character i. These are initialized
++ to NIL. Note there are 256 trees. */
++
++ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL; /* root */
++ for (i = 0; i < N; i++) dad[i] = NIL; /* node */
++}
++
++static void InsertNode(unsigned long r)
++ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
++ trees (text_buf[r]'th tree) and returns the longest-match position
++ and length via the global variables match_position and match_length.
++ If match_length = F, then removes the old node in favor of the new
++ one, because the old one will be deleted sooner.
++ Note r plays double role, as tree node and position in buffer. */
++{
++ unsigned long i, p, temp;
++ unsigned char *key;
++ signed long cmp;
++
++ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
++ rson[r] = lson[r] = NIL; match_length = 0;
++ for ( ; ; ) {
++ if (cmp >= 0) {
++ if (rson[p] != NIL) p = rson[p];
++ else { rson[p] = r; dad[r] = p; return; }
++ } else {
++ if (lson[p] != NIL) p = lson[p];
++ else { lson[p] = r; dad[r] = p; return; }
++ }
++ for (i = 1; i < F; i++)
++ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
++ if (i > THRESHOLD) {
++ if (i > match_length) {
++ match_position = (r - p) & (N - 1);
++ if ((match_length = i) >= F) break;
++ } else if (i == match_length) {
++ if ((temp = (r - p) & (N - 1)) < match_position)
++ match_position = temp;
++ }
++ }
++ }
++ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
++ dad[lson[p]] = r; dad[rson[p]] = r;
++ if (rson[dad[p]] == p) rson[dad[p]] = r;
++ else lson[dad[p]] = r;
++ dad[p] = NIL; /* remove p */
++}
++
++static void DeleteNode(unsigned long p) /* Delete node p from tree */
++{
++ unsigned long q;
++
++ if (dad[p] == NIL) return; /* not in tree */
++ if (rson[p] == NIL) q = lson[p];
++ else if (lson[p] == NIL) q = rson[p];
++ else {
++ q = lson[p];
++ if (rson[q] != NIL) {
++ do { q = rson[q]; } while (rson[q] != NIL);
++ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
++ lson[q] = lson[p]; dad[lson[p]] = q;
++ }
++ rson[q] = rson[p]; dad[rson[p]] = q;
++ }
++ dad[q] = dad[p];
++ if (rson[dad[p]] == p) rson[dad[p]] = q;
++ else lson[dad[p]] = q;
++ dad[p] = NIL;
++}
++
++/********** Arithmetic Compression **********/
++
++/* If you are not familiar with arithmetic compression, you should read
++ I. E. Witten, R. M. Neal, and J. G. Cleary,
++ Communications of the ACM, Vol. 30, pp. 520-540 (1987),
++ from which much have been borrowed. */
++
++#define M 15
++
++/* Q1 (= 2 to the M) must be sufficiently large, but not so
++ large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */
++
++#define Q1 (1UL << M)
++#define Q2 (2 * Q1)
++#define Q3 (3 * Q1)
++#define Q4 (4 * Q1)
++#define MAX_CUM (Q1 - 1)
++
++#define N_CHAR (256 - THRESHOLD + F)
++ /* character code = 0, 1, ..., N_CHAR - 1 */
++
++static unsigned long char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1];
++static unsigned long
++ sym_freq[N_CHAR + 1], /* frequency for symbols */
++ sym_cum[N_CHAR + 1], /* cumulative freq for symbols */
++ position_cum[N + 1]; /* cumulative freq for positions */
++
++static void StartModel(void) /* Initialize model */
++{
++ unsigned long ch, sym, i;
++
++ sym_cum[N_CHAR] = 0;
++ for (sym = N_CHAR; sym >= 1; sym--) {
++ ch = sym - 1;
++ char_to_sym[ch] = sym; sym_to_char[sym] = ch;
++ sym_freq[sym] = 1;
++ sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
++ }
++ sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */
++ position_cum[N] = 0;
++ for (i = N; i >= 1; i--)
++ position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
++ /* empirical distribution function (quite tentative) */
++ /* Please devise a better mechanism! */
++}
++
++static void UpdateModel(unsigned long sym)
++{
++ unsigned long c, ch_i, ch_sym;
++ unsigned long i;
++ if (sym_cum[0] >= MAX_CUM) {
++ c = 0;
++ for (i = N_CHAR; i > 0; i--) {
++ sym_cum[i] = c;
++ c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
++ }
++ sym_cum[0] = c;
++ }
++ for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
++ if (i < sym) {
++ ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym];
++ sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i;
++ char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i;
++ }
++ sym_freq[i]++;
++ while (--i > 0) sym_cum[i]++;
++ sym_cum[0]++;
++}
++
++static unsigned long BinarySearchSym(unsigned long x)
++ /* 1 if x >= sym_cum[1],
++ N_CHAR if sym_cum[N_CHAR] > x,
++ i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */
++{
++ unsigned long i, j, k;
++
++ i = 1; j = N_CHAR;
++ while (i < j) {
++ k = (i + j) / 2;
++ if (sym_cum[k] > x) i = k + 1; else j = k;
++ }
++ return i;
++}
++
++unsigned long BinarySearchPos(unsigned long x)
++ /* 0 if x >= position_cum[1],
++ N - 1 if position_cum[N] > x,
++ i such that position_cum[i] > x >= position_cum[i + 1] otherwise */
++{
++ unsigned long i, j, k;
++
++ i = 1; j = N;
++ while (i < j) {
++ k = (i + j) / 2;
++ if (position_cum[k] > x) i = k + 1; else j = k;
++ }
++ return i - 1;
++}
++
++/* modified for block compression */
++/* on return, srclen will contain the number of successfully compressed bytes
++ and dstlen will contain completed compressed bytes */
++
++static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
++ unsigned long *dstlen)
++{
++ unsigned long c, i, len, r, s, last_match_length, sym, range;
++ unsigned long low = 0;
++ unsigned long high = Q4;
++ unsigned long shifts = 0; /* counts for magnifying low and high around Q2 */
++ unsigned char *ip, *op;
++ unsigned long written = 0;
++ unsigned long read = 0;
++ unsigned char buffer = 0;
++ unsigned char mask = 128;
++ unsigned char *srcend = srcbuf + *srclen;
++ unsigned char *dstend = dstbuf + *dstlen;
++ ip = srcbuf;
++ op = dstbuf;
++ StartModel();
++ InitTree(); /* initialize trees */
++ s = 0; r = N - F;
++ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
++ any character that will appear often. */
++ for (len = 0; (len < F) && (ip < srcend); len++)
++ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
++ the buffer */
++ read = len;
++ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
++ each of which begins with one or more 'space' characters. Note
++ the order in which these strings are inserted. This way,
++ degenerate trees will be less likely to occur. */
++ InsertNode(r); /* Finally, insert the whole string just read. The
++ global variables match_length and match_position are set. */
++ do {
++ if (match_length > len) match_length = len; /* match_length
++ may be spuriously long near the end of text. */
++ if (match_length <= THRESHOLD) {
++ match_length = 1; /* Not long enough match. Send one byte. */
++ sym = char_to_sym[text_buf[r]];
++ range = high - low;
++ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
++ low += (range * sym_cum[sym ]) / sym_cum[0];
++ for ( ; ; ) {
++ if (high <= Q2) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else if (low >= Q2) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ low -= Q2;
++ high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ shifts++;
++ low -= Q1;
++ high -= Q1;
++ } else break;
++ low += low; high += high;
++ }
++ UpdateModel(sym);
++ } else {
++ sym = char_to_sym[255 - THRESHOLD + match_length];
++ range = high - low;
++ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
++ low += (range * sym_cum[sym ]) / sym_cum[0];
++ for ( ; ; ) {
++ if (high <= Q2) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else if (low >= Q2) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ low -= Q2;
++ high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ shifts++;
++ low -= Q1;
++ high -= Q1;
++ } else break;
++ low += low; high += high;
++ }
++ UpdateModel(sym);
++ range = high - low;
++ high = low + (range * position_cum[match_position - 1]) / position_cum[0];
++ low += (range * position_cum[match_position ]) / position_cum[0];
++ for ( ; ; ) {
++ if (high <= Q2) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else {
++ if (low >= Q2) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ low -= Q2;
++ high -= Q2;
++ } else {
++ if ((low >= Q1) && (high <= Q3)) {
++ shifts++;
++ low -= Q1;
++ high -= Q1;
++ } else {
++ break;
++ }
++ }
++ }
++ low += low;
++ high += high;
++ }
++ }
++ last_match_length = match_length;
++ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
++ c = *(ip++);
++ DeleteNode(s);
++ text_buf[s] = c;
++ if (s < F - 1)
++ text_buf[s + N] = c;
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ InsertNode(r);
++ }
++ read += i;
++ while (i++ < last_match_length) {
++ DeleteNode(s);
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ if (--len) InsertNode(r);
++ }
++ } while (len > 0);
++ shifts++;
++ if (low < Q1) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ }
++ for (i = 0; i < 7; i++) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ *dstlen = written;
++ return 0;
++}
++
++static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
++ unsigned long dstlen) /* Just the reverse of Encode(). */
++{
++ unsigned long i, r, j, k, c, range, sym;
++ unsigned char *ip, *op;
++ unsigned char *srcend = srcbuf + srclen;
++ unsigned char *dstend = dstbuf + dstlen;
++ unsigned char buffer = 0;
++ unsigned char mask = 0;
++ unsigned long low = 0;
++ unsigned long high = Q4;
++ unsigned long value = 0;
++ ip = srcbuf;
++ op = dstbuf;
++ for (i = 0; i < M + 2; i++) {
++ value *= 2;
++ if ((mask >>= 1) == 0) {
++ buffer = (ip >= srcend) ? 0 : *(ip++);
++ mask = 128;
++ }
++ value += ((buffer & mask) != 0);
++ }
++ StartModel();
++ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
++ r = N - F;
++ while (op < dstend) {
++ range = high - low;
++ sym = BinarySearchSym((unsigned long)
++ (((value - low + 1) * sym_cum[0] - 1) / range));
++ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
++ low += (range * sym_cum[sym ]) / sym_cum[0];
++ for ( ; ; ) {
++ if (low >= Q2) {
++ value -= Q2; low -= Q2; high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ value -= Q1; low -= Q1; high -= Q1;
++ } else if (high > Q2) break;
++ low += low; high += high;
++ value *= 2;
++ if ((mask >>= 1) == 0) {
++ buffer = (ip >= srcend) ? 0 : *(ip++);
++ mask = 128;
++ }
++ value += ((buffer & mask) != 0);
++ }
++ c = sym_to_char[sym];
++ UpdateModel(sym);
++ if (c < 256) {
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ } else {
++ j = c - 255 + THRESHOLD;
++ range = high - low;
++ i = BinarySearchPos((unsigned long)
++ (((value - low + 1) * position_cum[0] - 1) / range));
++ high = low + (range * position_cum[i ]) / position_cum[0];
++ low += (range * position_cum[i + 1]) / position_cum[0];
++ for ( ; ; ) {
++ if (low >= Q2) {
++ value -= Q2; low -= Q2; high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ value -= Q1; low -= Q1; high -= Q1;
++ } else if (high > Q2) break;
++ low += low; high += high;
++ value *= 2;
++ if ((mask >>= 1) == 0) {
++ buffer = (ip >= srcend) ? 0 : *(ip++);
++ mask = 128;
++ }
++ value += ((buffer & mask) != 0);
++ }
++ i = (r - i - 1) & (N - 1);
++ for (k = 0; k < j; k++) {
++ c = text_buf[(i + k) & (N - 1)];
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ }
++ }
++ }
++ return 0;
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++#define JFFS2_BBC_LZARI_BLOCK_SIGN {0x73, 0x9a, 0x1c, 0x4d}
++
++static int
++jffs2_bbc_lzari_compressor_init (void);
++
++static void
++jffs2_bbc_lzari_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzari_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzari_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzari_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzari_proc_info (void);
++
++static int
++jffs2_bbc_lzari_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzari = {
++ "lzari",
++ 0,
++ JFFS2_BBC_LZARI_BLOCK_SIGN,
++ jffs2_bbc_lzari_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzari_compressor_deinit,
++ jffs2_bbc_lzari_compress,
++ jffs2_bbc_lzari_estimate,
++ jffs2_bbc_lzari_decompress,
++ jffs2_bbc_lzari_proc_info,
++ jffs2_bbc_lzari_proc_command
++};
++
++static int
++jffs2_bbc_lzari_compressor_init (void)
++{
++ return 0;
++}
++
++static void
++jffs2_bbc_lzari_compressor_deinit (void)
++{
++}
++
++static int
++jffs2_bbc_lzari_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ int retval;
++ unsigned long dst = *dstlen;
++ *(output++) = jffs2_bbc_lzari.block_sign[0];
++ *(output++) = jffs2_bbc_lzari.block_sign[1];
++ dst -= 2;
++ retval = Encode(input, output, sourcelen, &dst);
++ dst += 2;
++ *dstlen = dst;
++ return retval;
++}
++
++static int
++jffs2_bbc_lzari_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen / 2;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 15;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 7;
++ return 0;
++}
++
++static int
++jffs2_bbc_lzari_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzari.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzari.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return Decode(input, output, sourcelen - 2, dstlen);
++ }
++}
++
++static char *
++jffs2_bbc_lzari_proc_info (void)
++{
++ return "Lempel-Ziv-Arithmetic coding compression module";
++}
++
++static int
++jffs2_bbc_lzari_proc_command (char *command)
++{
++ return 0;
++}
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzari_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzari) == 0)
++ {
++ return &jffs2_bbc_lzari;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzari_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzari);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzhd_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzhd_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzhd_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzhd_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,747 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzhd_comp.c -- Lempel-Ziv-(dynamic) Huffman compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the LZHUF source included in LDS (lossless datacompression sources)
++ Block-compression and bitstream modifications by Patrik Kluba
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++Original copyright follows:
++
++**************************************************************
++ lzhuf.c
++ written by Haruyasu Yoshizaki 11/20/1988
++ some minor changes 4/6/1989
++ comments translated by Haruhiko Okumura 4/7/1989
++**************************************************************
++
++LZHUF.C (c)1989 by Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
++All rights reserved. Permission granted for non-commercial use.
++
++*/
++
++/*
++
++ 2004-02-18 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Replaced name lzh-d with lzhd
++ Fixed no return value
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++
++*/
++
++/* required because of memmove */
++#ifndef __KERNEL__
++ #include <string.h>
++#else
++ #include <linux/string.h>
++#endif
++
++/* lzhuf.c */
++
++#define N 4096 /* size of ring buffer */
++#define F 60 /* upper limit for match_length */
++#define THRESHOLD 2 /* encode string into position and length
++ if match_length is greater than this */
++#define NIL N /* index for root of binary search trees */
++
++static unsigned char
++ text_buf[N + F - 1]; /* ring buffer of size N,
++ with extra F-1 bytes to facilitate string comparison */
++static unsigned long match_position, match_length, /* of longest match. These are
++ set by the InsertNode() procedure. */
++ lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
++ parents -- These constitute binary search trees. */
++
++static void InitTree(void) /* initialize trees */
++{
++ unsigned long i;
++
++ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
++ left children of node i. These nodes need not be initialized.
++ Also, dad[i] is the parent of node i. These are initialized to
++ NIL (= N), which stands for 'not used.'
++ For i = 0 to 255, rson[N + i + 1] is the root of the tree
++ for strings that begin with character i. These are initialized
++ to NIL. Note there are 256 trees. */
++
++ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL;
++ for (i = 0; i < N; i++) dad[i] = NIL;
++}
++
++static void InsertNode(unsigned long r)
++ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
++ trees (text_buf[r]'th tree) and returns the longest-match position
++ and length via the global variables match_position and match_length.
++ If match_length = F, then removes the old node in favor of the new
++ one, because the old one will be deleted sooner.
++ Note r plays double role, as tree node and position in buffer. */
++{
++ unsigned long i, p, c;
++ signed long cmp;
++ unsigned char *key;
++
++ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
++ rson[r] = lson[r] = NIL; match_length = 0;
++ for ( ; ; ) {
++ if (cmp >= 0) {
++ if (rson[p] != NIL) p = rson[p];
++ else { rson[p] = r; dad[r] = p; return; }
++ } else {
++ if (lson[p] != NIL) p = lson[p];
++ else { lson[p] = r; dad[r] = p; return; }
++ }
++ for (i = 1; i < F; i++)
++ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
++ if (i > THRESHOLD) {
++ if (i > match_length) {
++ match_position = ((r - p) & (N - 1)) - 1;
++ if ((match_length = i) >= F) break;
++ }
++ if (i == match_length) {
++ if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
++ match_position = c;
++ }
++ }
++ }
++ }
++ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
++ dad[lson[p]] = r; dad[rson[p]] = r;
++ if (rson[dad[p]] == p) rson[dad[p]] = r;
++ else lson[dad[p]] = r;
++ dad[p] = NIL; /* remove p */
++}
++
++static void DeleteNode(unsigned long p) /* deletes node p from tree */
++{
++ unsigned long q;
++
++ if (dad[p] == NIL) return; /* not in tree */
++ if (rson[p] == NIL) q = lson[p];
++ else if (lson[p] == NIL) q = rson[p];
++ else {
++ q = lson[p];
++ if (rson[q] != NIL) {
++ do { q = rson[q]; } while (rson[q] != NIL);
++ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
++ lson[q] = lson[p]; dad[lson[p]] = q;
++ }
++ rson[q] = rson[p]; dad[rson[p]] = q;
++ }
++ dad[q] = dad[p];
++ if (rson[dad[p]] == p) rson[dad[p]] = q; else lson[dad[p]] = q;
++ dad[p] = NIL;
++}
++
++/* Huffman coding */
++
++#define N_CHAR (256 - THRESHOLD + F)
++ /* kinds of characters (character code = 0..N_CHAR-1) */
++#define T (N_CHAR * 2 - 1) /* size of table */
++#define R (T - 1) /* position of root */
++#define MAX_FREQ 0x8000 /* updates tree when the */
++ /* root frequency comes to this value. */
++
++typedef unsigned long uchar; // much-much faster
++
++/* table for encoding and decoding the upper 6 bits of position */
++
++/* for encoding */
++static uchar p_len[64] = {
++ 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
++};
++
++static uchar p_code[64] = {
++ 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
++ 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
++ 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
++ 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
++ 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
++ 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
++ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
++ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
++};
++
++/* for decoding */
++static uchar d_code[256] = {
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
++ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
++ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
++ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
++ 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
++ 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
++ 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
++ 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
++ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
++ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
++ 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
++ 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
++ 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
++ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
++ 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
++ 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
++ 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
++};
++
++static uchar d_len[256] = {
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++};
++
++static unsigned long freq[T + 1]; /* frequency table */
++
++static unsigned long prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
++ /* elements [T..T + N_CHAR - 1] which are used to get */
++ /* the positions of leaves corresponding to the codes. */
++
++static unsigned long son[T]; /* pointers to child nodes (son[], son[] + 1) */
++
++/* initialization of tree */
++
++static void StartHuff(void)
++{
++ unsigned long i, j;
++
++ for (i = 0; i < N_CHAR; i++) {
++ freq[i] = 1;
++ son[i] = i + T;
++ prnt[i + T] = i;
++ }
++ i = 0; j = N_CHAR;
++ while (j <= R) {
++ freq[j] = freq[i] + freq[i + 1];
++ son[j] = i;
++ prnt[i] = prnt[i + 1] = j;
++ i += 2; j++;
++ }
++ freq[T] = 0xffff;
++ prnt[R] = 0;
++}
++
++/* reconstruction of tree */
++
++static void reconst(void)
++{
++ unsigned long f, l, i, j, k;
++
++ /* collect leaf nodes in the first half of the table */
++ /* and replace the freq by (freq + 1) / 2. */
++ j = 0;
++ for (i = 0; i < T; i++) {
++ if (son[i] >= T) {
++ freq[j] = (freq[i] + 1) / 2;
++ son[j] = son[i];
++ j++;
++ }
++ }
++ /* begin constructing tree by connecting sons */
++ for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
++ k = i + 1;
++ f = freq[j] = freq[i] + freq[k];
++ for (k = j - 1; f < freq[k]; k--);
++ k++;
++ l = (j - k) * 2;
++ memmove(&freq[k + 1], &freq[k], l*sizeof(unsigned long));
++ freq[k] = f;
++ memmove(&son[k + 1], &son[k], l*sizeof(unsigned long));
++ son[k] = i;
++ }
++ /* connect prnt */
++ for (i = 0; i < T; i++) {
++ if ((k = son[i]) >= T) {
++ prnt[k] = i;
++ } else {
++ prnt[k] = prnt[k + 1] = i;
++ }
++ }
++}
++
++/* increment frequency of given code by one, and update tree */
++
++static void update(unsigned long c)
++{
++ unsigned long i, j, k, l;
++
++ if (freq[R] == MAX_FREQ) {
++ reconst();
++ }
++ c = prnt[c + T];
++ do {
++ k = ++freq[c];
++
++ /* if the order is disturbed, exchange nodes */
++ if (k > freq[l = c + 1]) {
++ while (k > freq[++l]);
++ l--;
++ freq[c] = freq[l];
++ freq[l] = k;
++
++ i = son[c];
++ prnt[i] = l;
++ if (i < T) prnt[i + 1] = l;
++
++ j = son[l];
++ son[l] = i;
++
++ prnt[j] = c;
++ if (j < T) prnt[j + 1] = c;
++ son[c] = j;
++
++ c = l;
++ }
++ } while (c = prnt[c]); /* repeat up to root */
++}
++
++/* modified for block compression */
++/* on return, srclen will contain the number of successfully compressed bytes
++ and dstlen will contain completed compressed bytes */
++
++static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
++ unsigned long *dstlen)
++{
++ unsigned long c, i, j, k, len, r, s, last_match_length, code_buf_ptr;
++ unsigned char code_buf[17], mask;
++ unsigned char *ip, *op;
++ unsigned long written = 0;
++ unsigned long read = 0;
++ unsigned short putbuf = 0;
++ uchar putlen = 0;
++ unsigned char *srcend = srcbuf + *srclen;
++ unsigned char *dstend = dstbuf + *dstlen;
++ ip = srcbuf;
++ op = dstbuf;
++ StartHuff();
++ InitTree(); /* initialize trees */
++ code_buf[0] = 0; /* code_buf[1..16] saves eight units of code, and
++ code_buf[0] works as eight flags, "1" representing that the unit
++ is an unencoded letter (1 byte), "0" a position-and-length pair
++ (2 bytes). Thus, eight units require at most 16 bytes of code. */
++ code_buf_ptr = mask = 1;
++ s = 0; r = N - F;
++ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
++ any character that will appear often. */
++ for (len = 0; (len < F) && (ip < srcend); len++)
++ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
++ the buffer */
++ read = len;
++ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
++ each of which begins with one or more 'space' characters. Note
++ the order in which these strings are inserted. This way,
++ degenerate trees will be less likely to occur. */
++ InsertNode(r); /* Finally, insert the whole string just read. The
++ global variables match_length and match_position are set. */
++ do {
++ if (match_length > len) match_length = len; /* match_length
++ may be spuriously long near the end of text. */
++ if (match_length <= THRESHOLD) {
++ match_length = 1; /* Not long enough match. Send one byte. */
++ c = text_buf[r];
++ i = 0; j = 0; k = prnt[c + T];
++ do {
++ i >>= 1;
++ /* if node's address is odd-numbered, choose bigger brother node */
++ if (k & 1) i |= 0x8000;
++ j++;
++ } while ((k = prnt[k]) != R);
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**warm**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ update(c);
++ } else {
++ c = 255 - THRESHOLD + match_length;
++ i = 0; j = 0; k = prnt[c + T];
++ do {
++ i >>= 1;
++ /* if node's address is odd-numbered, choose bigger brother node */
++ if (k & 1) i |= 0x8000;
++ j++;
++ } while ((k = prnt[k]) != R);
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**warm**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ update(c);
++ j = p_len[match_position >> 6];
++ i = p_code[match_position >> 6] << 8;
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**hot**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ j = 6;
++ i = (match_position & 0x3f) << 10;
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**hot**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ }
++ last_match_length = match_length;
++ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
++ c = *(ip++);
++ DeleteNode(s);
++ text_buf[s] = c;
++ if (s < F - 1)
++ text_buf[s + N] = c;
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ InsertNode(r);
++ }
++ read += i;
++ while (i++ < last_match_length) {
++ DeleteNode(s);
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ if (--len) InsertNode(r);
++ }
++ } while (len > 0);
++ if (putlen) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ written++;
++ *srclen = read;
++ }
++ *dstlen = written;
++ return 0;
++}
++
++static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
++ unsigned long dstlen) /* Just the reverse of Encode(). */
++{
++ unsigned long i, r, j, k, c;
++ unsigned char *ip, *op;
++ unsigned char *srcend = srcbuf + srclen;
++ unsigned char *dstend = dstbuf + dstlen;
++ unsigned short getbuf = 0;
++ uchar getlen = 0;
++ ip = srcbuf;
++ op = dstbuf;
++ StartHuff();
++ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
++ r = N - F;
++ while (op < dstend) {
++ c = son[R];
++ /* travel from root to leaf, */
++ /* choosing the smaller child node (son[]) if the read bit is 0, */
++ /* the bigger (son[]+1} if 1 */
++ while (c < T) {
++ while (getlen <= 8) {
++ unsigned short t;
++ t = (ip >= srcend) ? 0 : *(ip++);
++ getbuf |= t << (8 - getlen);
++ getlen += 8;
++ }
++ c += ((signed short)getbuf < 0);
++ getbuf <<= 1;
++ getlen--;
++ c = son[c];
++ }
++ c -= T;
++ update(c);
++ if (c < 256) {
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ } else {
++ j = c - 255 + THRESHOLD;
++ while (getlen <= 8) {
++ unsigned short t;
++ t = (ip >= srcend) ? 0 : *(ip++);
++ getbuf |= t << (8 - getlen);
++ getlen += 8;
++ }
++ i = getbuf >> 8;
++ getbuf <<= 8;
++ getlen -= 8;
++ c = d_code[i] << 6;
++ k = d_len[i];
++ /* read lower 6 bits verbatim */
++ k -= 2;
++ while (k--) {
++ while (getlen <= 8) {
++ unsigned short t;
++ t = (ip >= srcend) ? 0 : *(ip++);
++ getbuf |= t << (8 - getlen);
++ getlen += 8;
++ }
++ i = (i << 1) + ((signed short)getbuf < 0);
++ getbuf <<= 1;
++ getlen--;
++ }
++ i = c | (i & 0x3F);
++ i = r - i - 1;
++ i &= (N - 1);
++ for (k = 0; k < j; k++) {
++ c = text_buf[(i + k) & (N - 1)];
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ }
++ }
++ }
++ return 0;
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++
++#define JFFS2_BBC_LZHD_BLOCK_SIGN {0x3a, 0x98, 0xf7, 0xda}
++
++static int
++jffs2_bbc_lzhd_compressor_init (void);
++
++static void
++jffs2_bbc_lzhd_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzhd_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzhd_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzhd_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzhd_proc_info (void);
++
++static int
++jffs2_bbc_lzhd_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzhd = {
++ "lzhd",
++ 0,
++ JFFS2_BBC_LZHD_BLOCK_SIGN,
++ jffs2_bbc_lzhd_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzhd_compressor_deinit,
++ jffs2_bbc_lzhd_compress,
++ jffs2_bbc_lzhd_estimate,
++ jffs2_bbc_lzhd_decompress,
++ jffs2_bbc_lzhd_proc_info,
++ jffs2_bbc_lzhd_proc_command
++};
++
++static int
++jffs2_bbc_lzhd_compressor_init (void)
++{
++ return 0;
++}
++
++static void
++jffs2_bbc_lzhd_compressor_deinit (void)
++{
++}
++
++static int
++jffs2_bbc_lzhd_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ int retval;
++ unsigned long dst = *dstlen;
++ *(output++) = jffs2_bbc_lzhd.block_sign[0];
++ *(output++) = jffs2_bbc_lzhd.block_sign[1];
++ dst -= 2;
++ retval = Encode(input, output, sourcelen, &dst);
++ dst += 2;
++ *dstlen = dst;
++ return retval;
++}
++
++static int
++jffs2_bbc_lzhd_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 55 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 8;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 65 / 10;
++ return 0;
++}
++
++static int
++jffs2_bbc_lzhd_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzhd.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzhd.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return Decode(input, output, sourcelen - 2, dstlen);
++ }
++}
++
++static char *
++jffs2_bbc_lzhd_proc_info (void)
++{
++ return "Lempel-Ziv-(dynamic) Huffman compression module";
++}
++
++static int
++jffs2_bbc_lzhd_proc_command (char *command)
++{
++ return 0;
++}
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzhd_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzhd) == 0)
++ {
++ return &jffs2_bbc_lzhd;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzhd_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzhd);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzo_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzo_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzo_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzo_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,2435 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzo_comp.c -- LZO1X-1 (and -999) compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the original LZO sources
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++ Original copyright notice follows:
++
++ lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
++ lzo_ptr.h -- low-level pointer constructs
++ lzo_swd.ch -- sliding window dictionary
++ lzoconf.h -- configuration for the LZO real-time data compression library
++ lzo_mchw.ch -- matching functions using a window
++ minilzo.c -- mini subset of the LZO real-time data compression library
++ config1x.h -- configuration for the LZO1X algorithm
++ lzo1x.h -- public interface of the LZO1X compression algorithm
++
++ These files are part of the LZO real-time data compression library.
++
++ Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
++ All Rights Reserved.
++
++ The LZO library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public License as
++ published by the Free Software Foundation; either version 2 of
++ the License, or (at your option) any later version.
++
++ The LZO library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with the LZO library; see the file COPYING.
++ If not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++ Markus F.X.J. Oberhumer
++ <markus@oberhumer.com>
++*/
++
++/*
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++ -removed all 16 bit code
++ -all sensitive data will be on 4 byte boundary
++ -removed check parts for library use
++ -removed all but LZO1X-* compression
++
++*/
++
++#ifndef __KERNEL__
++ #include <sys/types.h>
++ #include <stddef.h>
++ #include <string.h>
++ #include <limits.h>
++#else
++ #include <linux/kernel.h>
++ #include <linux/types.h>
++ #include <linux/stddef.h>
++ #include <linux/string.h>
++ #define USHRT_MAX 65535
++ /* #define UINT_MAX 4294967295U */
++#endif
++
++/* data type definitions */
++#define U32 unsigned long
++#define S32 signed long
++#define I32 long
++#define U16 unsigned short
++#define S16 signed short
++#define I16 short
++#define U8 unsigned char
++#define S8 signed char
++#define I8 char
++
++/*************************************/
++
++/* lzo_swd.ch */
++
++#define SWD_N N
++#define SWD_F F
++#define SWD_THRESHOLD THRESHOLD
++
++/* shortest unsigned int that 2 * SWD_F + SWD_N (currently 53248) fits in */
++typedef unsigned short swd_uint;
++/* upper limit of that data type */
++#define SWD_UINT_MAX USHRT_MAX
++
++/* minilzo.c */
++
++#define LZO_VERSION_DATE "Jul 12 2002"
++#define LZO_VERSION_STRING "1.08"
++#define LZO_VERSION 0x1080
++
++/* lzo_ptr.h */
++
++/* Integral types that have *exactly* the same number of bits as a lzo_voidp */
++typedef unsigned long lzo_ptr_t;
++typedef long lzo_sptr_t;
++
++
++/*************************************/
++
++/* config1x.h */
++
++#define M1_MAX_OFFSET 0x0400
++#define M2_MAX_OFFSET 0x0800
++#define M3_MAX_OFFSET 0x4000
++#define M4_MAX_OFFSET 0xbfff
++
++#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
++
++#define M1_MIN_LEN 2
++#define M1_MAX_LEN 2
++#define M2_MIN_LEN 3
++#define M2_MAX_LEN 8
++#define M3_MIN_LEN 3
++#define M3_MAX_LEN 33
++#define M4_MIN_LEN 3
++#define M4_MAX_LEN 9
++
++#define M1_MARKER 0
++#define M2_MARKER 64
++#define M3_MARKER 32
++#define M4_MARKER 16
++
++#define MIN_LOOKAHEAD (M2_MAX_LEN + 1)
++
++/* minilzo.c */
++
++#define LZO_BYTE(x) ((unsigned char) ((x) & 0xff))
++
++#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
++#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
++#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
++#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
++
++#define lzo_sizeof(type) ((lzo_uint) (sizeof(type)))
++
++#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array))))
++
++#define LZO_SIZE(bits) (1u << (bits))
++#define LZO_MASK(bits) (LZO_SIZE(bits) - 1)
++
++#define LZO_LSIZE(bits) (1ul << (bits))
++#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1)
++
++#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits))
++#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1)
++
++#define LZO_STYPE_MAX(b) (((1l << (8*(b)-2)) - 1l) + (1l << (8*(b)-2)))
++#define LZO_UTYPE_MAX(b) (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
++
++#define _LZO_STRINGIZE(x) #x
++#define _LZO_MEXPAND(x) _LZO_STRINGIZE(x)
++
++#define _LZO_CONCAT2(a,b) a ## b
++#define _LZO_CONCAT3(a,b,c) a ## b ## c
++#define _LZO_CONCAT4(a,b,c,d) a ## b ## c ## d
++#define _LZO_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
++
++#define _LZO_ECONCAT2(a,b) _LZO_CONCAT2(a,b)
++#define _LZO_ECONCAT3(a,b,c) _LZO_CONCAT3(a,b,c)
++#define _LZO_ECONCAT4(a,b,c,d) _LZO_CONCAT4(a,b,c,d)
++#define _LZO_ECONCAT5(a,b,c,d,e) _LZO_CONCAT5(a,b,c,d,e)
++
++#define lzo_dict_t const lzo_bytep
++#define lzo_dict_p lzo_dict_t *
++#define lzo_moff_t lzo_uint
++
++#define MEMCPY8_DS(dest,src,len) \
++ memcpy(dest,src,len); \
++ dest += len; \
++ src += len
++
++#define MEMCPY_DS(dest,src,len) \
++ do *dest++ = *src++; \
++ while (--len > 0)
++
++#define MEMMOVE_DS(dest,src,len) \
++ do *dest++ = *src++; \
++ while (--len > 0)
++
++#define BZERO8_PTR(s,l,n) memset((s),0,(lzo_uint)(l)*(n))
++
++#define LZO_BASE 65521u
++#define LZO_NMAX 5552
++
++#define LZO_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
++#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1);
++#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2);
++#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4);
++#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
++
++#define IS_SIGNED(type) (((type) (-1)) < ((type) 0))
++#define IS_UNSIGNED(type) (((type) (-1)) > ((type) 0))
++
++#define IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
++
++#define D_BITS 14
++#define D_INDEX1(d,p) d = DM((0x21*DX3(p,5,5,6)) >> 5)
++#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
++
++#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B
++
++#define DL_MIN_LEN M2_MIN_LEN
++
++#define D_SIZE LZO_SIZE(D_BITS)
++#define D_MASK LZO_MASK(D_BITS)
++
++#define D_HIGH ((D_MASK >> 1) + 1)
++
++#define DINDEX1 D_INDEX1
++#define DINDEX2 D_INDEX2
++
++#define DX2(p,s1,s2) \
++ (((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
++
++#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
++#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
++#define DM(v) DMS(v,0)
++
++#define DENTRY(p,in) (p)
++#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
++
++#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
++ (m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
++
++#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
++ (BOUNDS_CHECKING_OFF_IN_EXPR( \
++ (PTR_LT(m_pos,in) || \
++ (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
++ m_off > max_offset) ))
++
++#define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr)
++
++#define DD_BITS 0
++#define DD_SIZE LZO_SIZE(DD_BITS)
++#define DD_MASK LZO_MASK(DD_BITS)
++
++#define DL_BITS (D_BITS - DD_BITS)
++#define DL_SIZE LZO_SIZE(DL_BITS)
++#define DL_MASK LZO_MASK(DL_BITS)
++
++#define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in)
++#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in)
++#define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in)
++
++#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
++#define COPY4(dst,src) __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
++
++#define TEST_IP (ip < ip_end)
++#define TEST_OP (op <= op_end)
++
++#define NEED_IP(x) \
++ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
++#define NEED_OP(x) \
++ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
++#define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun
++
++/* lzo1x_9x.c */
++
++#define LZO_UINT_MAX UINT_MAX
++#define N M4_MAX_OFFSET
++#define THRESHOLD 1
++#define F 2048
++
++#define SWD_BEST_OFF (LZO_MAX3( M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN ) + 1)
++
++/* ../include/lzoconf.h */
++
++typedef U32 lzo_uint32;
++typedef I32 lzo_int32;
++typedef U32 lzo_uint;
++typedef I32 lzo_int;
++typedef int lzo_bool;
++
++#define lzo_byte U8
++#define lzo_bytep U8 *
++#define lzo_charp char *
++#define lzo_voidp void *
++#define lzo_shortp short *
++#define lzo_ushortp unsigned short *
++#define lzo_uint32p lzo_uint32 *
++#define lzo_int32p lzo_int32 *
++#define lzo_uintp lzo_uint *
++#define lzo_intp lzo_int *
++#define lzo_voidpp lzo_voidp *
++#define lzo_bytepp lzo_bytep *
++#define lzo_sizeof_dict_t sizeof(lzo_bytep)
++
++#define LZO_E_OK 0
++#define LZO_E_ERROR (-1)
++#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */
++#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */
++#define LZO_E_INPUT_OVERRUN (-4)
++#define LZO_E_OUTPUT_OVERRUN (-5)
++#define LZO_E_LOOKBEHIND_OVERRUN (-6)
++#define LZO_E_EOF_NOT_FOUND (-7)
++#define LZO_E_INPUT_NOT_CONSUMED (-8)
++
++#define LZO_PTR_ALIGN_UP(_ptr,_size) \
++ ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
++#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
++
++typedef int
++ (*lzo_compress_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_decompress_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_optimize_t) (lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_compress_dict_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len);
++
++typedef int
++ (*lzo_decompress_dict_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len);
++
++typedef int
++ (*lzo_compress_asm_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_decompress_asm_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef void (*lzo_progress_callback_t) (lzo_uint, lzo_uint);
++
++typedef union
++{
++ lzo_bytep p;
++ lzo_uint u;
++} __lzo_pu_u;
++typedef union
++{
++ lzo_bytep p;
++ lzo_uint32 u32;
++} __lzo_pu32_u;
++typedef union
++{
++ void *vp;
++ lzo_bytep bp;
++ lzo_uint32 u32;
++ long l;
++} lzo_align_t;
++
++/* lzo1x.h */
++
++#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
++#define LZO1X_999_MEM_COMPRESS ((lzo_uint32) (14 * 16384L * sizeof(short)))
++
++/* lzo_ptr.h */
++
++#define PTR(a) ((lzo_ptr_t) (a))
++#define PTR_LINEAR(a) PTR(a)
++#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0)
++#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0)
++#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
++#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
++#define PTR_LT(a,b) (PTR(a) < PTR(b))
++#define PTR_GE(a,b) (PTR(a) >= PTR(b))
++#define PTR_DIFF(a,b) ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
++#define pd(a,b) ((lzo_uint) ((a)-(b)))
++
++typedef ptrdiff_t lzo_ptrdiff_t;
++
++typedef union
++{
++ char a_char;
++ unsigned char a_uchar;
++ short a_short;
++ unsigned short a_ushort;
++ int a_int;
++ unsigned int a_uint;
++ long a_long;
++ unsigned long a_ulong;
++ lzo_int a_lzo_int;
++ lzo_uint a_lzo_uint;
++ lzo_int32 a_lzo_int32;
++ lzo_uint32 a_lzo_uint32;
++ ptrdiff_t a_ptrdiff_t;
++ lzo_ptrdiff_t a_lzo_ptrdiff_t;
++ lzo_ptr_t a_lzo_ptr_t;
++ lzo_voidp a_lzo_voidp;
++ void *a_void_p;
++ lzo_bytep a_lzo_bytep;
++ lzo_bytepp a_lzo_bytepp;
++ lzo_uintp a_lzo_uintp;
++ lzo_uint *a_lzo_uint_p;
++ lzo_uint32p a_lzo_uint32p;
++ lzo_uint32 *a_lzo_uint32_p;
++ unsigned char *a_uchar_p;
++ char *a_char_p;
++}
++lzo_full_align_t;
++
++/* lzo_mchw.ch */
++
++typedef struct
++{
++ int init;
++
++ lzo_uint look;
++
++ lzo_uint m_len;
++ lzo_uint m_off;
++
++ lzo_uint last_m_len;
++ lzo_uint last_m_off;
++
++ const lzo_byte *bp;
++ const lzo_byte *ip;
++ const lzo_byte *in;
++ const lzo_byte *in_end;
++ lzo_byte *out;
++
++ lzo_progress_callback_t cb;
++
++ lzo_uint textsize;
++ lzo_uint codesize;
++ lzo_uint printcount;
++
++ unsigned long lit_bytes;
++ unsigned long match_bytes;
++ unsigned long rep_bytes;
++ unsigned long lazy;
++
++ lzo_uint r1_lit;
++ lzo_uint r1_m_len;
++
++ unsigned long m1a_m, m1b_m, m2_m, m3_m, m4_m;
++ unsigned long lit1_r, lit2_r, lit3_r;
++}
++lzo1x_999_t;
++
++#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
++
++/* lzo_swd.ch */
++
++#define SWD_UINT(x) ((swd_uint)(x))
++#define SWD_HSIZE 16384
++#define SWD_MAX_CHAIN 2048
++#define HEAD3(b,p) \
++ (((0x9f5f*(((((lzo_uint32)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
++#define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
++#define NIL2 SWD_UINT_MAX
++
++typedef struct
++{
++ lzo_uint n;
++ lzo_uint f;
++ lzo_uint threshold;
++
++ lzo_uint max_chain;
++ lzo_uint nice_length;
++ lzo_bool use_best_off;
++ lzo_uint lazy_insert;
++
++ lzo_uint m_len;
++ lzo_uint m_off;
++ lzo_uint look;
++ int b_char;
++
++ lzo_uint best_off[SWD_BEST_OFF];
++
++ lzo1x_999_t *c;
++ lzo_uint m_pos;
++
++ lzo_uint best_pos[SWD_BEST_OFF];
++
++ const lzo_byte *dict;
++ const lzo_byte *dict_end;
++ lzo_uint dict_len;
++
++ lzo_uint ip;
++ lzo_uint bp;
++ lzo_uint rp;
++ lzo_uint b_size;
++
++ unsigned char *b_wrap;
++
++ lzo_uint node_count;
++ lzo_uint first_rp;
++
++ unsigned char b[SWD_N + SWD_F + SWD_F];
++ swd_uint head3[SWD_HSIZE];
++ swd_uint succ3[SWD_N + SWD_F];
++ swd_uint best3[SWD_N + SWD_F];
++ swd_uint llen3[SWD_HSIZE];
++
++ swd_uint head2[65536L];
++}
++lzo1x_999_swd_t;
++
++#define s_head3(s,key) s->head3[key]
++#define swd_pos2off(s,pos) \
++ (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
++
++static __inline__ void
++swd_getbyte (lzo1x_999_swd_t * s)
++{
++ int c;
++
++ if ((c = getbyte (*(s->c))) < 0)
++ {
++ if (s->look > 0)
++ --s->look;
++ }
++ else
++ {
++ s->b[s->ip] = LZO_BYTE (c);
++ if (s->ip < s->f)
++ s->b_wrap[s->ip] = LZO_BYTE (c);
++ }
++ if (++s->ip == s->b_size)
++ s->ip = 0;
++ if (++s->bp == s->b_size)
++ s->bp = 0;
++ if (++s->rp == s->b_size)
++ s->rp = 0;
++}
++
++static void
++swd_initdict (lzo1x_999_swd_t * s, const lzo_byte * dict, lzo_uint dict_len)
++{
++ s->dict = s->dict_end = NULL;
++ s->dict_len = 0;
++
++ if (!dict || dict_len <= 0)
++ return;
++ if (dict_len > s->n)
++ {
++ dict += dict_len - s->n;
++ dict_len = s->n;
++ }
++
++ s->dict = dict;
++ s->dict_len = dict_len;
++ s->dict_end = dict + dict_len;
++ memcpy (s->b, dict, dict_len);
++ s->ip = dict_len;
++}
++
++static void
++swd_insertdict (lzo1x_999_swd_t * s, lzo_uint node, lzo_uint len)
++{
++ lzo_uint key;
++
++ s->node_count = s->n - len;
++ s->first_rp = node;
++
++ while (len-- > 0)
++ {
++ key = HEAD3 (s->b, node);
++ s->succ3[node] = s_head3 (s, key);
++ s->head3[key] = SWD_UINT (node);
++ s->best3[node] = SWD_UINT (s->f + 1);
++ s->llen3[key]++;
++
++ key = HEAD2 (s->b, node);
++ s->head2[key] = SWD_UINT (node);
++
++ node++;
++ }
++}
++
++static int
++swd_init (lzo1x_999_swd_t * s, const lzo_byte * dict, lzo_uint dict_len)
++{
++
++ s->n = SWD_N;
++ s->f = SWD_F;
++ s->threshold = SWD_THRESHOLD;
++
++
++
++ s->max_chain = SWD_MAX_CHAIN;
++ s->nice_length = SWD_F;
++ s->use_best_off = 0;
++ s->lazy_insert = 0;
++
++ s->b_size = s->n + s->f;
++ if (2 * s->f >= s->n || s->b_size + s->f >= NIL2)
++ return LZO_E_ERROR;
++ s->b_wrap = s->b + s->b_size;
++ s->node_count = s->n;
++
++ memset (s->llen3, 0, sizeof (s->llen3[0]) * SWD_HSIZE);
++ memset (s->head2, 0xff, sizeof (s->head2[0]) * 65536L);
++
++ s->ip = 0;
++ swd_initdict (s, dict, dict_len);
++ s->bp = s->ip;
++ s->first_rp = s->ip;
++
++ s->look = (lzo_uint) (s->c->in_end - s->c->ip);
++ if (s->look > 0)
++ {
++ if (s->look > s->f)
++ s->look = s->f;
++ memcpy (&s->b[s->ip], s->c->ip, s->look);
++ s->c->ip += s->look;
++ s->ip += s->look;
++ }
++
++ if (s->ip == s->b_size)
++ s->ip = 0;
++
++ if (s->look >= 2 && s->dict_len > 0)
++ swd_insertdict (s, 0, s->dict_len);
++
++ s->rp = s->first_rp;
++ if (s->rp >= s->node_count)
++ s->rp -= s->node_count;
++ else
++ s->rp += s->b_size - s->node_count;
++
++ return LZO_E_OK;
++}
++
++static __inline__ void
++swd_remove_node (lzo1x_999_swd_t * s, lzo_uint node)
++{
++ if (s->node_count == 0)
++ {
++ lzo_uint key;
++
++ key = HEAD3 (s->b, node);
++
++ --s->llen3[key];
++
++ key = HEAD2 (s->b, node);
++
++ if ((lzo_uint) s->head2[key] == node)
++ s->head2[key] = NIL2;
++ }
++ else
++ --s->node_count;
++}
++
++static void
++swd_accept (lzo1x_999_swd_t * s, lzo_uint n)
++{
++
++ while (n--)
++ {
++ lzo_uint key;
++
++ swd_remove_node (s, s->rp);
++
++ key = HEAD3 (s->b, s->bp);
++ s->succ3[s->bp] = s_head3 (s, key);
++ s->head3[key] = SWD_UINT (s->bp);
++ s->best3[s->bp] = SWD_UINT (s->f + 1);
++ s->llen3[key]++;
++
++ key = HEAD2 (s->b, s->bp);
++ s->head2[key] = SWD_UINT (s->bp);;
++
++ swd_getbyte (s);
++ }
++}
++
++static void
++swd_search (lzo1x_999_swd_t * s, lzo_uint node, lzo_uint cnt)
++{
++ const unsigned char *p1;
++ const unsigned char *p2;
++ const unsigned char *px;
++
++ lzo_uint m_len = s->m_len;
++ const unsigned char *b = s->b;
++ const unsigned char *bp = s->b + s->bp;
++ const unsigned char *bx = s->b + s->bp + s->look;
++ unsigned char scan_end1;
++
++ scan_end1 = bp[m_len - 1];
++ for (; cnt-- > 0; node = s->succ3[node])
++ {
++ p1 = bp;
++ p2 = b + node;
++ px = bx;
++
++ if (p2[m_len - 1] == scan_end1 &&
++ p2[m_len] == p1[m_len] &&
++ p2[0] == p1[0] && p2[1] == p1[1])
++ {
++ lzo_uint i;
++
++ p1 += 2;
++ p2 += 2;
++ do
++ {
++ }
++ while (++p1 < px && *p1 == *++p2);
++
++ i = p1 - bp;
++
++ if (i < SWD_BEST_OFF)
++ {
++ if (s->best_pos[i] == 0)
++ s->best_pos[i] = node + 1;
++ }
++
++ if (i > m_len)
++ {
++ s->m_len = m_len = i;
++ s->m_pos = node;
++ if (m_len == s->look)
++ return;
++ if (m_len >= s->nice_length)
++ return;
++ if (m_len > (lzo_uint) s->best3[node])
++ return;
++ scan_end1 = bp[m_len - 1];
++ }
++ }
++ }
++}
++
++static lzo_bool
++swd_search2 (lzo1x_999_swd_t * s)
++{
++ lzo_uint key;
++
++ key = s->head2[HEAD2 (s->b, s->bp)];
++ if (key == NIL2)
++ return 0;
++
++ if (s->best_pos[2] == 0)
++ s->best_pos[2] = key + 1;
++
++ if (s->m_len < 2)
++ {
++ s->m_len = 2;
++ s->m_pos = key;
++ }
++ return 1;
++}
++
++static void
++swd_findbest (lzo1x_999_swd_t * s)
++{
++ lzo_uint key;
++ lzo_uint cnt, node;
++ lzo_uint len;
++
++ key = HEAD3 (s->b, s->bp);
++ node = s->succ3[s->bp] = s_head3 (s, key);
++ cnt = s->llen3[key]++;
++
++ if (cnt > s->max_chain && s->max_chain > 0)
++ cnt = s->max_chain;
++ s->head3[key] = SWD_UINT (s->bp);
++
++ s->b_char = s->b[s->bp];
++ len = s->m_len;
++ if (s->m_len >= s->look)
++ {
++ if (s->look == 0)
++ s->b_char = -1;
++ s->m_off = 0;
++ s->best3[s->bp] = SWD_UINT (s->f + 1);
++ }
++ else
++ {
++
++ if (swd_search2 (s))
++
++ if (s->look >= 3)
++ swd_search (s, node, cnt);
++ if (s->m_len > len)
++ s->m_off = swd_pos2off (s, s->m_pos);
++ s->best3[s->bp] = SWD_UINT (s->m_len);
++
++ if (s->use_best_off)
++ {
++ int i;
++ for (i = 2; i < SWD_BEST_OFF; i++)
++ if (s->best_pos[i] > 0)
++ s->best_off[i] =
++ swd_pos2off (s,
++ s->best_pos[i] -
++ 1);
++ else
++ s->best_off[i] = 0;
++ }
++
++ }
++
++ swd_remove_node (s, s->rp);
++
++ key = HEAD2 (s->b, s->bp);
++ s->head2[key] = SWD_UINT (s->bp);
++
++}
++
++/* lzo_mchw.ch */
++
++static int
++init_match (lzo1x_999_t * c, lzo1x_999_swd_t * s,
++ const lzo_byte * dict, lzo_uint dict_len, lzo_uint32 flags)
++{
++ int r;
++
++ c->init = 1;
++
++ s->c = c;
++
++ c->last_m_len = c->last_m_off = 0;
++
++ c->textsize = c->codesize = c->printcount = 0;
++ c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
++ c->lazy = 0;
++
++ r = swd_init (s, dict, dict_len);
++ if (r != 0)
++ return r;
++
++ s->use_best_off = (flags & 1) ? 1 : 0;
++ return r;
++}
++
++static int
++find_match (lzo1x_999_t * c, lzo1x_999_swd_t * s,
++ lzo_uint this_len, lzo_uint skip)
++{
++ if (skip > 0)
++ {
++ swd_accept (s, this_len - skip);
++ c->textsize += this_len - skip + 1;
++ }
++ else
++ {
++ c->textsize += this_len - skip;
++ }
++
++ s->m_len = 1;
++ s->m_len = 1;
++
++ if (s->use_best_off)
++ memset (s->best_pos, 0, sizeof (s->best_pos));
++
++ swd_findbest (s);
++ c->m_len = s->m_len;
++ c->m_off = s->m_off;
++
++ swd_getbyte (s);
++
++ if (s->b_char < 0)
++ {
++ c->look = 0;
++ c->m_len = 0;
++ }
++ else
++ {
++ c->look = s->look + 1;
++ }
++ c->bp = c->ip - c->look;
++
++ if (c->cb && c->textsize > c->printcount)
++ {
++ (*c->cb) (c->textsize, c->codesize);
++ c->printcount += 1024;
++ }
++
++ return LZO_E_OK;
++}
++
++/* lzo1x_9x.c */
++
++static lzo_byte *
++code_match (lzo1x_999_t * c, lzo_byte * op, lzo_uint m_len, lzo_uint m_off)
++{
++ lzo_uint x_len = m_len;
++ lzo_uint x_off = m_off;
++
++ c->match_bytes += m_len;
++
++ if (m_len == 2)
++ {
++ m_off -= 1;
++
++ *op++ = LZO_BYTE (M1_MARKER | ((m_off & 3) << 2));
++ *op++ = LZO_BYTE (m_off >> 2);
++
++ c->m1a_m++;
++ }
++
++ else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
++
++ {
++
++ m_off -= 1;
++ *op++ = LZO_BYTE (((m_len - 1) << 5) | ((m_off & 7) << 2));
++ *op++ = LZO_BYTE (m_off >> 3);
++ c->m2_m++;
++ }
++ else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET
++ && c->r1_lit >= 4)
++ {
++ m_off -= 1 + M2_MAX_OFFSET;
++
++ *op++ = LZO_BYTE (M1_MARKER | ((m_off & 3) << 2));
++ *op++ = LZO_BYTE (m_off >> 2);
++
++ c->m1b_m++;
++ }
++ else if (m_off <= M3_MAX_OFFSET)
++ {
++ m_off -= 1;
++ if (m_len <= M3_MAX_LEN)
++ *op++ = LZO_BYTE (M3_MARKER | (m_len - 2));
++ else
++ {
++ m_len -= M3_MAX_LEN;
++ *op++ = M3_MARKER | 0;
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (m_len);
++ }
++
++ *op++ = LZO_BYTE (m_off << 2);
++ *op++ = LZO_BYTE (m_off >> 6);
++
++ c->m3_m++;
++ }
++ else
++ {
++ lzo_uint k;
++
++ m_off -= 0x4000;
++ k = (m_off & 0x4000) >> 11;
++ if (m_len <= M4_MAX_LEN)
++ *op++ = LZO_BYTE (M4_MARKER | k | (m_len - 2));
++ else
++ {
++ m_len -= M4_MAX_LEN;
++ *op++ = LZO_BYTE (M4_MARKER | k | 0);
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (m_len);
++ }
++
++ *op++ = LZO_BYTE (m_off << 2);
++ *op++ = LZO_BYTE (m_off >> 6);
++
++ c->m4_m++;
++ }
++
++ c->last_m_len = x_len;
++ c->last_m_off = x_off;
++ return op;
++}
++
++static lzo_byte *
++STORE_RUN (lzo1x_999_t * c, lzo_byte * op, const lzo_byte * ii, lzo_uint t)
++{
++ c->lit_bytes += t;
++
++ if (op == c->out && t <= 238)
++ {
++ *op++ = LZO_BYTE (17 + t);
++ }
++ else if (t <= 3)
++ {
++ op[-2] |= LZO_BYTE (t);
++
++ c->lit1_r++;
++ }
++ else if (t <= 18)
++ {
++ *op++ = LZO_BYTE (t - 3);
++ c->lit2_r++;
++ }
++ else
++ {
++ lzo_uint tt = t - 18;
++
++ *op++ = 0;
++ while (tt > 255)
++ {
++ tt -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (tt);
++ c->lit3_r++;
++ }
++ do
++ *op++ = *ii++;
++ while (--t > 0);
++
++ return op;
++}
++
++static lzo_byte *
++code_run (lzo1x_999_t * c, lzo_byte * op, const lzo_byte * ii,
++ lzo_uint lit, lzo_uint m_len)
++{
++ if (lit > 0)
++ {
++ op = STORE_RUN (c, op, ii, lit);
++ c->r1_m_len = m_len;
++ c->r1_lit = lit;
++ }
++ else
++ {
++ c->r1_m_len = 0;
++ c->r1_lit = 0;
++ }
++
++ return op;
++}
++
++static int
++len_of_coded_match (lzo_uint m_len, lzo_uint m_off, lzo_uint lit)
++{
++ int n = 4;
++
++ if (m_len < 2)
++ return -1;
++ if (m_len == 2)
++ return (m_off <= M1_MAX_OFFSET && lit > 0
++ && lit < 4) ? 2 : -1;
++ if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
++ return 2;
++ if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
++ return 2;
++ if (m_off <= M3_MAX_OFFSET)
++ {
++ if (m_len <= M3_MAX_LEN)
++ return 3;
++ m_len -= M3_MAX_LEN;
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ n++;
++ }
++ return n;
++ }
++ if (m_off <= M4_MAX_OFFSET)
++ {
++ if (m_len <= M4_MAX_LEN)
++ return 3;
++ m_len -= M4_MAX_LEN;
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ n++;
++ }
++ return n;
++ }
++ return -1;
++}
++
++static lzo_int
++min_gain (lzo_uint ahead, lzo_uint lit1, lzo_uint lit2, int l1, int l2,
++ int l3)
++{
++ lzo_int lazy_match_min_gain = 0;
++
++ lazy_match_min_gain += ahead;
++
++ if (lit1 <= 3)
++ lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
++ else if (lit1 <= 18)
++ lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
++
++ lazy_match_min_gain += (l2 - l1) * 2;
++ if (l3 > 0)
++ lazy_match_min_gain -= (ahead - l3) * 2;
++
++ if (lazy_match_min_gain < 0)
++ lazy_match_min_gain = 0;
++
++ return lazy_match_min_gain;
++}
++
++static void
++better_match (const lzo1x_999_swd_t * swd, lzo_uint * m_len, lzo_uint * m_off)
++{
++ if (*m_len <= M2_MIN_LEN)
++ return;
++
++ if (*m_off <= M2_MAX_OFFSET)
++ return;
++
++ if (*m_off > M2_MAX_OFFSET &&
++ *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 &&
++ swd->best_off[*m_len - 1]
++ && swd->best_off[*m_len - 1] <= M2_MAX_OFFSET)
++ {
++ *m_len = *m_len - 1;
++ *m_off = swd->best_off[*m_len];
++ return;
++ }
++
++ if (*m_off > M3_MAX_OFFSET &&
++ *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 &&
++ swd->best_off[*m_len - 2]
++ && swd->best_off[*m_len - 2] <= M2_MAX_OFFSET)
++ {
++ *m_len = *m_len - 2;
++ *m_off = swd->best_off[*m_len];
++ return;
++ }
++
++ if (*m_off > M3_MAX_OFFSET &&
++ *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 &&
++ swd->best_off[*m_len - 1]
++ && swd->best_off[*m_len - 1] <= M3_MAX_OFFSET)
++ {
++ *m_len = *m_len - 1;
++ *m_off = swd->best_off[*m_len];
++ }
++
++}
++
++/* minilzo.c */
++
++static lzo_bool
++lzo_assert (int expr)
++{
++ return (expr) ? 1 : 0;
++}
++
++/* lzo1x_9x.c */
++
++static int
++lzo1x_999_compress_internal (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len,
++ lzo_progress_callback_t cb,
++ int try_lazy,
++ lzo_uint good_length,
++ lzo_uint max_lazy,
++ lzo_uint nice_length,
++ lzo_uint max_chain, lzo_uint32 flags)
++{
++ lzo_byte *op;
++ const lzo_byte *ii;
++ lzo_uint lit;
++ lzo_uint m_len, m_off;
++ lzo1x_999_t cc;
++ lzo1x_999_t *const c = &cc;
++ lzo1x_999_swd_t *const swd = (lzo1x_999_swd_t *) wrkmem;
++ int r;
++
++ if (!lzo_assert
++ (LZO1X_999_MEM_COMPRESS >= lzo_sizeof (lzo1x_999_swd_t)))
++ return LZO_E_ERROR;
++
++ if (try_lazy < 0)
++ try_lazy = 1;
++
++ if (good_length <= 0)
++ good_length = 32;
++
++ if (max_lazy <= 0)
++ max_lazy = 32;
++
++ if (nice_length <= 0)
++ nice_length = 0;
++
++ if (max_chain <= 0)
++ max_chain = SWD_MAX_CHAIN;
++
++ c->init = 0;
++ c->ip = c->in = in;
++ c->in_end = in + in_len;
++ c->out = out;
++ c->cb = cb;
++ c->m1a_m = c->m1b_m = c->m2_m = c->m3_m = c->m4_m = 0;
++ c->lit1_r = c->lit2_r = c->lit3_r = 0;
++
++ op = out;
++ ii = c->ip;
++ lit = 0;
++ c->r1_lit = c->r1_m_len = 0;
++
++ r = init_match (c, swd, dict, dict_len, flags);
++ if (r != 0)
++ return r;
++ if (max_chain > 0)
++ swd->max_chain = max_chain;
++ if (nice_length > 0)
++ swd->nice_length = nice_length;
++
++ r = find_match (c, swd, 0, 0);
++ if (r != 0)
++ return r;
++ while (c->look > 0)
++ {
++ lzo_uint ahead;
++ lzo_uint max_ahead;
++ int l1, l2, l3;
++
++ c->codesize = op - out;
++
++ m_len = c->m_len;
++ m_off = c->m_off;
++
++ if (lit == 0)
++ ii = c->bp;
++
++ if (m_len < 2 ||
++ (m_len == 2
++ && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4))
++ || (m_len == 2 && op == out) || (op == out && lit == 0))
++ {
++
++ m_len = 0;
++ }
++ else if (m_len == M2_MIN_LEN)
++ {
++
++ if (m_off > MX_MAX_OFFSET && lit >= 4)
++ m_len = 0;
++ }
++
++ if (m_len == 0)
++ {
++
++ lit++;
++ swd->max_chain = max_chain;
++ r = find_match (c, swd, 1, 0);
++ continue;
++ }
++
++ if (swd->use_best_off)
++ better_match (swd, &m_len, &m_off);
++
++ ahead = 0;
++ if (try_lazy <= 0 || m_len >= max_lazy)
++ {
++
++ l1 = 0;
++ max_ahead = 0;
++ }
++ else
++ {
++
++ l1 = len_of_coded_match (m_len, m_off, lit);
++
++ max_ahead = LZO_MIN (try_lazy, l1 - 1);
++
++ }
++
++ while (ahead < max_ahead && c->look > m_len)
++ {
++ lzo_int lazy_match_min_gain;
++
++ if (m_len >= good_length)
++ swd->max_chain = max_chain >> 2;
++ else
++ swd->max_chain = max_chain;
++ r = find_match (c, swd, 1, 0);
++ ahead++;
++
++ if (c->m_len < m_len)
++ continue;
++
++ if (c->m_len == m_len && c->m_off >= m_off)
++ continue;
++
++ if (swd->use_best_off)
++ better_match (swd, &c->m_len, &c->m_off);
++
++ l2 = len_of_coded_match (c->m_len, c->m_off,
++ lit + ahead);
++ if (l2 < 0)
++ continue;
++
++ l3 = (op == out) ? -1 : len_of_coded_match (ahead,
++ m_off,
++ lit);
++
++ lazy_match_min_gain =
++ min_gain (ahead, lit, lit + ahead, l1, l2,
++ l3);
++ if (c->m_len >= m_len + lazy_match_min_gain)
++ {
++ c->lazy++;
++
++ if (l3 > 0)
++ {
++
++ op = code_run (c, op, ii, lit, ahead);
++ lit = 0;
++
++ op = code_match (c, op, ahead, m_off);
++ }
++ else
++ {
++ lit += ahead;
++ }
++ goto lazy_match_done;
++ }
++ }
++
++ op = code_run (c, op, ii, lit, m_len);
++ lit = 0;
++
++ op = code_match (c, op, m_len, m_off);
++ swd->max_chain = max_chain;
++ r = find_match (c, swd, m_len, 1 + ahead);
++
++ lazy_match_done:;
++ }
++
++ if (lit > 0)
++ op = STORE_RUN (c, op, ii, lit);
++
++ *op++ = M4_MARKER | 1;
++ *op++ = 0;
++ *op++ = 0;
++
++ c->codesize = op - out;
++
++ *out_len = op - out;
++
++ if (c->cb)
++ (*c->cb) (c->textsize, c->codesize);
++
++ return LZO_E_OK;
++}
++
++static int
++lzo1x_999_compress_level (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len,
++ lzo_progress_callback_t cb, int compression_level)
++{
++ static const struct
++ {
++ int try_lazy;
++ lzo_uint good_length;
++ lzo_uint max_lazy;
++ lzo_uint nice_length;
++ lzo_uint max_chain;
++ lzo_uint32 flags;
++ } c[9] =
++ {
++ {
++ 0, 0, 0, 8, 4, 0},
++ {
++ 0, 0, 0, 16, 8, 0},
++ {
++ 0, 0, 0, 32, 16, 0},
++ {
++ 1, 4, 4, 16, 16, 0},
++ {
++ 1, 8, 16, 32, 32, 0},
++ {
++ 1, 8, 16, 128, 128, 0},
++ {
++ 2, 8, 32, 128, 256, 0},
++ {
++ 2, 32, 128, F, 2048, 1},
++ {
++ 2, F, F, F, 4096, 1}
++ };
++
++ if (compression_level < 1 || compression_level > 9)
++ return LZO_E_ERROR;
++
++ compression_level -= 1;
++ return lzo1x_999_compress_internal (in, in_len, out, out_len, wrkmem,
++ dict, dict_len, cb,
++ c[compression_level].try_lazy,
++ c[compression_level].good_length,
++ c[compression_level].max_lazy,
++ 0,
++ c[compression_level].max_chain,
++ c[compression_level].flags);
++}
++
++static int
++lzo1x_999_compress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ return lzo1x_999_compress_level (in, in_len, out, out_len, wrkmem,
++ NULL, 0, 0, 8);
++}
++
++/* minilzo.c */
++
++static const lzo_byte __lzo_copyright[] = LZO_VERSION_STRING;
++
++static lzo_uint
++_lzo1x_1_do_compress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++
++ register const lzo_byte *ip;
++
++ lzo_byte *op;
++ const lzo_byte *const in_end = in + in_len;
++ const lzo_byte *const ip_end = in + in_len - 8 - 5;
++ const lzo_byte *ii;
++ lzo_dict_p const dict = (lzo_dict_p) wrkmem;
++
++ op = out;
++ ip = in;
++ ii = ip;
++
++ ip += 4;
++ for (;;)
++ {
++ register const lzo_byte *m_pos;
++
++ lzo_uint m_off;
++ lzo_uint m_len;
++ lzo_uint dindex;
++
++ DINDEX1 (dindex, ip);
++ GINDEX (m_pos, m_off, dict, dindex, in);
++ if (LZO_CHECK_MPOS_NON_DET
++ (m_pos, m_off, in, ip, M4_MAX_OFFSET))
++ goto literal;
++
++ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
++ goto try_match;
++ DINDEX2 (dindex, ip);
++ GINDEX (m_pos, m_off, dict, dindex, in);
++
++ if (LZO_CHECK_MPOS_NON_DET
++ (m_pos, m_off, in, ip, M4_MAX_OFFSET))
++ goto literal;
++ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
++ goto try_match;
++ goto literal;
++
++ try_match:
++ if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
++ {
++ }
++ else
++ {
++ if (m_pos[2] == ip[2])
++ {
++ goto match;
++ }
++ else
++ {
++ }
++ }
++
++ literal:
++ UPDATE_I (dict, 0, dindex, ip, in);
++ ++ip;
++ if (ip >= ip_end)
++ break;
++ continue;
++
++ match:
++ UPDATE_I (dict, 0, dindex, ip, in);
++
++ if (pd (ip, ii) > 0)
++ {
++ register lzo_uint t = pd (ip, ii);
++
++ if (t <= 3)
++ {
++ op[-2] |= LZO_BYTE (t);
++ }
++ else if (t <= 18)
++ *op++ = LZO_BYTE (t - 3);
++ else
++ {
++ register lzo_uint tt = t - 18;
++
++ *op++ = 0;
++ while (tt > 255)
++ {
++ tt -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (tt);;
++ }
++ do
++ *op++ = *ii++;
++ while (--t > 0);
++ }
++
++ ip += 3;
++ if (m_pos[3] != *ip++ || m_pos[4] != *ip++
++ || m_pos[5] != *ip++ || m_pos[6] != *ip++
++ || m_pos[7] != *ip++ || m_pos[8] != *ip++)
++ {
++ --ip;
++ m_len = ip - ii;
++
++ if (m_off <= M2_MAX_OFFSET)
++ {
++ m_off -= 1;
++
++ *op++ = LZO_BYTE (((m_len -
++ 1) << 5) | ((m_off & 7) <<
++ 2));
++ *op++ = LZO_BYTE (m_off >> 3);
++ }
++ else if (m_off <= M3_MAX_OFFSET)
++ {
++ m_off -= 1;
++ *op++ = LZO_BYTE (M3_MARKER | (m_len - 2));
++ goto m3_m4_offset;
++ }
++ else
++
++ {
++ m_off -= 0x4000;
++
++ *op++ = LZO_BYTE (M4_MARKER |
++ ((m_off & 0x4000) >> 11) |
++ (m_len - 2));
++ goto m3_m4_offset;
++ }
++ }
++ else
++ {
++ {
++ const lzo_byte *end = in_end;
++ const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
++ while (ip < end && *m == *ip)
++ m++, ip++;
++ m_len = (ip - ii);
++ }
++
++
++ if (m_off <= M3_MAX_OFFSET)
++ {
++ m_off -= 1;
++ if (m_len <= 33)
++ *op++ = LZO_BYTE (M3_MARKER |
++ (m_len - 2));
++ else
++ {
++ m_len -= 33;
++ *op++ = M3_MARKER | 0;
++ goto m3_m4_len;
++ }
++ }
++ else
++ {
++ m_off -= 0x4000;
++
++ if (m_len <= M4_MAX_LEN)
++ *op++ = LZO_BYTE (M4_MARKER |
++ ((m_off & 0x4000) >>
++ 11) | (m_len - 2));
++
++ else
++ {
++ m_len -= M4_MAX_LEN;
++ *op++ = LZO_BYTE (M4_MARKER |
++ ((m_off & 0x4000) >>
++ 11));
++ m3_m4_len:
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ *op++ = 0;
++ }
++
++ *op++ = LZO_BYTE (m_len);
++ }
++ }
++
++ m3_m4_offset:
++ *op++ = LZO_BYTE ((m_off & 63) << 2);
++ *op++ = LZO_BYTE (m_off >> 6);
++ }
++ ii = ip;
++ if (ip >= ip_end)
++ break;
++ }
++
++ *out_len = op - out;
++ return pd (in_end, ii);
++}
++
++static int
++lzo1x_1_compress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ lzo_byte *op = out;
++ lzo_uint t;
++
++ if (in_len <= M2_MAX_LEN + 5)
++ t = in_len;
++ else
++ {
++ t = _lzo1x_1_do_compress (in, in_len, op, out_len, wrkmem);
++ op += *out_len;
++ }
++
++ if (t > 0)
++ {
++ const lzo_byte *ii = in + in_len - t;
++
++ if (op == out && t <= 238)
++ *op++ = LZO_BYTE (17 + t);
++ else if (t <= 3)
++ op[-2] |= LZO_BYTE (t);
++ else if (t <= 18)
++ *op++ = LZO_BYTE (t - 3);
++ else
++ {
++ lzo_uint tt = t - 18;
++
++ *op++ = 0;
++ while (tt > 255)
++ {
++ tt -= 255;
++ *op++ = 0;
++ }
++
++ *op++ = LZO_BYTE (tt);
++ }
++ do
++ *op++ = *ii++;
++ while (--t > 0);
++ }
++
++ *op++ = M4_MARKER | 1;
++ *op++ = 0;
++ *op++ = 0;
++
++ *out_len = op - out;
++ return 0;
++}
++
++static int
++lzo1x_decompress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ register lzo_byte *op;
++ register const lzo_byte *ip;
++ register lzo_uint t;
++
++ register const lzo_byte *m_pos;
++
++ const lzo_byte *const ip_end = in + in_len;
++ lzo_byte *const op_end = out + *out_len;
++
++ *out_len = 0;
++
++ op = out;
++ ip = in;
++
++ if (*ip > 17)
++ {
++ t = *ip++ - 17;
++ if (t < 4)
++ goto match_next;
++ NEED_OP (t);
++ NEED_IP (t + 1);
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ goto first_literal_run;
++ }
++
++ while (TEST_IP && TEST_OP)
++ {
++ t = *ip++;
++ if (t >= 16)
++ goto match;
++ if (t == 0)
++ {
++ NEED_IP (1);
++ while (*ip == 0)
++ {
++ t += 255;
++ ip++;
++ NEED_IP (1);
++ }
++ t += 15 + *ip++;
++ }
++ NEED_OP (t + 3);
++ NEED_IP (t + 4);
++ if (PTR_ALIGNED2_4 (op, ip))
++ {
++ COPY4 (op, ip);
++
++ op += 4;
++ ip += 4;
++ if (--t > 0)
++ {
++ if (t >= 4)
++ {
++ do
++ {
++ COPY4 (op, ip);
++ op += 4;
++ ip += 4;
++ t -= 4;
++ }
++ while (t >= 4);
++ if (t > 0)
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ }
++ else
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ }
++ }
++ else
++ {
++ *op++ = *ip++;
++ *op++ = *ip++;
++ *op++ = *ip++;
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ }
++ first_literal_run:
++
++ t = *ip++;
++ if (t >= 16)
++ goto match;
++
++ m_pos = op - (1 + M2_MAX_OFFSET);
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (3);
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos;
++
++ goto match_done;
++
++ while (TEST_IP && TEST_OP)
++ {
++ match:
++ if (t >= 64)
++ {
++ m_pos = op - 1;
++ m_pos -= (t >> 2) & 7;
++ m_pos -= *ip++ << 3;
++ t = (t >> 5) - 1;
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (t + 3 - 1);
++ goto copy_match;
++
++ }
++ else if (t >= 32)
++ {
++ t &= 31;
++ if (t == 0)
++ {
++ NEED_IP (1);
++ while (*ip == 0)
++ {
++ t += 255;
++ ip++;
++ NEED_IP (1);
++ }
++ t += 31 + *ip++;
++ }
++
++ m_pos = op - 1;
++ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
++
++ ip += 2;
++ }
++ else if (t >= 16)
++ {
++ m_pos = op;
++ m_pos -= (t & 8) << 11;
++
++ t &= 7;
++ if (t == 0)
++ {
++ NEED_IP (1);
++ while (*ip == 0)
++ {
++ t += 255;
++ ip++;
++ NEED_IP (1);
++ }
++ t += 7 + *ip++;
++ }
++
++ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
++
++ ip += 2;
++ if (m_pos == op)
++ goto eof_found;
++ m_pos -= 0x4000;
++ }
++ else
++ {
++
++ m_pos = op - 1;
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (2);
++ *op++ = *m_pos++;
++ *op++ = *m_pos;
++
++ goto match_done;
++ }
++
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (t + 3 - 1);
++ if (t >= 2 * 4 - (3 - 1)
++ && PTR_ALIGNED2_4 (op, m_pos))
++ {
++ COPY4 (op, m_pos);
++ op += 4;
++ m_pos += 4;
++ t -= 4 - (3 - 1);
++ do
++ {
++ COPY4 (op, m_pos);
++ op += 4;
++ m_pos += 4;
++ t -= 4;
++ }
++ while (t >= 4);
++ if (t > 0)
++ do
++ *op++ = *m_pos++;
++ while (--t > 0);
++ }
++ else
++
++ {
++ copy_match:
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ do
++ *op++ = *m_pos++;
++ while (--t > 0);
++ }
++
++ match_done:
++ t = ip[-2] & 3;
++
++ if (t == 0)
++ break;
++
++ match_next:
++ NEED_OP (t);
++ NEED_IP (t + 1);
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ t = *ip++;
++ }
++ }
++ *out_len = op - out;
++ return LZO_E_EOF_NOT_FOUND;
++
++ eof_found:
++ *out_len = op - out;
++ return (ip == ip_end ? LZO_E_OK :
++ (ip <
++ ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
++
++ input_overrun:
++ *out_len = op - out;
++ return LZO_E_INPUT_OVERRUN;
++
++ output_overrun:
++ *out_len = op - out;
++ return LZO_E_OUTPUT_OVERRUN;
++
++ lookbehind_overrun:
++ *out_len = op - out;
++ return LZO_E_LOOKBEHIND_OVERRUN;
++}
++
++/* lzo1x_oo.ch */
++
++#define NO_LIT LZO_UINT_MAX
++
++static void
++copy2 (lzo_byte * ip, const lzo_byte * m_pos, lzo_ptrdiff_t off)
++{
++ ip[0] = m_pos[0];
++ if (off == 1)
++ ip[1] = m_pos[0];
++ else
++ ip[1] = m_pos[1];
++}
++
++static void
++copy3 (lzo_byte * ip, const lzo_byte * m_pos, lzo_ptrdiff_t off)
++{
++ ip[0] = m_pos[0];
++ if (off == 1)
++ {
++ ip[2] = ip[1] = m_pos[0];
++ }
++ else if (off == 2)
++ {
++ ip[1] = m_pos[1];
++ ip[2] = m_pos[0];
++ }
++ else
++ {
++ ip[1] = m_pos[1];
++ ip[2] = m_pos[2];
++ }
++}
++
++static int
++lzo1x_optimize (lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ register lzo_byte *op;
++ register lzo_byte *ip;
++ register lzo_uint t;
++ register lzo_byte *m_pos;
++ lzo_uint nl;
++ const lzo_byte *const ip_end = in + in_len;
++ const lzo_byte *const op_end = out + *out_len;
++ lzo_byte *litp = NULL;
++ lzo_uint lit = 0;
++ lzo_uint next_lit = NO_LIT;
++ long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
++
++ *out_len = 0;
++
++ op = out;
++ ip = in;
++
++ if (*ip > 17)
++ {
++ t = *ip++ - 17;
++ if (t < 4)
++ goto match_next;
++ goto first_literal_run;
++ }
++
++ while (TEST_IP && TEST_OP)
++ {
++ t = *ip++;
++ if (t >= 16)
++ goto match;
++ litp = ip - 1;
++ if (t == 0)
++ {
++ t = 15;
++ while (*ip == 0)
++ t += 255, ip++;
++ t += *ip++;
++ }
++ lit = t + 3;
++ copy_literal_run:
++ *op++ = *ip++;
++ *op++ = *ip++;
++ *op++ = *ip++;
++ first_literal_run:
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++
++ t = *ip++;
++
++ if (t >= 16)
++ goto match;
++ m_pos = op - 1 - 0x800;
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ lit = 0;
++ goto match_done;
++
++ while (TEST_IP && TEST_OP)
++ {
++ if (t < 16)
++ {
++ m_pos = op - 1;
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++
++ if (litp == NULL)
++ goto copy_m1;
++
++ nl = ip[-2] & 3;
++ if (nl == 0 && lit == 1 && ip[0] >= 16)
++ {
++ next_lit = nl;
++ lit += 2;
++ *litp = LZO_BYTE ((*litp & ~3) | lit);
++ copy2 (ip - 2, m_pos, op - m_pos);
++ o_m1_a++;
++ }
++ else if (nl == 0 && ip[0] < 16 && ip[0] != 0
++ && (lit + 2 + ip[0] < 16))
++ {
++ t = *ip++;
++ *litp &= ~3;
++ copy2 (ip - 3 + 1, m_pos, op - m_pos);
++ litp += 2;
++ if (lit > 0)
++ memmove (litp + 1, litp, lit);
++ lit += 2 + t + 3;
++ *litp = LZO_BYTE (lit - 3);
++
++ o_m1_b++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ goto copy_literal_run;
++ }
++ copy_m1:
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ }
++ else
++ {
++ match:
++ if (t >= 64)
++ {
++ m_pos = op - 1;
++ m_pos -= (t >> 2) & 7;
++ m_pos -= *ip++ << 3;
++ t = (t >> 5) - 1;
++ if (litp == NULL)
++ goto copy_m;
++
++ nl = ip[-2] & 3;
++ if (t == 1 && lit > 3 && nl == 0 &&
++ ip[0] < 16 && ip[0] != 0
++ && (lit + 3 + ip[0] < 16))
++ {
++ t = *ip++;
++ copy3 (ip - 1 - 2, m_pos,
++ op - m_pos);
++ lit += 3 + t + 3;
++ *litp = LZO_BYTE (lit - 3);
++ o_m2++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ goto copy_literal_run;
++ }
++ }
++ else
++ {
++ if (t >= 32)
++ {
++ t &= 31;
++ if (t == 0)
++ {
++ t = 31;
++ while (*ip == 0)
++ t += 255,
++ ip++;
++ t += *ip++;
++ }
++ m_pos = op - 1;
++ m_pos -= *ip++ >> 2;
++ m_pos -= *ip++ << 6;
++ }
++ else
++ {
++ m_pos = op;
++ m_pos -= (t & 8) << 11;
++ t &= 7;
++ if (t == 0)
++ {
++ t = 7;
++ while (*ip == 0)
++ t += 255,
++ ip++;
++ t += *ip++;
++ }
++ m_pos -= *ip++ >> 2;
++ m_pos -= *ip++ << 6;
++ if (m_pos == op)
++ goto eof_found;
++ m_pos -= 0x4000;
++ }
++ if (litp == NULL)
++ goto copy_m;
++
++ nl = ip[-2] & 3;
++ if (t == 1 && lit == 0 && nl == 0
++ && ip[0] >= 16)
++ {
++ next_lit = nl;
++ lit += 3;
++ *litp = LZO_BYTE ((*litp & ~3)
++ | lit);
++ copy3 (ip - 3, m_pos,
++ op - m_pos);
++ o_m3_a++;
++ }
++ else if (t == 1 && lit <= 3 && nl == 0
++ && ip[0] < 16 && ip[0] != 0
++ && (lit + 3 + ip[0] < 16))
++ {
++ t = *ip++;
++ *litp &= ~3;
++ copy3 (ip - 4 + 1, m_pos,
++ op - m_pos);
++ litp += 2;
++ if (lit > 0)
++ memmove (litp + 1,
++ litp, lit);
++ lit += 3 + t + 3;
++ *litp = LZO_BYTE (lit - 3);
++
++ o_m3_b++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ goto copy_literal_run;
++ }
++ }
++ copy_m:
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ do
++ *op++ = *m_pos++;
++ while (--t > 0);
++ }
++
++ match_done:
++ if (next_lit == NO_LIT)
++ {
++ t = ip[-2] & 3;
++ lit = t;
++ litp = ip - 2;
++ }
++ else
++ t = next_lit;
++ next_lit = NO_LIT;
++ if (t == 0)
++ break;
++ match_next:
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ t = *ip++;
++ }
++ }
++
++ *out_len = op - out;
++ return LZO_E_EOF_NOT_FOUND;
++
++ eof_found:
++ *out_len = op - out;
++ return (ip == ip_end ? LZO_E_OK :
++ (ip <
++ ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++#define BLOCKSIZE 4096
++#define OUTBLOCKSIZE (BLOCKSIZE + BLOCKSIZE / 64 + 16 + 3)
++
++#define JFFS2_BBC_LZO_BLOCK_SIGN {0x3f, 0x47, 0x5a, 0x18}
++
++static int
++jffs2_bbc_lzo_compressor_init (void);
++
++static void
++jffs2_bbc_lzo_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzo_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzo_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzo_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzo_proc_info (void);
++
++static int
++jffs2_bbc_lzo_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzo = {
++ "lzo",
++ 0,
++ JFFS2_BBC_LZO_BLOCK_SIGN,
++ jffs2_bbc_lzo_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzo_compressor_deinit,
++ jffs2_bbc_lzo_compress,
++ jffs2_bbc_lzo_estimate,
++ jffs2_bbc_lzo_decompress,
++ jffs2_bbc_lzo_proc_info,
++ jffs2_bbc_lzo_proc_command
++};
++
++static int
++no_lzo1x_optimize (lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len, lzo_voidp wrkmem)
++{
++ return 0;
++}
++
++#ifdef __KERNEL__
++static lzo_compress_t lzo1x_compressor = lzo1x_1_compress;
++static lzo_optimize_t lzo1x_optimizer = no_lzo1x_optimize;
++static int lzo1x_compressor_type = 1;
++static int lzo1x_optimize_type = 0;
++static unsigned long lzo1x_compressor_memsize = LZO1X_1_MEM_COMPRESS;
++#else
++static lzo_compress_t lzo1x_compressor = lzo1x_999_compress;
++static lzo_optimize_t lzo1x_optimizer = lzo1x_optimize;
++static int lzo1x_compressor_type = 999;
++static int lzo1x_optimize_type = 1;
++static unsigned long lzo1x_compressor_memsize = LZO1X_999_MEM_COMPRESS;
++#endif
++
++static lzo_bytep wrkmem = NULL; /* temporary buffer for compression, used by lzo */
++static lzo_bytep cmprssmem = NULL; /* temporary buffer for compression, used by interface */
++
++static int
++jffs2_bbc_lzo_compressor_init (void)
++{
++ wrkmem = (lzo_bytep) jffs2_bbc_malloc (lzo1x_compressor_memsize);
++ cmprssmem = (lzo_bytep) jffs2_bbc_malloc (OUTBLOCKSIZE);
++ return !(wrkmem && cmprssmem);
++}
++
++static void
++jffs2_bbc_lzo_compressor_deinit (void)
++{
++ jffs2_bbc_free (wrkmem);
++ jffs2_bbc_free (cmprssmem);
++}
++
++static int
++jffs2_bbc_lzo_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ lzo_uint csize = OUTBLOCKSIZE;
++ lzo_uint isize = *sourcelen;
++ int retval;
++ if ((retval =
++ lzo1x_compressor (input, *sourcelen, cmprssmem, &csize,
++ wrkmem)) != LZO_E_OK)
++ {
++ *sourcelen = *dstlen = 0;
++ return retval;
++ }
++ else
++ {
++ retval = lzo1x_optimizer (cmprssmem, csize, input, &isize,
++ NULL);
++ csize += 2;
++ if (csize <= *dstlen) {
++ *dstlen = csize;
++ *(output++) = jffs2_bbc_lzo.block_sign[0];
++ *(output++) = jffs2_bbc_lzo.block_sign[1];
++ memcpy (output, cmprssmem, csize - 2);
++ return retval;
++ } else {
++ *sourcelen = *dstlen = 0;
++ return -1;
++ }
++ }
++}
++
++static int
++jffs2_bbc_lzo_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 55 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME / 2;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 8 / 10; /* LZO1X-1 is much-much faster,
++ but LZO1X-999 is slow. The default mode for inside kernel compression is LZO1X-1
++ This should be *0.4 really */
++ return 0;
++}
++
++static int
++jffs2_bbc_lzo_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ lzo_uint outlen = dstlen;
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzo.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzo.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return lzo1x_decompress (input, sourcelen - 2, output, &outlen, NULL);
++ }
++}
++
++static char *
++jffs2_bbc_lzo_proc_info (void)
++{
++ if (lzo1x_compressor_type == 1)
++ {
++ if (lzo1x_optimize_type == 1)
++ {
++ return "LZO1X-1 compression with optimization";
++ }
++ else
++ {
++ return "LZO1X-1 compression without optimization";
++ }
++ }
++ else if (lzo1x_compressor_type == 999)
++ {
++ if (lzo1x_optimize_type == 1)
++ {
++ return "LZO1X-999 compression with optimization";
++ }
++ else
++ {
++ return "LZO1X-999 compression without optimization";
++ }
++ }
++ else
++ {
++ return "Unknown configuration!";
++ }
++}
++
++static int
++jffs2_bbc_lzo_proc_command (char *command)
++{
++ switch (*command)
++ {
++ case 'o':
++ /* switch optimization off */
++ lzo1x_optimizer = no_lzo1x_optimize;
++ lzo1x_optimize_type = 0;
++ jffs2_bbc_print1 ("Compression optimization switched off.\n");
++ return 0;
++ case 'O':
++ /* switch optimization on */
++ lzo1x_optimizer = lzo1x_optimize;
++ lzo1x_optimize_type = 1;
++ jffs2_bbc_print1 ("Compression optimization switched on.\n");
++ return 0;
++ case '1':
++ /* switch compression to LZO1X-1 */
++ jffs2_bbc_free (wrkmem);
++ lzo1x_compressor_type = 1;
++ lzo1x_compressor = lzo1x_1_compress;
++ lzo1x_compressor_memsize = LZO1X_1_MEM_COMPRESS;
++ wrkmem = (lzo_bytep)
++ jffs2_bbc_malloc (lzo1x_compressor_memsize);
++ jffs2_bbc_print1 ("Compression type switched to LZO1X-1.\n");
++ return 0;
++ case '9':
++ /* switch compression to LZO1X-999 */
++ jffs2_bbc_free (wrkmem);
++ lzo1x_compressor_type = 999;
++ lzo1x_compressor = lzo1x_999_compress;
++ lzo1x_compressor_memsize = LZO1X_999_MEM_COMPRESS;
++ wrkmem = (lzo_bytep)
++ jffs2_bbc_malloc (lzo1x_compressor_memsize);
++ jffs2_bbc_print1
++ ("Compression type switched to LZO1X-999.\n");
++ return 0;
++ default:
++ jffs2_bbc_print1 ("Unknown command!\n");
++ return 0;
++ }
++}
++
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzo_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzo) == 0)
++ {
++ return &jffs2_bbc_lzo;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzo_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzo);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzss_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzss_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzss_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzss_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,385 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzss_comp.c -- Lempel-Ziv-Storer-Szymanski compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the LZSS source included in LDS (lossless datacompression sources)
++ Block-compression modifications by Patrik Kluba
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++Original copyright follows:
++
++**************************************************************
++ LZSS.C -- A Data Compression Program
++**************************************************************
++ 4/6/1989 Haruhiko Okumura
++ Use, distribute, and modify this program freely.
++ Please send me your improved versions.
++ PC-VAN SCIENCE
++ NIFTY-Serve PAF01022
++ CompuServe 74050,1022
++**************************************************************
++
++*/
++
++/*
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++
++*/
++
++/* lzss.c */
++
++#define N 4096 /* size of ring buffer */
++#define F 18 /* upper limit for match_length */
++#define THRESHOLD 2 /* encode string into position and length
++ if match_length is greater than this */
++#define NIL N /* index for root of binary search trees */
++
++static unsigned char
++ text_buf[N + F - 1]; /* ring buffer of size N,
++ with extra F-1 bytes to facilitate string comparison */
++static unsigned long match_position, match_length; /* of longest match. These are
++ set by the InsertNode() procedure. */
++static unsigned long lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
++ parents -- These constitute binary search trees. */
++
++static void InitTree(void) /* initialize trees */
++{
++ unsigned long i;
++
++ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
++ left children of node i. These nodes need not be initialized.
++ Also, dad[i] is the parent of node i. These are initialized to
++ NIL (= N), which stands for 'not used.'
++ For i = 0 to 255, rson[N + i + 1] is the root of the tree
++ for strings that begin with character i. These are initialized
++ to NIL. Note there are 256 trees. */
++
++ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL;
++ for (i = 0; i < N; i++) dad[i] = NIL;
++}
++
++static void InsertNode(unsigned long r)
++ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
++ trees (text_buf[r]'th tree) and returns the longest-match position
++ and length via the global variables match_position and match_length.
++ If match_length = F, then removes the old node in favor of the new
++ one, because the old one will be deleted sooner.
++ Note r plays double role, as tree node and position in buffer. */
++{
++ unsigned long i, p;
++ unsigned char *key;
++ signed long cmp;
++
++ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
++ rson[r] = lson[r] = NIL; match_length = 0;
++ for ( ; ; ) {
++ if (cmp >= 0) {
++ if (rson[p] != NIL) p = rson[p];
++ else { rson[p] = r; dad[r] = p; return; }
++ } else {
++ if (lson[p] != NIL) p = lson[p];
++ else { lson[p] = r; dad[r] = p; return; }
++ }
++ for (i = 1; i < F; i++)
++ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
++ if (i > match_length) {
++ match_position = p;
++ if ((match_length = i) >= F) break;
++ }
++ }
++ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
++ dad[lson[p]] = r; dad[rson[p]] = r;
++ if (rson[dad[p]] == p) rson[dad[p]] = r;
++ else lson[dad[p]] = r;
++ dad[p] = NIL; /* remove p */
++}
++
++static void DeleteNode(unsigned long p) /* deletes node p from tree */
++{
++ unsigned long q;
++
++ if (dad[p] == NIL) return; /* not in tree */
++ if (rson[p] == NIL) q = lson[p];
++ else if (lson[p] == NIL) q = rson[p];
++ else {
++ q = lson[p];
++ if (rson[q] != NIL) {
++ do { q = rson[q]; } while (rson[q] != NIL);
++ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
++ lson[q] = lson[p]; dad[lson[p]] = q;
++ }
++ rson[q] = rson[p]; dad[rson[p]] = q;
++ }
++ dad[q] = dad[p];
++ if (rson[dad[p]] == p) rson[dad[p]] = q; else lson[dad[p]] = q;
++ dad[p] = NIL;
++}
++
++/* modified for block compression */
++/* on return, srclen will contain the number of successfully compressed bytes
++ and dstlen will contain completed compressed bytes */
++
++static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
++ unsigned long *dstlen)
++{
++ unsigned long i, len, r, c, s, last_match_length, code_buf_ptr;
++ unsigned char code_buf[17], mask;
++ unsigned char *ip, *op;
++ unsigned long written = 0;
++ unsigned long read = 0;
++ unsigned char *srcend = srcbuf + *srclen;
++ unsigned char *dstend = dstbuf + *dstlen;
++ ip = srcbuf;
++ op = dstbuf;
++ InitTree(); /* initialize trees */
++ code_buf[0] = 0; /* code_buf[1..16] saves eight units of code, and
++ code_buf[0] works as eight flags, "1" representing that the unit
++ is an unencoded letter (1 byte), "0" a position-and-length pair
++ (2 bytes). Thus, eight units require at most 16 bytes of code. */
++ code_buf_ptr = mask = 1;
++ s = 0; r = N - F;
++ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
++ any character that will appear often. */
++ for (len = 0; (len < F) && (ip < srcend); len++)
++ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
++ the buffer */
++ read = len;
++ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
++ each of which begins with one or more 'space' characters. Note
++ the order in which these strings are inserted. This way,
++ degenerate trees will be less likely to occur. */
++ InsertNode(r); /* Finally, insert the whole string just read. The
++ global variables match_length and match_position are set. */
++ do {
++ if (match_length > len) match_length = len; /* match_length
++ may be spuriously long near the end of text. */
++ if (match_length <= THRESHOLD) {
++ match_length = 1; /* Not long enough match. Send one byte. */
++ code_buf[0] |= mask; /* 'send one byte' flag */
++ code_buf[code_buf_ptr++] = text_buf[r]; /* Send uncoded. */
++ } else {
++ code_buf[code_buf_ptr++] = match_position;
++ code_buf[code_buf_ptr++] = (((match_position >> 4) & 0xf0)
++ | (match_length - (THRESHOLD + 1))); /* Send position and
++ length pair. Note match_length > THRESHOLD. */
++ }
++ if ((mask <<= 1) == 0) { /* Shift mask left one bit. */
++ if ((op + code_buf_ptr) > dstend) {
++ *dstlen = written; /* written contains bytes of complete compressed
++ code */
++ return -1;
++ };
++ for (i = 0; i < code_buf_ptr; *(op++) = code_buf[i++]); /* Send at most 8 units of */
++ /* code together */
++ written += code_buf_ptr;
++ *srclen = read; /* this many bytes have been successfully compressed */
++ code_buf[0] = 0; code_buf_ptr = mask = 1;
++ }
++ last_match_length = match_length;
++ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
++ c = *(ip++);
++ DeleteNode(s); /* Delete old strings and */
++ text_buf[s] = c; /* read new bytes */
++ if (s < F - 1) text_buf[s + N] = c; /* If the position is
++ near the end of buffer, extend the buffer to make
++ string comparison easier. */
++ s = (s + 1) & (N - 1); r = (r + 1) & (N - 1);
++ /* Since this is a ring buffer, increment the position
++ modulo N. */
++ InsertNode(r); /* Register the string in text_buf[r..r+F-1] */
++ }
++ read += i;
++ while (i++ < last_match_length) { /* After the end of text, */
++ DeleteNode(s); /* no need to read, but */
++ s = (s + 1) & (N - 1); r = (r + 1) & (N - 1);
++ if (--len) InsertNode(r); /* buffer may not be empty. */
++ }
++ } while (len > 0); /* until length of string to be processed is zero */
++ if (code_buf_ptr > 1) { /* Send remaining code. */
++ if ((op + code_buf_ptr) > dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ for (i = 0; i < code_buf_ptr; *(op++) = code_buf[i++]);
++ written += code_buf_ptr;
++ *srclen = read;
++ }
++ *dstlen = written;
++ return 0;
++}
++
++static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
++ unsigned long dstlen) /* Just the reverse of Encode(). */
++{
++ unsigned long i, r, c, j, k, flags;
++ unsigned char *ip, *op;
++ unsigned long written;
++ unsigned long read;
++ unsigned char *srcend = srcbuf + srclen;
++ unsigned char *dstend = dstbuf + dstlen;
++ read = written = 0;
++ ip = srcbuf;
++ op = dstbuf;
++ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
++ r = N - F; flags = 0;
++ for ( ; ; ) {
++ if (((flags >>= 1) & 256) == 0) {
++ if (ip >= srcend) return 0;
++ c = *(ip++);
++ flags = c | 0xff00; /* uses higher byte cleverly */
++ } /* to count eight */
++ if (flags & 1) {
++ if (ip >= srcend) return 0;
++ c = *(ip++);
++ if (op >= dstend) return -1;
++ *(op++) = text_buf[r++] = c; r &= (N - 1);
++ } else {
++ if ((ip + 2) > srcend) return 0;
++ i = *(ip++);
++ j = *(ip++);
++ i |= ((j & 0xf0) << 4); j = (j & 0x0f) + THRESHOLD;
++ if ((op + j + 1) > dstend) return -1;
++ for (k = 0; k <= j; k++) {
++ c = text_buf[(i + k) & (N - 1)];
++ *(op++) = text_buf[r++] = c; r &= (N - 1);
++ }
++ }
++ }
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++
++#define JFFS2_BBC_LZSS_BLOCK_SIGN {0x27, 0x6f, 0x12, 0xc4}
++
++static int
++jffs2_bbc_lzss_compressor_init (void);
++
++static void
++jffs2_bbc_lzss_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzss_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzss_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzss_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzss_proc_info (void);
++
++static int
++jffs2_bbc_lzss_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzss = {
++ "lzss",
++ 0,
++ JFFS2_BBC_LZSS_BLOCK_SIGN,
++ jffs2_bbc_lzss_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzss_compressor_deinit,
++ jffs2_bbc_lzss_compress,
++ jffs2_bbc_lzss_estimate,
++ jffs2_bbc_lzss_decompress,
++ jffs2_bbc_lzss_proc_info,
++ jffs2_bbc_lzss_proc_command
++};
++
++static int
++jffs2_bbc_lzss_compressor_init (void)
++{
++ return 0;
++}
++
++static void
++jffs2_bbc_lzss_compressor_deinit (void)
++{
++}
++
++static int
++jffs2_bbc_lzss_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ int retval;
++ unsigned long dst = *dstlen;
++ *(output++) = jffs2_bbc_lzss.block_sign[0];
++ *(output++) = jffs2_bbc_lzss.block_sign[1];
++ dst -= 2;
++ retval = Encode(input, output, sourcelen, &dst);
++ dst += 2;
++ *dstlen = dst;
++ return retval;
++}
++
++static int
++jffs2_bbc_lzss_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 60 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 12 / 10;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 3;
++ return 0;
++}
++
++static int
++jffs2_bbc_lzss_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzss.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzss.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return Decode(input, output, sourcelen - 2, dstlen);
++ }
++}
++
++static char *
++jffs2_bbc_lzss_proc_info (void)
++{
++ return "Lempel-Ziv-Storer-Szymanski compression module";
++}
++
++static int
++jffs2_bbc_lzss_proc_command (char *command)
++{
++ return 0;
++}
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzss_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzss) == 0)
++ {
++ return &jffs2_bbc_lzss;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzss_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzss);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/linux-2.4.25.hpatch linux-mips/fs/jffs2/linux-2.4.25.hpatch
+--- linux-mips-cvs/fs/jffs2/linux-2.4.25.hpatch 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/linux-2.4.25.hpatch 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,97 @@
++FMakefile
++=BBC insertion
++-COMPR_OBJS
++iMakefile.bbc.inc
+++
++I
++?JFFS2_OBJS
+++ $(JFFS2_BBC_KERNEL_OBJS) \
++
++F../Config.in
++=BBC insertion
++-tristate 'Compressed ROM file system support' CONFIG_CRAMFS
++iConfig.in.bbc.inc
+++
++I
++F../../Documentation/Configure.help
++=BBC insertion
++-JFFS stats available
++iConfigure.help.bbc.inc
+++
++I
++Fcompr_zlib.c
++=(de)compress->(de)compress2
++-int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+++int jffs2_zlib_compress2(unsigned char *data_in, unsigned char *cpage_out,
++-void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+++void jffs2_zlib_decompress2(unsigned char *data_in, unsigned char *cpage_out,
++?inflateEnd(&strm);
++?}
+++
+++extern int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 * sourcelen, __u32 * dstlen);
+++extern void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
+++
+++int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+++ __u32 *sourcelen, __u32 *dstlen)
+++{
+++ return jffs2_zlib_compress(data_in,cpage_out,sourcelen,dstlen);
+++}
+++
+++void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+++ __u32 srclen, __u32 destlen)
+++{
+++ jffs2_zlib_decompress(data_in,cpage_out,srclen,destlen);
+++}
+++
++
++Ffile.c
++=set_act_sb before write
++-#include
+++#include "jffs2_bbc_framework.h" /**BBC**/
++I
++?int jffs2_commit_write
++-jffs2_compress(
+++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
++I
++
++Fgc.c
++=set_act_sb before write
++-#include
+++#include "jffs2_bbc_framework.h" /**BBC**/
++I
++?int jffs2_garbage_collect_dnode(
++-jffs2_compress(
+++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
++I
++
++Fread.c
++=set_act_sb before read
++-#include
+++#include "jffs2_bbc_framework.h" /**BBC**/
++I
++?int jffs2_read_dnode(
++-jffs2_decompress(
+++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
++I
++
++Fsuper.c
++=init, load_model
++-#include
+++#include "jffs2_bbc_fs.h" /**BBC**/
++I
++?struct super_block *jffs2_read_super(
++-return sb;
+++ jffs2_bbc_load_model(sb); /**BBC**/
++I
++?void jffs2_put_super
++?c = JFFS2_SB_INFO
+++ jffs2_bbc_unload_model(sb); /**BBC**/
++?init_jffs2_fs(void)
++?int ret;
+++
+++ jffs2_bbc_proc_init(); /**BBC**/
+++
++?exit_jffs2_fs(void)
++?{
+++ jffs2_bbc_proc_deinit(); /**BBC**/
+++
+diff -Nur linux-mips-cvs/fs/jffs2/read.c linux-mips/fs/jffs2/read.c
+--- linux-mips-cvs/fs/jffs2/read.c 2003-11-17 02:07:44.000000000 +0100
++++ linux-mips/fs/jffs2/read.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_framework.h" /**BBC**/
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/jffs2.h>
+@@ -140,6 +141,7 @@
+ D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
+ if (ri->compr != JFFS2_COMPR_NONE) {
+ D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf));
++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
+ ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize);
+ if (ret) {
+ printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
+diff -Nur linux-mips-cvs/fs/jffs2/super.c linux-mips/fs/jffs2/super.c
+--- linux-mips-cvs/fs/jffs2/super.c 2003-01-11 18:53:17.000000000 +0100
++++ linux-mips/fs/jffs2/super.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_fs.h" /**BBC**/
+ #include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -272,6 +273,7 @@
+ sb->s_magic = JFFS2_SUPER_MAGIC;
+ if (!(sb->s_flags & MS_RDONLY))
+ jffs2_start_garbage_collect_thread(c);
++ jffs2_bbc_load_model(sb); /**BBC**/
+ return sb;
+
+ out_root_i:
+@@ -288,6 +290,7 @@
+ void jffs2_put_super (struct super_block *sb)
+ {
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
++ jffs2_bbc_unload_model(sb); /**BBC**/
+
+ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
+
+@@ -344,6 +347,9 @@
+ {
+ int ret;
+
++ jffs2_bbc_proc_init(); /**BBC**/
++
++
+ printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n");
+
+ #ifdef JFFS2_OUT_OF_KERNEL
+@@ -388,6 +394,8 @@
+
+ static void __exit exit_jffs2_fs(void)
+ {
++ jffs2_bbc_proc_deinit(); /**BBC**/
++
+ jffs2_destroy_slab_caches();
+ jffs2_zlib_exit();
+ unregister_filesystem(&jffs2_fs_type);