/* Copyright 1996 Acorn Computers Ltd
 *
 * 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.
 */
/* -> c.squashff
 * Test harness for the file to file and other variants of
 * the LZW compression/decompression.
 * Copyright (C) 1991 J.G.Thackray
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "kernel.h"

#define Compress_CompressStoreStore         0x42700
#define Compress_DecompressStoreStore       0x42701
#define Compress_CompressStoreFile          0x42702
#define Compress_DecompressStoreFile        0x42703
#define Compress_CompressFileStore          0x42704
#define Compress_DecompressFileStore        0x42705
#define Compress_CompressFileFile           0x42706
#define Compress_DecompressFileFile         0x42707

#define Compress_CompressStoreStoreFast     0x42708
#define Compress_DecompressStoreStoreFast   0x42709

#define USAGE "Usage: squashff [-z] filename filename"

int main(int argc, char *argv[])
{
int bad = 1;
int do_compress = 1;
if (argc == 3 || argc == 4) {
  argv++;
  for (;;) {
    int riscos_input,
        riscos_output,
        i;
    _kernel_swi_regs r;
    _kernel_oserror *err;
    FILE *input,
         *output;
#define workspace_size 0x8000
    char *workspace = malloc(workspace_size);
    char *output_store,
         *output_store_temp,
         *input_store;
    long input_size,
         output_size;
    if (argc == 4) {
      if (strlen(*argv) == 2 && argv[0][0] == '-' &&
        tolower(argv[0][1]) == 'z') {
        do_compress = 0;
        argv++;
      } else {
        break;
      };
    };
/* Test file to file algorithm */
    printf("Testing %sompressFileFile\n", (do_compress) ? "C" : "Dec");
    riscos_input = _kernel_osfind(0x4f, *argv);
    err = _kernel_last_oserror();
    if (err || !riscos_input) {
      fprintf(stderr, "squashff: cannot open '%s' for input\n", *argv);
      if (err) fprintf(stderr, "squashff: error was (0x%x), '%s'\n",
        err->errnum, err->errmess);
      break;
    };
    riscos_output = _kernel_osfind(0x83, argv[1]);
    err = _kernel_last_oserror();
    if (err || !riscos_output) {
      (void)_kernel_osfind(0, (char *)riscos_input); /* Close the input */
      fprintf(stderr, "squashff: cannot open '%s' for output\n", argv[1]);
      if (err) fprintf(stderr, "squashff: error was (0x%x), '%s'\n",
        err->errnum, err->errmess);
      break;
    };
    r.r[0] = (int)workspace;
    r.r[1] = workspace_size;
    r.r[2] = riscos_input;
    r.r[4] = riscos_output;
    r.r[6] = 0;
    err = (do_compress) ? _kernel_swi(Compress_CompressFileFile, &r, &r) :
      _kernel_swi(Compress_DecompressFileFile, &r, &r);
    (void)_kernel_osfind(0, (char *)riscos_input);
    (void)_kernel_osfind(0, (char *)riscos_output);
    if (err) {
      fprintf(stderr, "squashff: %s failed: error (0x%x) '%s'\n",
        (do_compress) ? "Compress" : "Decompress", err->errnum, err->errmess);
      break;
    };
    err = _kernel_last_oserror();
    if (err) {
      fprintf(stderr, "squashff: cannot close files: error (0x%x) '%s'\n",
        err->errnum, err->errmess);
      break;
    };
