Gitweb links:

...log 
http://git.netsurf-browser.org/toolchains.git/shortlog/e5e2f2da388b1e5efb02479dbab06d0fb801ad65
...commit 
http://git.netsurf-browser.org/toolchains.git/commit/e5e2f2da388b1e5efb02479dbab06d0fb801ad65
...tree 
http://git.netsurf-browser.org/toolchains.git/tree/e5e2f2da388b1e5efb02479dbab06d0fb801ad65

The branch, upstream/squeeze has been created
        at  e5e2f2da388b1e5efb02479dbab06d0fb801ad65 (commit)

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/toolchains.git/commit/?id=e5e2f2da388b1e5efb02479dbab06d0fb801ad65
commit e5e2f2da388b1e5efb02479dbab06d0fb801ad65
Author: John-Mark Bell <[email protected]>
Commit: John-Mark Bell <[email protected]>

    Upstream squeeze git.d54d441

diff --git a/CastleLicence.txt b/CastleLicence.txt
new file mode 100644
index 0000000000..721bb3e881
--- /dev/null
+++ b/CastleLicence.txt
@@ -0,0 +1,159 @@
+  * [topbar]   [topba] 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 *   *   [topbar]          *
+[l]                                            Welcome to 
www.castle-technology.co.uk                                                   
[r]
+    Castle
+    Technology         
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 *   *   [bottombar]       *
+    Ltd.               
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 *     * [topbar]          *
+               [diag]                                  Castle Technology Ltd   
                               [r] [l]                   [r]
