/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

static void compress_decompress(uchar *src_adr, ulong src_len,
	uchar *dst_adr, ulong *p_dst_len);
static void fast_copy(uchar *p_src,uchar *p_dst,ulong len);

Handle GetCompResource(OSType theType, short theID)
{
	long srcLen, dstLen;
	Handle srcHandle;

	srcHandle = GetResource(theType, theID);
	if (!srcHandle) return nil;
	srcLen = GetHandleSize(srcHandle);
	SetHandleSize(srcHandle, 32768L);
	if (MemError()) {
		ReleaseResource(srcHandle);
		return nil;
	}
	HLock(srcHandle);
	BlockMove(*srcHandle, (uchar *)*srcHandle + 32768L - srcLen, srcLen);
	compress_decompress((uchar *)*srcHandle + 32768L - srcLen, srcLen,
						(uchar *)*srcHandle, (ulong *)&dstLen);
	SetHandleSize(srcHandle, dstLen);
	HUnlock(srcHandle);
	return srcHandle;
}

//------------------------------------------------------------------------------

#define UBYTE unsigned char      /* Unsigned byte                       */
#define UWORD unsigned int       /* Unsigned word (2 bytes)             */
#define ULONG unsigned long      /* Unsigned word (4 bytes)             */
#define BOOL  unsigned char      /* Boolean                             */
#define REAL double              /* USed for floating point stuff.      */

#define DONE_PORT                   /* Don't do all this again.            */
#define MALLOC_FAIL NULL            /* Failure status from malloc()        */
#define LOCAL static                /* For non-exported routines.          */
#define EXPORT                      /* Signals exported function.          */
#define then                        /* Useful for aligning ifs.            */
#define FLAG_BYTES    4     /* How many bytes does the flag use up?           */
#define FLAG_COMPRESS 0     /* Signals that output was result of compression. */
#define FLAG_COPY     1     /* Signals that output was simply copied over.    */
#define GROUP_CMP 34
#define GROUP_RAW 288
#define CONTROL_INIT 0xFFFF8000

void fast_copy(UBYTE *p_src,UBYTE *p_dst,ULONG len) /* Fast copy routine.             */
{while (len--) *p_dst++=*p_src++;}

static void compress_decompress(uchar *p_src_first, ulong src_len,
	uchar *p_dst_first, ulong *p_dst_len)
/* Input  : Specify input block using p_src_first and src_len.          */
/* Input  : Point p_dst_first to the start of the output zone.          */
/* Input  : Point p_dst_len to a ULONG to receive the output length.    */
/* Input  : Input block and output zone must not overlap. User knows    */
/* Input  : upperbound on output block length from earlier compression. */
/* Input  : In any case, maximum expansion possible is nine times.      */
/* Output : Length of output block written to *p_dst_len.               */
/* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
/* Output : Writes only  in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */
{
 register UBYTE *p_src=p_src_first+FLAG_BYTES, *p_dst=p_dst_first;
 UBYTE *p_src_post=p_src_first+src_len;
 UBYTE *p_src_max16=p_src_first+src_len-(16*2);
 register ULONG control=1;
 if (*p_src_first==FLAG_COPY)
   {fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES);
    *p_dst_len=src_len-FLAG_BYTES; return;}
 while (p_src!=p_src_post)
   {register UWORD unroll;
    if (control==1) {control=0x10000|*p_src++; control|=(*p_src++)<<8;}
    unroll= p_src<=p_src_max16 ? 16 : 1;
    while (unroll--)
      {if (control&1)
         {register UWORD lenmt; register UBYTE *p;
          lenmt=*p_src++; p=p_dst-(((lenmt&0xF0)<<4)|*p_src++);
          *p_dst++=*p++; *p_dst++=*p++; *p_dst++=*p++;
          lenmt&=0xF; while (lenmt--) *p_dst++=*p++;}
       else
          *p_dst++=*p_src++;
       control>>=1;
      }
   }
 *p_dst_len=p_dst-p_dst_first;
}
