Commit 49e960c2 authored by Stewart Brodie's avatar Stewart Brodie
Browse files

Completely rewritten version of unmodsqz.

Detail:
  Rewritten the main desqueeze code in C so that this tool can
    be used on Solaris (required for STB-400 baseline)
  The new unsqueezec.c file was reverse engineered from the
    old assembler code.
Admin:
  Tested on RISC OS, x86 Solaris and SPARC Solaris.

Version 0.02. Tagged as 'unmodsqz-0_02'
parent 71180376
s/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true
c/** gitlab-language=c linguist-language=c linguist-detectable=true
h/** gitlab-language=c linguist-language=c linguist-detectable=true
......@@ -58,7 +58,7 @@ SQZFLAGS = -f
#
# Include files
#
INCLUDES= -IC:
INCLUDES= -IC: -IC:CLX
#
# Libraries
......@@ -66,18 +66,19 @@ INCLUDES= -IC:
CLIB = Clib:o.Stubs
ROMCSTUBS = RISCOSLIB:o.romcstubs
ABSSYM = RISC_OSLib:o.AbsSym
CLXLIB = C:CLX.o.CLXlib
DEPEND = -depend !Depend
ASFLAGS = ${DEPEND} ${THROWBACK}
CFLAGS = -c -ffah ${INCLUDES} ${DEPEND} ${THROWBACK}
LDFLAGS = -aif
RAM_OBJS = o.UnSqueeze o.unmodsqz
RAM_OBJS = o.unsqueezec o.unmodsqz
#
# Rule patterns
#
.c.o:; ${CC} ${CFLAGS} -o $@ $<
.c.o:; ${CC} ${CFLAGS} -DTARGET_IS_RISCOS -o $@ $<
.s.o:; ${AS} ${ASFLAGS} -o $@ $<
#
......@@ -104,7 +105,7 @@ export:
#
${RAM_MODULE}: ${RAM_OBJS} ${CLIB}
${MKDIR} aif
${LD} ${LDFLAGS} -o $@ ${RAM_OBJS} ${CLIB}
${LD} ${LDFLAGS} -o $@ ${RAM_OBJS} ${CLXLIB} ${CLIB}
${SQUEEZE} ${SQZFLAGS} $@
Access $@ RW/R
......
/* (0.01)
/* (0.02)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 0.01
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 05 Nov 1998
#define Module_MajorVersion_CMHG 0.02
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 19 Aug 2000
#define Module_MajorVersion "0.01"
#define Module_Version 1
#define Module_MinorVersion ""
#define Module_Date "05 Nov 1998"
#define Module_MajorVersion "0.02"
#define Module_Version 2
#define Module_MinorVersion ""
#define Module_Date "19 Aug 2000"
#define Module_ApplicationDate2 "19-Aug-00"
#define Module_ApplicationDate4 "19-Aug-2000"
#define Module_FullVersion "0.02"
......@@ -20,208 +20,170 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "VersionNum"
#include "bytesex.h"
#include "err.h"
#include "prgname.h"
#include "wholefls.h"
#include "unmodsqz.h"
#ifdef TARGET_IS_RISCOS
#include "kernel.h"
#include "swis.h"
#include "VersionNum"
#endif
#define Program_Title "unmodsqz"
static int verbose = 0;
/*
* This structure mimics that which the kernel uses to remember module
* details. We pass this to the assembler code we pinched from the kernel
* to avoid having to change any of the main parts of the unsqueezing code.
*/
typedef struct modchain {
struct modchain *next;
int *code;
int podule_base;
void *incarn_list;
int rommodule_node;
} modchain;
/* The assembler entry point */
extern void CheckModule(modchain *);
/* Error messages */
static const char err_NO_FILENAME[] = "missing filename";
static const char err_HELP[] =
"\nUsage: " Program_Title " [options] infile [outfile]\n\n"
"Options:\n"
" -o output Writes unsqueezed module to output\n"
" -v Verbose\n"
" -h -? Display help message\n";
static const char err_BAD_OPTION[] = "unrecognised option '%c'";
static const char err_BAD_PARAMETERS[] = "too many parameters";
static const char err_NO_OPEN[] = "unable to open `%s' for %sing";
static const char err_NOT_MODULE[] = "not a relocatable module";
static const char err_NO_RMA[] = "Unable to allocate RAM for module";
static const char err_NO_LOAD[] = "Unable to load input file";
static const char err_NO_PARAMS[] = "missing filenames";
static void banner(void)
static char *errors[] = {
"",
"This module is not squeezed",
"Out of memory",
"internal error: decode failed",
"missing filename",
"unrecognised option '%c'",
"too many parameters",
"not a relocatable module",
"Unable to load input file %s",
"Unable to save output file %s",
"missing filenames"
};
static void banner(const char *prog)
{
static int shown = 0;
if (shown) return;
++shown;
fputs("Acorn Module Unsqueeze Utility version " Module_MajorVersion " ["
Module_Date "] " Module_MinorVersion "\n", stderr);
fprintf(stderr,
"Module Unsqueeze Utility version " Module_MajorVersion " ["
Module_Date "] " Module_MinorVersion "\n\n"
"Usage: %s [options] infile [outfile]\n\n"
"Options:\n"
" -o output Writes unsqueezed module to output\n"
" -v Verbose\n"
" -h -? Display help message\n",
prog);
exit(EXIT_FAILURE);
}
/* Print error message - does not return */
static void err(const char *errstring, ...)
{
va_list ap;
banner();
if (errstring != err_HELP) fprintf(stderr, Program_Title ": ");
va_start(ap, errstring);
vfprintf(stderr, errstring, ap);
va_end(ap);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
static void info(const char *info, ...)
{
va_list ap;
banner();
va_start(ap, info);
vfprintf(stderr, info, ap);
va_end(ap);
}
static int file_length(const char *filename, int *load, int *exec, int *attr)
static int32 file_length(char *filename, int32 *load, int32 *exec, int32 *attr)
{
#ifdef TARGET_IS_RISCOS
_kernel_oserror *e;
int size;
int objtype, filetype;
e = _swix(OS_File, _INR(0,1)|_OUT(0)|_OUTR(2,6), 20, filename,
&objtype, load, exec, &size, attr, &filetype);
if (e != NULL) {
err("%s", e->errmess);
err_fail("%s", e->errmess);
}
else {
if (!(objtype & 1) || filetype != 0xFFA) {
err(err_NOT_MODULE);
err_fail(errors[errcode_NOT_MODULE]);
}
}
return size;
#else
int32 size = wf_filesize(filename);
*load = *exec = *attr = 0;
if (size == -1) {
err_fail(errors[errcode_NO_LOAD], filename);
}
return size;
#endif
}
static void restamp(const char *filename, int load, int exec, int attr)
#ifdef TARGET_IS_RISCOS
static void restamp(const char *filename, int32 load, int32 exec, int32 attr)
{
load |= 0xFFFFFA00;
(void) _swix(OS_File, _INR(0,3)|_IN(5), 1, filename, load, exec, attr);
}
#endif
static void unmodsqz_bytesex_init(void)
{
union {
char b;
unsigned int i;
} b;
b.i = 1;
bytesex_reverse(b.b == 0);
}
int main(int argc, char *argv[])
{
modchain chn;
int load, exec, attr, size;
int realsize;
int *orig;
FILE *f = 0;
char *outfile = 0, *infile = 0;
int ac;
for (ac=1; ac<argc; ++ac) {
char *arg = argv[ac];
if (arg[0] == '-') {
while (*++arg) switch (*arg) {
case 'v': ++verbose; break;
case 'o':
if ((ac+1)<argc) {
if (outfile) {
err(err_BAD_PARAMETERS);
}
outfile = argv[++ac];
}
else {
err(err_NO_FILENAME);
}
break;
case 'h': case '?':
err(err_HELP);
break;
default:
err(err_BAD_OPTION, *arg);
break;
}
continue;
}
if (!infile) infile = arg;
else if (!outfile) outfile = arg;
else err(err_BAD_PARAMETERS);
}
if (!infile) err(err_NO_PARAMS);
if (!outfile) outfile = infile;
size = file_length(infile, &load, &exec, &attr);
if (verbose) info("-- original file is %d bytes\n", size);
f = fopen(infile, "rb+");
if (f == NULL) {
err(err_NO_OPEN, infile, "read");
}
memset(&chn, 0, sizeof(chn));
/* Need to do this in the RMA because the assembler code assumes
* that the squeezed module is living somewhere where it can
* OS_Module 7 it.
*/
if (_swix(OS_Module, _IN(0)|_IN(3)|_OUT(2), 6, size, &chn.code)) {
err(err_NO_RMA);
}
if (fread(chn.code, size, 1, f) != 1) {
err(err_NO_LOAD);
}
orig = chn.code;
/* may include extra zero bytes to pad out original to even number
* of complete words
*/
realsize = chn.code[1];
/* Was the top bit set in the initialise entry? */
if (realsize < 0) {
realsize = (chn.code + ((realsize ^ 0x80000000) >> 2))[-5];
}
else {
free(chn.code);
if (verbose) info("-- source was not squeezed - module copied\n");
exit(EXIT_SUCCESS);
}
CheckModule(&chn);
if (chn.code != orig) {
/* Clear invincible bit - if set, stops *RMClear killing it!! */
chn.code[2] &= ~0x80000000;
if (infile != outfile) {
f = freopen(outfile, "wb", f);
}
else {
rewind(f);
}
if (f) fwrite(chn.code, realsize, 1, f);
else err(err_NO_OPEN, outfile, "writ");
fclose(f);
restamp(outfile, load, exec, attr);
}
else {
if (verbose) info("-- not squeezed with modsqz\n");
}
free(chn.code);
if (verbose) info("-- output size %d bytes\n", realsize);
return EXIT_SUCCESS;
int32 load, exec, attr, size, realsize;
void *realdata;
void *data;
char *outfile = 0, *infile = 0;
int ac;
char *arg;
error_code e;
char program[32];
err_init(program_name(argv[0], program, sizeof(program)));
for (arg=argv[ac=1]; ac<argc; arg=argv[++ac]) if (arg[0] == '-') {
while (*++arg) switch (*arg) {
case 'v':
++verbose;
break;
case 'o':
if ((ac+1)>=argc) err_fail(errors[errcode_NO_FILENAME]);
if (outfile) err_fail(errors[errcode_BAD_PARAMETERS]);
outfile = argv[++ac];
break;
case 'h':
case '?':
banner(program);
break;
default:
err_fail(errors[errcode_BAD_OPTION], *arg);
break;
}
}
else {
if (!infile) infile = arg;
else if (!outfile) outfile = arg;
else err_fail(errors[errcode_BAD_PARAMETERS]);
}
if (!infile) err_fail(errors[errcode_NO_PARAMS]);
if (!outfile) outfile = infile;
size = file_length(infile, &load, &exec, &attr);
if (verbose) err_report("-- original file is %ld bytes", size);
data = malloc((size_t) size);
if (data == NULL) err_fail(errors[errcode_NO_MEM]);
if (-1 == wf_load(infile, data, size)) err_fail(errors[errcode_NO_LOAD], infile);
unmodsqz_bytesex_init();
e = unsqueeze_module((void *)data, &realdata, (size_t *) &realsize);
if (e == errcode_NOT_SQUEEZED) {
if (verbose && outfile != infile) {
err_report("-- source was not squeezed - module copied");
}
realdata = data;
realsize = size;
}
else if (e != ok) {
err_fail(errors[e]);
}
else {
free(data);
}
if (-1 == wf_save(outfile, realdata, realsize)) {
err_fail(errors[errcode_NO_SAVE], outfile);
}
#ifdef TARGET_IS_RISCOS
restamp(outfile, load, exec, attr);
#endif
if (verbose) err_report("-- output size %ld bytes", realsize);
return EXIT_SUCCESS;
}
/* Copyright 2000 Pace Micro Technology plc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* unmodsqz - reverses the effect of modsqz
*
* Copyright (C) Pace Micro Technology plc. 2000
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "bytesex.h"
#include "unmodsqz.h"
/*
*
* This source code is a translation of the assembler source code that you will find
* elsewhere in this component.
*
*/
enum constants {
nibslong = 7,
nibsshort = 14 - nibslong,
minshort = 2 + nibslong,
minlong = 2,
init_compressed_bit = (int32) 0x80000000
};
enum header_fields {
entry_start,
entry_init,
entry_final,
entry_service,
entry_title,
entry_help
};
typedef struct {
int32 decoded_size;
int32 encoded_size;
int32 tables_size;
int32 nshorts;
int32 nlongs;
} module_comp_data_table;
#define absolute_address(ptr, offset) ((void *) (((char *)(ptr)) + (offset)) )
/*
static void *(absolute_address)(void *ptr, int32 offset)
{
return ((char *)ptr) + offset;
}
*/
error_code unsqueeze_module(
int32 *ptr,
void **output,
size_t *output_len)
{
error_code e = ok;
int32 init = bytesex_hostval(ptr[entry_init]) ^ init_compressed_bit;
if (init & init_compressed_bit) {
e = errcode_NOT_SQUEEZED;
}
else {
module_comp_data_table t;
int32 *module;
unsigned char *encoded_hwm;
unsigned char *encoded_lwm;
size_t dt_size = sizeof(module_comp_data_table);
void *void_table_ptr = absolute_address(ptr, init - dt_size);
int32 *data_table_end = void_table_ptr;
module_comp_data_table *pt = void_table_ptr;
/* Take a copy of the information table at the end of the module */
t.decoded_size = bytesex_hostval(pt->decoded_size);
t.encoded_size = bytesex_hostval(pt->encoded_size);
t.tables_size = bytesex_hostval(pt->tables_size);
t.nshorts = bytesex_hostval(pt->nshorts);
t.nlongs = bytesex_hostval(pt->nlongs);
encoded_hwm = absolute_address(data_table_end, -t.tables_size);
encoded_lwm = absolute_address(encoded_hwm, -t.encoded_size);
*output_len = (size_t) t.decoded_size;
*output = module = malloc(*output_len);
if (module == NULL) {
e = errcode_NO_MEM;
}
else {
int32 shortlong_size = (t.nshorts + t.nlongs) * 4;
int32 *exptable = malloc((size_t) shortlong_size);
if (exptable == NULL) {
e = errcode_NO_MEM;
free(module);
}
else {
int32 *decoded_hwm = absolute_address(module, t.decoded_size);
unsigned char *tables_lwm = encoded_hwm;
int32 *decoded_table = exptable;
int32 *decoded_shorts_table = exptable;
int32 *decoded_longs_table = NULL;
enum {
doing_shorts,
doing_longs,
done_shorts_and_longs
} decode_type = doing_shorts;
while (decode_type == doing_shorts || decode_type == doing_longs) {
/* this while loop represents the label decodeTab */
int32 nels = (decode_type == doing_shorts) ? t.nshorts : t.nlongs;
int32 prev_entry = -1;
while (--nels >= 0) {
int32 byte = *tables_lwm++, num;
num = byte - 10;
if (num >= 0) {
/* greaterThan9 */
if (byte < 92) {
prev_entry += num;
*decoded_table++ = prev_entry;
}
else {
num = byte - 174;
if (num >= 0) {
/* twoMore */
num = (*tables_lwm++) | (num << 16);
prev_entry += num | ((int32) (*tables_lwm++) << 8);
*decoded_table++ = prev_entry;
}
else {
/* oneMore */
prev_entry += ((byte - 92) << 8) | (*tables_lwm++);
*decoded_table++ = prev_entry;
}
}
}
else {
/* literalOrOnes */
if (byte == 0) {
/* literal */
num = *tables_lwm++;
num |= ((int32) (*tables_lwm++) << 8);
num |= ((int32) (*tables_lwm++) << 16);
if (decode_type == doing_shorts) {
num |= ((int32) (*tables_lwm++) << 24);
}
prev_entry += num;
*decoded_table++ = prev_entry;
}
else {
/* ones */
nels = (nels - byte) + 1;
while (byte-- > 0) {
*decoded_table++ = ++prev_entry;
}
}
}
}
switch (decode_type) {
case doing_shorts:
decode_type = doing_longs;
decoded_longs_table = decoded_table;
break;
case doing_longs:
decode_type = done_shorts_and_longs;
break;
}
}
/* label: decodedBothTabs
* Matching up register/variable assignments to the assembler:
* R12 = &shorts[0] => decoded_shorts_table
* R11 = &longs[0] => decoded_longs_table
* R10 = highest address + 1 of encoded data => encoded_hwm
* R9 = lowest address of encoded data => encoded_lwm
* R8 = highest address +1 of decoded data => decoded_hwm
*/
while (encoded_hwm > encoded_lwm) {
int32 thisbyte = *--encoded_hwm;
int32 byte;
int32 nib, w[2];
int i;
for (i=0; i<2; thisbyte >>= 4, ++i) {
nib = thisbyte & 0xF;
if (nib >= minshort) {
/* shortX */
w[i] = decoded_shorts_table[((nib - minshort) << 8) | (*--encoded_hwm)];
}
else if (nib >= minlong) {
/* longX */
w[i] = decoded_longs_table[(nib - minlong) << 8 | (*--encoded_hwm)];
w[i] = (w[i] << 8) | (*--encoded_hwm);
}