+
+  * [bottomb]          
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 *     * [bottombar]       *
+*   [topbar]              *      
+[l]                       [r]
+                                                                        
+*   [bottombar]           *         Download as a pdf file here
+*   [topbar]              *
+[l]                       [r]       LICENCE TERMS AND CONDITIONS FOR COPYING, 
DISTRIBUTION AND MODIFICATION
+                                    OF RISC OS AND ITS DERIVATIVES
+*   [bottombar]           *
+                                    This licence agreement ("Licence") is 
between Castle Technology Limited
+                                    ("Castle") and any person ("You", "Your") 
who exercises any of the legal
+                                    rights over any components of the computer 
operating system known as
+                                    RISC OS granted by Castle in this Licence. 
The phrase "RISC OS" used in
+                                    this Licence refers to those components of 
version 5.0 of RISC OS that
+                                   Castle chooses to release from time to time 
and any subsequent release of
+                                    RISC OS which is made generally available 
by Castle pursuant to this
+                                    Licence. The phrase "Derivative Work" 
means any derivative work which is
+                                    based on, or derived from, RISC OS or any 
part of RISC OS (whether by
+                                    modification or translation) and any work 
subsequently derived from such
+                                   Derivative Work or any part of it PROVIDED 
THAT such work is only intended
+                                  to be used in conjunction with an embodiment 
(whether physical or emulated)
+                                    of one or more versions of the ARM 
processor architecture. By exercising
+                                    any of the rights granted to You by Castle 
pursuant to this Licence You
+                                  indicate Your acceptance of all of the terms 
and conditions of this Licence
+                                    which shall therefore be legally binding 
on You.
+
+                                    1 LICENCE GRANT
+                                    1.1 Subject to the restrictions set out in 
the remainder of this Licence
+                                   Castle hereby grants to You a non-exclusive 
royalty free worldwide licence
+                                   to use, copy and distribute the RISC OS 
source code and object code in any
+                                   medium PROVIDED THAT you ensure that each 
copy You distribute incorporates
+                                    the text of, or an Internet link to, this 
Licence.
+                                 1.2 You may modify your copy of RISC OS or 
any part of it (and any Derivative
+                                    Work or any part of it) to create a 
Derivative Work and You may copy and
+                                   distribute the source code and object code 
of such Derivative Work in any
+                                    medium PROVIDED THAT you meet all of the 
following conditions:
+                                   1.2.1 You shall ensure that each Derivative 
Work You distribute carries a
+                                   notice stating that it is ultimately 
derived from RISC OS and the date of
+                                    Your modifications;
+                                   1.2.2 You shall ensure that each Derivative 
Work You distribute as source
+                                  code prominently carries the following 
header text in each individual source
+                                    code file:
+                                 This source code in this file is licensed to 
You by Castle Technology Limited
+                                  ("Castle") and its licensors on contractual 
terms and conditions ("Licence")
+                                    which entitle you freely to modify and/or 
to distribute this source code
+                                    subject to Your compliance with the terms 
of the Licence.
+                                    This source code has been made available 
to You without any warranties
+                                   whatsoever. Consequently, Your use, 
modification and distribution of this
+                                 source code is entirely at Your own risk and 
neither Castle, its licensors nor
+                                  any other person who has contributed to this 
source code shall be liable to
+                                    You for any loss or damage which You may 
suffer as a result of Your use,
+                                    modification or distribution of this 
source code.
+                                  Full details of Your rights and obligations 
are set out in the Licence. You
+                                   should have received a copy of the Licence 
with this source code file. If
+                                   You have not received a copy, the text of 
the Licence is available online
+                                    at 
www.castle-technology.co.uk/riscosbaselicence.htm
+                                    1.2.3 You shall ensure that each 
Derivative Work distributed by You is
+                                   distributed and licensed in its entirety at 
no charge on the terms of this
+                                Licence to any third party who is prepared to 
accept the terms of this Licence.
+                                    If any part of any Derivative Work 
distributed by You can reasonably be
+                                 considered an independent and separate work 
then this Licence shall not apply
+                                 to any such part where You distribute such 
part as an independent and separate
+                                    work;
+                                  1.2.4 You undertake, in respect of each 
Derivative Work that You distribute,
+                                 to make the whole source code of every 
individual component of the Derivative
+                                 Work available for unrestricted access by 
third parties by including a copy of
+                                 the source code with Your distribution and/or 
by uploading the source code to
+                                    the official RISC OS source code 
repository at
+                                    www.riscosopen.org/content/sources
+                                  1.2.5 You hereby grant to Castle a royalty 
free worldwide licence (with the
+                                   right to grant sub-licences) to incorporate 
into RISC OS or any Derivative
+                                  Work produced by Castle, the whole or any 
part of any Derivative Work which                       
+                                    You create or distribute pursuant to this 
Licence. You acknowledge that
+                                    Castle may make the whole or any part of 
RISC OS or any Derivative Work
+                                   produced by Castle available to OEM 
organisations on commercial terms for
+                                 incorporation into hardware products intended 
for sale. Your hereby waive any
+                                   moral rights You may have in any part of 
any Derivative Work which Castle
+                                    so incorporates into RISC OS or any 
Derivative Work produced by Castle.
+                                    Nothing in this Clause 1.2.5 shall oblige 
Castle to incorporate into
+                                  RISC OS or any Derivative Work produced by 
Castle any part of any Derivative
+                                    Work which You create or distribute 
pursuant to this Licence.
+
+                                    2 LICENCE RESTRICTIONS
+                                    2.1 You may not copy, modify, sublicense 
or distribute RISC OS or any
+                                  Derivative Work except as expressly provided 
under this Licence. Any attempt
+                                   by You otherwise to copy, modify, 
sublicense or distribute RISC OS or any
+                                   Derivative Work shall be void and shall 
lead to the automatic termination
+                                  of Your rights under this Licence but such 
termination shall not affect the
+                                  rights of any person to whom You have 
distributed RISC OS or any Derivative
+                                  Work provided they continue to comply with 
the terms and conditions of this
+                                    Licence.
+                                 2.2 You may not impose on any third party to 
whom You have distributed copies
+                                  of RISC OS or any Derivative Work any 
licence restrictions other than those
+                                    set out in this Licence.
+                                 2.3 If, as a consequence of any court 
judgment, allegation of infringement of
+                                 any proprietary right or any other reason You 
are unable to comply fully with
+                                    the terms and conditions of this Licence 
then You shall refrain from
+                                    distributing RISC OS or such Derivative 
Works (as appropriate) for the
+                                    duration of such non-compliance.
+                                 2.4 This Licence is not an OEM licence. 
Consequently, You may not incorporate
+                                  or embed RISC OS or any Derivative Work or 
any part of them in any hardware
+                                  product which is intended for commercial 
sale, nor may You distribute, sell,
+                                    supply or otherwise dispose of any such 
hardware product unless You have
+                                   obtained the prior written consent of 
Castle. Castle is generally prepared
+                                    to grant OEM licences on commercial terms 
to any person who wishes to
+                                  incorporate or embed RISC OS or any 
Derivative Work or any part of them into
+                                    a hardware product and/or to sell, supply 
or otherwise dispose of such
+                                    hardware products. Details of Castle's 
standard OEM licensing terms are
+                                    available from Castle's website at
+                                    
www.castle-techology.co.uk/riscosoemlicence.htm or
+                                    by email from 
[email protected]
+
+                                    3 NO WARRANTY
+                                    3.1 RISC OS AND ALL DERIVATIVE WORKS ARE 
SUPPLIED "AS IS" WITHOUT ANY
+                                  WARRANTIES OF ANY KIND WHETHER EXPRESS OR 
IMPLIED INCLUDING BUT NOT LIMITED
+                                   TO ANY IMPLIED WARRANTIES OR CONDITIONS 
THAT RISC OS AND/OR ANY DERIVATIVE
+                                    WORK IS ERROR FREE, FIT FOR ANY PARTICULAR 
PURPOSE OR THAT ITS USE,
+                                    MODIFICATION OR DISTRIBUTION SHALL NOT 
LEAD TO INFRINGEMENT OF ANY THIRD
+                                    PARTY PROPRIETARY RIGHTS. ALL IMPLIED 
WARRANTIES AND CONDITIONS ARE
+                                    EXCLUDED TO THE EXTENT PERMITTED BY LAW.
+                                    4 DISCLAIMER OF LIABILITY
+                                    4.1 IN NO EVENT SHALL CASTLE OR ANY PERSON 
WHO HAS MODIFIEID AND/OR
+                                    DISTRIBUTED THE WHOLE OR ANY PART OF RISC 
OS OR ANY DERIVATIVE WORK IN
+                                    ACCORDANCE WITH THIS LICENCE BE LIABLE TO 
YOU FOR ANY LOSS OR DAMAGE
+                                    WHATSOEVER ARISING OUT OF YOUR USE, 
MODIFICATION OR DISTRIBUTION OR YOUR
+                                    INABILITY TO USE, MODIFY OR DISTRIBUTE 
RISC OS OR ANY DERIVATIVE WORK OR
+                                    YOUR EXERCISE OF ANY OF THE RIGHTS GRANTED 
UNDER THIS LICENCE (INCLUDING
+                                    BUT NOT LIMITED TO LOSS OF OR DAMAGE TO 
YOUR OR ANY THIRD PARTY'S DATA
+                                    CAUSED BY ANY DEFECT IN RISC OS OR ANY 
DERIVATIVE WORK OR ANY
+                                    INCOMPATIBILITY BETWEEN RISC OS OR ANY 
DERIVATIVE WORK AND ANY OTHER
+                                    SOFTWARE). ALL SUCH LIABILITIES ARE 
EXCLUDED TO THE MAXIMUM EXTENT
+                                    PERMITTED BY APPLICABLE LAW.
+
+
+                                    Document No.1852007 version 1 dated 18th 
May 2007
+
+
+
+
+
+
+
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+ © Castle Technology Ltd 2001-2011. Castle is a trading name of Castle
+  Technology Ltd. IYONIX and the IYONIX logo are trademarks of Castle
+                            Technology Ltd.
+RISC OS is © Castle Technology Ltd. XScale is a registered trademark of
+Intel Corporation. ARM is a registered trademark of ARM Ltd. All other
+                     trademarks acknowledged. E&OE
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..8ea781031f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,51 @@
+# This makefile attempts to build a squeeze executable which can be used
+# on Linux to compress RISC OS binaries.
+
+GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/arm-unknown-riscos/cross/bin
+
+PREFIX ?= $(GCCSDK_INSTALL_CROSSBIN)/..
+
+PERL ?= perl
+export PERL
+
+MAKEHEADER = $(PERL) makeheader.pl
+
+CC := gcc
+ASASM := $(GCCSDK_INSTALL_CROSSBIN)/asasm
+OBJCOPY := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*objcopy)
+
+CFLAGS := $(CFLAGS) -O2
+
+all: squeeze
+
+install: squeeze
+       mkdir -p $(DESTDIR)$(PREFIX)/bin
+       install -m 755 squeeze $(DESTDIR)$(PREFIX)/bin/squeeze
+
+clean:
+       $(RM) squeeze squeeze.o unsqueeze.o unsqrm.o
+       $(RM) unsqueeze1.h unsqrm1.h unsqueeze.bin unsqrm.bin
+
+distclean: clean
+       $(RM) *~
+
+squeeze: squeeze.o
+       $(CC) $(CFLAGS) -o $@ $^
+
+squeeze.o: squeeze.c unsqueeze1.h unsqrm1.h
+       $(CC) $(CFLAGS) -o $@ -c $<
+
+unsqrm1.h: unsqrm.bin
+       $(MAKEHEADER) unsqueeze_base unsqueeze_limit unsqueeze_end $< $@
+
+unsqueeze1.h: unsqueeze.bin
+       $(MAKEHEADER) UnSqueeze_UnSqueezeBase '' UnSqueeze_UnSqueezeLimit $< $@
+
+unsqueeze.bin: unsqueeze.o
+       $(OBJCOPY) -O binary -j 'M2$$$$Code' $< $@
+
+unsqrm.bin: unsqrm.o
+       $(OBJCOPY) -O binary -j unsqueeze $< $@
+
+%.o:%.s
+       $(ASASM) -o $@ -elf -32 $<
diff --git a/VersionNum b/VersionNum
new file mode 100644
index 0000000000..5f76dd3c6a
--- /dev/null
+++ b/VersionNum
@@ -0,0 +1,23 @@
+/* (5.12)
+ *
+ * This file is automatically maintained by srccommit, do not edit manually.
+ * Last processed by srccommit version: 1.1.
+ *
+ */
+#define Module_MajorVersion_CMHG        5.12
+#define Module_MinorVersion_CMHG        
+#define Module_Date_CMHG                05 Feb 2012
+
+#define Module_MajorVersion             "5.12"
+#define Module_Version                  512
+#define Module_MinorVersion             ""
+#define Module_Date                     "05 Feb 2012"
+
+#define Module_ApplicationDate          "05-Feb-12"
+
+#define Module_ComponentName            "squeeze"
+#define Module_ComponentPath            "castle/RiscOS/Tools/Sources/squeeze"
+
+#define Module_FullVersion              "5.12"
+#define Module_HelpVersion              "5.12 (05 Feb 2012)"
+#define Module_LibraryVersionInfo       "5:12"
diff --git a/asmcall.s b/asmcall.s
new file mode 100644
index 0000000000..1523187289
--- /dev/null
+++ b/asmcall.s
@@ -0,0 +1,63 @@
+; This source code in this file is licensed to You by Castle Technology
+; Limited ("Castle") and its licensors on contractual terms and conditions
+; ("Licence") which entitle you freely to modify and/or to distribute this
+; source code subject to Your compliance with the terms of the Licence.
+; 
+; This source code has been made available to You without any warranties
+; whatsoever. Consequently, Your use, modification and distribution of this
+; source code is entirely at Your own risk and neither Castle, its licensors
+; nor any other person who has contributed to this source code shall be
+; liable to You for any loss or damage which You may suffer as a result of
+; Your use, modification or distribution of this source code.
+; 
+; Full details of Your rights and obligations are set out in the Licence.
+; You should have received a copy of the Licence with this source code file.
+; If You have not received a copy, the text of the Licence is available
+; online at www.castle-technology.co.uk/riscosbaselicence.htm
+; 
+; > s.asmcall RCC 24-Mar-88
+;
+; This makes it possible to call code which scribbles on all the
+; registers with a standard ARM procedure call, e.g. from C.
+;
+; If the code called also scribbles on lk, you must regain control
+; by forcing it to branch to asmcall_exit.
+;
+; NB it relies on scribbling on memory addressed pc-relative, so it
+; won't work if the code area is not writable.
+;
+
+r0  RN 0
+r1  RN 1
+r2  RN 2
+r3  RN 3
+r4  RN 4
+ip  RN 12
+lk  RN 14
+pc  RN 15
+
+    AREA |C$$code|, CODE, READONLY
+    EXPORT  asmcall_call
+    EXPORT  asmcall_exit
+
+asmcall_savedregs
+       DCD     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  ; 11 words for registers
+asmcall_call
+       ;  Enter with r0: thing to call
+       ;             r1, r2, r3: parameters for it
+
+       ADR     ip, asmcall_savedregs
+       STMIA   ip, {r4-lk}
+       MOV     ip, r0
+       MOV     r0, r1
+       MOV     r1, r2
+       MOV     r2, r3
+       MOV     lk, pc
+       MOV     pc, ip
+asmcall_exit
+       NOP             ; 2 spurious instructions here in case the caller
+       NOP             ; forgets to allow for prefetch ...
+       ADR     ip, asmcall_savedregs
+       LDMIA   ip, {r4-lk}
+       MOV     pc, lk
+    END
diff --git a/bin2c.pl b/bin2c.pl
new file mode 100644
index 0000000000..5a60ca9ee7
--- /dev/null
+++ b/bin2c.pl
@@ -0,0 +1,78 @@
+#!/usr/bin/perl
+## -----------------------------------------------------------------------
+##
+##   Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+##
+##   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, Inc., 53 Temple Place Ste 330,
+##   Boston MA 02111-1307, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+#
+# bin2c.pl: binary file to C source converter
+#
+
+eval { use bytes; };
+eval { binmode STDIN; };
+
+($table_name, $pad) = @ARGV;
+
+if ( !defined($table_name) ) {
+    print STDERR "Usage: $0 table_name [pad] < input_file > output_file\n";
+    exit 1;
+}
+
+$pad = 1 if ($pad < 1);
+
+printf "unsigned char %s[] = {\n", $table_name;
+
+$pos = 0;
+$linelen = 8;
+
+$total_len = 0;
+
+while ( ($n = read(STDIN, $data, 4096)) > 0 ) {
+    $total_len += $n;
+    for ( $i = 0 ; $i < $n ; $i++ ) {
+       $byte = substr($data, $i, 1);
+       if ( $pos >= $linelen ) {
+           print ",\n\t";
+           $pos = 0;
+       } elsif ( $pos > 0 ) {
+           print ", ";
+       } else {
+           print "\t";
+       }
+       printf("0x%02x", unpack("C", $byte));
+       $pos++;
+    }
+}
+
+$align = $total_len % $pad;
+if ($align != 0) {
+    $n = $pad - $align;
+    $total_len += $n;
+    for ( $i = 0 ; $i < $n ; $i++ ) {
+       if ( $pos >= $linelen ) {
+           print ",\n\t";
+           $pos = 0;
+       } elsif ( $pos > 0 ) {
+           print ", ";
+       } else {
+           print "\t";
+       }
+       print '0x00';
+       $pos++;
+    }
+}
+
+printf "\n};\n\nunsigned int %s_len = %u;\n", $table_name, $total_len;
+
+@st = stat STDIN;
+
+printf "\nint %s_mtime = %d;\n", $table_name, $st[9];
+
+exit 0;
diff --git a/makeheader.pl b/makeheader.pl
new file mode 100644
index 0000000000..58d587ea31
--- /dev/null
+++ b/makeheader.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my ($basename, $midname, $endname, $infilename, $outfilename) = @ARGV;
+
+my $perl = $ENV{PERL};
+
+my $output_text = `$perl bin2c.pl THINGY < $infilename`;
+
+$output_text =~ s/unsigned char THINGY\[\]/const unsigned char $basename\[\]/;
+
+my $objlen = ($output_text =~ /unsigned int THINGY_len = (\d+)/)[0];
+
+$output_text =~ s/unsigned int THINGY_len = (\d+)/const unsigned char 
\*$endname = $basename + $1/;
+
+my $repltext = "const unsigned char \*$midname = $basename + $objlen - 4;";
+$repltext = "" if ($midname eq '');
+
+$output_text =~ s/int THINGY_mtime = \d+;/$repltext/;
+
+open JELLY, ">", $outfilename;
+
+print JELLY $output_text;
+
+close JELLY;
diff --git a/squeeze.c b/squeeze.c
new file mode 100644
index 0000000000..5d6dc73c1b
--- /dev/null
+++ b/squeeze.c
@@ -0,0 +1,1020 @@
+/* This source code in this file is licensed to You by Castle Technology
+ * Limited ("Castle") and its licensors on contractual terms and conditions
+ * ("Licence") which entitle you freely to modify and/or to distribute this
+ * source code subject to Your compliance with the terms of the Licence.
+ * 
+ * This source code has been made available to You without any warranties
+ * whatsoever. Consequently, Your use, modification and distribution of this
+ * source code is entirely at Your own risk and neither Castle, its licensors
+ * nor any other person who has contributed to this source code shall be
+ * liable to You for any loss or damage which You may suffer as a result of
+ * Your use, modification or distribution of this source code.
+ * 
+ * Full details of Your rights and obligations are set out in the Licence.
+ * You should have received a copy of the Licence with this source code file.
+ * If You have not received a copy, the text of the Licence is available
+ * online at www.castle-technology.co.uk/riscosbaselicence.htm
+ */
+/*
+ * Title:     squeeze - compression of ADFS executable images
+ * Author:    RCC
+ * Copyright: (C) 1987, Acorn Computers Ltd, Cambridge, England.
+ * Date:      03-Nov-87
+ * LastEdit:  28-Mar-88
+             19-Jul-88 just to change the version to 1.00, and date (JSutton)
+             21-Jul-88 remove reference to xpand in help text (JRS)
+             07-Mar-91 add recognition of MOV R0, R0 as well as BLNV $0
+ */
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#ifdef __STDC__
+#  include <string.h>
+#  include <stdlib.h>
+#else
+#  include <strings.h>
+/* extern char *malloc(); */
+/*#  define  DATE      "Mar 07 1991" */
+#endif
+
+#include "VersionNum"
+
+#include <stdio.h>
+#include <time.h>
+#include <signal.h>
+#ifdef __riscos
+#include "CLib/kernel.h"
+#include "CLib/swis.h"
+#else
+typedef struct {
+   int load, exec;       /* load, exec addresses */
+   int start, end;       /* start address/length, end address/attributes */
+} _kernel_osfile_block;
+#endif
+
+//#include "CLX/err.h"
+//#include "CLX/host.h"
+//#include "CLX/hash.h"
+//#include "CLX/wholefls.h"
+
+#ifndef __riscos
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+/*
+ * squeeze takes an ARM executable image file and compresses it, usually
+ * to about half the size, adding decompression code so that the image
+ * will automatically expand itself when it is run.
+ *
+ * For details of the compression scheme, see doc.squeeze.  Briefly,
+ * the image is treated as a sequence of 32-bit words, and each word
+ * is encoded in one of four ways, specified by a 4-bit nibble:
+ *   zero -> nibble 0
+ *   the 7*256 most common word values are encoded with one byte extra as
+ *   an index into a table
+ *   the 7*256 most common upper-3-byte values are encoded with one byte
+ *   extra as index into another table, with the low byte separate
+ *   anything else is given in full as 4 bytes.
+ *
+ * The tables of common values are sorted into ascending order
+ * and encoded in a devious way.
+ */
+
+#define DATE Module_Date
+/* If macro value is empty, expression rewrites to "0 * + 1" which is zero. */
+#if 0 * Module_MinorVersion_CMHG + 1 == 0
+#  define VSN  Module_MajorVersion
+#else
+#  define VSN  Module_MajorVersion " (" Module_MinorVersion ")"
+#endif
+#define BRIEF     "compress an executable ARM-code program"
+#define SELF      "squeeze"
+#define HASHSIZE   (8*1024)
+#define CHUNKSIZE  (16*1024)
+
+#include "squeeze.h"
+
+#if 1
+#include "unsqueeze1.h"
+#include "unsqrm1.h"
+#else
+/*extern void UnSqueeze_FindUnSqueezeCode(int *base, int *limit); */
+extern int UnSqueeze_UnSqueezeBase, UnSqueeze_UnSqueezeLimit;
+extern int unsqueeze_base, unsqueeze_limit, unsqueeze_end;
+#endif
+
+static int verbose;
+static int debug;
+static int force;
+
+static clock_t lastticks;
+
+/*
+ * CLX ickyness
+ */
+
+#define err_fail(X...) do { fprintf(stderr, X); fprintf(stderr, "\n"); 
exit(EXIT_FAILURE); } while(0)
+#define err_report(X...) do { fprintf(stderr, X); fprintf(stderr, "\n"); } 
while (0)
+char host_dir_sep_char() { return '/'; }
+
+int wf_load(char *filename, void *ptr, int len)
+{
+       FILE *f;
+       f = fopen(filename, "rb");
+       if (f == NULL)
+               return -1;
+       if (fread(ptr, 1, len, f) != len) {
+               fclose(f);
+               return -1;
+       }
+       fclose(f);
+       return 0;
+}
+
+int wf_save(char *filename, void *ptr, int len)
+{
+       FILE *f;
+       f = fopen(filename, "wb");
+       if (f == NULL)
+               return -1;
+       if (fwrite(ptr, 1, len, f) != len) {
+               fclose(f);
+               return -1;
+       }
+       fclose(f);
+       return 0;
+}
+
+/*
+ * Veneer on file-handling.
+ */
+
+#define SAVE     0
+#define WRITEINFO 1
+#define READINFO  5
+#define LOAD     0xff
+
+#define FILEFOUND  1
+
+static int ticks(void)
+{ int last;
+  last = lastticks;
+  lastticks = (clock() * 100) / CLOCKS_PER_SEC; 
+  
+  return(lastticks-last);
+}
+
+static int fileinfo(_kernel_osfile_block *info, const char *name)
+{
+#ifdef __riscos
+  if (_kernel_osfile(READINFO, name, info) != FILEFOUND)
+      return -1;
+#else
+  struct stat buf;
+  int len, ftype;
+
+  if (stat(name, &buf) != 0) return -1;
+
+  len = strlen(name);
+  if (len > 4 && name[len-4] == ',')
+    ftype = (int)strtoul(name + len - 4, NULL, 16);
+  else
+    ftype = 0xfff;
+
+  info->load = 0xfff00000 | (ftype << 8);
+  info->exec = buf.st_mtime * 100 / 256;
+  info->start = buf.st_size;
+  info->end = 0;
+#endif
+  return 0;
+}
+
+/*
+ * Declarations of nibble values for the encoding.
+ */
+
+#define NSHORTS 7
+#define NLONGS (14-NSHORTS)
+#define MAXTAB (7*256)
+
+#define ZERO   0
+#define LITERAL 1
+#define LONG   2
+#define SHORT  (LONG+NLONGS)
+
+/*
+ * Data structure declarations.
+ */
+
+/*
+ * The Info structure is really a 3-word thing, but we are keen to save
+ * space, so pack together the pointer to the next element in the list
+ * and the count of number of occurrences of this value into a single
+ * word.  To get as many bits as possible for the count, we constrain
+ * all Info structures to be 8-byte aligned (freeing 3 low bits) and
+ * take the top 8 bits of the address off.  This will only work if we
+ * are in the low 16MBytes of address space, but it leaves us 11 bits
+ * for the count, which is nearly always enough.
+ *
+ * Later on, we use these same records to build hash tables mapping
+ * word values -> index in table of common values, for fast encoding.
+ * Fortunately, the tables are of size 7*256 < 2**11, so the same
+ * packing dodge still works.  I'm afraid this is all a bit tweaky,
+ * but making it fast and small is worth the effort.
+ *
+ * The alternative is to look up each word by binary search, but that
+ * would be slower (I think), viz 10 iterations for each table.
+ */
+
+
+#ifdef __riscos
+
+typedef struct Info {
+  word nextandcount;
+  word value;
+} Info;
+
+#define COUNTBITS 11
+#define MAXCOUNT  ((1<<COUNTBITS)-1)
+
+#define unpack(p,n,c)    { word t = p->nextandcount;                 \
+                           n = (Info *)((t>>COUNTBITS)<<3);          \
+                           c = t & MAXCOUNT; }
+
+#define pack(p,n,c)      { word t = (((word)n)<<(COUNTBITS-3)) | c;  \
+                           p->nextandcount = t; }
+
+#define inccount(p,n,c)   { if (c < MAXCOUNT) ++c;                   \
+                           p->nextandcount = (((word)n)<<(COUNTBITS-3)) | c; }
+#else /* !__riscos */
+
+typedef struct Info {
+  struct Info *next;
+  word count;
+  word value;
+} Info;
+
+#define MAXCOUNT  INT_MAX
+
+#define unpack(p,n,c)    { n = p->next;                      \
+                           c = p->count; }
+
+#define pack(p,n,c)      { p->next = n;  \
+                           p->count = c; }
+
+#define inccount(p,n,c)          { p->next = n;  \
+                           p->count = ++c; }
+
+#endif /* !__riscos */
+
+typedef Info *HashTab[HASHSIZE];
+
+typedef struct VTable { /* sorted vector of common values */
+  int nhits;       /* sum of frequencies of words in this table */
+  Info *misses;     /* list of (freq, word) pairs not in this table */
+  int size;        /* number of els in the table */
+  word els[MAXTAB]; /* table els: [0..size-1] are valid */
+} VTable;
+
+typedef struct Freqs { /* list of (value, frequency) pairs */
+  int nzeros;      /* no of zero words */
+  int maxfreq;     /* max frequency in list - useful for sorting */
+  Info *freqs;     /* list of (value, frequency) */
+} Freqs;
+
+/*
+ * Some ugly stuff to allocate 2-word Info structures efficiently with
+ * correct (8-byte) alignment.
+ */
+
+typedef struct InfoChunk {
+  struct InfoChunk *next;
+  Info *free;
+  Info *limit;
+  Info chunks[(CHUNKSIZE-12)/sizeof(Info)];
+} InfoChunk;
+
+static Info *align(Info *p, int n)
+{ intptr_t x = (intptr_t)p;
+  x += (n - 1); x -= (x % n); return (Info *)x;
+}
+
+#if DEBUGGING
+static char *heaplwm;
+static char *heaphwm;
+#endif
+
+static void *xalloc(int bytes, char *what)
+{ void *p = malloc(bytes);
+  if (p == NULL) err_fail("no more room");
+/*  if ((int)p < 0) err_fail("storage corruption (%d)", (int)p); */
+#if DEBUGGING
+  if (debug) fprintf(stderr, "-- alloc(%d, %s) -> &%x\n", bytes, what, (int)p);
+  if ((char *)p + bytes > heaphwm) heaphwm = (char *)p + bytes;
+  if ((char *)p < heaplwm) heaplwm = (char *)p;
+#else
+  what = NULL;
+#endif
+  return(p);
+}
+
+static void xfree(void *p)
+{
+#if DEBUGGING
+  if (debug) fprintf(stderr, "-- free(&%x)\n", (int)p);
+#endif
+  free(p);
+}
+
+static InfoChunk *curchunk;
+
+static void freechunks(void)
+{ InfoChunk *p, *next;
+  for (p = curchunk; p != NULL; p = next) { next = p->next; xfree(p); }
+  curchunk = NULL;
+}
+
+static Info *newinfo(Info *next, word v)
+{ InfoChunk *chunk;
+  Info *p;
+
+  chunk = curchunk;
+  if ((chunk == NULL) || ((p = chunk->free) >= chunk->limit)) {
+    chunk = (InfoChunk *)xalloc(CHUNKSIZE, "InfoChunk");
+    chunk->next  = curchunk;
+    chunk->free  = p = align(chunk->chunks, 8);
+    chunk->limit = (Info *)(((intptr_t)chunk) + CHUNKSIZE - sizeof(Info));
+    curchunk = chunk;
+  }
+  chunk->free = (p + 1);
+  pack(p, next, 1); p->value = v;
+  return(p);
+}
+
+static void countwords(word *code, word *limit, Freqs *ans)
+/*
+ * Counts number of occurrences of each word value in the specified block
+ * of code [code, limit), and returns list of (value, freqency) pairs.
+ */
+{ HashTab *hash;
+  Info **list;
+  Info *p, *next, *freqs;
+  int j, nzeros, maxfreq;
+  word w;
+
+  hash = xalloc(sizeof(HashTab), "HashTab");
+  for (j = 0; j < HASHSIZE; ++j) (*hash)[j] = NULL;
+  nzeros = 0;
+  while (code < limit) {
+/*    fprintf(stderr, "code %p limit %p\n", code, limit); */
+    w = *code++;
+    if (w == 0) { ++nzeros; continue; }
+    j = (w + (w >> 11) + (w >> 22)) % HASHSIZE; /* simple hash function */
+    list = &((*hash)[j]);
+    p = *list;
+    while (1) {
+       if (p == NULL) { /*fprintf(stderr, "newinfo\n");*/ *list = 
newinfo(*list, w); /*fprintf(stderr, "newinfo out\n");*/ break; }
+      unpack(p, next, j);
+      if (w == p->value) { inccount(p, next, j); break; }
+      p = next;
+    }
+  } /* while code < limit */
+/*fprintf(stderr, "done countwords\n");*/
+  /*
+   * Now flatten the hash table into a single list, and free the vector.
+   */
+  freqs = NULL; maxfreq = 0;
+  for (j = 0; j < HASHSIZE; ++j) {
+    for (p = (*hash)[j]; p != NULL; p = next) {
+      unpack(p, next, w); pack(p, freqs, w); freqs = p;
+      if (w > maxfreq) maxfreq = w; /* keep track of max frequency */
+    }
+  }
+  ans->nzeros  = nzeros;
+  ans->maxfreq = maxfreq;
+  ans->freqs   = freqs;
+  xfree(hash);
+}
+
+static int comparewords(const void *a, const void *b)
+/*
+ * This proc is passed to the library qsort for sorting table elements.
+ * We know that all table elements are distinct, so can cheat a little.
+ */
+{ word x = *(word *)a;
+  word y = *(word *)b;
+  if (x > y) return(+1);
+  return(-1);
+}
+
+static void maketable(Freqs *freqs, int maxsize, int wantmisses, VTable *tab)
+/*
+ * Builds a VTable of the most common values in the list freqs,
+ * taking at most maxsize of them, destroying the freqs list
+ * in the process, and leaving the remnants hung off the VTable
+ * record.
+ */
+{ Info **withfreq = xalloc((freqs->maxfreq+1) * sizeof(Info *), "withfreq");
+  Info **list;
+  Info *p, *next, *misses;
+  int  freq, nhits, size;
+
+  /*
+   * It is easy to sort things by frequency, as frequency range is
+   * limited to 1..freqs->maxfreq.  So just build a vector of lists.
+   */
+  for (list = withfreq + freqs->maxfreq; list >= withfreq; *list-- = NULL);
+
+  for (p = freqs->freqs; p != NULL; p = next) { /* put p into bucket */
+    unpack(p, next, freq);
+    pack(p, (withfreq[freq]), freq);
+    withfreq[freq] = p;
+  }
+  freqs->freqs = NULL;
+
+  nhits  = 0;
+  misses = NULL;
+  size  = 0;
+  for (list = withfreq + freqs->maxfreq; list >= withfreq; --list) {
+    for (p = *list; p != NULL; p = next) {
+      unpack(p, next, freq);
+      if (size < maxsize) {                       /* add to table */
+       tab->els[size++] = p->value; nhits += freq;
+      } else {                                    /* add to misses list */
+       if (!wantmisses) break;
+       pack(p, misses, freq); misses = p;
+      }
+    }
+  }
+  tab->nhits  = nhits;
+  tab->misses = misses;
+  tab->size   = size;
+  xfree(withfreq);
+  qsort((void *)(tab->els), size, sizeof(word), &comparewords);
+  if (verbose > 1) printf("-- built table in %d csec\n", ticks());
+}
+
+static void masklowbyte(Info *list, Freqs *ans)
+/*
+ * Take a list of (value, frequency) of 4-byte values, merge values
+ * with the same low byte to produce list of 3-byte values.
+ */
+#define VECBITS 12
+#define VECSIZE (1<<VECBITS)
+{ Info **vec = xalloc(VECSIZE * sizeof(Info *), "mergevec");
+  Info **pp;
+  Info *p, *next;
+  Info *q, *qnext, *qprev;
+  int freq, qfreq, qprevfreq, maxfreq;
+  word val, qval;
+
+  for (pp = vec + VECSIZE-1; pp >= vec; *pp-- = NULL);
+  for (p = list; p != NULL; p = next) {
+    unpack(p, next, freq);
+    val = (p->value >> 8); p->value = val;
+    pp = vec + ((val + (val >> 9) + (val >> 12)) % VECSIZE);
+    /*
+     * Now insert p in the ascending-value sorted list pp.
+     * This is tricky because of the packing of the nextandcount field,
+     * so have to handle start of list specially.
+     */
+    q = *pp;
+    if (q == NULL) { pack(p, NULL, freq); *pp = p; continue; }
+    unpack(q, qnext, qfreq); qval = q->value;
+    if (val < qval) { pack(p, q, freq); *pp = p; continue; }
+    if (val == qval) {
+      qfreq += freq; if (qfreq > MAXCOUNT) qfreq = MAXCOUNT;
+      pack(q, qnext, qfreq); continue;
+    }
+    while (1) {
+      qprev = q; qprevfreq = qfreq; q = qnext;
+      if (q == NULL) {  /* end of list: add it here */
+       pack(p, NULL, freq); pack(qprev, p, qprevfreq); break;
+      }
+      unpack(q, qnext, qfreq); qval = q->value;
+      if (val < qval) {  /* not in list: add it */
+       pack(p, q, freq); pack(qprev, p, qprevfreq); break;
+      }
+      if (val == qval) { /* value matches: add frequency */
+       qfreq += freq; if (qfreq > MAXCOUNT) qfreq = MAXCOUNT;
+       pack(q, qnext, qfreq); break;
+      }
+    }
+  }
+  /*
+   * Phew! That should keep the register allocator busy.
+   * Now we have a vector of sorted lists: just have to flatten it.
+   */
+  q = NULL; maxfreq = 0;
+  for (pp = vec + VECSIZE-1; pp >= vec; --pp) {
+    for (p = *pp; p != NULL; p = next) {
+      unpack(p, next, freq); pack(p, q, freq); q = p;
+      if (freq > maxfreq) maxfreq = freq;
+    }
+  }
+  ans->maxfreq = maxfreq;
+  ans->freqs   = q;
+  xfree(vec);
+}
+
+#define FASTSIZE 4096
+#define FASTHASH(v) ((v + (v >> 7) + (v >> 15)) % FASTSIZE)
+
+static Info **fasttab(VTable *tab)
+/*
+ * Builds a hash table for translating value -> index in table.
+ */
+{ Info **vec = xalloc(FASTSIZE * sizeof(Info *), "fasthash");
+  Info **pp;
+  int idx;
+  word val;
+  Info *p;
+
+  for (pp = vec + FASTSIZE; pp > vec; *--pp = NULL);
+
+  for (idx = 0; idx < tab->size; ++idx) {
+    val = tab->els[idx];
+    pp = vec + FASTHASH(val);
+    /*
+     * Values in table are unique, so just add it to chain.
+     */
+    p = newinfo(NULL, val); pack(p, *pp, idx); *pp = p;
+  }
+  return(vec);
+}
+
+static int lookup(Info **fast, word val)
+{ Info *p, *next;
+  int idx;
+
+  for (p = fast[FASTHASH(val)]; p != NULL; p = next) {
+    unpack(p, next, idx);
+    if (val == p->value) return(idx);
+  }
+  return(-1);
+}
+
+#define TOPBYTE(n) ((n)>>24)
+#define LOWBYTE(n) ((n)&0xff)
+#define PUTLOWBYTE(p, n) (*p++ = (n)) /* relies on store masking low byte */
+
+#define ENCODEVALUE(w, nibble, p) \
+    if (w == 0) {                                            \
+      nibble = ZERO;                                         \
+    } else if ((idx = lookup(fshorts, w)) >= 0) {            \
+      PUTLOWBYTE(p, idx);                                    \
+      nibble = SHORT + (idx >> 8);                           \
+    } else if ((idx = lookup(flongs, w>>8)) >= 0) {          \
+      PUTLOWBYTE(p, w); PUTLOWBYTE(p, idx);                  \
+      nibble = LONG + (idx >> 8);                            \
+    } else {                                                 \
+      *p++ = TOPBYTE(w); w <<= 8; *p++ = TOPBYTE(w); w <<= 8; \
+      *p++ = TOPBYTE(w); w <<= 8; *p++ = TOPBYTE(w);         \
+      nibble = LITERAL;                                      \
+    }
+
+#define ENCSIZE 8192
+
+/*
+ * We encode a pair of words at a time.  To avoid unnecessary copying of data,
+ * things are done in a rather curious order, not quite the opposite of the
+ * optimal decoding order.  I can't quite convince myself that this is optimal,
+ * but I think it is quite good.
+ */
+
+static char *encode(word *base, word *limit, Info **fshorts, Info **flongs,
+            SqueezeHeader *h)
+/*
+ * Returns pointer to byte after the encoded data.
+ */
+{ word *code;
+  word w;
+  int idx, nib0, nib1;
+  char *buf, *p;
+
+  buf = xalloc(ENCSIZE, "encodebuf"); p = buf;
+
+  h->decodedsize = ((char *)limit - (char *)base);
+  for (code = base; code < limit; code += 2) {
+    w = code[1]; ENCODEVALUE(w, nib1, p);
+    w = code[0]; ENCODEVALUE(w, nib0, p);
+    *p++ = (nib0 | (nib1 << 4));
+    if (buf != NULL) {
+      idx = ((intptr_t)code - (intptr_t)base - 12 - (p - buf));
+      if (idx > 0) { h->bytestomove = (p - buf); }
+      if ((idx > 256) || (p - buf > ENCSIZE - 16)) {
+       /*
+        * Swap from encoding into buf to encoding on top of old stuff
+        * once we get 256 bytes clear, or run out of buf space.
+        */
+       memcpy(base+1, buf, p-buf); p = (p-buf) + (char *)(base+1);
+       xfree(buf); buf = NULL;
+      }
+    } else {
+      if (p >= (char *)(code-2))
+       err_fail("pathological file - can't cope");
+    }
+  }
+  h->encodedsize = p - (char *)(base+1);
+  return(p);
+}
+
+static char *encodetable(VTable *tab, int threebytes, char *out)
+/*
+ * Encode the table of 3 or 4 byte values, starting at address p,
+ * return pointer to first free byte after table.
+ */
+{ word *p, *limit;
+  word prev, w;
+  int delta, ones;
+
+  ones = 0; prev = (word)(-1);
+  p = tab->els; limit = p + tab->size;
+  while (p < limit) {
+    w = *p++; delta = (w - prev); prev = w;
+    if (delta == 1) ++ones;
+    if ((ones > 0) && ((delta != 1) || (ones >= 9))) {
+      *out++ = ones; ones = 0;
+    }
+    if (delta < 2) {  /* dealt with above: no zeros, ones are peepholed */ }
+    else if (delta <= 91-10) { *out++ = delta+10; }
+    else if (delta < 82*256) {
+      *out++ = (delta>>8)+92; *out++ = LOWBYTE(delta);
+    }
+    else if (delta < 82*256*256) {
+      *out++ = (delta>>16)+174;
+      *out++ = LOWBYTE(delta); delta >>= 8;
+      *out++ = LOWBYTE(delta);
+    }
+    else {
+      *out++ = 0;
+      *out++ = LOWBYTE(delta); delta >>= 8;
+      *out++ = LOWBYTE(delta); delta >>= 8;
+      *out++ = LOWBYTE(delta);
+      if (!threebytes) { delta >>= 8; *out++ = delta; }
+    }
+  } /* end loop over values in table */
+  if (ones > 0) *out++ = ones;
+  return(out);
+}
+
+static char *writeunsqueeze(char *out, int execoffset)
+{ intptr_t base, limit;
+  word *p;
+  int n, rotr, op;
+
+  /* UnSqueeze_FindUnSqueezeCode(&base, &limit); */
+  base = (intptr_t)&UnSqueeze_UnSqueezeBase[6*4];
+  limit = (intptr_t)&UnSqueeze_UnSqueezeLimit[0];
+  n = limit - base;
+  memcpy(out, (void *)base, n); out += n;
+  /*
+   * Now construct ARM code to jump to exec address, starting with
+   * load address in R8.
+   */
+  op = ADD_R8_R8_0;
+  if (execoffset < 0) { op = SUB_R8_R8_0; execoffset = -execoffset; }
+  rotr = 32; p = (word *)out;
+  while (execoffset > 0) {
+    /* Generate ADD/SUB R8, R8, #thing */
+    n = LOWBYTE(execoffset); execoffset >>= 8;
+    if (n != 0) {
+      *p++ = op + (0x100 * ((rotr % 32) / 2)) + n;
+    }
+    rotr -= 8;
+  }
+  *p++ = SUB_R1_R8_IMM4;
+  *p++ = SWI_XOS_SynchroniseCodeAreas;
+  *p++ = MOV_PC_R8;
+  return((char *)p);
+}
+
+static char *compresscode(word *code, intptr_t size, int execoffset)
+/*
+ * Returns NULL if no compression, else pointer to top of compressed thing.
+ */
+{ Freqs  freqs;
+  word  *limit;
+  VTable *shorts, *longs;
+  Info **fshorts, **flongs;
+  int   nwords, guess, nliterals;
+  SqueezeHeader header;
+  char *pos, *tabstart;
+
+  size += 7; size &= ~7; /* round up to an even number of words */
+  limit = (word *)((char *)code + size);
+  countwords(code, limit, &freqs);
+  if (verbose > 1) printf("-- counted %" PRIdPTR " bytes in %d csec\n", size, 
ticks());
+  /*
+   * Allocate the VTables here to avoid nasty storage interactions, which
+   * can lose us some chunks if we're not careful.
+   */
+  shorts = xalloc(sizeof(VTable), "shorts");
+  longs  = xalloc(sizeof(VTable), "longs");
+  maketable(&freqs, NSHORTS*256, 1, shorts);
+  masklowbyte(shorts->misses, &freqs);
+  if (verbose > 1) printf("-- masklowbyte took %d csec\n", ticks());
+  maketable(&freqs, NLONGS*256, 0, longs);
+  freechunks();
+  /*
+   * Now guess what the size of the compressed thing would be.
+   * The estimates of size of encoded data are exact, but the
+   * estimates of encoded table size are a guess, so we over-estimate
+   * the size of the decompression code to be on the safe side.
+   */
+  nwords    = (size / sizeof(word));
+  nliterals = nwords - freqs.nzeros - shorts->nhits - longs->nhits;
+
+  guess     =  (nwords / 2)           /* 0.5 bytes per word of original */
+             + (1 * shorts->nhits)    /* 1 more byte for each short */
+             + (2 * longs->nhits)     /* 2 for each long */
+             + (4 * nliterals)        /* 4 for each literal */
+             + (2 * shorts->size)     /* rough size of shorts table */
+             + (2 * longs->size)      /* rough size of longs table */
+             + 1024;                  /* decompression code + safety margin */
+
+  if (verbose)
+         fprintf(stderr, "-- encoding stats (0,1,2,4) %d%% %d%% %d%% %d%%\n",
+         (freqs.nzeros  * 100) / nwords,
+         (shorts->nhits * 100) / nwords,
+         (longs->nhits  * 100) / nwords,
+         (nliterals     * 100) / nwords);
+
+  if (guess > (9*size)/10) { /* not much squeeze to be had */
+    if ((!force) || (guess > size)) return(NULL);
+  }
+
+  /*
+   * Now can actually start encoding stuff.
+   */
+  fshorts = fasttab(shorts);
+  flongs  = fasttab(longs);
+  if (verbose > 1) fprintf(stderr, "-- built speedup tables in %d csec\n", 
ticks());
+  pos = encode(code, limit, fshorts, flongs, &header);
+  xfree(flongs);
+  xfree(fshorts);
+  freechunks();
+  if (verbose > 1)
+    fprintf(stderr, "-- encode gives %d in %d csec\n", header.encodedsize, 
ticks());
+  tabstart = pos;
+  pos = encodetable(shorts, 0, pos);
+  pos = encodetable(longs,  1, pos);
+  header.nshorts = shorts->size;
+  xfree(shorts);
+  header.nlongs  = longs->size;
+  xfree(longs);
+  /* now word-align before the header words */
+  while (((intptr_t)pos & 3) != 0) *pos++ = 0;
+  header.encodedtabs = (pos - tabstart);
+  if (verbose > 1)
+    fprintf(stderr, "-- decode tables occupy %d bytes\n", header.encodedtabs);
+  memcpy(pos, &header, sizeof(SqueezeHeader)); pos += sizeof(SqueezeHeader);
+  /*
+   * Now the branch instruction to be put at the start: this has a word
+   * offset, with suitable allowance for ARM prefetch.
+   * In fact we want to skip the first 3 instructions of decompression
+   * code, as these are executed only for an AIF image.
+   */
+  *code = B + ((word *)pos - code) + AIFPRELUDE - PREFETCH;
+  pos = writeunsqueeze(pos, execoffset);
+  pos += sprintf(pos, "rcc %s\n", Module_MajorVersion);
+  /* Pad size to be 15 mod 16 */
+  while ((((intptr_t)pos - (intptr_t)code) & 0xf) != 0xf) *pos++ = ' ';
+  return(pos);
+}
+
+static char *compress(word *code, int size, int execoffset)
+/*
+ * This handles the AIF-specific stuff.
+ * Returns NULL if no compression, else pointer to top of compressed thing.
+ */
+{ char *top;
+
+  if (code[0] != BL+NV && code [0] != MOV_R0_R0)
+  { /* not BLNV $+0, not NOOP => not an AIF image */
+    return compresscode(code, size, execoffset);
+  }
+  top = compresscode(code+AIFWORDS, size-AIFBYTES, execoffset-AIFBYTES+4);
+  /*
+   * Now first word of the stuff we have just compressed is
+   * B UnsqueezeADFSImage.  We want the first word of the header to
+   * be BL UnsqueezeAIFImage, i.e. destination AIFPRELUDE words earlier.
+   */
+  code[0] = BL + (code[32] & 0x00ffffff) + AIFWORDS - AIFPRELUDE;
+  return(top);
+}
+
+#ifdef __riscos
+static void arthurise(_kernel_osfile_block *info, int type)
+{ int data[2];
+  if ((info->load == info->exec) && (info->load == 0x8000)) {
+    /* can we use Arthur 'FF8' filetype ? */
+      if (_kernel_hostos() == _kernel_ARTHUR) {
+      /* This is Arthur - get time of day */
+      if (verbose > 1) fprintf(stderr, "-- getting timestamp from Arthur\n");
+      data[0] = 3;
+      (void) _kernel_osword(14, data);
+      info->exec = data[0];
+      info->load = 0xfffff800 + (data[1] & 0xff);
+      if (type)
+          info->load = type + (data[1] & 0xff);
+    }
+  }
+}
+#endif
+
+static int squeeze(char *in, char *out)
+{ _kernel_osfile_block info;
+  int rc, t, squeezed, isdata;
+  intptr_t size;
+  void *load;
+  datahdr *d;
+  word *code;
+  char *top, *p;
+  int type = 0;
+
+  if (verbose) fprintf(stderr, "-- squeezing '%s' to '%s'\n", in, out);
+  squeezed = 0; isdata = 0;
+  if (fileinfo(&info, in) == -1) err_fail("'%s' does not exist", in);
+  size = info.start;
+  if ((!force) && (strcmp(in, out) == 0)) {
+    /* Check quickly to see if worth loading */
+    if (size < 2048) {
+      err_report("'%s' is too small to squeeze", in);
+      return(0);
+    }
+    if ((size & 0xf) == 0xf) {
+      err_report("'%s' is already squeezed", in);
+      return(0);
+    }
+  }
+  if ((info.load & 0xffffff00) == 0xfffffa00) { /* Module */
+      int header_size;
+
+      header_size = (intptr_t)&unsqueeze_limit[0] - 
(intptr_t)&unsqueeze_base[0];
+      unsqueeze_end = (void *)size;
+      size += header_size;
+      code = xalloc(size+DATABYTES+8, "code");
+      d = (datahdr *)code; code += DATAWORDS;
+      top = ((char *)code) + size+8;
+      for (p = top-8; p < top; *p++ = 0); /* Clear the padding space */
+      memcpy(code, &unsqueeze_base, header_size);
+      load = code + header_size;
+  } else {
+      code = xalloc(size+DATABYTES+8, "code"); /* Pad to even no of words */
+      d = (datahdr *)code; code += DATAWORDS;  /* Space for data header */
+      top = ((char *)code) + size+8;
+      for (p = top-8; p < top; *p++ = 0); /* Clear the padding space */
+      load = code;
+  }
+  if (wf_load(in, load, info.start) == -1)
+      err_fail("can't load '%s'", in);
+  if ((info.load & 0xfff00000) == 0xfff00000) {
+      type = (info.load & ~0xff);
+      if (type == 0xfffffa00)
+          type = 0xfffff800;
+      info.load = 0x8000;
+      info.exec = 0x8000;
+  } else {
+      if (info.load & 0xfc000000) {
+          isdata = 1; d->datamagic = DATAMAGIC;
+          d->load = info.load; d->exec = info.exec; d->size = size;
+      }
+  }
+  if (verbose > 1) fprintf(stderr, "-- loaded %" PRIdPTR " bytes in %d 
csec\n", size, ticks());
+  t = (clock() * 100) / CLOCKS_PER_SEC;
+
+  if (isdata) top = compresscode(code, size, (-DATABYTES) + 4);
+  else top = compress(code, size, info.exec - info.load);
+
+  if (top != NULL) {
+    t = ((clock() * 100) / CLOCKS_PER_SEC) - t;
+    if (isdata) {
+      d->bl_decompress = code[0] + DATAWORDS; /* dirty... */
+      code -= DATAWORDS;
+      info.load = SQUEEZED | (info.load & 0xff);
+    } else
+      info.exec = info.load;
+    rc = (top - (char *)code);
+    if (verbose) {
+      fprintf(stderr, "-- compressed size %d is %" PRIdPTR "%% of %" PRIdPTR 
"\n", rc, (rc*100)/size, size);
+      fprintf(stderr, "-- compression took %d csec, %" PRIdPTR " 
bytes/cpusec\n", t, (size*100)/(t?t:1));
+    }
+    squeezed = 1;
+  } else {
+    top = (char *)code + size;
+    if (verbose) err_report("can't compress '%s', will copy", in);
+  }
+  if (squeezed || (strcmp(in, out) != 0)) { /* Write it out */
+#ifdef __riscos
+    arthurise(&info, type);
+#endif
+    if (wf_save(out, code, top - (char *)code) == -1)
+       err_fail("failed to write '%s'", out);
+#ifdef __riscos
+    _swix(OS_File, _INR(0,2), 18, out, (info.load << 12) >> 20);
+#endif
+  }
+  xfree(d);
+#if DEBUGGING
+  if (debug) {
+    printf("-- heaphwm = &%x = &8000+%d\n",(int)heaphwm,(int)heaphwm-0x8000);
+    printf("-- heaplwm = &%x, range = %d\n", (int)heaplwm, heaphwm - heaplwm);
+  }
+#endif
+  return(0);
+}
+
+static void help(void)
+{ char ch = host_dir_sep_char();
+  fprintf(stderr, "\n%s vsn %s [%s] - %s\n", SELF, VSN, DATE, BRIEF);
+  fprintf(stderr, "\n%s [options] unsqueezed-file [squeezed-file]\n", SELF);
+  fprintf(stderr, "\nOptions:-\n");
+  fprintf(stderr, "-f   try harder to squeeze unpleasant things\n");
+  fprintf(stderr, "-v   output messages and compression statistics\n");
+  fprintf(stderr, "\nExamples:-\n");
+  fprintf(stderr, "     %s myprog      %s -v myprog squozen%cmyprog\n", SELF, 
SELF, ch);
+  exit(EXIT_SUCCESS);
+}
+
+static void handle_escape(int signo)
+{
+  signal(signo, handle_escape);
+  exit(EXIT_FAILURE);
+}
+
+
+#define err_init(X)
+#define host_init()
+#define hash_cistrcmp strcmp
+
+static void initialise(void)
+{
+  signal(SIGINT, handle_escape);
+  host_init();
+  err_init(SELF);
+  debug = 0; force = 0; verbose = 0;
+  curchunk = NULL;
+  ticks();
+}
+
+int main(int argc, char *argv[])
+{ int j;
+  char *arg;
+  char *a = NULL;
+  char *b = NULL;
+
+  initialise();
+
+  /* parse help or identify args */
+  for (j = 1;  j < argc;  ++j) {
+    arg = argv[j];
+    if (hash_cistrcmp("-help", arg) == 0 || hash_cistrcmp("-h", arg) == 0) {
+      help();
+    }
+  }
+
+  /* parse args */
+  for (j = 1; j < argc; ++j) {
+    arg = argv[j];
+    if (arg[0] == '-') {
+      int i = 1;
+      while (arg[i]) {
+       switch (arg[i]) {
+         case 'f':
+         case 'F': ++force; break;
+         case 'v':
+         case 'V': ++verbose; break;
+#if DEBUGGING
+         case 'z':
+         case 'Z': ++debug; break;
+#endif
+          case 'o':
+              ++j;
+              if (argv[j])
+                  b = argv[j];
+              else
+                  err_fail("no filename on -o flag\n");
+              break;
+         default : err_fail("flag '%c' not recognised", arg[i]);
+       }
+       ++i;
+      }
+    } else { /* a filename */
+      if      (a == NULL) a = arg;
+      else if (b == NULL) b = arg;
+      else err_fail("too many filename arguments '%s'\n", arg);
+    }
+  }
+  if (a == NULL) err_fail("missing filename");
+  if (b == NULL) b = a; /* squeeze it to itself */
+
+#if DEBUGGING
+  if (debug) { heaplwm = (char *)0x03ffffff; heaphwm = NULL; }
+#endif
+
+  return(squeeze(a, b));
+}
diff --git a/squeeze.h b/squeeze.h
new file mode 100644
index 0000000000..1368a81bd6
--- /dev/null
+++ b/squeeze.h
@@ -0,0 +1,77 @@
+/* This source code in this file is licensed to You by Castle Technology
+ * Limited ("Castle") and its licensors on contractual terms and conditions
+ * ("Licence") which entitle you freely to modify and/or to distribute this
+ * source code subject to Your compliance with the terms of the Licence.
+ * 
+ * This source code has been made available to You without any warranties
+ * whatsoever. Consequently, Your use, modification and distribution of this
+ * source code is entirely at Your own risk and neither Castle, its licensors
+ * nor any other person who has contributed to this source code shall be
+ * liable to You for any loss or damage which You may suffer as a result of
+ * Your use, modification or distribution of this source code.
+ * 
+ * Full details of Your rights and obligations are set out in the Licence.
+ * You should have received a copy of the Licence with this source code file.
+ * If You have not received a copy, the text of the Licence is available
+ * online at www.castle-technology.co.uk/riscosbaselicence.htm
+ */
+typedef unsigned int word;
+typedef enum { NO, YES } bool;
+
+typedef struct aifhdr {
+    word  bl_decompress;
+    word  bl_selfreloc;
+    word  bl_zeroinit;
+    word  bl_imageentry;
+    word  swi_exit;
+    int   codesize;
+    int   datasize;
+    int   debugsize;
+    int   zerosize;
+    int   debugtype;
+    int   imagebase;
+    int   reserved[5];
+    word  zeroinit[16];
+} aifhdr;
+
+#define AIFBYTES   sizeof(aifhdr)  /* size in bytes of an AIF header */
+#define AIFWORDS   (AIFBYTES / sizeof(int))
+#define AIFPRELUDE 5 /* no of extra instructions in AIF decompression */
+#define PREFETCH   2 /* words of ARM prefetch */
+
+typedef struct datahdr {
+    word  bl_decompress;
+    word  datamagic;
+    word  load;
+    word  exec;
+    word  size;
+} datahdr;
+
+#define DATABYTES ((int)(sizeof(datahdr)))
+#define DATAWORDS (DATABYTES / sizeof(int))
+#define DATAMAGIC 0x213542
+#define SQUEEZED 0xffffea00
+
+typedef struct SqueezeHeader {
+  int decodedsize;
+  int encodedsize;
+  int encodedtabs;
+  int nshorts;
+  int nlongs;
+  int bytestomove;
+} SqueezeHeader;
+
+#define SQUEEZEBYTES sizeof(SqueezeHeader)
+#define SQUEEZEWORDS (SQUEEZEBYTES / sizeof(int))
+
+#define B 0xea000000
+#define BL 0xeb000000
+#define B_OFFSET 0x00ffffff
+#define MOV_PC_R8 0xe1a0f008
+#define ADD_R8_R8_0 0xe2888000
+#define SUB_R8_R8_0 0xe2488000
+#define MOV_R0_R0 0xe1a00000
+#define LDR_PC_R8_MINUS4 0xe518f004
+#define NV (0xf0000000 - 0xe0000000)
+#define SUB_R1_R8_IMM4 (0xE2481004)
+#define SWI_XOS_SynchroniseCodeAreas (0xEF02006E)
diff --git a/unsqrm.s b/unsqrm.s
new file mode 100644
index 0000000000..8a2797c129
--- /dev/null
+++ b/unsqrm.s
@@ -0,0 +1,94 @@
+; This source code in this file is licensed to You by Castle Technology
+; Limited ("Castle") and its licensors on contractual terms and conditions
+; ("Licence") which entitle you freely to modify and/or to distribute this
+; source code subject to Your compliance with the terms of the Licence.
+; 
+; This source code has been made available to You without any warranties
+; whatsoever. Consequently, Your use, modification and distribution of this
+; source code is entirely at Your own risk and neither Castle, its licensors
+; nor any other person who has contributed to this source code shall be
+; liable to You for any loss or damage which You may suffer as a result of
+; Your use, modification or distribution of this source code.
+; 
+; Full details of Your rights and obligations are set out in the Licence.
+; You should have received a copy of the Licence with this source code file.
+; If You have not received a copy, the text of the Licence is available
+; online at www.castle-technology.co.uk/riscosbaselicence.htm
+; 
+r0              RN      0
+r1              RN      1
+r2              RN      2
+r3              RN      3
+r4              RN      4
+r5              RN      5
+r6              RN      6
+r12             RN     12
+lr              RN     14
+pc              RN     15
+
+OS_GetEnv             EQU &10
+OS_Exit               EQU &11
+XOS_Module            EQU &2001e
+OS_Module             EQU &1e
+OS_GenerateError      EQU &2b
+OS_ChangeEnvironment  EQU &40
+OS_ReadDefaultHandler EQU &55
+
+XWimp_SlotSize  EQU     &600ec
+
+n_module_run    EQU      2
+n_module_load   EQU     11
+
+n_upcall_h      EQU     16
+
+o_run_entry     EQU     &00
+o_title_entry   EQU     &10
+
+                EXPORT  unsqueeze_base
+                EXPORT  unsqueeze_end
+                EXPORT  unsqueeze_limit
+
+                AREA    unsqueeze, CODE, READONLY
+
+unsqueeze_base  MOV     r0, r0
+                MOV     r0, #-1
+                MOV     r1, #-1
+                SWI     XWimp_SlotSize
+                MOV     r6, #0
+                MOVVC   r6, r0
+                ADR     r0, unsqueeze_end
+                LDR     r1, [r0], #4
+                ADD     r0, r0, r1
+                SUB     r0, r0, #&8000
+                MOV     r1, #-1
+                SWI     XWimp_SlotSize
+                MOV     r0, #n_upcall_h
+                ADR     r1, upcall_handler
+                SWI     OS_ChangeEnvironment
+                ADR     r1, unsqueeze_end
+                LDR     r2, [r1], #4
+                MOV     r0, #n_module_load
+                SWI     XOS_Module
+                MOV     r5, r0
+                MOV     r0, #n_upcall_h
+                SWI     OS_ReadDefaultHandler
+                SWI     OS_ChangeEnvironment
+                MOVS    r0, r6
+                MOVNE   r1, #-1
+                SWINE   XWimp_SlotSize
+                MOV     r0, r5
+                CMP     r0, #n_module_load
+                SWINE   OS_GenerateError
+                SWI     OS_Exit
+
+upcall_handler  SUB     r12, r0, #256
+                CMP     r12, #1
+                MOVEQ   r0, #0
+                MOV     pc, lr
+
+unsqueeze_end   DCD     0
+
+unsqueeze_limit
+module_start
+
+                END
diff --git a/unsqueeze.s b/unsqueeze.s
new file mode 100644
index 0000000000..7c1cbee383
--- /dev/null
+++ b/unsqueeze.s
@@ -0,0 +1,468 @@
+; This source code in this file is licensed to You by Castle Technology
+; Limited ("Castle") and its licensors on contractual terms and conditions
+; ("Licence") which entitle you freely to modify and/or to distribute this
+; source code subject to Your compliance with the terms of the Licence.
+; 
+; This source code has been made available to You without any warranties
+; whatsoever. Consequently, Your use, modification and distribution of this
+; source code is entirely at Your own risk and neither Castle, its licensors
+; nor any other person who has contributed to this source code shall be
+; liable to You for any loss or damage which You may suffer as a result of
+; Your use, modification or distribution of this source code.
+; 
+; Full details of Your rights and obligations are set out in the Licence.
+; You should have received a copy of the Licence with this source code file.
+; If You have not received a copy, the text of the Licence is available
+; online at www.castle-technology.co.uk/riscosbaselicence.htm
+; 
+;
+; s.UnSqueeze by RCC 25-Aug-87
+; This is a bit of code to be included in self-decompressing images to
+; expand the image in place.  See elsewhere for details of the compression
+; algorithm.
+;
+; ***********************************
+; ***    C h a n g e   L i s t    ***
+; ***********************************
+
+; Date       Name       Description
+; ----       ----       -----------
+; 13-Feb-90  TDobson    Minor optimisation which saves 1 instruction for
+;                       every output word that isn't a "short" or a "long".
+
+        AREA |M2$$Data|, DATA
+;        EXPORT |UnSqueeze_C$|
+;        EXPORT |UnSqueeze_CS$|
+        EXPORT |UnSqueeze_UnSqueezeBase|
+        EXPORT |UnSqueeze_UnSqueezeLimit|
+;        EXPORT |UnSqueeze_D$|
+;        EXPORT |UnSqueeze_FindUnSqueezeCode|
+;        IMPORT  |SYSTEM.STKOVF|
+;        IMPORT  |SYSTEM.RAISE|
+|UnSqueeze_D$|
+        %       4
+        AREA |M2$$Code|, CODE, READONLY
+
+R0 RN 0
+R1 RN 1
+R2 RN 2
+R3 RN 3
+R4 RN 4
+R5 RN 5
+R6 RN 6
+R7 RN 7
+R8 RN 8
+R9 RN 9
+R10 RN 10
+R11 RN 11
+R12 RN 12
+R13 RN 13
+LR RN 14
+PC RN 15
+
+|UnSqueeze_CS$| EQU     40
+|UnSqueeze_C$|
+
+StackSize   * 64
+decodedSize * 0
+encodedSize * 4
+tableSize   * 8
+nShorts     * 12
+nLongs      * 16
+sizeToMove  * 20
+
+       GBLL    expand_memcheck
+expand_memcheck        SETL    {TRUE}
+
+       [ expand_memcheck
+;      GET     hdr:ListOpts
+;      GET     hdr:Macros
+;      GET     hdr:System
+;      GET     hdr:MsgTrans
+OS_GetEnv             EQU &10
+OS_GenerateError      EQU &2b
+XOS_SynchroniseCodeAreas EQU &2006e
+XMessageTrans_ErrorLookup EQU &61506
+       ]
+
+; Constants defining partition of nibble value space: these must match
+; corresponding values in mod.squeeze.
+
+NibsLong    * 7
+NibsShort   * (14-NibsLong)
+MinShort    * (2+NibsLong)
+MinLong     * 2
+
+; Code between UnSqueezeBase and UnSqueezeLimit will be copied into
+; the start of a squeezed image, and when the image is loaded it will
+; jump to the start.
+
+; Before start of unsqueeze code there will be 6 words to tell
+; it where the data is, how big it is etc.
+
+|UnsqueezeDataBlock|
+        NOP
+        NOP
+        NOP
+        NOP
+        NOP
+        NOP
+
+|UnSqueeze_UnSqueezeBase|
+|UnsqueezeAIFImage|
+        ; If it was an AIF image, we enter here and overwrite the BL decompress
+        ; xpand relies on the first instruction here being MOV r0, #<imm>
+        MOV   R0, #&E1000000 ; hex for instruction MOV r0, r0
+        ORR   R0, R0, #&00A00000
+        SUB   R1, LR, PC     ; mode independent status bit removal
+        ADD   R1, PC, R1     ; R1 = LR (- any PSR bits if there) + 4
+        STR   R0, [R1, #-8]! ; overwrite the instruction we just BL'ed from
+
+|UnsqueezeADFSImage|
+        [ UnsqueezeADFSImage - UnsqueezeAIFImage <> 5*4
+        ! 1, "Change AIFPRELUDE in squeeze.h"
+        ]
+        ; We arrive here knowing very little about anything.
+        ; First find out where we are, and where the tables start.
+
+        ADR   R0, |UnsqueezeDataBlock|  ; R0 points to data (PC-relative)
+        LDMIA R0, {R8-R13}  ; load all the data
+                            ; R13 := sizeToMove
+                            ; R12 := nLongs
+                            ; R11 := nShorts
+        SUB   R10, R0, R10  ; R10 := base of encoded tables
+        SUB   R9, R10, R9   ; R9  := base of encoded data
+        ADD   R8, R9, R8    ; R8  := top of decoded image
+
+        ; We only need nLongs and nShorts while we are decoding the tables.
+        ; Afterwards we will re-use the registers for pointers to start
+        ; of tables.
+
+        ; SWI   &10            ; GetEnv - returns RAM limit in R1
+        ; SUB   R6, R1, #&4000 ; grab 16K workspace, remember table base
+        ADR   R6, |UnSqueeze_UnSqueezeLimit|+24 ; top of squeezed image
+        CMP   R6, R8  ; find highest of top of squeezed and unsqueezed image
+        MOVLO R6, R8  ; use SWI if you prefer... (UNIX ?)
+
+        ; Allocate space for tables
+        ADD   R1, R11, R12  ; nLongs + nShorts
+        ADD   R7, R6, R1, LSL #2 ; curFree += (nLongs + nShorts) * 4;
+
+       [ expand_memcheck
+       SWI   OS_GetEnv     ; returns RAM limit in R1
+        ; R7 points to end of tables; add space required for copied-up
+        ; decode routine.
+        ADD   R2,R7, #|UnSqueeze_UnSqueezeLimit| + 24 - decodeImage
+        ; if PC < the RAM limit, and R2 > the RAM limit, we're in trouble
+        ; (if PC > the RAM limit, we assume we're not in the application slot)
+        CMP   PC,R1
+        CMPLO R1,R2
+       BLO   expand_would_overwrite
+       ]
+
+        MOV   R5, R10       ; R5 is ptr into encoded tables
+        MOV   R4, #0        ; this is the first table el
+decodeTab
+        ; Require:  R11 -- no of els left to decode
+        ;           R6  -- ptr into decoded table
+        ;           R5  -- ptr into encoding
+        ;           R4  -- = 0 iff this is the shorts table (i.e. 4-byte vals)
+
+; I believe this loop could be made good deal smaller and possibly
+; faster, but it's only a couple of hundred bytes and it works.
+
+
+        MOV   R2, R6        ; stash away base of first table
+        MOV   R3, #-1       ; start as if previous entry was -1
+decodeEntry
+        SUBS  R11, R11, #1  ; while (--nEntries >= 0) {
+        BLT   decodedTab    ; assert: previous word is in R3
+        LDRB  R1, [R5], #1  ; byte = *p++
+        SUBS  R0, R1, #10
+        BGE   greaterThan9
+literalOrOnes
+        CMPS  R1, #0
+        BNE   ones
+literal
+        LDRB  R0, [R5], #1
+        LDRB  R1, [R5], #1
+        ORR   R0, R0, R1, LSL #8
+        LDRB  R1, [R5], #1
+        ORR   R0, R0, R1, LSL #16
+        CMPS  R4, #0                 ; in the 4-byte (short encodings) table?
+        LDREQB R1, [R5], #1          ; yes, so include the 4th byte
+        ORREQ  R0, R0, R1, LSL #24   ; in the resultant word
+        ADD   R3, R3, R0
+        STR   R3, [R6], #4
+        B     decodeEntry
+ones
+        SUB   R11, R11, R1
+        ADD   R11, R11, #1
+anotherOne        ; Have number of increment-by-ones in R1
+        ADD   R3, R3, #1
+        STR   R3, [R6], #4
+        SUBS  R1, R1, #1
+        BGT   anotherOne
+        B     decodeEntry
+greaterThan9
+        CMPS  R1, #92
+        ADDLT R3, R3, R0
+        STRLT R3, [R6], #4
+        BLT   decodeEntry
+greaterThan91
+        SUBS  R0, R1, #174
+        BLT   oneMore
+twoMore
+        LDRB  R1, [R5], #1
+        ORR   R0, R1, R0, LSL #16
+        LDRB  R1, [R5], #1
+        ORR   R0, R0, R1, LSL #8
+        ADD   R3, R3, R0
+        STR   R3, [R6], #4
+        B     decodeEntry
+oneMore
+        SUBS  R0, R1, #92
+        LDRB  R1, [R5], #1
+        ORR   R0, R1, R0, LSL #8
+        ADD   R3, R3, R0
+        STR   R3, [R6], #4
+        B     decodeEntry   ; } /* end while (--nEntries >= 0) { */
+
+decodedTab
+        CMPS  R4, #0        ; if isShorts then
+        BNE   finishLongs   ; else finishLongs
+finishShorts
+        MOV   R11, R12      ; no of els to decode = nLongs
+        MOV   R12, R2       ; R12 = &shorts[0]
+        MOV   R2, R6        ; stash away start of longs table
+        MOV   R4, #1        ; next table is longs
+        B     decodeTab
+      [ {TRUE}
+        ; ROL has adopted a policy in their fork of the OS of not allowing
+        ; compressed binaries to run unless their version of UnsqueezeAIF
+        ; recognises characteristic instruction sequences within the
+        ; application's unsqueeze code, which it knows how to patch up and
+        ; run during Service_UKCompression 0. The justification for this is
+        ; apparently that they didn't like the fact that the binary is
+        ; still compressed during Service_UKCompression 1 if UnsqueezeAIF
+        ; drops back to letting the application unsqueeze code run itself
+        ; when normal execution at &8000 starts. So, basically they're
+        ; saying: if this is an application which UnsqueezeAIF doesn't
+        ; currently know for a fact to handle its own cache coherency, then
+        ; on the off-chance that one day in the future it might be
+        ; desirable to be able to patch the application using AppPatcher -
+        ; and yet it would for some reason be impractical to update
+        ; UnsqueezeAIF at *that* point to recognise these cases (!?!) -
+        ; then the OS should already refuse to run the application!
+        ;
+        ; On the other hand, there is a real downside, in that this policy
+        ; hinders the development of alternative compression schemes, or as
+        ; happened in squeeze 5.09, the fixing of certain bugs that have
+        ; a demonstrable effect on real hardware.
+        ;
+        ; Since ROL has failed for nearly 7 years now to adapt their OS
+        ; to cope with squeeze 5.09, we don't have much option but to try
+        ; to work around it. By inserting a pre-StrongARM code sequence
+        ; here (where it will never be executed, but after the start of
+        ; the unsqueeze code where UnsqueezeAIF starts looking for it), we
+        ; can trick UnsqueezeAIF into thinking it recognises us and trusts
+        ; us to be run.
+FakeUnsqSignature
+        LDMIA   R5!,{R0-R3}
+        STMIA   R7!,{R0-R3}
+        CMP     R5,R6
+        BLT     FakeUnsqSignature
+        MOV     PC,R4
+      ]
+finishLongs
+        MOV   R11, R2       ; R11 = &longs[0]
+decodedBothTabs
+        ; Now have:  R13 = sizeToMove
+        ;            R12 = &shorts[0]
+        ;            R11 = &longs[0]
+        ;            R10 = top of encoded data
+        ;            R9  = base of encoded data
+        ;            R8  = top of decoded data
+        ;            R7  = curFree - base of unused memory
+        ;            R0..R6 unused
+
+moveRestOfCode
+        ; Decompression is going to scribble on us here, so copy the
+        ; rest of the code up into free space.
+        ADR   R5, decodeImage
+        ADR   R6, |UnSqueeze_UnSqueezeLimit|+24 ; allow for branch to exec addr
+        MOV   R4, R7  ; we will jump to R4
+
+        ; The following code is what is recognised by UnSqzAIF to interfere
+        ; in the decompression (to do OS_SynchroniseCodeAreas).  Changing it
+        ; will stop it interfering.
+moveCode
+        LDMIA R5!, {R0-R3}
+        STMIA R7!, {R0-R3}  ; NB this updates free space pointer as we go
+        CMPS  R5, R6
+        BLT   moveCode
+        MOV   R1, R4        ; this instruction causes a non-match in UnSqzAIF
+        ADD   R2, R1, #|UnSqueeze_UnSqueezeLimit|+28-decodeImage
+        MOV   R0, #1
+        SWI   XOS_SynchroniseCodeAreas  ; we've written some code.
+        MOV   PC, R4        ; jump to the new copy of the rest of the code
+
+       [ expand_memcheck
+       ; If we were to let the expansion occur, either a data abort would
+       ; occur, or we would overwrite our parent application.
+expand_would_overwrite
+       ADR   R0, error_block - 6 * 4
+       LDMIB R0!, {R1,R2,R4-R7}
+       SWI   XMessageTrans_ErrorLookup
+       LDR   R1,[R0]
+       TEQ   R1, #0
+       ADRNE R0, error_block_failed
+       SWI   OS_GenerateError
+       DCD   0, 0, 0, 0, 0
+error_block
+       DCD   0
+       DCB   "NoMem", 0
+       ALIGN
+error_block_failed
+       DCD   0
+       DCB   "Not enough memory", 0
+       ALIGN
+       ]
+
+decodeImage
+        ; The code from here on gets executed only after it is copied
+        ; elsewhere.  This is confusing, but necessary.
+
+        ; Most of the data gets decoded in place, but we have to go round twice
+        ; just in case we have to copy some data elsewhere, so first
+        ; time round we use a higher R9 (bottom of encoded data).
+
+        ADD   R9, R9, R13   ; base = base + sizeToMove
+
+        ; top of encoded data in R10
+        ; base of encoded data in R9
+        ; top of decoded data in R8
+        ; ptr to shorts in R12
+        ; ptr to longs  in R11
+        ; R0..R6 are free for workspace
+
+; For the moment, we want to overwrite the first word of the image,
+; I think this is just a kludge...
+        SUB   R8, R8, #4
+
+decodePair
+        CMPS  R10, R9           ; Have we reached the base ?
+        BLE   doneDecode
+        LDRB  R6, [R10, #-1]!   ; byte value
+        ; The words will be put in R4 and R5, to be STMDB'd
+        AND   R3, R6, #15       ; first nibble
+        SUBS  R0, R3, #MinShort ; idx = (val - 8)
+        BLT   notshort0
+short0
+        LDRB  R1, [R10, #-1]!
+        ORR   R0, R1, R0, LSL #8
+        LDR   R4, [R12, R0, LSL #2]    ; w = shorts[(nibble-8)<<8 | *p--]
+        B     gotFirst
+notshort0
+        SUBS  R0, R3, #MinLong         ; idx = (val - 2)
+        BLT   notlong0
+long0
+        LDRB  R1, [R10, #-1]!
+        ORR   R0, R1, R0, LSL #8
+        LDR   R0, [R11, R0, LSL #2]    ; w = longs[(nibble-2)<<8 | *p--]
+        LDRB  R1, [R10, #-1]!
+        ORR   R4, R1, R0, LSL #8
+        B     gotFirst
+notlong0
+        MOVS  R4, R3            ; TMD 13-Feb-90: combine 2 instructions here
+                                ; used to be CMPS R3,#0; MOVEQ R4,R3
+        BEQ   gotFirst
+literal0
+        LDRB  R0, [R10, #-1]!
+        LDRB  R1, [R10, #-1]!
+        ORR   R0, R0, R1, LSL #8
+        LDRB  R1, [R10, #-1]!
+        ORR   R0, R0, R1, LSL #16
+        LDRB  R1, [R10, #-1]!
+        ORR   R4, R0, R1, LSL #24
+
+gotFirst
+        ; Phew!  We have the first word of the pair (in R4), now we have
+        ; to do (almost) the same again, result in R5, and STMDB.
+
+        MOV   R3, R6, LSR #4     ; second nibble
+        SUBS  R0, R3, #MinShort  ; idx = (val - 8)
+        BLT   notshort1
+short1
+        LDRB  R1, [R10, #-1]!
+        ORR   R0, R1, R0, LSL #8
+        LDR   R5, [R12, R0, LSL #2]    ; w = shorts[(nibble-8)<<8 | *p--]
+        STMDB R8!, {R4,R5}
+        B     decodePair
+notshort1
+        SUBS  R0, R3, #MinLong        ; idx = (val - 2)
+        BLT   notlong1
+long1
+        LDRB  R1, [R10, #-1]!
+        ORR   R0, R1, R0, LSL #8
+        LDR   R0, [R11, R0, LSL #2]    ; w = longs[(nibble-2)<<8 | *p--]
+        LDRB  R1, [R10, #-1]!
+        ORR   R5, R1, R0, LSL #8
+        STMDB R8!, {R4,R5}
+        B     decodePair
+notlong1
+        MOVS  R5, R3            ; TMD 13-Feb-90: combine 2 instructions here
+                                ; used to be CMPS R3,#0; MOVEQ R5,R3
+
+                                       ; This doesn't pay off much
+        STMEQDB R8!, {R4,R5}           ; might be better to swap round
+        BEQ   decodePair               ; literal and zero, to save 3S on
+literal1                               ; the longer path ?
+        LDRB  R0, [R10, #-1]!
+        LDRB  R1, [R10, #-1]!          ; If I had the right byte-sex and
+        ORR   R0, R0, R1, LSL #8       ; a couple of registers to spare,
+        LDRB  R1, [R10, #-1]!          ; could do this in 15S instead of 22S
+        ORR   R0, R0, R1, LSL #16      ; using the load non-aligned word code
+        LDRB  R1, [R10, #-1]!          ; given in ARM CPU Manual.
+        ORR   R5, R0, R1, LSL #24
+        STMDB R8!, {R4,R5}
+        B     decodePair
+
+doneDecode
+        CMPS  R13, #0      ; Any data need to be copied elsewhere ?
+        BLE   runImage     ; No -- just run the image
+        SUB   R6, R9, R13  ; R6 points to base of encoded data
+        MOV   R9, R7       ; R9 points to base of copied data
+        ADD   R10, R9, R13 ; R10 is current pointer into copied data
+moveEncoded
+        LDMIA R6!, {R0-R3}
+        STMIA R7!, {R0-R3}
+        SUBS  R13, R13, #16
+        BGT   moveEncoded
+        B     decodePair   ; Carry on decoding
+
+; Now R8 should be a pointer to the first word of the decoded image,
+; so lets cross our fingers and jump to it...
+runImage
+        ADR   r2, decodeImage-4
+        MOV   R0, #1
+;       [up to 3 SUB instructions here] R8 adjusted to point back to AIF header
+;       SUB   R1, R8, #4
+;       SWI   XOS_SynchroniseCodeAreas
+;       MOV   PC, R8
+
+|UnSqueeze_UnSqueezeLimit|
+
+; Now the bit of code that actually runs in the image compression program:
+; this just tells it where the decompression code lives.  Are you confused ?
+
+; Entry point to PROCEDURE FindUnSqueezeCode
+; Parameters: base: [FP,#-20]/R0  limit: [FP,#-16]/R1
+;|UnSqueeze_FindUnSqueezeCode|
+;        ADR   R2, |UnSqueeze_UnSqueezeBase|
+;        STR   R2, [R0]
+;        ADR   R2, |UnSqueeze_UnSqueezeLimit|
+;        STR   R2, [R1]
+;        MOV   PC, LR
+
+        END
diff --git a/xpand.c b/xpand.c
new file mode 100644
index 0000000000..2b29acb891
--- /dev/null
+++ b/xpand.c
@@ -0,0 +1,348 @@
+/* This source code in this file is licensed to You by Castle Technology
+ * Limited ("Castle") and its licensors on contractual terms and conditions
+ * ("Licence") which entitle you freely to modify and/or to distribute this
+ * source code subject to Your compliance with the terms of the Licence.
+ * 
+ * This source code has been made available to You without any warranties
+ * whatsoever. Consequently, Your use, modification and distribution of this
+ * source code is entirely at Your own risk and neither Castle, its licensors
+ * nor any other person who has contributed to this source code shall be
+ * liable to You for any loss or damage which You may suffer as a result of
+ * Your use, modification or distribution of this source code.
+ * 
+ * Full details of Your rights and obligations are set out in the Licence.
+ * You should have received a copy of the Licence with this source code file.
+ * If You have not received a copy, the text of the Licence is available
+ * online at www.castle-technology.co.uk/riscosbaselicence.htm
+ */
+/*
+ * Title:     xpand - decompression of squeezed AIF executable images
+ * Author:    RCC
+ * Copyright: (C) 1988, Acorn Computers Ltd, Cambridge, England.
+ * Date:      24-Mar-88
+ * LastEdit:  24-Mar-88
+
+ * 22Feb99: SJM: Note started to convert this to be able to run on
+ * Solaris. However this isn't easily possible since currently it xpands
+ * by running the unsqueeze code embedded in the code.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "CLX/wholefls.h"
+
+#ifdef __riscos
+#include "CLib/kernel.h"
+#include "CLib/swis.h"
+#else
+typedef struct {
+   int load, exec;       /* load, exec addresses */
+   int start, end;       /* start address/length, end address/attributes */
+} _kernel_osfile_block;
+#endif
+
+#ifndef __riscos
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#include "squeeze.h"
+#include "VersionNum"
+
+#define DATE Module_Date
+/* If macro value is empty, expression rewrites to "0 * + 1" which is zero. */
+#if 0 * Module_MinorVersion_CMHG + 1 == 0
+#  define VSN  Module_MajorVersion
+#else
+#  define VSN  Module_MajorVersion " (" Module_MinorVersion ")"
+#endif
+#define SELF "xpand"
+
+typedef int func(int, int, int);
+
+#ifndef __riscos
+# include "asmcall1.h"
+#else
+extern int asmcall_call(func *, int, int, int);
+extern int *asmcall_exit;
+#endif
+
+static int debug;
+static int verbose;
+
+#undef AIFPRELUDE /* musn't rely on this constant - it's changed over time */
+
+/*
+ * Veneer on file-handling.
+ */
+
+#define SAVE     0
+#define WRITEINFO 1
+#define READINFO  5
+#define LOAD     0xff
+
+#define FILFOUND  1
+
+#ifdef __riscos
+static void arthurise(_kernel_osfile_block *info)
+{ if ((info->load == info->exec) && (info->load == 0x8000)) {
+    /* can we use Arthur 'FF8' filetype ? */
+    if (_kernel_hostos() == _kernel_ARTHUR) {
+      /* This is Arthur - get time of day */
+      int data[2];
+      data[0] = 3;
+      if (_kernel_osword(14, data) != _kernel_ERROR) {
+       info->exec = data[0];
+       info->load = 0xfffff800 + (data[1] & 0xff);
+      }
+    }
+  }
+}
+#endif
+
+static int fileinfo(_kernel_osfile_block *info, const char *name)
+{
+#ifdef __riscos
+  if (_kernel_osfile(READINFO, name, info) != FILFOUND)
+      return -1;
+#else
+  struct stat buf;
+  int len, ftype;
+
+  if (stat(name, &buf) != 0) return -1;
+
+  len = strlen(name);
+  if (len > 4 && name[len-4] == ',')
+    ftype = (int)strtoul(name + len - 4, NULL, 16);
+  else
+    ftype = 0xfff;
+
+  info->load = 0xfff00000 | (ftype << 8);
+  info->exec = buf.st_mtime * 100 / 256;
+  info->start = buf.st_size;
+  info->end = 0;
+#endif
+  return 0;
+}
+
+static void fatalerror(const char *format, const char *name) {
+  fputs(SELF ": ", stderr);
+  fprintf(stderr, format, name);
+#ifdef __riscos
+  { _kernel_oserror *e = _kernel_last_oserror();
+    if (e != 0) fprintf(stderr, " (host error %#x: %s)", e->errnum, 
e->errmess);
+  }
+#endif
+  fputc('\n', stderr);
+  exit(1);
+}
+
+#define ROR(x, n) (((x)<<(32-(n))) | (((x)>>(n)) & ((1<<(32-(n)))-1)))
+
+static int immfield(word inst) {
+  int shift = (inst & 0xf00) >> 7;
+  int val = inst & 0xff;
+  return ROR(val, shift);
+}
+
+static SqueezeHeader *find_squeeze_header(int isaif, int *decompress)
+{
+    /*
+     * The size of the decoded thing is stored 6 words before the
+     * start of the unsqueezing code (see squeeze.c).
+     */
+    if (!isaif) {
+        /*
+         * Non-AIF images skip the first few instructions of the unsqueezing
+         * code; this has changed over time, so search backwards for
+         * MOV R0, #<imm>, which is always the first instruction
+         */
+        while (((*decompress & 0xfffff000) != 0xe3a00000)) decompress--;
+    }
+    return (SqueezeHeader *) (decompress-SQUEEZEWORDS);
+}
+
+static int xpand(char *in, char *out)
+{   _kernel_osfile_block info;
+    bool isaif, isdata;
+    int squeezedby = 0;
+    int size;
+    int *ws;
+    aifhdr  *hdr;
+    char *lastb;
+
+    if (verbose)
+      fprintf(stderr, "-- xpanding '%s' to '%s'\n", in, out);
+
+    if (fileinfo(&info, in) == -1)
+      fatalerror("no file '%s'", in);
+    size = info.start;
+    ws = (int *)malloc(size + sizeof(int) + (24*1024)); /* allow space for 
unsqueezing */
+    hdr = (aifhdr *)(ws + 1);
+    if (wf_load(in, hdr, size) == -1)
+      fatalerror("can't load '%s'", in);
+    if ((info.load & 0xfc000000) != 0) { /* Not a valid address */
+       if ((info.load & 0xffffff00) == 0xfffff800) { /* Arthur absolute */
+           info.load = 0x8000; info.exec = 0x8000;
+       } else if ((info.load & 0xffffff00) != SQUEEZED) {
+           info.exec = info.load;
+       }
+    }
+
+    if ((size & 15) == 15 &&
+       ((hdr->bl_decompress & ~B_OFFSET) == BL ||
+        (hdr->bl_decompress & ~B_OFFSET) == B)
+       ) {
+      int d1, d2, d3;
+      lastb = (char *)hdr + size;
+      while (*--lastb == ' ') /* nothing */;
+      if (isdigit(d3 = *--lastb) &&
+         isdigit(d2 = *--lastb) &&
+         *--lastb == '.' &&
+         isdigit(d1 = *--lastb) &&
+         *--lastb == ' ' &&
+         *--lastb == 'c' &&
+         *--lastb == 'c' &&
+         *--lastb == 'r')
+       squeezedby = (d1-'0')*100+(d2-'0')*10+(d3-'0');
+    }
+
+    if (squeezedby == 0)
+      fatalerror("'%s' is not squeezed", in);
+
+    if (hdr->swi_exit == 0xef000011)      /* OK, it's AIF */
+       isdata = NO, isaif = YES;
+    else if (((datahdr *)hdr)->datamagic == DATAMAGIC) /* OK, it's squeezed 
data */
+       isdata = YES, isaif = NO;
+    else
+       isdata = NO, isaif = NO;
+
+    { int *decompress = &(((int *)hdr)[(hdr->bl_decompress & B_OFFSET) + 
PREFETCH]);
+      SqueezeHeader *h = find_squeeze_header(isaif, decompress);
+      int realsize = h->decodedsize;
+      word *lastw = (word *)lastb - 1;
+
+      if (debug)
+       fprintf(stderr, "decodedsize %x  encodedsize %x  encodedtabs %x\n"
+                       "nshorts %x  nlongs %x  bytestomove %x\n"
+                       "squeezer %d.%02d\n",
+                       h->decodedsize, h->encodedsize, h->encodedtabs,
+                       h->nshorts, h->nlongs, h->bytestomove,
+                       squeezedby/100, squeezedby%100);
+      /* Arrange to get back control after decompression.  We can't plant a
+        branch, since the decompression code gets shifted up store before
+        executing (and we'd rather not know the details).  We rely on the
+        fact that at the end of decompression, r8 points to the base of the
+        decompressed image and this is followed by
+           SUB r8, r8, #&7c
+           MOV pc, r8
+        (for aif images) or
+
+           ADD r8, r8, #exec_address - load_address
+           MOV pc, r8
+        (otherwise)
+       */
+
+      if (((int)lastb & 3) != 0 ||
+         *lastw != MOV_PC_R8)
+         fatalerror("format error in '%s'", in);
+      if (isaif) {
+          int backwards;
+          for (backwards = 1; backwards < 8; ++backwards) {
+            if (*(lastw-backwards) == (SUB_R8_R8_0 | 0x7c)) break;
+          }
+          if (backwards == 8) {
+            fatalerror("aif format error in '%s' (end of expansion code not 
found)", in);
+          }
+          *(lastw-backwards) = (SUB_R8_R8_0 | 0x80);
+      } else {
+         int execoffset = 0;
+         for (;; lastw--) {
+             word inst = *(lastw-1);
+             if ((inst & ~0xfff) == ADD_R8_R8_0)
+                 execoffset += immfield(inst);
+             else if ((inst & ~0xfff) == SUB_R8_R8_0)
+                 execoffset -= immfield(inst);
+             else
+                 break;
+         }
+         info.exec += execoffset;
+      }
+      *lastw = LDR_PC_R8_MINUS4;
+      *ws = (int)(&asmcall_exit);
+      asmcall_call((func *)hdr, 0, 0, 0);
+    /*
+     * Just have to save it again.
+     */
+      if (isdata) {
+         datahdr *d = (datahdr *)hdr;
+         info.load = (int)d->load;
+         info.exec = d->exec;
+         info.start = (int)(d+1);
+         info.end = info.start + d->size;
+      } else {
+#ifdef __riscos
+         arthurise(&info);
+#endif
+         info.start = (int)hdr;
+         if (isaif)
+           info.end = info.start + sizeof(*hdr) + realsize;
+         else
+           info.end = info.start + realsize;
+      }
+      if (wf_save(out, (void *)info.start, info.end - info.start) == -1)
+       fatalerror("failed to write '%s'", out);
+#ifdef __riscos
+      _swix(OS_File, _INR(0,2), 18, out, (info.load << 12) >> 20);
+#endif
+
+      return(0);
+    }
+}
+
+static void help(void)
+{
+    fprintf(stderr, "\n%s vsn %s [%s] - \n", SELF, VSN, DATE);
+    fprintf(stderr, "takes an executable AIF image or data file compressed 
by\n");
+    fprintf(stderr, "'squeeze' and decompresses it to reproduce the original 
image\n");
+    fprintf(stderr, "(possibly with an extra 4 bytes of zeros on the 
end).\n\n");
+    fprintf(stderr, "syntax: xpand <squeezed-file> [<unsqueezed-file>]\n");
+}
+
+int main(int argc, char *argv[])
+{   int j;
+    char *arg;
+    char *a = NULL;
+    char *b = NULL;
+    char c;
+
+    debug = verbose = 0;
+    for (j = 1; j < argc; ++j) {
+       arg = argv[j];
+       if (arg[0] == '-') {
+           c = arg[1];
+           if (('A' <= c) && (c <= 'Z')) c += ('a' - 'A');
+           switch (c) {
+               case 'h':  help();    exit(0);
+               case 'q':  ++debug;   break;
+               case 'v':  ++verbose; break;
+               default:
+                   fprintf(stderr, SELF ": flag '%c' not recognised", c);
+                   help();
+                   exit(1);
+           }
+       } else { /* a filename */
+           if      (a == NULL) a = arg;
+           else if (b == NULL) b = arg;
+           else {
+               fatalerror("too many args '%s'", arg);
+           }
+       }
+    }
+    if (a == NULL) fatalerror("need <file-to-xpand>", 0);
+    if (b == NULL) b = a; /* xpand it to itself */
+    return(xpand(a, b));
+}


-----------------------------------------------------------------------


-- 
Cross-compilation toolchains and environments


Reply via email to