/* Now try using file to store algorithm */
    printf("Testing %sompressFileStore\n", (do_compress) ? "C" : "Dec");
    output = fopen(argv[1], "r"); /* Already written by above */
    if (!output) {
      fprintf(stderr, "Cannot reopen '%s' for input\n", argv[1]);
      break;
    };
    fseek(output, 0, SEEK_END);
    output_size = ftell(output);
    output_store = malloc((size_t)output_size);
    fseek(output, 0, SEEK_SET);
    if (fread(output_store, 1, (size_t)output_size, output) != output_size) {
      fprintf(stderr, "Cannot read all of '%s' for input\n", argv[1]);
      fclose(output);
      break;
    };
    fclose(output);
    riscos_input = _kernel_osfind(0x4f, *argv);
    err = _kernel_last_oserror();
    if (err || !riscos_input) {
      fprintf(stderr, "squashff: cannot open '%s' for input\n", *argv);
      if (err) fprintf(stderr, "squashff: error was (0x%x), '%s'\n",
        err->errnum, err->errmess);
      break;
    };
    output_store_temp = malloc((size_t)output_size);
    r.r[0] = (int)workspace;
    r.r[1] = workspace_size;
    r.r[2] = riscos_input;
    r.r[4] = (int)output_store_temp;
    r.r[5] = (int)output_size;
    r.r[6] = 0;
    err = (do_compress) ? _kernel_swi(Compress_CompressFileStore, &r, &r) :
      _kernel_swi(Compress_DecompressFileStore, &r, &r);
    (void)_kernel_osfind(0, (char *)riscos_input);
    if (err) {
      fprintf(stderr, "squashff: %s failed: error (0x%x) '%s'\n",
        (do_compress) ? "Compress" : "Decompress", err->errnum, err->errmess);
      break;
    };
    if (do_compress && r.r[0] != 0) {
      fprintf(stderr, "squashff: CompressFileStore fails to complete\n");
      break;
    };
    if (r.r[5] != output_size) {
      fprintf(stderr, "squashff: %s fails to produce correct amount of output\nShould produce 0x%lx, but produced 0x%x\n",
      (do_compress) ? "Compress" : "Decompress", output_size, r.r[5]);
      break;
    };
    if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
      fprintf(stderr, "squashff: CompressFileStore comparison error\n");
      break;
    };
/* Now try file to store restartability on compression */
    if (do_compress) {
      int i = 0;
      printf("Testing CompressFileStore restartability\n");
      while (i < output_size) output_store_temp[i++] = 0;
      /* Clear the output */
      riscos_input = _kernel_osfind(0x4f, *argv);
      err = _kernel_last_oserror();
      if (err || !riscos_input) {
        fprintf(stderr, "squashff: cannot open '%s' for input\n", *argv);
        if (err) fprintf(stderr, "squashff: error was (0x%x), '%s'\n",
          err->errnum, err->errmess);
        break;
      };
      r.r[0] = (int)workspace;
      r.r[1] = workspace_size;
      r.r[2] = riscos_input;
      r.r[4] = (int)output_store_temp;
      r.r[5] = (int)(output_size/2);
      r.r[6] = 0; /* From scratch */
      err = _kernel_swi(Compress_CompressFileStore, &r, &r);
      if (err) {
        fprintf(stderr, "squashff: Compress failed: error (0x%x) '%s'\n",
          err->errnum, err->errmess);
        (void)_kernel_osfind(0, (char *)riscos_input);
        break;
      };
      if (r.r[0] != 0) {
/*
        printf("squashff: CompressFileStore fails to complete first time, continuing\n");
        printf("squashff: output size used 0x%x\n", r.r[5]);
*/
        r.r[0] = (int)workspace;
        r.r[1] = workspace_size;
        r.r[2] = riscos_input;
        r.r[4] = (int)output_store_temp + r.r[5];
        r.r[5] = (int)(output_size); /* Full size */
        r.r[6] = 1; /* From workspace */
        err = _kernel_swi(Compress_CompressFileStore, &r, &r);
        (void)_kernel_osfind(0, (char *)riscos_input);
        if (err) {
          fprintf(stderr, "squashff: CompressFileStore failed: error (0x%x) '%s'\n",
            err->errnum, err->errmess);
          break;
        };
        if (r.r[0] != 0) {
          fprintf(stderr, "squashff: CompressFileStore fails to complete second time\n");
          break;
        };
      } else {
        printf("squashff: CompressFileStore completes first time?\n");
      };
      if (r.r[5] != output_size) {
        fprintf(stderr, "squashff: CompressFileStore fails to produce correct amount of output\nShould produce 0x%lx, but produced 0x%x\n",
        output_size, r.r[5]);
        break;
      };
      if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
        fprintf(stderr, "squashff: CompressFileStore comparison error\n");
        break;
      };
    };
