diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-10-06 15:55:53 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-10-06 15:55:53 +0100 |
commit | e962168ecfe389000d07ed20203e8aa558827e9f (patch) | |
tree | 932e5907f3c13ad102143550fb4c04c8b5af7cb1 /xpand.c | |
download | squeeze-e962168ecfe389000d07ed20203e8aa558827e9f.tar.gz squeeze-e962168ecfe389000d07ed20203e8aa558827e9f.tar.bz2 |
Initial dump of Castle sources
Diffstat (limited to 'xpand.c')
-rw-r--r-- | xpand.c | 348 |
1 files changed, 348 insertions, 0 deletions
@@ -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)); +} |