aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorMichael Brown <mcb30@etherboot.org>2005-03-08 18:53:11 +0000
committerMichael Brown <mcb30@etherboot.org>2005-03-08 18:53:11 +0000
commit3d6123e69ab879c72ff489afc5bf93ef0b7a94ce (patch)
tree9f3277569153a550fa8d81ebd61bd88f266eb8da /src/util
downloadipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.zip
ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.gz
ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.bz2
Initial revision
Diffstat (limited to 'src/util')
-rwxr-xr-xsrc/util/catrom.pl48
-rwxr-xr-xsrc/util/disrom.pl114
-rwxr-xr-xsrc/util/geniso56
-rwxr-xr-xsrc/util/genliso85
-rwxr-xr-xsrc/util/get-pci-ids135
-rw-r--r--src/util/lzhuf.c764
-rwxr-xr-xsrc/util/makelilo.pl40
-rwxr-xr-xsrc/util/makerom.pl226
-rwxr-xr-xsrc/util/modrom.pl226
-rw-r--r--src/util/nrv2b.c1501
-rwxr-xr-xsrc/util/swapdevids.pl49
-rwxr-xr-xsrc/util/zfilelen.pl8
12 files changed, 3252 insertions, 0 deletions
diff --git a/src/util/catrom.pl b/src/util/catrom.pl
new file mode 100755
index 0000000..fe37e6b
--- /dev/null
+++ b/src/util/catrom.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+
+use bytes;
+
+use constant MAX_ROM_LEN => 1024*1024;
+use constant PCI_OFF => 0x18;
+use constant INDICATOR_OFF => 0x15;
+
+my $total_len = 0;
+my @romfiles = @ARGV
+ or die "Usage: $0 rom-file-1 rom-file-2 ... > multi-rom-file\n";
+
+while ( my $romfile = shift @romfiles ) {
+ my $last = @romfiles ? 0 : 1;
+
+ open ROM, "<$romfile" or die "Could not open $romfile: $!\n";
+ my $len = read ( ROM, my $romdata, MAX_ROM_LEN )
+ or die "Could not read $romfile: $!\n";
+ close ROM;
+
+ die "$romfile is not a ROM file\n"
+ unless substr ( $romdata, 0, 2 ) eq "\x55\xAA";
+
+ ( my $checklen ) = unpack ( 'C', substr ( $romdata, 2, 1 ) );
+ $checklen *= 512;
+ die "$romfile has incorrect length field $checklen (should be $len)\n"
+ unless $len == $checklen;
+
+ ( my $pci ) = unpack ( 'v', substr ( $romdata, PCI_OFF, 2 ) );
+ die "Invalid PCI offset field in $romfile\n"
+ if $pci >= $len;
+ die "No PCIR signature in $romfile\n"
+ unless substr ( $romdata, $pci, 4 ) eq "PCIR";
+
+ ( my $indicator ) =
+ unpack ( 'C', substr ( $romdata, $pci + INDICATOR_OFF, 1 ) );
+ my $msg = sprintf ( "$romfile: indicator was %02x, ", $indicator );
+ $indicator &= ! ( 1 << 7 );
+ $indicator |= ( $last << 7 );
+ $msg .= sprintf ( "now %02x\n", $indicator );
+ substr ( $romdata, $pci + INDICATOR_OFF, 1 ) = pack ( 'C', $indicator );
+ warn $msg;
+
+ print $romdata;
+}
diff --git a/src/util/disrom.pl b/src/util/disrom.pl
new file mode 100755
index 0000000..6412869
--- /dev/null
+++ b/src/util/disrom.pl
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+#
+# Program to display key information about a boot ROM
+# including PCI and PnP structures
+#
+# GPL, Ken Yap 2001
+#
+
+use bytes;
+
+sub getid ($)
+{
+ my ($offset) = @_;
+
+ return '' if ($offset == 0 or $offset > $len);
+ my ($string) = unpack('Z32', substr($data, $offset, 32));
+ return ($string);
+}
+
+sub dispci
+{
+ my ($pcidata) = substr($data, $pci, 0x18);
+ my ($dummy, $vendorid, $deviceid, $vpd, $pcilen, $pcirev,
+ $class1, $class2, $class3, $imglen, $coderev, $codetype,
+ $indicator) = unpack('a4v4C4v2C2', $pcidata);
+ $imglen *= 512;
+ my $vendorstr = sprintf('%#04x', $vendorid);
+ my $devicestr = sprintf('%#04x', $deviceid);
+ my $coderevstr = sprintf('%#04x', $coderev);
+ print <<EOF;
+PCI structure:
+
+Vital product data: $vpd
+Vendor ID: $vendorstr
+Device ID: $devicestr
+Device base type: $class1
+Device sub type: $class2
+Device interface type: $class3
+Image length: $imglen
+Code revision: $coderevstr
+Code type: $codetype
+Indicator: $indicator
+
+EOF
+}
+
+sub dispnp
+{
+ my ($pnpdata) = substr($data, $pnp, 0x20);
+ my ($dummy1, $pnprev, $pnplen, $nextpnp, $dummy2,
+ $pnpcsum, $deviceid, $mfrid, $productid,
+ $class1, $class2, $class3, $indicator,
+ $bcv, $dv, $bev, $dummy, $sri) = unpack('a4C2vC2a4v2C4v5', $pnpdata);
+ print <<EOF;
+PnP structure:
+
+EOF
+ print 'Vendor: ', &getid($mfrid), "\n";
+ print 'Device: ', &getid($productid), "\n";
+ my $indicatorstr = sprintf('%#02x', $indicator);
+ my $bcvstr = sprintf('%#04x', $bcv);
+ my $dvstr = sprintf('%#04x', $dv);
+ my $bevstr = sprintf('%#04x', $bev);
+ my $sristr = sprintf('%#04x', $sri);
+ my $checksum = unpack('%8C*', $pnpdata);
+ print <<EOF;
+Device base type: $class1
+Device sub type: $class2
+Device interface type: $class3
+Device indicator: $indicatorstr
+Boot connection vector: $bcvstr
+Disconnect vector: $dvstr
+Bootstrap entry vector: $bevstr
+Static resource information vector: $sristr
+Checksum: $checksum
+
+EOF
+}
+
+sub pcipnp
+{
+ ($pci, $pnp) = unpack('v2', substr($data, 0x18, 4));
+ if ($pci >= $len or $pnp >= $len) {
+ print "$file: Not a PCI PnP ROM image\n";
+ return;
+ }
+ if (substr($data, $pci, 4) ne 'PCIR' or substr($data, $pnp, 4) ne '$PnP') {
+ print "$file: No PCI and PNP structures, not a PCI PNP ROM image\n";
+ return;
+ }
+ &dispci();
+ &dispnp();
+}
+
+$file = $#ARGV >= 0 ? $ARGV[0] : '-';
+open(F, "$file") or die "$file: $!\n";
+binmode(F);
+# Handle up to 64kB ROM images
+$len = read(F, $data, 64*1024);
+close(F);
+defined($len) or die "$file: $!\n";
+substr($data, 0, 2) eq "\x55\xAA" or die "$file: Not a boot ROM image\n";
+my ($codelen) = unpack('C', substr($data, 2, 1));
+$codelen *= 512;
+if ($codelen < $len) {
+ my $pad = $len - $codelen;
+ print "Image is $codelen bytes and has $pad bytes of padding following\n";
+ $data = substr($data, 0, $codelen);
+} elsif ($codelen > $len) {
+ print "Image should be $codelen bytes but is truncated to $len bytes\n";}
+&pcipnp();
+($csum) = unpack('%8C*', $data);
+print "ROM checksum: $csum \n";
+exit(0);
diff --git a/src/util/geniso b/src/util/geniso
new file mode 100755
index 0000000..5bd5c7b
--- /dev/null
+++ b/src/util/geniso
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Generate a isolinux ISO boot image
+#
+# geniso foo.iso foo.zlilo
+#
+# the ISO image is the first argument so that a list of .zlilo images
+# to include can be specified
+#
+case $# in
+0|1)
+ echo Usage: $0 foo.iso foo.zlilo ...
+ exit 1
+ ;;
+esac
+# This should be the default location of the isolinux.bin file
+isolinux_bin=${ISOLINUX_BIN:-util/isolinux.bin}
+if [ ! -r $isolinux_bin ]
+then
+ echo $0: $isolinux_bin not found, please install, or set ISOLINUX_BIN in arch/i386/config correctly
+ exit 1
+fi
+out=$1
+shift
+dir=bin/iso.dir
+mkdir -p $dir
+cfg=$dir/isolinux.cfg
+cp -p $isolinux_bin $dir
+cat > $cfg <<EOF
+# These default options can be changed in the geniso script
+SAY Etherboot ISO boot image generated by geniso
+TIMEOUT 30
+EOF
+first=
+for f
+do
+ if [ ! -r $f ]
+ then
+ echo $f does not exist, skipping 1>&2
+ continue
+ fi
+ b=$(basename $f)
+ g=${b%.zlilo}
+ g=${g//[^a-z0-9]}.zli
+ case "$first" in
+ "")
+ echo DEFAULT $g
+ ;;
+ esac
+ first=$g
+ echo LABEL $b
+ echo "" KERNEL $g
+ cp -p $f $dir/$g
+done >> $cfg
+mkisofs -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
+rm -fr $dir
diff --git a/src/util/genliso b/src/util/genliso
new file mode 100755
index 0000000..b8d9a11
--- /dev/null
+++ b/src/util/genliso
@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# Generate a legacy floppy emulation ISO boot image
+#
+# genliso foo.liso foo.zlilo
+#
+# the ISO image is the first argument so that a list of .zlilo images
+# to include can be specified
+#
+case $0 in
+*genliso)
+ ;;
+*genfdimg)
+ genfdimg=1
+ ;;
+esac
+case $# in
+0|1)
+ echo Usage: $0 foo.liso foo.zlilo ...
+ exit 1
+ ;;
+esac
+case "`mtools -V`" in
+Mtools\ version\ 3.9.9*|Mtools\ version\ 4.*)
+ ;;
+*)
+ echo Mtools version 3.9.9 or later is required
+ exit 1
+ ;;
+esac
+out=$1
+shift
+dir=bin/liso.dir
+mkdir -p $dir
+case "$genfdimg" in
+1)
+ img=$out
+ ;;
+*)
+ img=$dir/boot.img
+ ;;
+esac
+mformat -f 1440 -C -i $img ::
+cfg=bin/syslinux.cfg
+cat > $cfg <<EOF
+# These default options can be changed in the genliso script
+SAY Etherboot ISO boot image generated by genliso
+TIMEOUT 30
+EOF
+first=
+for f
+do
+ if [ ! -r $f ]
+ then
+ echo $f does not exist, skipping 1>&2
+ continue
+ fi
+ # shorten name for 8.3 filesystem
+ b=$(basename $f)
+ g=${b%.zlilo}
+ g=${g//[^a-z0-9]}
+ g=${g:0:8}.zli
+ case "$first" in
+ "")
+ echo DEFAULT $g
+ ;;
+ esac
+ first=$g
+ echo LABEL $b
+ echo "" KERNEL $g
+ mcopy -m -i $img $f ::$g
+done >> $cfg
+mcopy -i $img $cfg ::syslinux.cfg
+if ! syslinux $img
+then
+ exit 1
+fi
+case "$genfdimg" in
+1)
+ ;;
+*)
+ mkisofs -o $out -c boot.cat -b boot.img $dir
+ ;;
+esac
+rm -fr $dir
diff --git a/src/util/get-pci-ids b/src/util/get-pci-ids
new file mode 100755
index 0000000..6501a7f
--- /dev/null
+++ b/src/util/get-pci-ids
@@ -0,0 +1,135 @@
+#! /usr/bin/perl -w
+
+# get-pci-ids: extract pci vendor/device ids from linux net drivers
+
+# Copyright (C) 2003 Georg Baum <gbaum@users.sf.net>
+
+# 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
+
+
+# Known bugs/limitations:
+# - Does not recognize all drivers because some require special cflags.
+# Fails also on some drivers that do belong to other architectures
+# than the one of the machine this script is running on.
+# This is currently not so important because all drivers that have an
+# Etherboot counterpart are recognized.
+
+
+use strict;
+use File::Basename "dirname";
+use POSIX "uname";
+
+# Where to find the kernel sources
+my $kernel_src = "/usr/src/linux";
+
+if($#ARGV >= 0) {
+ $kernel_src = shift;
+}
+
+# Sanity checks
+if($#ARGV >= 0) {
+ print STDERR "Too many arguments.\n";
+ print STDERR "Usage: get-pci-ids [path to kernel sources]\n";
+ print STDERR " /usr/src/linux is assumed if no path is given.\n";
+ exit 1;
+}
+
+unless(-f "$kernel_src/include/linux/version.h") {
+ print STDERR "Could not find $kernel_src/include/linux/version.h.\n";
+ print STDERR "$kernel_src is probably no Linux kernel source tree.\n";
+ exit 1;
+}
+
+# Flags that are needed to preprocess the drivers.
+# Some drivers need optimization
+my $cflags="-D__KERNEL__ -I$kernel_src/include -I$kernel_src/net/inet -O2";
+
+# The C preprocessor. It needs to spit out the preprocessed source on stdout.
+my $cpp="gcc -E";
+
+# List of drivers. We parse every .c file. It does not harm if it does not contain a driver.
+my @drivers = split /\s+/, `find $kernel_src/drivers/net -name '*.c' | sort`;
+
+# Kernel version
+my $version = `grep UTS_RELEASE $kernel_src/include/linux/version.h`;
+chomp $version;
+$version =~ s/\s*#define\s+UTS_RELEASE\s+"(\S+)".*$/$1/g;
+
+# Architecture
+my @uname = uname();
+
+
+# Print header
+print "# PCI vendor/device ids extracted from Linux $version on $uname[4] at " . gmtime() . "\n";
+
+my $driver;
+
+# Process the drivers
+foreach $driver (@drivers) {
+
+ # Preprocess to expand macros
+ my $command = "$cpp $cflags -I" . dirname($driver) . " $driver";
+ open DRIVER, "$command |" or die "Could not execute\n\"$command\".\n";
+
+ # Extract the pci_device_id structure
+ my $found = 0;
+ my $line = "";
+ my @lines;
+ while(<DRIVER>) {
+ if(/^\s*static\s+struct\s+pci_device_id/) {
+ # This file contains a driver. Print the name.
+ $driver =~ s!$kernel_src/drivers/net/!!g;
+ print "\n$driver\n";
+ $found = 1;
+ next;
+ }
+ if($found == 1){
+ if(/\};/ or /{\s*0\s*,?\s*}/) {
+ # End of struct
+ $found = 0;
+ } else {
+ chomp;
+ if(/\}\s*,?\s*\n?$/) {
+ # This line contains a full entry or the last part of it.
+ $_ = $line . $_;
+ $line = "";
+ s/[,\{\};\(\)]//g; # Strip punctuation
+ s/^\s+//g; # Eat whitespace at beginning of line
+ tr[A-Z][a-z]; # Convert to lowercase
+ # Push the vendor and device id to @lines if this line is not empty.
+ # We ignore everything else that might be there
+ my ($vendor_id, $device_id, $remainder) = split /\W+/, $_, 3;
+ push @lines, "$vendor_id $device_id\n" if($vendor_id && $device_id);
+ } else {
+ # This line does contain a partial entry. Remember it.
+ $line .= "$_ ";
+ }
+ }
+ }
+ }
+ close DRIVER; # No "or die", because $cpp fails on some files
+
+ # Now print out the sorted values
+ @lines = sort @lines;
+ my $lastline = "";
+ foreach(@lines) {
+ # Print each vendor/device id combination only once.
+ # Some drivers (e.g. e100) do contain subfamilies
+ print if($_ ne $lastline);
+ $lastline = $_;
+ }
+}
+
+
diff --git a/src/util/lzhuf.c b/src/util/lzhuf.c
new file mode 100644
index 0000000..ea65b5e
--- /dev/null
+++ b/src/util/lzhuf.c
@@ -0,0 +1,764 @@
+/*
+----------------------------------------------------------------------------
+
+M. LZHuf Compression
+
+This is the LZHuf compression algorithm as used in DPBOX and F6FBB.
+
+----------------------------------------------------------------------------
+*/
+/**************************************************************
+ lzhuf.c
+ written by Haruyasu Yoshizaki 11/20/1988
+ some minor changes 4/6/1989
+ comments translated by Haruhiko Okumura 4/7/1989
+
+ minor beautifications and adjustments for compiling under Linux
+ by Markus Gutschke <gutschk@math.uni-muenster.de>
+ 1997-01-27
+
+ Modifications to allow use as a filter by Ken Yap <ken_yap@users.sourceforge.net>.
+ 1997-07-01
+
+ Small mod to cope with running on big-endian machines
+ by Jim Hague <jim.hague@acm.org)
+ 1998-02-06
+
+ Make compression statistics report shorter
+ by Ken Yap <ken_yap@users.sourceforge.net>.
+ 2001-04-25
+**************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr 0
+#else
+#define Fprintf(x) fprintf x
+#if defined(ENCODE) || defined(DECODE)
+static char wterr[] = "Can't write.";
+#ifdef ENCODE
+static unsigned long int codesize = 0;
+#endif
+static unsigned long int printcount = 0;
+#endif
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned long int textsize = 0;
+
+static __inline__ void Error(char *message)
+{
+ Fprintf((stderr, "\n%s\n", message));
+ exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+ unsigned long res = 0;
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ u.ul = ul;
+ for (i = 3; i >= 0; i--)
+ res = (res << 8) + u.c[i];
+ return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ for (i = 0; i < 4; i++)
+ {
+ u.c[i] = ul & 0xff;
+ ul >>= 8;
+ }
+ return u.ul;
+}
+#endif
+
+/********** LZSS compression **********/
+
+#define N 4096 /* buffer size */
+/* Attention: When using this file for f6fbb-type compressed data exchange,
+ set N to 2048 ! (DL8HBS) */
+#define F 60 /* lookahead buffer size */
+#define THRESHOLD 2
+#define NIL N /* leaf of tree */
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned char
+ text_buf[N + F - 1];
+#endif
+
+#ifdef ENCODE
+static int match_position, match_length,
+ lson[N + 1], rson[N + 257], dad[N + 1];
+
+static void InitTree(void) /* initialize trees */
+{
+ int i;
+
+ 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(int r) /* insert to tree */
+{
+ int i, p, cmp;
+ unsigned char *key;
+ unsigned c;
+
+ 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(int p) /* remove from tree */
+{
+ int q;
+
+ if (dad[p] == NIL)
+ return; /* not registered */
+ 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;
+}
+#endif
+
+/* 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 char uchar;
+
+/* table for encoding and decoding the upper 6 bits of position */
+
+/* for encoding */
+
+#ifdef ENCODE
+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
+};
+#endif
+
+#ifdef DECODE
+/* 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,
+};
+#endif
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned freq[T + 1]; /* frequency table */
+
+static int 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 int son[T]; /* pointers to child nodes (son[], son[] + 1) */
+#endif
+
+#ifdef DECODE
+static unsigned getbuf = 0;
+static uchar getlen = 0;
+
+static int GetBit(void) /* get one bit */
+{
+ int i;
+
+ while (getlen <= 8) {
+ if ((i = getc(infile)) < 0) i = 0;
+ getbuf |= i << (8 - getlen);
+ getlen += 8;
+ }
+ i = getbuf;
+ getbuf <<= 1;
+ getlen--;
+ return ((signed short)i < 0);
+}
+
+static int GetByte(void) /* get one byte */
+{
+ unsigned short i;
+
+ while (getlen <= 8) {
+ if ((signed short)(i = getc(infile)) < 0) i = 0;
+ getbuf |= i << (8 - getlen);
+ getlen += 8;
+ }
+ i = getbuf;
+ getbuf <<= 8;
+ getlen -= 8;
+ return i >> 8;
+}
+#endif
+
+#ifdef ENCODE
+static unsigned putbuf = 0;
+static uchar putlen = 0;
+
+static void Putcode(int l, unsigned c) /* output c bits of code */
+{
+ putbuf |= c >> putlen;
+ if ((putlen += l) >= 8) {
+ if (putc(putbuf >> 8, outfile) == EOF) {
+ Error(wterr);
+ }
+ if ((putlen -= 8) >= 8) {
+ if (putc(putbuf, outfile) == EOF) {
+ Error(wterr);
+ }
+#ifdef VERBOSE
+ codesize += 2;
+#endif
+ putlen -= 8;
+ putbuf = c << (l - putlen);
+ } else {
+ putbuf <<= 8;
+#ifdef VERBOSE
+ codesize++;
+#endif
+ }
+ }
+}
+#endif
+
+/* initialization of tree */
+
+#if defined(ENCODE) || defined(DECODE)
+static void StartHuff(void)
+{
+ int 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)
+{
+ int i, j, k;
+ unsigned f, l;
+
+ /* 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);
+ freq[k] = f;
+ memmove(&son[k + 1], &son[k], l);
+ 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(int c)
+{
+ int 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]) != 0); /* repeat up to root */
+}
+#endif
+
+#ifdef ENCODE
+#if 0
+static unsigned code, len;
+#endif
+
+static void EncodeChar(unsigned c)
+{
+ unsigned i;
+ int j, k;
+
+ i = 0;
+ j = 0;
+ k = prnt[c + T];
+
+ /* travel from leaf to root */
+ 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);
+ Putcode(j, i);
+#if 0
+ code = i;
+ len = j;
+#endif
+ update(c);
+}
+
+static void EncodePosition(unsigned c)
+{
+ unsigned i;
+
+ /* output upper 6 bits by table lookup */
+ i = c >> 6;
+ Putcode(p_len[i], (unsigned)p_code[i] << 8);
+
+ /* output lower 6 bits verbatim */
+ Putcode(6, (c & 0x3f) << 10);
+}
+
+static void EncodeEnd(void)
+{
+ if (putlen) {
+ if (putc(putbuf >> 8, outfile) == EOF) {
+ Error(wterr);
+ }
+#ifdef VERBOSE
+ codesize++;
+#endif
+ }
+}
+#endif
+
+#ifdef DECODE
+static int DecodeChar(void)
+{
+ unsigned c;
+
+ 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) {
+ c += GetBit();
+ c = son[c];
+ }
+ c -= T;
+ update(c);
+ return c;
+}
+
+static int DecodePosition(void)
+{
+ unsigned i, j, c;
+
+ /* recover upper 6 bits from table */
+ i = GetByte();
+ c = (unsigned)d_code[i] << 6;
+ j = d_len[i];
+
+ /* read lower 6 bits verbatim */
+ j -= 2;
+ while (j--) {
+ i = (i << 1) + GetBit();
+ }
+ return c | (i & 0x3f);
+}
+#endif
+
+#ifdef ENCODE
+/* compression */
+
+void Encode(void) /* compression */
+{
+ int i, c, len, r, s, last_match_length;
+ unsigned long tw;
+
+ fseek(infile, 0L, 2);
+ textsize = ftell(infile);
+#ifdef VERBOSE
+ if ((signed long)textsize < 0)
+ Fprintf((stderr, "Errno: %d", errno));
+#endif
+ tw = host_to_i86ul(textsize);
+ if (fwrite(&tw, sizeof tw, 1, outfile) < 1)
+ Error(wterr); /* output size of text */
+ if (textsize == 0)
+ return;
+ rewind(infile);
+ textsize = 0; /* rewind and re-read */
+ StartHuff();
+ InitTree();
+ s = 0;
+ r = N - F;
+ for (i = s; i < r; i++)
+ text_buf[i] = ' ';
+ for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
+ text_buf[r + len] = c;
+ textsize = len;
+ for (i = 1; i <= F; i++)
+ InsertNode(r - i);
+ InsertNode(r);
+ do {
+ if (match_length > len)
+ match_length = len;
+ if (match_length <= THRESHOLD) {
+ match_length = 1;
+ EncodeChar(text_buf[r]);
+ } else {
+ EncodeChar(255 - THRESHOLD + match_length);
+ EncodePosition(match_position);
+ }
+ last_match_length = match_length;
+ for (i = 0; i < last_match_length &&
+ (c = getc(infile)) != EOF; i++) {
+ 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);
+ }
+ if ((textsize += i) > printcount) {
+#if defined(VERBOSE) && defined(EXTRAVERBOSE)
+ Fprintf((stderr, "%12ld\r", textsize));
+#endif
+ printcount += 1024;
+ }
+ while (i++ < last_match_length) {
+ DeleteNode(s);
+ s = (s + 1) & (N - 1);
+ r = (r + 1) & (N - 1);
+ if (--len) InsertNode(r);
+ }
+ } while (len > 0);
+ EncodeEnd();
+#ifdef LONG_REPORT
+ Fprintf((stderr, "input size %ld bytes\n", codesize));
+ Fprintf((stderr, "output size %ld bytes\n", textsize));
+ Fprintf((stderr, "input/output %.3f\n", (double)codesize / textsize));
+#else
+ Fprintf((stderr, "input/output = %ld/%ld = %.3f\n", codesize, textsize,
+ (double)codesize / textsize));
+#endif
+}
+#endif
+
+#ifdef DECODE
+void Decode(void) /* recover */
+{
+ int i, j, k, r, c;
+ unsigned long int count;
+ unsigned long tw;
+
+ if (fread(&tw, sizeof tw, 1, infile) < 1)
+ Error("Can't read"); /* read size of text */
+ textsize = i86ul_to_host(tw);
+ if (textsize == 0)
+ return;
+ StartHuff();
+ for (i = 0; i < N - F; i++)
+ text_buf[i] = ' ';
+ r = N - F;
+ for (count = 0; count < textsize; ) {
+ c = DecodeChar();
+ if (c < 256) {
+ if (putc(c, outfile) == EOF) {
+ Error(wterr);
+ }
+ text_buf[r++] = c;
+ r &= (N - 1);
+ count++;
+ } else {
+ i = (r - DecodePosition() - 1) & (N - 1);
+ j = c - 255 + THRESHOLD;
+ for (k = 0; k < j; k++) {
+ c = text_buf[(i + k) & (N - 1)];
+ if (putc(c, outfile) == EOF) {
+ Error(wterr);
+ }
+ text_buf[r++] = c;
+ r &= (N - 1);
+ count++;
+ }
+ }
+ if (count > printcount) {
+#if defined(VERBOSE) && defined(EXTRAVERBOSE)
+ Fprintf((stderr, "%12ld\r", count));
+#endif
+ printcount += 1024;
+ }
+ }
+ Fprintf((stderr, "%12ld\n", count));
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+ char *s;
+ FILE *f;
+ int c;
+
+ if (argc == 2) {
+ outfile = stdout;
+ if ((f = tmpfile()) == NULL) {
+ perror("tmpfile");
+ return EXIT_FAILURE;
+ }
+ while ((c = getchar()) != EOF)
+ fputc(c, f);
+ rewind(infile = f);
+ }
+ else if (argc != 4) {
+ Fprintf((stderr, "'lzhuf e file1 file2' encodes file1 into file2.\n"
+ "'lzhuf d file2 file1' decodes file2 into file1.\n"));
+ return EXIT_FAILURE;
+ }
+ if (argc == 4) {
+ if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+ || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
+ || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+ Fprintf((stderr, "??? %s\n", s));
+ return EXIT_FAILURE;
+ }
+ }
+ if (toupper(*argv[1]) == 'E')
+ Encode();
+ else
+ Decode();
+ fclose(infile);
+ fclose(outfile);
+ return EXIT_SUCCESS;
+}
+#endif
diff --git a/src/util/makelilo.pl b/src/util/makelilo.pl
new file mode 100755
index 0000000..8f995bc
--- /dev/null
+++ b/src/util/makelilo.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+use constant SYSSIZE_LOC => 500; # bytes from beginning of boot block
+use constant MINSIZE => 32768;
+
+use strict;
+
+use bytes;
+
+$#ARGV >= 1 or die "Usage: $0 liloprefix file ...\n";
+open(L, "$ARGV[0]") or die "$ARGV[0]: $!\n";
+undef($/);
+my $liloprefix = <L>;
+close(L);
+length($liloprefix) >= 512 or die "LILO prefix too short\n";
+shift(@ARGV);
+my $totalsize = 0;
+for my $file (@ARGV) {
+ next if (! -f $file or ! -r $file);
+ $totalsize += -s $file;
+}
+my $pad = 0;
+if ($totalsize < MINSIZE) {
+ $pad = MINSIZE - $totalsize;
+ $totalsize = MINSIZE;
+}
+print STDERR "LILO payload is $totalsize bytes\n";
+$totalsize += 16;
+$totalsize >>= 4;
+substr($liloprefix, SYSSIZE_LOC, 2) = pack('v', $totalsize);
+print $liloprefix;
+for my $file (@ARGV) {
+ next unless open(I, "$file");
+ undef($/);
+ my $data = <I>;
+ print $data;
+ close(I);
+}
+print "\x0" x $pad;
+exit(0);
diff --git a/src/util/makerom.pl b/src/util/makerom.pl
new file mode 100755
index 0000000..695468c
--- /dev/null
+++ b/src/util/makerom.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+
+use Getopt::Std;
+
+use constant MINROMSIZE => 8192;
+use constant MAXROMSIZE => 262144;
+
+use constant PCI_PTR_LOC => 0x18; # from beginning of ROM
+use constant PCI_HDR_SIZE => 0x18;
+use constant PNP_PTR_LOC => 0x1a; # from beginning of ROM
+use constant PNP_HDR_SIZE => 0x20;
+use constant PNP_CHKSUM_OFF => 0x9; # bytes from beginning of PnP header
+use constant PNP_DEVICE_OFF => 0x10; # bytes from beginning of PnP header
+use constant PCI_VEND_ID_OFF => 0x4; # bytes from beginning of PCI header
+use constant PCI_DEV_ID_OFF => 0x6; # bytes from beginning of PCI header
+use constant PCI_SIZE_OFF => 0x10; # bytes from beginning of PCI header
+
+use constant UNDI_PTR_LOC => 0x16; # from beginning of ROM
+use constant UNDI_HDR_SIZE => 0x16;
+use constant UNDI_CHKSUM_OFF => 0x05;
+
+use strict;
+
+use vars qw(%opts);
+
+use bytes;
+
+sub getromsize ($) {
+ my ($romref) = @_;
+ my $i;
+
+ print STDERR "BIOS extension ROM Image did not start with 0x55 0xAA\n"
+ if (substr($$romref, 0, 2) ne "\x55\xaa");
+ my $size = ord(substr($$romref, 2, 1)) * 512;
+ for ($i = MINROMSIZE; $i < MAXROMSIZE and $i < $size; $i *= 2) { }
+ print STDERR "$size is a strange size for a boot ROM\n"
+ if ($size > 0 and $i > $size);
+ return ($size);
+}
+
+sub addident ($) {
+ my ($romref) = @_;
+
+ return (0) unless (my $s = $opts{'i'});
+ # include the terminating NUL byte too
+ $s .= "\x00";
+ my $len = length($s);
+ # Put the identifier in only if the space is blank
+ my $pos = length($$romref) - $len - 2;
+ return (0) if (substr($$romref, $pos, $len) ne ("\xFF" x $len));
+ substr($$romref, $pos, $len) = $s;
+ return ($pos);
+}
+
+sub pcipnpheaders ($$) {
+ my ($romref, $identoffset) = @_;
+ my ($pci_hdr_offset, $pnp_hdr_offset);
+
+ $pci_hdr_offset = unpack('v', substr($$romref, PCI_PTR_LOC, 2));
+ $pnp_hdr_offset = unpack('v', substr($$romref, PNP_PTR_LOC, 2));
+ # Sanity checks
+ if ($pci_hdr_offset < PCI_PTR_LOC + 2
+ or $pci_hdr_offset > length($$romref) - PCI_HDR_SIZE
+ or $pnp_hdr_offset < PNP_PTR_LOC + 2
+ or $pnp_hdr_offset > length($$romref) - PNP_HDR_SIZE
+ or substr($$romref, $pci_hdr_offset, 4) ne 'PCIR'
+ or substr($$romref, $pnp_hdr_offset, 4) ne '$PnP') {
+ $pci_hdr_offset = $pnp_hdr_offset = 0;
+ } else {
+ printf "PCI header at %#x and PnP header at %#x\n",
+ $pci_hdr_offset, $pnp_hdr_offset;
+ }
+ if ($pci_hdr_offset > 0) {
+ my ($pci_vendor_id, $pci_device_id);
+ # if no -p option, just report what's there
+ if (!defined($opts{'p'})) {
+ $pci_vendor_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2));
+ $pci_device_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2));
+ printf "PCI Vendor ID %#x Device ID %#x\n",
+ $pci_vendor_id, $pci_device_id;
+ } else {
+ substr($$romref, $pci_hdr_offset + PCI_SIZE_OFF, 2)
+ = pack('v', length($$romref) / 512);
+ ($pci_vendor_id, $pci_device_id) = split(/,/, $opts{'p'});
+ substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2)
+ = pack('v', oct($pci_vendor_id)) if ($pci_vendor_id);
+ substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2)
+ = pack('v', oct($pci_device_id)) if ($pci_device_id);
+ }
+ }
+ if ($pnp_hdr_offset > 0 and defined($identoffset)) {
+ # Point to device id string at end of ROM image
+ substr($$romref, $pnp_hdr_offset+PNP_DEVICE_OFF, 2)
+ = pack('v', $identoffset);
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $pnp_hdr_offset,
+ PNP_HDR_SIZE));
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub undiheaders ($) {
+ my ($romref) = @_;
+ my ($undi_hdr_offset);
+
+ $undi_hdr_offset = unpack('v', substr($$romref, UNDI_PTR_LOC, 2));
+ # Sanity checks
+ if ($undi_hdr_offset < UNDI_PTR_LOC + 2
+ or $undi_hdr_offset > length($$romref) - UNDI_HDR_SIZE
+ or substr($$romref, $undi_hdr_offset, 4) ne 'UNDI') {
+ $undi_hdr_offset = 0;
+ } else {
+ printf "UNDI header at %#x\n", $undi_hdr_offset;
+ }
+ if ($undi_hdr_offset > 0) {
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $undi_hdr_offset,
+ UNDI_HDR_SIZE));
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub writerom ($$) {
+ my ($filename, $romref) = @_;
+
+ open(R, ">$filename") or die "$filename: $!\n";
+ print R $$romref;
+ close(R);
+}
+
+sub checksum ($) {
+ my ($romref) = @_;
+
+ substr($$romref, 5, 1) = "\x00";
+ my $sum = unpack('%8C*', $$romref);
+ substr($$romref, 5, 1) = chr(256 - $sum);
+ # Double check
+ $sum = unpack('%8C*', $$romref);
+ if ($sum != 0) {
+ print "Checksum fails\n"
+ } elsif ($opts{'v'}) {
+ print "Checksum ok\n";
+ }
+}
+
+sub makerom () {
+ my ($rom, $romsize);
+
+ getopts('3xi:p:s:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ # If PXE image, just fill the length field and write it out
+ if ($opts{'x'}) {
+ substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
+ &writerom($ARGV[0], \$rom);
+ return;
+ }
+ # Size specified with -s overrides value in 3rd byte in image
+ # -s 0 means round up to next 512 byte block
+ if (defined($opts{'s'})) {
+ if (($romsize = oct($opts{'s'})) <= 0) {
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511
+ }
+ } else {
+ $romsize = &getromsize(\$rom);
+ # 0 put there by *loader.S means makerom should pick the size
+ if ($romsize == 0) {
+ # Shrink romsize down to the smallest power of two that will do
+ for ($romsize = MAXROMSIZE;
+ $romsize > MINROMSIZE and $romsize >= 2*$filesize;
+ $romsize /= 2) { }
+ }
+ }
+ if ($filesize > $romsize) {
+ print STDERR "ROM size of $romsize not big enough for data, ";
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511;
+ print "will use $romsize instead\n"
+ }
+ # Pad with 0xFF to $romsize
+ $rom .= "\xFF" x ($romsize - length($rom));
+ if ($romsize >= 128 * 1024) {
+ print "Warning: ROM size exceeds extension BIOS limit\n";
+ }
+ substr($rom, 2, 1) = chr(($romsize / 512) % 256);
+ print "ROM size is $romsize\n" if $opts{'v'};
+ my $identoffset = &addident(\$rom);
+ &pcipnpheaders(\$rom, $identoffset);
+ &undiheaders(\$rom);
+ # 3c503 requires last two bytes to be 0x80
+ substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
+ if ($opts{'3'} and $romsize == MINROMSIZE);
+ &checksum(\$rom);
+ &writerom($ARGV[0], \$rom);
+}
+
+sub modrom () {
+ my ($rom);
+
+ getopts('p:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-p vendorid,deviceid] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ &pcipnpheaders(\$rom);
+ &undiheaders(\$rom);
+ &checksum(\$rom);
+ &writerom($ARGV[0], \$rom);
+}
+
+# Main routine. See how we were called and behave accordingly
+if ($0 =~ m:modrom(\.pl)?$:) {
+ &modrom();
+} else {
+ &makerom();
+}
+exit(0);
diff --git a/src/util/modrom.pl b/src/util/modrom.pl
new file mode 100755
index 0000000..695468c
--- /dev/null
+++ b/src/util/modrom.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+
+use Getopt::Std;
+
+use constant MINROMSIZE => 8192;
+use constant MAXROMSIZE => 262144;
+
+use constant PCI_PTR_LOC => 0x18; # from beginning of ROM
+use constant PCI_HDR_SIZE => 0x18;
+use constant PNP_PTR_LOC => 0x1a; # from beginning of ROM
+use constant PNP_HDR_SIZE => 0x20;
+use constant PNP_CHKSUM_OFF => 0x9; # bytes from beginning of PnP header
+use constant PNP_DEVICE_OFF => 0x10; # bytes from beginning of PnP header
+use constant PCI_VEND_ID_OFF => 0x4; # bytes from beginning of PCI header
+use constant PCI_DEV_ID_OFF => 0x6; # bytes from beginning of PCI header
+use constant PCI_SIZE_OFF => 0x10; # bytes from beginning of PCI header
+
+use constant UNDI_PTR_LOC => 0x16; # from beginning of ROM
+use constant UNDI_HDR_SIZE => 0x16;
+use constant UNDI_CHKSUM_OFF => 0x05;
+
+use strict;
+
+use vars qw(%opts);
+
+use bytes;
+
+sub getromsize ($) {
+ my ($romref) = @_;
+ my $i;
+
+ print STDERR "BIOS extension ROM Image did not start with 0x55 0xAA\n"
+ if (substr($$romref, 0, 2) ne "\x55\xaa");
+ my $size = ord(substr($$romref, 2, 1)) * 512;
+ for ($i = MINROMSIZE; $i < MAXROMSIZE and $i < $size; $i *= 2) { }
+ print STDERR "$size is a strange size for a boot ROM\n"
+ if ($size > 0 and $i > $size);
+ return ($size);
+}
+
+sub addident ($) {
+ my ($romref) = @_;
+
+ return (0) unless (my $s = $opts{'i'});
+ # include the terminating NUL byte too
+ $s .= "\x00";
+ my $len = length($s);
+ # Put the identifier in only if the space is blank
+ my $pos = length($$romref) - $len - 2;
+ return (0) if (substr($$romref, $pos, $len) ne ("\xFF" x $len));
+ substr($$romref, $pos, $len) = $s;
+ return ($pos);
+}
+
+sub pcipnpheaders ($$) {
+ my ($romref, $identoffset) = @_;
+ my ($pci_hdr_offset, $pnp_hdr_offset);
+
+ $pci_hdr_offset = unpack('v', substr($$romref, PCI_PTR_LOC, 2));
+ $pnp_hdr_offset = unpack('v', substr($$romref, PNP_PTR_LOC, 2));
+ # Sanity checks
+ if ($pci_hdr_offset < PCI_PTR_LOC + 2
+ or $pci_hdr_offset > length($$romref) - PCI_HDR_SIZE
+ or $pnp_hdr_offset < PNP_PTR_LOC + 2
+ or $pnp_hdr_offset > length($$romref) - PNP_HDR_SIZE
+ or substr($$romref, $pci_hdr_offset, 4) ne 'PCIR'
+ or substr($$romref, $pnp_hdr_offset, 4) ne '$PnP') {
+ $pci_hdr_offset = $pnp_hdr_offset = 0;
+ } else {
+ printf "PCI header at %#x and PnP header at %#x\n",
+ $pci_hdr_offset, $pnp_hdr_offset;
+ }
+ if ($pci_hdr_offset > 0) {
+ my ($pci_vendor_id, $pci_device_id);
+ # if no -p option, just report what's there
+ if (!defined($opts{'p'})) {
+ $pci_vendor_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2));
+ $pci_device_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2));
+ printf "PCI Vendor ID %#x Device ID %#x\n",
+ $pci_vendor_id, $pci_device_id;
+ } else {
+ substr($$romref, $pci_hdr_offset + PCI_SIZE_OFF, 2)
+ = pack('v', length($$romref) / 512);
+ ($pci_vendor_id, $pci_device_id) = split(/,/, $opts{'p'});
+ substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2)
+ = pack('v', oct($pci_vendor_id)) if ($pci_vendor_id);
+ substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2)
+ = pack('v', oct($pci_device_id)) if ($pci_device_id);
+ }
+ }
+ if ($pnp_hdr_offset > 0 and defined($identoffset)) {
+ # Point to device id string at end of ROM image
+ substr($$romref, $pnp_hdr_offset+PNP_DEVICE_OFF, 2)
+ = pack('v', $identoffset);
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $pnp_hdr_offset,
+ PNP_HDR_SIZE));
+ substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub undiheaders ($) {
+ my ($romref) = @_;
+ my ($undi_hdr_offset);
+
+ $undi_hdr_offset = unpack('v', substr($$romref, UNDI_PTR_LOC, 2));
+ # Sanity checks
+ if ($undi_hdr_offset < UNDI_PTR_LOC + 2
+ or $undi_hdr_offset > length($$romref) - UNDI_HDR_SIZE
+ or substr($$romref, $undi_hdr_offset, 4) ne 'UNDI') {
+ $undi_hdr_offset = 0;
+ } else {
+ printf "UNDI header at %#x\n", $undi_hdr_offset;
+ }
+ if ($undi_hdr_offset > 0) {
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = "\x00";
+ my $sum = unpack('%8C*', substr($$romref, $undi_hdr_offset,
+ UNDI_HDR_SIZE));
+ substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = chr(256 - $sum);
+ }
+}
+
+sub writerom ($$) {
+ my ($filename, $romref) = @_;
+
+ open(R, ">$filename") or die "$filename: $!\n";
+ print R $$romref;
+ close(R);
+}
+
+sub checksum ($) {
+ my ($romref) = @_;
+
+ substr($$romref, 5, 1) = "\x00";
+ my $sum = unpack('%8C*', $$romref);
+ substr($$romref, 5, 1) = chr(256 - $sum);
+ # Double check
+ $sum = unpack('%8C*', $$romref);
+ if ($sum != 0) {
+ print "Checksum fails\n"
+ } elsif ($opts{'v'}) {
+ print "Checksum ok\n";
+ }
+}
+
+sub makerom () {
+ my ($rom, $romsize);
+
+ getopts('3xi:p:s:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ # If PXE image, just fill the length field and write it out
+ if ($opts{'x'}) {
+ substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
+ &writerom($ARGV[0], \$rom);
+ return;
+ }
+ # Size specified with -s overrides value in 3rd byte in image
+ # -s 0 means round up to next 512 byte block
+ if (defined($opts{'s'})) {
+ if (($romsize = oct($opts{'s'})) <= 0) {
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511
+ }
+ } else {
+ $romsize = &getromsize(\$rom);
+ # 0 put there by *loader.S means makerom should pick the size
+ if ($romsize == 0) {
+ # Shrink romsize down to the smallest power of two that will do
+ for ($romsize = MAXROMSIZE;
+ $romsize > MINROMSIZE and $romsize >= 2*$filesize;
+ $romsize /= 2) { }
+ }
+ }
+ if ($filesize > $romsize) {
+ print STDERR "ROM size of $romsize not big enough for data, ";
+ # NB: This roundup trick only works on powers of 2
+ $romsize = ($filesize + 511) & ~511;
+ print "will use $romsize instead\n"
+ }
+ # Pad with 0xFF to $romsize
+ $rom .= "\xFF" x ($romsize - length($rom));
+ if ($romsize >= 128 * 1024) {
+ print "Warning: ROM size exceeds extension BIOS limit\n";
+ }
+ substr($rom, 2, 1) = chr(($romsize / 512) % 256);
+ print "ROM size is $romsize\n" if $opts{'v'};
+ my $identoffset = &addident(\$rom);
+ &pcipnpheaders(\$rom, $identoffset);
+ &undiheaders(\$rom);
+ # 3c503 requires last two bytes to be 0x80
+ substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
+ if ($opts{'3'} and $romsize == MINROMSIZE);
+ &checksum(\$rom);
+ &writerom($ARGV[0], \$rom);
+}
+
+sub modrom () {
+ my ($rom);
+
+ getopts('p:v', \%opts);
+ $ARGV[0] or die "Usage: $0 [-p vendorid,deviceid] rom-file\n";
+ open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
+ # Read in the whole ROM in one gulp
+ my $filesize = read(R, $rom, MAXROMSIZE+1);
+ close(R);
+ defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
+ print "$filesize bytes read\n" if $opts{'v'};
+ &pcipnpheaders(\$rom);
+ &undiheaders(\$rom);
+ &checksum(\$rom);
+ &writerom($ARGV[0], \$rom);
+}
+
+# Main routine. See how we were called and behave accordingly
+if ($0 =~ m:modrom(\.pl)?$:) {
+ &modrom();
+} else {
+ &makerom();
+}
+exit(0);
diff --git a/src/util/nrv2b.c b/src/util/nrv2b.c
new file mode 100644
index 0000000..6bac4cd
--- /dev/null
+++ b/src/util/nrv2b.c
@@ -0,0 +1,1501 @@
+/**************************************************************
+ Form adapted from lzhuf.c
+ written by Haruyasu Yoshizaki 11/20/1988
+ some minor changes 4/6/1989
+ comments translated by Haruhiko Okumura 4/7/1989
+
+ minor beautifications and adjustments for compiling under Linux
+ by Markus Gutschke <gutschk@math.uni-muenster.de>
+ 1997-01-27
+
+ Modifications to allow use as a filter by Ken Yap
+ <ken_yap@users.sourceforge.net>.
+
+ 1997-07-01
+
+ Small mod to cope with running on big-endian machines
+ by Jim Hague <jim.hague@acm.org)
+ 1998-02-06
+
+ Make compression statistics report shorter
+ by Ken Yap <ken_yap@users.sourceforge.net>.
+ 2001-04-25
+
+ Replaced algorithm with nrv2b from ucl the compression
+ library from upx. That code is:
+ Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+ And is distributed under the terms of the GPL.
+ The conversion was performed
+ by Eric Biederman <ebiederman@lnxi.com>.
+ 20 August 2002
+
+**************************************************************/
+#define UCLPACK_COMPAT 0
+#define NDEBUG 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef __FreeBSD__
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <limits.h>
+#include <assert.h>
+#if UCLPACK_COMPAT
+#include <netinet/in.h>
+#endif
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr 0
+#else
+#define Fprintf(x) fprintf x
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+
+#ifndef ENDIAN
+#define ENDIAN 0
+#endif
+#ifndef BITSIZE
+#define BITSIZE 32
+#endif
+
+static __inline__ void Error(char *message)
+{
+ Fprintf((stderr, "\n%s\n", message));
+ exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+ unsigned long res = 0;
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ u.ul = ul;
+ for (i = 3; i >= 0; i--)
+ res = (res << 8) + u.c[i];
+ return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+ int i;
+ union
+ {
+ unsigned char c[4];
+ unsigned long ul;
+ } u;
+
+ for (i = 0; i < 4; i++)
+ {
+ u.c[i] = ul & 0xff;
+ ul >>= 8;
+ }
+ return u.ul;
+}
+#endif
+
+
+
+#if UCLPACK_COMPAT
+/* magic file header for compressed files */
+static const unsigned char magic[8] =
+{ 0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a };
+
+#endif
+
+#ifdef ENCODE
+/********** NRV2B_99 compression **********/
+
+/* Note by limiting the ring buffer I have limited the maximum
+ * offset to 64K. Since etherboot rarely gets that big it
+ * is not a problem and it gives me a firm guarantee
+ * that I will never get a 3 byte string match that is encodes
+ * to more than 9/8 it's original size.
+ * That guaranteee is important to for the inplace decompressor.
+ * There are better ways to do this if a larger offset and buffer
+ * would give better compression.
+ */
+#define N (65536ul) /* size of ring buffer */
+#define THRESHOLD 1 /* lower limit for match length */
+#define F 2048 /* upper limit for match length */
+#define M2_MAX_OFFSET 0xd00
+
+/* note: to use default values pass -1, i.e. initialize
+ * this struct by a memset(x,0xff,sizeof(x)) */
+struct ucl_compress_config
+{
+ int bb_endian;
+ int bb_size;
+ unsigned int max_offset;
+ unsigned int max_match;
+ int s_level;
+ int h_level;
+ int p_level;
+ int c_flags;
+ unsigned int m_size;
+};
+
+struct ucl_compress
+{
+ int init;
+
+ unsigned int look; /* bytes in lookahead buffer */
+
+ unsigned int m_len;
+ unsigned int m_off;
+
+ unsigned int last_m_len;
+ unsigned int last_m_off;
+
+ const unsigned char *bp;
+ const unsigned char *ip;
+ const unsigned char *in;
+ const unsigned char *in_end;
+ unsigned char *out;
+
+ uint64_t bb_b;
+ unsigned bb_k;
+ unsigned bb_c_endian;
+ unsigned bb_c_s;
+ unsigned bb_c_s8;
+ unsigned char *bb_p;
+ unsigned char *bb_op;
+
+ struct ucl_compress_config conf;
+ unsigned int *result;
+
+ unsigned int textsize; /* text size counter */
+ unsigned int codesize; /* code size counter */
+ unsigned int printcount; /* counter for reporting progress every 1K
+ bytes */
+
+
+ /* some stats */
+ unsigned long lit_bytes;
+ unsigned long match_bytes;
+ unsigned long rep_bytes;
+ unsigned long lazy;
+};
+
+
+
+#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+#define UCL_E_OK 0
+#define UCL_E_INVALID_ARGUMENT 1
+#define UCL_E_OUT_OF_MEMORY 2
+#define UCL_E_ERROR 3
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define SWD_HSIZE 16384
+#define SWD_MAX_CHAIN 2048
+#define SWD_BEST_OFF 1
+
+#define HEAD3(b,p) \
+ (((0x9f5f*(((((uint32_t)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 UINT_MAX
+
+struct ucl_swd
+{
+/* public - "built-in" */
+ unsigned int n;
+ unsigned int f;
+ unsigned int threshold;
+
+/* public - configuration */
+ unsigned int max_chain;
+ unsigned int nice_length;
+ int use_best_off;
+ unsigned int lazy_insert;
+
+/* public - output */
+ unsigned int m_len;
+ unsigned int m_off;
+ unsigned int look;
+ int b_char;
+#if defined(SWD_BEST_OFF)
+ unsigned int best_off[ SWD_BEST_OFF ];
+#endif
+
+/* semi public */
+ struct ucl_compress *c;
+ unsigned int m_pos;
+#if defined(SWD_BEST_OFF)
+ unsigned int best_pos[ SWD_BEST_OFF ];
+#endif
+
+/* private */
+ const uint8_t *dict;
+ const uint8_t *dict_end;
+ unsigned int dict_len;
+
+/* private */
+ unsigned int ip; /* input pointer (lookahead) */
+ unsigned int bp; /* buffer pointer */
+ unsigned int rp; /* remove pointer */
+ unsigned int b_size;
+
+ unsigned char *b_wrap;
+
+ unsigned int node_count;
+ unsigned int first_rp;
+
+ unsigned char b [ N + F + F ];
+ unsigned int head3 [ SWD_HSIZE ];
+ unsigned int succ3 [ N + F ];
+ unsigned int best3 [ N + F ];
+ unsigned int llen3 [ SWD_HSIZE ];
+ unsigned int head2 [ 65536U ];
+};
+
+#define s_head3(s,key) s->head3[key]
+
+
+#if !defined( NDEBUG)
+static void assert_match(const struct ucl_swd * swd, unsigned int m_len,
+ unsigned int m_off )
+
+{
+ const struct ucl_compress *c = swd->c;
+ unsigned int d_off;
+
+ assert(m_len >= 2);
+ if (m_off <= (unsigned int) (c->bp - c->in))
+ {
+ assert(c->bp - m_off + m_len < c->ip);
+ assert(memcmp(c->bp, c->bp - m_off, m_len) == 0);
+ }
+ else
+ {
+ assert(swd->dict != NULL);
+ d_off = m_off - (unsigned int) (c->bp - c->in);
+ assert(d_off <= swd->dict_len);
+ if (m_len > d_off)
+ {
+ assert(memcmp(c->bp, swd->dict_end - d_off, d_off) ==
+ 0);
+
+ assert(c->in + m_len - d_off < c->ip);
+ assert(memcmp(c->bp + d_off, c->in, m_len - d_off) ==
+ 0);
+
+ }
+ else
+ {
+ assert(memcmp(c->bp, swd->dict_end - d_off, m_len) ==
+ 0);
+
+ }
+ }
+}
+#else
+# define assert_match(a,b,c) ((void)0)
+#endif
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_initdict(struct ucl_swd *s, const uint8_t *dict, unsigned int 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(struct ucl_swd *s, unsigned int node, unsigned int len)
+{
+ unsigned int 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] = (unsigned int)(node);
+ s->best3[node] = (unsigned int)(s->f + 1);
+ s->llen3[key]++;
+ assert(s->llen3[key] <= s->n);
+
+ key = HEAD2(s->b,node);
+ s->head2[key] = (unsigned int)(node);
+
+ node++;
+ }
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+int swd_init(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+{
+ unsigned int i = 0;
+ int c = 0;
+
+ if (s->n == 0)
+ s->n = N;
+ if (s->f == 0)
+ s->f = F;
+ s->threshold = THRESHOLD;
+ if (s->n > N || s->f > F)
+ return UCL_E_INVALID_ARGUMENT;
+
+ /* defaults */
+ s->max_chain = SWD_MAX_CHAIN;
+ s->nice_length = s->f;
+ s->use_best_off = 0;
+ s->lazy_insert = 0;
+
+ s->b_size = s->n + s->f;
+ if (s->b_size + s->f >= UINT_MAX)
+ return UCL_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);
+ for (i = 0; i < 65536U; i++)
+ s->head2[i] = NIL2;
+
+ s->ip = 0;
+ swd_initdict(s,dict,dict_len);
+ s->bp = s->ip;
+ s->first_rp = s->ip;
+
+ assert(s->ip + s->f <= s->b_size);
+
+ s->look = (unsigned int) (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;
+
+ /* unused i */
+ /* unused c */
+ return UCL_E_OK;
+}
+
+
+static
+void swd_exit(struct ucl_swd *s)
+{
+ /* unused s */
+
+}
+
+#define swd_pos2off(s,pos) \
+ (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
+
+/***********************************************************************
+//
+************************************************************************/
+
+static __inline__
+void swd_getbyte(struct ucl_swd *s)
+{
+ int c;
+
+ if ((c = getbyte(*(s->c))) < 0)
+ {
+ if (s->look > 0)
+ --s->look;
+ }
+ else
+ {
+ s->b[s->ip] = (uint8_t)(c);
+ if (s->ip < s->f)
+ s->b_wrap[s->ip] = (uint8_t)(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;
+}
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+
+static __inline__
+void swd_remove_node(struct ucl_swd *s, unsigned int node)
+{
+ if (s->node_count == 0)
+ {
+ unsigned int key;
+
+#ifdef UCL_DEBUG
+ if (s->first_rp != UINT_MAX)
+ {
+ if (node != s->first_rp)
+ printf("Remove %5d: %5d %5d %5d %5d %6d %6d\n",
+
+ node, s->rp, s->ip, s->bp, s->first_rp,
+ s->ip - node, s->ip - s->bp);
+ assert(node == s->first_rp);
+ s->first_rp = UINT_MAX;
+ }
+#endif
+
+ key = HEAD3(s->b,node);
+ assert(s->llen3[key] > 0);
+ --s->llen3[key];
+
+ key = HEAD2(s->b,node);
+ assert(s->head2[key] != NIL2);
+ if ((unsigned int) s->head2[key] == node)
+ s->head2[key] = NIL2;
+ }
+ else
+ --s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_accept(struct ucl_swd *s, unsigned int n)
+{
+ assert(n <= s->look);
+
+ if (n > 0) do
+ {
+ unsigned int key;
+
+ swd_remove_node(s,s->rp);
+
+ /* add bp into HEAD3 */
+ key = HEAD3(s->b,s->bp);
+ s->succ3[s->bp] = s_head3(s,key);
+ s->head3[key] = (unsigned int)(s->bp);
+ s->best3[s->bp] = (unsigned int)(s->f + 1);
+ s->llen3[key]++;
+ assert(s->llen3[key] <= s->n);
+
+ /* add bp into HEAD2 */
+ key = HEAD2(s->b,s->bp);
+ s->head2[key] = (unsigned int)(s->bp);
+
+ swd_getbyte(s);
+ } while (--n > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_search(struct ucl_swd *s, unsigned int node, unsigned int cnt)
+{
+ const unsigned char *p1;
+ const unsigned char *p2;
+ const unsigned char *px;
+
+ unsigned int 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;
+
+ assert(s->m_len > 0);
+
+ scan_end1 = bp[m_len - 1];
+ for ( ; cnt-- > 0; node = s->succ3[node])
+ {
+ p1 = bp;
+ p2 = b + node;
+ px = bx;
+
+ assert(m_len < s->look);
+
+ if (
+ p2[m_len - 1] == scan_end1 &&
+ p2[m_len] == p1[m_len] &&
+ p2[0] == p1[0] &&
+ p2[1] == p1[1])
+ {
+ unsigned int i;
+ assert(memcmp(bp,&b[node],3) == 0);
+
+ p1 += 2; p2 += 2;
+ do {} while (++p1 < px && *p1 == *++p2);
+ i = p1 - bp;
+
+#ifdef UCL_DEBUG
+ if (memcmp(bp,&b[node],i) != 0)
+ printf("%5ld %5ld %02x%02x %02x%02x\n",
+ (long)s->bp, (long) node,
+ bp[0], bp[1], b[node], b[node+1]);
+#endif
+ assert(memcmp(bp,&b[node],i) == 0);
+
+#if defined(SWD_BEST_OFF)
+ if (i < SWD_BEST_OFF)
+ {
+ if (s->best_pos[i] == 0)
+ s->best_pos[i] = node + 1;
+ }
+#endif
+ 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 > (unsigned int) s->best3[node])
+ return;
+ scan_end1 = bp[m_len - 1];
+ }
+ }
+ }
+}
+
+static int swd_search2(struct ucl_swd *s)
+{
+ unsigned int key;
+
+ assert(s->look >= 2);
+ assert(s->m_len > 0);
+
+ key = s->head2[ HEAD2(s->b,s->bp) ];
+ if (key == NIL2)
+ return 0;
+#ifdef UCL_DEBUG
+ if (memcmp(&s->b[s->bp],&s->b[key],2) != 0)
+ printf("%5ld %5ld %02x%02x %02x%02x\n", (long)s->bp, (long)key,
+ s->b[s->bp], s->b[s->bp+1], s->b[key], s->b[key+1]);
+#endif
+ assert(memcmp(&s->b[s->bp],&s->b[key],2) == 0);
+#if defined(SWD_BEST_OFF)
+ if (s->best_pos[2] == 0)
+ s->best_pos[2] = key + 1;
+#endif
+
+ if (s->m_len < 2)
+ {
+ s->m_len = 2;
+ s->m_pos = key;
+ }
+ return 1;
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_findbest(struct ucl_swd *s)
+{
+ unsigned int key;
+ unsigned int cnt, node;
+ unsigned int len;
+
+ assert(s->m_len > 0);
+
+ /* get current head, add bp into HEAD3 */
+ key = HEAD3(s->b,s->bp);
+ node = s->succ3[s->bp] = s_head3(s,key);
+ cnt = s->llen3[key]++;
+ assert(s->llen3[key] <= s->n + s->f);
+ if (cnt > s->max_chain && s->max_chain > 0)
+ cnt = s->max_chain;
+ s->head3[key] = (unsigned int)(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] = (unsigned int)(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] = (unsigned int)(s->m_len);
+
+#if defined(SWD_BEST_OFF)
+ 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;
+ }
+#endif
+ }
+
+ swd_remove_node(s,s->rp);
+
+ /* add bp into HEAD2 */
+ key = HEAD2(s->b,s->bp);
+ s->head2[key] = (unsigned int)(s->bp);
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+init_match ( struct ucl_compress *c, struct ucl_swd *s,
+ const uint8_t *dict, unsigned int dict_len,
+ uint32_t flags )
+{
+ int r;
+
+ assert(!c->init);
+ 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 != UCL_E_OK)
+ {
+ swd_exit(s);
+ return r;
+ }
+
+ s->use_best_off = (flags & 1) ? 1 : 0;
+ return UCL_E_OK;
+}
+
+static int
+find_match ( struct ucl_compress *c, struct ucl_swd *s,
+ unsigned int this_len, unsigned int skip )
+{
+ assert(c->init);
+
+ if (skip > 0)
+ {
+ assert(this_len >= skip);
+ swd_accept(s, this_len - skip);
+ c->textsize += this_len - skip + 1;
+ }
+ else
+ {
+ assert(this_len <= 1);
+ c->textsize += this_len - skip;
+ }
+
+ s->m_len = THRESHOLD;
+#ifdef SWD_BEST_OFF
+ if (s->use_best_off)
+ memset(s->best_pos,0,sizeof(s->best_pos));
+#endif
+ 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;
+ swd_exit(s);
+ }
+ else
+ {
+ c->look = s->look + 1;
+ }
+ c->bp = c->ip - c->look;
+
+#if 0
+ /* brute force match search */
+ if (c->m_len > THRESHOLD && c->m_len + 1 <= c->look)
+ {
+ const uint8_t *ip = c->bp;
+ const uint8_t *m = c->bp - c->m_off;
+ const uint8_t *in = c->in;
+
+ if (ip - in > N)
+ in = ip - N;
+ for (;;)
+ {
+ while (*in != *ip)
+ in++;
+ if (in == ip)
+ break;
+ if (in != m)
+ if (memcmp(in,ip,c->m_len+1) == 0)
+ printf("%p %p %p %5d\n",in,ip,m,c->m_len);
+
+ in++;
+ }
+ }
+#endif
+
+ return UCL_E_OK;
+}
+
+
+static int bbConfig(struct ucl_compress *c, int endian, int bitsize)
+{
+ if (endian != -1)
+ {
+ if (endian != 0)
+ return UCL_E_ERROR;
+ c->bb_c_endian = endian;
+ }
+ if (bitsize != -1)
+ {
+ if (bitsize != 8 && bitsize != 16 && bitsize != 32 && bitsize != 64)
+ return UCL_E_ERROR;
+ c->bb_c_s = bitsize;
+ c->bb_c_s8 = bitsize / 8;
+ }
+ c->bb_b = 0; c->bb_k = 0;
+ c->bb_p = NULL;
+ c->bb_op = NULL;
+ return UCL_E_OK;
+}
+
+static void bbWriteBits(struct ucl_compress *c)
+{
+ uint8_t *p = c->bb_p;
+ uint64_t b = c->bb_b;
+
+ p[0] = (uint8_t)(b >> 0);
+ if (c->bb_c_s >= 16)
+ {
+ p[1] = (uint8_t)(b >> 8);
+ if (c->bb_c_s >= 32)
+ {
+ p[2] = (uint8_t)(b >> 16);
+ p[3] = (uint8_t)(b >> 24);
+ if (c->bb_c_s == 64)
+ {
+ p[4] = (uint8_t)(b >> 32);
+ p[5] = (uint8_t)(b >> 40);
+ p[6] = (uint8_t)(b >> 48);
+ p[7] = (uint8_t)(b >> 56);
+ }
+ }
+ }
+}
+
+
+static void bbPutBit(struct ucl_compress *c, unsigned bit)
+{
+ assert(bit == 0 || bit == 1);
+ assert(c->bb_k <= c->bb_c_s);
+
+ if (c->bb_k < c->bb_c_s)
+ {
+ if (c->bb_k == 0)
+ {
+ assert(c->bb_p == NULL);
+ c->bb_p = c->bb_op;
+ c->bb_op += c->bb_c_s8;
+ }
+ assert(c->bb_p != NULL);
+ assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+ c->bb_b = (c->bb_b << 1) + bit;
+ c->bb_k++;
+ }
+ else
+ {
+ assert(c->bb_p != NULL);
+ assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+ bbWriteBits(c);
+ c->bb_p = c->bb_op;
+ c->bb_op += c->bb_c_s8;
+ c->bb_b = bit;
+ c->bb_k = 1;
+ }
+}
+
+
+static void bbPutByte(struct ucl_compress *c, unsigned b)
+{
+ /**printf("putbyte %p %p %x (%d)\n", op, bb_p, x, bb_k);*/
+ assert(c->bb_p == NULL || c->bb_p + c->bb_c_s8 <= c->bb_op);
+ *c->bb_op++ = (uint8_t)(b);
+}
+
+static void bbFlushBits(struct ucl_compress *c, unsigned filler_bit)
+{
+ if (c->bb_k > 0)
+ {
+ assert(c->bb_k <= c->bb_c_s);
+ while (c->bb_k != c->bb_c_s)
+ bbPutBit(c, filler_bit);
+ bbWriteBits(c);
+ c->bb_k = 0;
+ }
+ c->bb_p = NULL;
+}
+
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static void code_prefix_ss11(struct ucl_compress *c, uint32_t i)
+{
+ if (i >= 2)
+ {
+ uint32_t t = 4;
+ i += 2;
+ do {
+ t <<= 1;
+ } while (i >= t);
+ t >>= 1;
+ do {
+ t >>= 1;
+ bbPutBit(c, (i & t) ? 1 : 0);
+ bbPutBit(c, 0);
+ } while (t > 2);
+ }
+ bbPutBit(c, (unsigned)i & 1);
+ bbPutBit(c, 1);
+}
+
+static void
+code_match(struct ucl_compress *c, unsigned int m_len, const unsigned int m_off)
+
+{
+ while (m_len > c->conf.max_match)
+ {
+ code_match(c, c->conf.max_match - 3, m_off);
+ m_len -= c->conf.max_match - 3;
+ }
+
+ c->match_bytes += m_len;
+ if (m_len > c->result[3])
+ c->result[3] = m_len;
+ if (m_off > c->result[1])
+ c->result[1] = m_off;
+
+ bbPutBit(c, 0);
+
+ if (m_off == c->last_m_off)
+ {
+ bbPutBit(c, 0);
+ bbPutBit(c, 1);
+ }
+ else
+ {
+ code_prefix_ss11(c, 1 + ((m_off - 1) >> 8));
+ bbPutByte(c, (unsigned)m_off - 1);
+ }
+ m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
+ if (m_len >= 4)
+ {
+ bbPutBit(c,0);
+ bbPutBit(c,0);
+ code_prefix_ss11(c, m_len - 4);
+ }
+ else
+ {
+ bbPutBit(c, m_len > 1);
+ bbPutBit(c, (unsigned)m_len & 1);
+ }
+
+ c->last_m_off = m_off;
+}
+
+static void
+code_run(struct ucl_compress *c, const uint8_t *ii, unsigned int lit)
+{
+ if (lit == 0)
+ return;
+ c->lit_bytes += lit;
+ if (lit > c->result[5])
+ c->result[5] = lit;
+ do {
+ bbPutBit(c, 1);
+ bbPutByte(c, *ii++);
+ } while (--lit > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+len_of_coded_match(struct ucl_compress *c, unsigned int m_len, unsigned int
+ m_off)
+
+{
+ int b;
+ if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+ || m_off > c->conf.max_offset)
+ return -1;
+ assert(m_off > 0);
+
+ m_len = m_len - 2 - (m_off > M2_MAX_OFFSET);
+
+ if (m_off == c->last_m_off)
+ b = 1 + 2;
+ else
+ {
+ b = 1 + 10;
+ m_off = (m_off - 1) >> 8;
+ while (m_off > 0)
+ {
+ b += 2;
+ m_off >>= 1;
+ }
+ }
+
+ b += 2;
+ if (m_len < 3)
+ return b;
+ m_len -= 3;
+
+ do {
+ b += 2;
+ m_len >>= 1;
+ } while (m_len > 0);
+
+ return b;
+}
+
+int ucl_nrv2b_99_compress(
+ const uint8_t *in, unsigned long in_len,
+ uint8_t *out, unsigned long *out_len,
+ unsigned int *result)
+{
+ const uint8_t *ii;
+ unsigned int lit;
+ unsigned int m_len, m_off;
+ struct ucl_compress c_buffer;
+ struct ucl_compress * const c = &c_buffer;
+ struct ucl_swd *swd;
+ unsigned int result_buffer[16];
+ int r;
+
+/* max compression */
+#define SC_TRY_LAZY 2
+#define SC_GOOD_LENGTH F
+#define SC_MAX_LAZY F
+#define SC_NICE_LENGTH F
+#define SC_MAX_CHAIN 4096
+#define SC_FLAGS 1
+#define SC_MAX_OFFSET N
+
+ memset(c, 0, sizeof(*c));
+ c->ip = c->in = in;
+ c->in_end = in + in_len;
+ c->out = out;
+ c->result = result ? result : result_buffer;
+ memset(c->result, 0, 16*sizeof(*c->result));
+ c->result[0] = c->result[2] = c->result[4] = UINT_MAX;
+ result = NULL;
+ memset(&c->conf, 0xff, sizeof(c->conf));
+ r = bbConfig(c, ENDIAN, BITSIZE);
+ if (r == 0)
+ r = bbConfig(c, c->conf.bb_endian, c->conf.bb_size);
+ if (r != 0)
+ return UCL_E_INVALID_ARGUMENT;
+ c->bb_op = out;
+
+ ii = c->ip; /* point to start of literal run */
+ lit = 0;
+
+
+ swd = (struct ucl_swd *) malloc(sizeof(*swd));
+ if (!swd)
+ return UCL_E_OUT_OF_MEMORY;
+
+ swd->f = F;
+ swd->n = N;
+ if (in_len >= 256 && in_len < swd->n)
+ swd->n = in_len;
+ if (swd->f < 8 || swd->n < 256)
+ return UCL_E_INVALID_ARGUMENT;
+
+ r = init_match(c,swd,NULL,0, SC_FLAGS);
+ if (r != UCL_E_OK)
+ {
+ free(swd);
+ return r;
+ }
+ if (SC_MAX_CHAIN > 0)
+ swd->max_chain = SC_MAX_CHAIN;
+ if (SC_NICE_LENGTH > 0)
+ swd->nice_length = SC_NICE_LENGTH;
+ if (c->conf.max_match < swd->nice_length)
+ swd->nice_length = c->conf.max_match;
+
+ c->last_m_off = 1;
+ r = find_match(c,swd,0,0);
+ if (r != UCL_E_OK)
+ return r;
+ while (c->look > 0)
+ {
+ unsigned int ahead;
+ unsigned int max_ahead;
+ int l1, l2;
+
+ c->codesize = c->bb_op - out;
+
+ m_len = c->m_len;
+ m_off = c->m_off;
+
+ assert(c->bp == c->ip - c->look);
+ assert(c->bp >= in);
+ if (lit == 0)
+ ii = c->bp;
+ assert(ii + lit == c->bp);
+ assert(swd->b_char == *(c->bp));
+
+ if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+ || m_off > c->conf.max_offset)
+ {
+ /* a literal */
+ lit++;
+ swd->max_chain = SC_MAX_CHAIN;
+ r = find_match(c,swd,1,0);
+ assert(r == 0);
+ continue;
+ }
+
+ /* a match */
+ assert_match(swd,m_len,m_off);
+
+ /* shall we try a lazy match ? */
+ ahead = 0;
+ if (SC_TRY_LAZY <= 0 || m_len >= SC_MAX_LAZY || m_off ==
+ c->last_m_off)
+
+ {
+ /* no */
+ l1 = 0;
+ max_ahead = 0;
+ }
+ else
+ {
+ /* yes, try a lazy match */
+ l1 = len_of_coded_match(c,m_len,m_off);
+ assert(l1 > 0);
+ max_ahead = SC_TRY_LAZY;
+ if ((m_len - 1) < max_ahead) {
+ max_ahead = m_len -1;
+ }
+ }
+
+ while (ahead < max_ahead && c->look > m_len)
+ {
+ if (m_len >= SC_GOOD_LENGTH)
+ swd->max_chain = SC_MAX_CHAIN >> 2;
+ else
+ swd->max_chain = SC_MAX_CHAIN;
+ r = find_match(c,swd,1,0);
+ ahead++;
+
+ assert(r == 0);
+ assert(c->look > 0);
+ assert(ii + lit + ahead == c->bp);
+
+ if (c->m_len < 2)
+ continue;
+ l2 = len_of_coded_match(c,c->m_len,c->m_off);
+ if (l2 < 0)
+ continue;
+ if (l1 + (int)(ahead + c->m_len - m_len) * 5 > l2 +
+ (int)(ahead) * 9)
+ {
+ c->lazy++;
+ assert_match(swd,c->m_len,c->m_off);
+ lit += ahead;
+ assert(ii + lit == c->bp);
+ goto lazy_match_done;
+ }
+ }
+
+ assert(ii + lit + ahead == c->bp);
+
+ /* 1 - code run */
+ code_run(c,ii,lit);
+ lit = 0;
+
+ /* 2 - code match */
+ code_match(c,m_len,m_off);
+ swd->max_chain = SC_MAX_CHAIN;
+ r = find_match(c,swd,m_len,1+ahead);
+ assert(r == 0);
+
+ lazy_match_done: ;
+ }
+
+ /* store final run */
+ code_run(c,ii,lit);
+
+ /* EOF */
+ bbPutBit(c, 0);
+ code_prefix_ss11(c, 0x1000000U);
+ bbPutByte(c, 0xff);
+
+ bbFlushBits(c, 0);
+
+ assert(c->textsize == in_len);
+ c->codesize = c->bb_op - out;
+ *out_len = c->bb_op - out;
+
+#if 0
+ printf("%7ld %7ld -> %7ld %7ld %7ld %ld (max: %d %d %d)\n",
+ (long) c->textsize, (long) in_len, (long) c->codesize,
+ c->match_bytes, c->lit_bytes, c->lazy,
+ c->result[1], c->result[3], c->result[5]);
+#endif
+ assert(c->lit_bytes + c->match_bytes == in_len);
+
+ swd_exit(swd);
+ free(swd);
+
+ return UCL_E_OK;
+}
+
+
+void Encode(void) /* compression */
+{
+ uint8_t *in, *out;
+ unsigned long in_len, out_len;
+ uint32_t tw;
+ int r;
+ fseek(infile, 0, SEEK_END);
+ in_len = ftell(infile);
+#ifdef VERBOSE
+ if ((signed long)in_len < 0)
+ Fprintf((stderr, "Errno: %d", errno));
+#endif
+#if UCLPACK_COMPAT
+ {
+ uint8_t byte;
+ if (fwrite(magic, sizeof(magic), 1, outfile) != 1)
+ Error("Can't write.");
+ tw = htonl(0); /* flags */
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write.");
+ byte = 0x2b; /* method */
+ if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+ Error("Can't write.");
+ byte = 10; /* level */
+ if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+ Error("Can't write.");
+ tw = htonl(256*1024); /* block_size */
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write.");
+ tw = htonl(in_len);
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write."); /* output size of text */
+ }
+#else
+ tw = host_to_i86ul(in_len);
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write."); /* output size of text */
+#endif
+ if (in_len == 0)
+ return;
+ rewind(infile);
+
+ in = malloc(in_len);
+ out_len = in_len + (in_len/8) + 256;
+ out = malloc(out_len);
+ if (!in || !out) {
+ Error("Can't malloc");
+ }
+ if (fread(in, in_len, 1, infile) != 1) {
+ Error("Can't read");
+ }
+ r = ucl_nrv2b_99_compress(in, in_len, out, &out_len, 0 );
+ if (r != UCL_E_OK)
+ Error("Compression failure\n");
+#if UCLPACK_COMPAT
+ tw = htonl(out_len);
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write."); /* file size of text */
+
+#endif
+ if (fwrite(out, out_len, 1, outfile) != 1) {
+ Error("Write error\n");
+ }
+#if UCLPACK_COMPAT
+ tw = htonl(0); /* EOF marker */
+ if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+ Error("Can't write.");
+
+#endif
+
+#ifdef LONG_REPORT
+ Fprintf((stdout, "input size %ld bytes\n", in_len));
+ Fprintf((stdout, "output size %ld bytes\n", out_len));
+ Fprintf((stdout, "input/output %.3f\n", (double)in_len / out_len));
+#else
+ Fprintf((stdout, "input/output = %ld/%ld = %.3f\n", in_len, out_len,
+ (double)in_len / out_len));
+#endif
+
+}
+
+#endif
+
+#ifdef DECODE
+
+#define GETBIT_8(bb, src, ilen) \
+ (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)
+
+#define GETBIT_LE16(bb, src, ilen) \
+ (bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1))
+
+#define GETBIT_LE32(bb, src, ilen) \
+ (bc > 0 ? ((bb>>--bc)&1) : (bc=31,\
+ bb=*(const uint32_t *)((src)+ilen),ilen+=4,(bb>>31)&1))
+
+#define GETBIT_LE64(bb, src, ilen) \
+ (bc > 0 ? ((bb>>--bc)&1) : (bc=63, \
+ bb=*(const uint64_t *)((src)+ilen),ilen+=8,(bb>>63)&1))
+
+#if ENDIAN == 0 && BITSIZE == 8
+#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 16
+#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 32
+#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 64
+#define GETBIT(bb, src, ilen) GETBIT_LE64(bb, src, ilen)
+#endif
+#ifndef GETBIT
+#error "Bad Combination of ENDIAN and BITSIZE values specified"
+#endif
+
+#undef SAFE
+
+#ifdef SAFE
+#define FAIL(x,r) if (x) { Error(r); }
+#else
+#define FAIL(x,r)
+#endif
+
+void Decode(void) /* recover */
+{
+ uint32_t tw;
+ uint8_t *src, *dst;
+ unsigned long max_src_len, src_len, dst_len;
+ unsigned long ilen = 0, olen = 0, last_m_off = 1;
+#if BITSIZE <= 32
+ uint32_t bb = 0;
+#elif BITSIZE == 64
+ uint64_t bb = 0;
+#endif
+ unsigned bc = 0;
+#if UCLPACK_COMPAT
+ if (fseek(infile, sizeof(magic) + sizeof(tw) + 1 + 1 + sizeof(tw),
+ SEEK_SET) != 0)
+
+ Error("Seek Error");
+ if (fread(&tw, sizeof(tw), 1, infile) < 1)
+ Error("Can't read"); /* read size of text */
+ dst_len = ntohl(tw);
+ if (fread(&tw, sizeof(tw), 1, infile) < 1)
+ Error("Can't read"); /* read size of file */
+ max_src_len = ntohl(tw);
+#else
+ if (fread(&tw, sizeof(tw), 1, infile) < 1)
+ Error("Can't read"); /* read size of text */
+ dst_len = i86ul_to_host(tw);
+ max_src_len = dst_len + (dst_len/8) + 256;
+#endif
+ if (dst_len == 0)
+ return;
+ dst = malloc(dst_len);
+ if (!dst)
+ Error("Can't malloc");
+ src = malloc(max_src_len);
+ if (!src)
+ Error("Can't malloc");
+ src_len = fread(src, 1, max_src_len, infile);
+ if (src_len <= 0)
+ Error("Can't read");
+
+ for(;;) {
+ unsigned int m_off, m_len;
+ while(GETBIT(bb, src, ilen)) {
+ FAIL(ilen >= src_len, "input overrun");
+ FAIL(olen >= dst_len, "output overrun");
+ dst[olen++] = src[ilen++];
+ }
+ m_off = 1;
+ do {
+ m_off = m_off*2 + GETBIT(bb, src, ilen);
+ FAIL(ilen >= src_len, "input overrun");
+ FAIL(m_off > 0xffffffU +3, "lookbehind overrun");
+ } while (!GETBIT(bb, src, ilen));
+ if (m_off == 2)
+ {
+ m_off = last_m_off;
+ }
+ else
+ {
+ FAIL(ilen >= src_len, "input overrun");
+ m_off = (m_off - 3)*256 + src[ilen++];
+ if (m_off == 0xffffffffU)
+ break;
+ last_m_off = ++m_off;
+ }
+ m_len = GETBIT(bb, src, ilen);
+ m_len = m_len*2 + GETBIT(bb, src, ilen);
+ if (m_len == 0)
+ {
+ m_len++;
+ do {
+ m_len = m_len*2 + GETBIT(bb, src, ilen);
+ FAIL(ilen >= src_len, "input overrun");
+ FAIL(m_len >= dst_len, "output overrun");
+ } while(!GETBIT(bb, src, ilen));
+ m_len += 2;
+ }
+ m_len += (m_off > 0xd00);
+ FAIL(olen + m_len > dst_len, "output overrun");
+ FAIL(m_off > olen, "lookbeind overrun");
+ {
+ const uint8_t *m_pos;
+ m_pos = dst + olen - m_off;
+ dst[olen++] = *m_pos++;
+ do {
+ dst[olen++] = *m_pos++;
+ } while(--m_len > 0);
+ }
+ }
+ FAIL(ilen < src_len, "input not consumed");
+ FAIL(ilen > src_len, "input overrun");
+ assert(ilen == src_len);
+ Fprintf((stderr, "%12ld\n", olen));
+ if (dst_len != olen) {
+ fprintf(stderr, "length != expected length\n");
+ }
+ if (fwrite(dst, olen, 1, outfile) != 1)
+ Error("Write error\n");
+ free(src);
+ free(dst);
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+ char *s;
+ FILE *f;
+ int c;
+
+ if (argc == 2) {
+ outfile = stdout;
+ if ((f = tmpfile()) == NULL) {
+ perror("tmpfile");
+ return EXIT_FAILURE;
+ }
+ while ((c = getchar()) != EOF)
+ fputc(c, f);
+ rewind(infile = f);
+ }
+ else if (argc != 4) {
+ Fprintf((stderr, "'nrv2b e file1 file2' encodes file1 into file2.\n"
+ "'nrv2b d file2 file1' decodes file2 into file1.\n"));
+ return EXIT_FAILURE;
+ }
+ if (argc == 4) {
+ if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+ || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
+ || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+ Fprintf((stderr, "??? %s\n", s));
+ return EXIT_FAILURE;
+ }
+ }
+ if (toupper(*argv[1]) == 'E')
+ Encode();
+ else
+ Decode();
+ fclose(infile);
+ fclose(outfile);
+ return EXIT_SUCCESS;
+}
+#endif
diff --git a/src/util/swapdevids.pl b/src/util/swapdevids.pl
new file mode 100755
index 0000000..c6255ae
--- /dev/null
+++ b/src/util/swapdevids.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+#
+# Program to reverse the device identifier IDs in the PCIR and PnP
+# structures in a ROM for old non-compliant BIOSes
+#
+# GPL, Ken Yap 2001
+#
+
+use bytes;
+
+use IO::Seekable;
+
+sub swaplocs ($$$)
+{
+ my ($dataref, $loc1, $loc2) = @_;
+ my ($t);
+
+ $t = substr($$dataref, $loc1, 1);
+ substr($$dataref, $loc1, 1) = substr($$dataref, $loc2, 1);
+ substr($$dataref, $loc2, 1) = $t;
+}
+
+sub printdevids ($$)
+{
+ my ($dataref, $loc) = @_;
+
+ return (sprintf "%02x %02x %02x", unpack('C3', substr($$dataref, $loc, 3)));
+}
+
+$#ARGV >= 0 or die "Usage: $0 romimage\n";
+$file = $ARGV[0];
+open(F, "+<$file") or die "$file: $!\n";
+binmode(F);
+# Handle up to 64kB ROM images
+$len = read(F, $data, 64*1024);
+defined($len) or die "$file: $!\n";
+substr($data, 0, 2) eq "\x55\xAA" or die "$file: Not a boot ROM image\n";
+($pci, $pnp) = unpack('v2', substr($data, 0x18, 4));
+($pci < $len and $pnp < $len) or die "$file: Not a PCI PnP ROM image\n";
+(substr($data, $pci, 4) eq 'PCIR' and substr($data, $pnp, 4) eq '$PnP')
+ or die "$file: No PCI and PNP structures, not a PCI PNP ROM image\n";
+&swaplocs(\$data, $pci+13, $pci+15);
+&swaplocs(\$data, $pnp+18, $pnp+20);
+seek(F, 0, SEEK_SET) or die "$file: Cannot seek to beginning\n";
+print F $data;
+close(F);
+print "PCI devids now: ", &printdevids(\$data, $pci+13), "\n";
+print "PnP devids now: ", &printdevids(\$data, $pnp+18), "\n";
+exit(0);
diff --git a/src/util/zfilelen.pl b/src/util/zfilelen.pl
new file mode 100755
index 0000000..1f58ff9
--- /dev/null
+++ b/src/util/zfilelen.pl
@@ -0,0 +1,8 @@
+#!/usr/bin/perl -w
+
+use bytes;
+
+local $/;
+$_ = <>;
+print length($_);
+exit;