/* Now try using store to store algorithm */
    printf("Testing %sompressStoreStore\n", (do_compress) ? "C" : "Dec");
    i = 0;
    while (i < output_size) output_store_temp[i++] = 0;
    /* Clear the output buffer */
    input = fopen(argv[0], "r");
    if (!output) {
      fprintf(stderr, "Cannot reopen '%s' for input\n", argv[0]);
      break;
    };
    fseek(input, 0, SEEK_END);
    input_size = ftell(input);
    input_store = malloc((size_t)input_size);
    fseek(input, 0, SEEK_SET);
    if (fread(input_store, 1, (size_t)input_size, input) != input_size) {
      fprintf(stderr, "Cannot read all of '%s' for input\n", argv[0]);
      fclose(input);
      break;
    };
    fclose(input);
    r.r[0] = (int)workspace;
    r.r[1] = workspace_size;
    r.r[2] = (int)input_store;
    r.r[3] = (int)input_size;
    r.r[4] = (int)output_store_temp;
    r.r[5] = (int)output_size;
    r.r[6] = 0; /* From scratch, no more input if decompress */
    err = (do_compress) ? _kernel_swi(Compress_CompressStoreStore, &r, &r) :
      _kernel_swi(Compress_DecompressStoreStore, &r, &r);
    if (err) {
      fprintf(stderr, "squashff: %s failed: error (0x%x) '%s'\n",
        (do_compress) ? "Compress" : "Decompress", err->errnum, err->errmess);
      break;
    };
    if (r.r[0] != 0) {
      fprintf(stderr, "squashff: %s fails to complete, r0 = 0x%x, r3 = 0x%x, input_size = 0x%lx\n",
        (do_compress) ? "Compress" : "Decompress", r.r[0], r.r[3], input_size);
      break;
    };
    if (r.r[5] != output_size) {
      fprintf(stderr, "squashff: %s fails to produce correct amount of output\nShould produce 0x%lx, but produced 0x%x\n",
      (do_compress) ? "Compress" : "Decompress", output_size, r.r[5]);
      break;
    };
    if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
      fprintf(stderr, "squashff: CompressStoreStore comparison error\n");
      break;
    };
/* Now try store to store restartability on compression */
    if (do_compress) {
      int i = 0;
      printf("Testing CompressStoreStore restartibility\n");
      while (i < output_size) output_store_temp[i++] = 0;
      /* Clear the output */
      r.r[0] = (int)workspace;
      r.r[1] = workspace_size;
      r.r[2] = (int)input_store;
      r.r[3] = (int)input_size;
      r.r[4] = (int)output_store_temp;
      r.r[5] = (int)(output_size/2);
      r.r[6] = 0; /* From scratch */
      err = _kernel_swi(Compress_CompressStoreStore, &r, &r);
      if (err) {
        fprintf(stderr, "squashff: Compress failed: error (0x%x) '%s'\n",
          err->errnum, err->errmess);
        break;
      };
      if (r.r[0] != 0) {
/*
        printf("squashff: CompressStoreStore fails to complete first time, continuing\n");
        printf("squashff: input size used 0x%x\noutput size used 0x%x\n",
          r.r[3], r.r[5]);
*/
        r.r[0] = (int)workspace;
        r.r[1] = workspace_size;
        r.r[2] = (int)input_store + r.r[3];
        r.r[3] = (int)input_size; /* Should be ignored */
        r.r[4] = (int)output_store_temp + r.r[5];
        r.r[5] = (int)(output_size); /* Full size */
        r.r[6] = 1; /* From workspace */
        err = _kernel_swi(Compress_CompressStoreStore, &r, &r);
        if (err) {
          fprintf(stderr, "squashff: CompressStoreStore failed: error (0x%x) '%s'\n",
            err->errnum, err->errmess);
          break;
        };
        if (r.r[0] != 0) {
          fprintf(stderr, "squashff: CompressStoreStore fails to complete second time\n");
          break;
        };
      } else {
        printf("squashff: CompressStoreStore completes first time?\n");
      };
      if (r.r[5] != output_size) {
        fprintf(stderr, "squashff: CompressStoreStore fails to produce correct amount of output\nShould produce 0x%lx, but produced 0x%x\n",
          output_size, r.r[5]);
        break;
      };
      if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
        fprintf(stderr, "squashff: CompressStoreStore comparison error\n");
        break;
      };
    };
