/*
 * compress.c
 * Part of the !Memphis distribution
 * (c) bdb/nas, 1991-3
 */

#define SQUASH

#include "kernel.h"
#include "swis.h"
/* #include "_swis.h" */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "compress.h"

/* #define DEBUG */
#ifdef DEBUG
#define DEBUGF printf
#else
#define DEBUGF 1?(void)0:(void)printf
#endif

#ifdef LZW
#ifndef LZW_Compress
#define LZW_Compress 0xCD000
#define LZW_Decompress 0xCD001
#endif
void compress(char *from, int fromlen, char *to, int *tolen/*out*/)
{ int l;
  _kernel_swi_regs r;
  
  
  if (_swix(LZW_Compress,_INR(0,4)|_OUT(5),3,from,to,fromlen,fromlen,&l) || l==fromlen)
  { memcpy(to,from,fromlen);
    l = fromlen;
  }
  *tolen = l;
}

void uncompress(char *from, int fromlen, char *to, int tolen)
{ if (tolen == fromlen)
  { memcpy(to,from,fromlen);
    return;
  }
  _swix(LZW_Decompress,_INR(0,4),3,from,to,fromlen,tolen);
}
#endif

#ifdef SQUASH
#ifndef Squash_Compress
#define Squash_Compress         0x42700
#define Squash_Decompress       0x42701
#endif

/* Call Squash module SWI to compress data
 * Assumes that tolen >= fromlen
 * In the case where compressed >= exceeds uncompressed size (buffer full) then we
 * simply copy the data.
 * If source data < 32 bytes in length, then it is not work the overheads to compress it.
 */
int compress(char *from, int fromlen, char *to, int tolen)
{ int f,l;
  char *work;
  _kernel_swi_regs r;

  if (fromlen >= 32)
  {
    r.r[0] = 8;
    r.r[1] = -1;
    _kernel_swi(XOS_Bit + Squash_Compress, &r, &r);
    f = r.r[0];
    work = malloc(f);
    r.r[0] = 0;
    r.r[1] = (int) work;
    r.r[2] = (int) from;
    r.r[3] = fromlen;
    r.r[4] = (int) to;
    r.r[5] = fromlen;
    _kernel_swi(XOS_Bit + Squash_Compress, &r, &r);
    f = r.r[0];
    l = r.r[5];
    free(work);
    if ((f == 2) || (l == 0)) /* out of output space */
    {
      memcpy(to,from,fromlen);
      l = 0;
    } 
  } else
  {
    memcpy(to,from,fromlen);
    l = 0;
  }

  DEBUGF("compress: %d to %d (buf = %d)\n", fromlen, fromlen-l, tolen);
  return(fromlen - l);
}


/* Decompression routine
 * This has a couple of messy hacks in it. Since we don't store anywhere whether
 * a page is compressed, or copied, we have to use the following rules:
 *   If the 'compressed size' and the expected file size are equal, then copied
 *   If 'compressed size' < 32 bytes then copied
 *   If 'compressed data' starts with byte 0x1f then compressed, else copied
 */
void uncompress(char *from, int fromlen, char *to, int tolen)
{ int f,l;
  char *work;
  _kernel_swi_regs r;

  if (((tolen == fromlen) || (fromlen < 32)) && (*from != 0x1f))
  {
    DEBUGF("copy1: %d\n", fromlen);
    memcpy(to,from,fromlen);
    return;
  }
  if (*from == 0x1f)
  {
    r.r[0] = 8;
    r.r[1] = -1;
    _kernel_swi(XOS_Bit + Squash_Decompress, &r, &r);
    f = r.r[0];
    work = malloc(f);
    r.r[0] = 4;
    r.r[1] = (int) work;
    r.r[2] = (int) from;
    r.r[3] = fromlen;
    r.r[4] = (int) to;
    r.r[5] = fromlen;
    _kernel_swi(XOS_Bit + Squash_Decompress, &r, &r);
    f = r.r[0];
    l = r.r[5];    
    free(work);
    DEBUGF("uncompress: %d to %d\n", fromlen, tolen);
  } else
  {
    DEBUGF("copy2: %d\n", fromlen);
    memcpy(to,from,fromlen);
    return;
  }

}

#endif