/* Now try store to store restartability on decompression */
    if (!do_compress) {
      int i = 0;
      printf("Testing DecompressStoreStore restartibility\n");
      while (i < output_size) output_store_temp[i++] = 0;
      /* Clear the output */
      r.r[0] = (int)workspace;
      r.r[1] = workspace_size;
      r.r[2] = (int)input_store;
      r.r[3] = (int)(input_size/2);
      r.r[4] = (int)output_store_temp;
      r.r[5] = (int)output_size;
      r.r[6] = 1; /* From scratch, allow continuation */
      err = _kernel_swi(Compress_DecompressStoreStore, &r, &r);
      if (err) {
        fprintf(stderr, "squashff: Decompress failed: error (0x%x) '%s'\n",
          err->errnum, err->errmess);
        break;
      };
      if (r.r[0] != 0) {
/*
        printf("squashff: DeompressStoreStore fails to complete first time, continuing\n");
        printf("squashff: input size remaining 0x%x\noutput size used 0x%x\n",
          r.r[3], r.r[5]);
*/
        r.r[0] = (int)workspace;
        r.r[1] = workspace_size;
        r.r[2] = (int)input_store + (int)(input_size/2) - r.r[3];
        r.r[3] += (int)(input_size/4);
        r.r[4] = (int)output_store_temp + r.r[5];
        r.r[5] = (int)output_size;
        r.r[6] = 3; /* From workspace, continue when run out */
        err = _kernel_swi(Compress_DecompressStoreStore, &r, &r);
        if (err) {
          fprintf(stderr, "squashff: DecompressStoreStore failed: error (0x%x) '%s'\n",
            err->errnum, err->errmess);
          break;
        };
        if (r.r[0] != 0) {
/*
          printf("squashff: DeompressStoreStore fails to complete second time, continuing\n");
          printf("squashff: input size remaining 0x%x\noutput size used 0x%x\n",
            r.r[3], r.r[5]);
*/
          r.r[0] = (int)workspace;
          r.r[1] = workspace_size;
          r.r[2] = (int)input_store + (int)(input_size/2) +
            (int)(input_size/4) - r.r[3];
          r.r[3] += (int)input_size - (int)(input_size/2) -
            (int)(input_size/4);
          r.r[4] = (int)output_store_temp + r.r[5];
          r.r[5] = (int)output_size;
          r.r[6] = 2; /* From workspace, terminate when run out */
          err = _kernel_swi(Compress_DecompressStoreStore, &r, &r);
          if (err) {
            fprintf(stderr, "squashff: DecompressStoreStore failed: error (0x%x) '%s'\n",
              err->errnum, err->errmess);
            break;
          };
          if (r.r[0] != 0) {
            fprintf(stderr, "squashff: DecompressStoreStore fails to complete third time\n");
            break;
          };
        } else {
          printf("squashff: DecompressStoreStore completes second time?\n");
        };
      } else {
        printf("squashff: DecompressStoreStore completes first time?\n");
      };
      if (r.r[5] != output_size) {
        fprintf(stderr, "squashff: DecompressStoreStore fails to produce correct amount of output\nShould produce 0x%lx, but produced 0x%x\n",
          output_size, r.r[5]);
        break;
      };
      if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
        fprintf(stderr, "squashff: DecompressStoreStore comparison error\n");
        break;
      };
    };
/* Now try using store to file algorithm */
    printf("Testing %sompressStoreFile\n", (do_compress) ? "C" : "Dec");
    riscos_output = _kernel_osfind(0x83, argv[1]);
    err = _kernel_last_oserror();
    if (err || !riscos_output) {
      fprintf(stderr, "squashff: cannot open '%s' for output\n", argv[1]);
      if (err) fprintf(stderr, "squashff: error was (0x%x), '%s'\n",
        err->errnum, err->errmess);
      break;
    };
    r.r[0] = (int)workspace;
    r.r[1] = workspace_size;
    r.r[2] = (int)input_store;
    r.r[3] = (int)input_size;
    r.r[4] = riscos_output;
    r.r[6] = 0; /* From scratch, no more input */
    err = (do_compress) ? _kernel_swi(Compress_CompressStoreFile, &r, &r) :
      _kernel_swi(Compress_DecompressStoreFile, &r, &r);
    (void)_kernel_osfind(0, (char *)riscos_output);
    if (err) {
      fprintf(stderr, "squashff: %s failed: error (0x%x) '%s'\n",
        (do_compress) ? "Compress" : "Decompress", err->errnum, err->errmess);
      break;
    };
    output = fopen(argv[1], "r"); /* Already written by above */
    if (!output) {
      fprintf(stderr, "Cannot reopen '%s' for input\n", argv[1]);
      break;
    };
    fseek(output, 0, SEEK_END);
    if (output_size != ftell(output)) {
      fprintf(stderr, "%s produces incorrect output size, should be 0x%lx but was 0x%lx\n", (do_compress) ? "Compress" : "Decompress", output_size,
      ftell(output));
      fclose(output);
      break;
    };
    fseek(output, 0, SEEK_SET);
    if (fread(output_store_temp, 1, (size_t)output_size, output) !=
      output_size) {
      fprintf(stderr, "Cannot read all of '%s' for input\n", argv[1]);
      fclose(output);
      break;
    };
    fclose(output);
    if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
      fprintf(stderr, "squashff: CompressFileStore comparison error\n");
      break;
    };
/* Now try store to file restartability on decompression */
    if (!do_compress) {
      int i = 0;
      printf("Testing DecompressStoreFile restartibility\n");
      while (i < output_size) output_store_temp[i++] = 0;
      /* Clear the output */
      riscos_output = _kernel_osfind(0x83, argv[1]);
      err = _kernel_last_oserror();
      if (err || !riscos_output) {
        fprintf(stderr, "squashff: cannot open '%s' for output\n", argv[1]);
        if (err) fprintf(stderr, "squashff: error was (0x%x), '%s'\n",
          err->errnum, err->errmess);
        break;
      };
      r.r[0] = (int)workspace;
      r.r[1] = workspace_size;
      r.r[2] = (int)input_store;
      r.r[3] = (int)(input_size/2);
      r.r[4] = riscos_output;
      r.r[6] = 1; /* From scratch, allow continuation */
      err = _kernel_swi(Compress_DecompressStoreFile, &r, &r);
      if (err) {
        fprintf(stderr, "squashff: Decompress failed: error (0x%x) '%s'\n",
          err->errnum, err->errmess);
        (void)_kernel_osfind(0, (char *)riscos_output);
        break;
      };
      if (r.r[0] != 0) {
/*
        printf("squashff: DeompressStoreFile fails to complete first time, continuing\n");
        printf("squashff: input size remaining 0x%x\noutput size used 0x%x\n",
          r.r[3], r.r[5]);
*/
        r.r[0] = (int)workspace;
        r.r[1] = workspace_size;
        r.r[2] = (int)input_store + (int)(input_size/2) - r.r[3];
        r.r[3] += (int)(input_size/4);
        r.r[4] = riscos_output;
        r.r[6] = 3; /* From workspace, continue when run out */
        err = _kernel_swi(Compress_DecompressStoreFile, &r, &r);
        if (err) {
          fprintf(stderr, "squashff: DecompressStoreFile failed: error (0x%x) '%s'\n",
            err->errnum, err->errmess);
         (void)_kernel_osfind(0, (char *)riscos_output);
          break;
        };
        if (r.r[0] != 0) {
/*
          printf("squashff: DeompressStoreFile fails to complete second time, continuing\n");
          printf("squashff: input size remaining 0x%x\noutput size used 0x%x\n",
            r.r[3], r.r[5]);
*/
          r.r[0] = (int)workspace;
          r.r[1] = workspace_size;
          r.r[2] = (int)input_store + (int)(input_size/2) +
            (int)(input_size/4) - r.r[3];
          r.r[3] += (int)input_size - (int)(input_size/2) -
            (int)(input_size/4);
          r.r[4] = riscos_output;
          r.r[6] = 2; /* From workspace, terminate when run out */
          err = _kernel_swi(Compress_DecompressStoreFile, &r, &r);
          if (err) {
            fprintf(stderr, "squashff: DecompressStoreFile failed: error (0x%x) '%s'\n",
              err->errnum, err->errmess);
            (void)_kernel_osfind(0, (char *)riscos_output);
            break;
          };
          if (r.r[0] != 0) {
            fprintf(stderr, "squashff: DecompressStoreFile fails to complete third time\n");
            (void)_kernel_osfind(0, (char *)riscos_output);
            break;
          };
        } else {
          printf("squashff: DecompressStoreFile completes second time?\n");
        };
      } else {
        printf("squashff: DecompressStoreFile completes first time?\n");
      };
      (void)_kernel_osfind(0, (char *)riscos_output);
      output = fopen(argv[1], "r"); /* Already written by above */
      if (!output) {
        fprintf(stderr, "Cannot reopen '%s' for input\n", argv[1]);
        break;
      };
      fseek(output, 0, SEEK_END);
      if (output_size != ftell(output)) {
        fprintf(stderr, "DecompressStoreFile produces incorrect output size, should be 0x%lx but was 0x%lx\n", output_size, ftell(output));
        fclose(output);
        break;
      };
      fseek(output, 0, SEEK_SET);
      if (fread(output_store_temp, 1, (size_t)output_size, output) !=
        output_size) {
        fprintf(stderr, "Cannot read all of '%s' for input\n", argv[1]);
        fclose(output);
        break;
      };
      fclose(output);
      if (memcmp(output_store, output_store_temp, (size_t)output_size)) {
        fprintf(stderr, "squashff: DecompressStoreFile comparison error\n");
        break;
      };
    };
    printf("All tests ok\n");
    bad = 0;
    break;
  };
};
if (bad) printf("squashff: %s\n", USAGE);
return 0;
}
