/*****************************************************************************
 * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved
 * 
 * This  software  contains  proprietary  and  confidential   information   of
 * Digi International  Inc.   By  accepting  transfer  of this copy, Recipient
 * agrees to retain this software in  confidence,  to  prevent  disclosure  to
 * others,  and  to make no  use of this software other than that for which it
 * was delivered.  This is an unpublished copyright work  Digi   International
 * Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is
 * strictly prohibited.
 * 
 * Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc.
 * Confidential  when   combined   with   the   aggregated  modules  for  this
 * product) OBJECT CODE ONLY SOURCE MATERIALS
 * 
 * (C) COPYRIGHT Digi International Inc. 1995
 * 
 * All Rights Reserved
 * 
 * US   Government   Users   Restricted   Rights   -   Use,   duplication   or
 * disclosure  restricted by GSA ADP Schedule Contract with Digi International
 * Inc.
 * 
 *****************************************************************************/

/******************************************************************
 * Stac Software Library
 *
 * This file contains a lower-layer interface to the STAC software
 * routines.  This file is compliant with the interface defined
 * in staclib.c.
 ******************************************************************/

/*
 * @(#) $Id: stacswlib.c,v 1.3 1997/10/21 20:48:33 gary Exp $
 */

#include "types.h"
#include "errno.h"
#include "stream.h"
#include "system.h"
#include "device.h"
#include "stacswlib.h"
#include "lzs.h"

#define	STACLIB_MAX_CONTEXTS	4

/* This is the size of a Look4Match structure, in bytes */
#define	STACLIB_COMPRESS_HISTORY_SIZE	20368
#define	STACLIB_DECOMPRESS_HISTORY_SIZE	4144

/*
 * Context database
 */
static StacContext_t StacContext[STACLIB_MAX_CONTEXTS] ;

/*
 * History databases
 */
static uint8 StacCompressHistory[STACLIB_MAX_CONTEXTS*STACLIB_COMPRESS_HISTORY_SIZE];
static uint8 StacDecompressHistory[STACLIB_MAX_CONTEXTS*STACLIB_DECOMPRESS_HISTORY_SIZE];

/*
 * External variables and functions
 */
extern mblk_t *allocb() ;

/****************************************************************************
 * StacInit  --  API call.
 *
 * Purpose:  To intialize the STAC database to an idle state, and
 *           intialize all contexts.
 *
 * Paramters: NONE
 *
 * Returns:   1 on success, 0 on failure
 *
 * Notes:    This function should only be called once.
 */

int
StacInit()
{
	int i, j ;

	for(i = 0; i < STACLIB_MAX_CONTEXTS; i++) {
		/*
		 * Initialize Context Table
		 */
		StacContext[i].DecompHist = (int3264)&StacDecompressHistory[STACLIB_DECOMPRESS_HISTORY_SIZE*i] ;
		StacContext[i].CompHist   = (int3264)&StacCompressHistory[STACLIB_COMPRESS_HISTORY_SIZE*i] ;
		StacContext[i].CompOptions= LZS_PERFORMANCE_MODE_2 ;
		StacContext[i].State = 0 ;
	}


	return 1 ;
}


/****************************************************************************
 * StacGetNewContext  --  API call
 *
 * Purpose:  To provide the caller with a compression/decompression context.
 *
 * Paramters: KeepHist -- If set to a non-zero value, the compression history
 *                        will be preserved across compression operations
 *                        in this context.  Otherwise, the history will be
 *                        reset after each compression operation completes.
 *                        This feature usually yields better compression
 *                        ratios, but generally requires some degree of
 *                        higher level error checking across the link.
 *
 * Returns:   Pointer (handle) to a new context on success.
 *            0 on failure.
 *
 * Notes:    The pointer returned from this function should be used as
 *           a handle to all basic compression/decompression function calls.
 *           StacResetHistory() should be executed on the resulting context.
 */

caddr_t
StacGetNewContext(KeepHist)
uint32 KeepHist ;
{
	static int FirstCall = 1 ;
	StacContext_t *NewContext ;
	register int i ;

	if (FirstCall) {
		if (StacInit())
			FirstCall = 0 ;
		else
			return ((caddr_t) 0) ;
	}

	/* Search for first unused context with NO JOBS OUTSTANDING */
	for(NewContext = StacContext, i = 0; i < STACLIB_MAX_CONTEXTS; NewContext++, i++)
		if (!NewContext->State) break;

	/* Mark context "used".  Set KEEP_HISTORY bit when appropriate. */
	if (i < STACLIB_MAX_CONTEXTS) {
		/* Initialize history */
		LZS_InitCompressionHistory((void *) NewContext->CompHist) ;
		LZS_InitDecompressionHistory((void *) NewContext->DecompHist) ;

		NewContext->State |= STAC_CONTEXT_USED ;
		if (KeepHist)
			NewContext->CompOptions |= LZS_SAVE_HISTORY ;
		else
			NewContext->CompOptions &= ~(LZS_SAVE_HISTORY) ;

		return ((caddr_t) NewContext) ;
	}

	/* Failure */
	return ((caddr_t) 0) ;
}

/****************************************************************************
 * StacReleaseContext  --  API Call
 *
 * Purpose:  Places a compression/decompression context back into the pool.
 *
 * Paramters: Context -- A pointer to a StacContext entry.
 *
 * Returns:   1 always.
 *
 * Notes:    None.
 */

int
StacReleaseContext(Context)
StacContext_t *Context ;
{
	/* Simply free the context */
	Context->State = 0 ;

	return 1 ;
}

/****************************************************************************
 * StacResetHistory  --  API call
 *
 * Purpose:  Resets the compression history for a particular context.
 *
 * Paramters: Context -- A pointer to a StacContext entry.
 *            Callback -- This parameter is here to provide compatibility
 *                        with the hardware version of this library.
 *                        It does not affect the outcome of this function.
 *            Callparm -- This parameter is here to provide compatibility
 *                        with the hardware version of this library.
 *                        It does not affect the outcome of this function.
 *
 * Returns:   1 on success, 0 on failure
 *
 * Notes:    This will reset the compression history structure only.
 *           Unlike the hardware version of this library, this does not
 *           need to be called after StacGetNewContext().
 */

uint32
StacResetHistory(Context, Callback, Callparm)
StacContext_t *Context ;
void (*Callback)() ;
uint3264 Callparm ;
{
	/* Error check */
	if (!Context->State) return 0 ;

	/* Reset compression history */
	LZS_InitCompressionHistory((void *) Context->CompHist) ;

	return 1 ;
}

/****************************************************************************
 * StacCompress  --  API Call
 *
 * Purpose:  Start compressing a series of character buffers.
 *
 * Paramters: Context  -- A pointer to a StacContext entry.
 *            Source   -- An mblk_t pointer to the source buffer(s) to compress.
 *            Callback -- This parameter is here to provide compatibility
 *                        with the hardware version of this library.
 *                        It does not affect the outcome of this function.
 *            Callparm -- This parameter is here to provide compatibility
 *                        with the hardware version of this library.
 *                        It does not affect the outcome of this function.
 *            XORByte  -- A pointer to a uint8.  If compression succeeds,
 *                        the LCB (longitudinal check byte) of the original
 *                        data will be stored at this address.
 *                        Set to 0 to decline this option.
 *
 * Returns:   0 if an error occurred;
 *            Otherwise, a mblk_t pointer which points to the
 *            output of the compression operation.
 *
 * Notes:    This function will place the compression output into a single
 *           mblk_t data buffer.  It is possible that the compression operation
 *           itself will succeed, but no memory is available for the output.
 *           Thus, if this function call fails when the KeepHist feature is
 *           being utilized, the user MUST reset the compression history
 *           (via StacResetHistory) or release the context.
 *
 *           This function does NOT free the buffers pointed to by Source.
 */

uint3264
StacCompress(Context, Source, Callback, Callparm, XORByte)
StacContext_t *Context ;
mblk_t *Source ;
void (*Callback)() ;
uint32 Callparm ;
uint8 *XORByte ;
{
	uint32 SourceCount = 0 ;
	uint32 DestCount = 0 ;
	register uint8 LocalXOR = 0xFF ;
	mblk_t *Localmp ;
	mblk_t *Destmp ;
	uint8 *SourcePtrCopy ;

	/* Error check */
	if (!Context->State) return 0 ;

	/* Count the total number of bytes in the buffer chain */
	for(Localmp = Source; Localmp; Localmp = Localmp->b_cont) {
		SourceCount += (uint32)(Localmp->b_wptr - Localmp->b_rptr) ;
	}

	/*
	 * Prealloc the worst-case output buffer.  According to the
	 * STAC software spec, the destination buffer MUST be at
	 * least LZS_DEST_MIN bytes long.
	 */
	DestCount = ((SourceCount * 9) / 8) + 4 ;
	if (DestCount < LZS_DEST_MIN) DestCount = LZS_DEST_MIN ;
	if (!(Destmp = allocb(DestCount+STAC_PREPEND_MARGIN, BPRI_MED))) {
		return 0 ;
	}

#if STAC_PREPEND_MARGIN
	Destmp->b_rptr += STAC_PREPEND_MARGIN ;
	Destmp->b_wptr += STAC_PREPEND_MARGIN ;
#endif

	/*
	 * Compress all buffers into the destination block.
	 * Do not flush until the last block.
	 */
	for(Localmp = Source; Localmp; Localmp = Localmp->b_cont) {
		SourcePtrCopy = Localmp->b_rptr ;
		SourceCount = (uint32)(Localmp->b_wptr - Localmp->b_rptr) ;
		if (!LZS_Compress(&SourcePtrCopy, &Destmp->b_wptr,
			&SourceCount, &DestCount, (void *) Context->CompHist,
			(unsigned short) ( Context->CompOptions | (unsigned short) ((Localmp->b_cont ?
			0 : LZS_SOURCE_FLUSH)) ), STAC_PERFORMANCE_PARAMETER)) {
			freemsg(Destmp) ;
			return 0 ;
		}
		/* Calculate LCB if required */
		if (XORByte) {
			SourcePtrCopy = Localmp->b_rptr ;
			while(SourcePtrCopy != Localmp->b_wptr)
				LocalXOR ^= *SourcePtrCopy++ ;
		}
	}

	/* Save LCB if required */
	if (XORByte)
		*XORByte = LocalXOR ;

	return (uint3264)Destmp ;
}

/****************************************************************************
 * StacDecompress  --  API Call
 *
 * Purpose:  Decompresses a series of character buffers.
 *
 * Paramters: Context  -- A pointer to a StacContext entry.
 *            Source   -- An mblk_t pointer to the compressed data buffer(s).
 *            Callback -- This parameter is here to provide compatibility
 *                        with the hardware version of this library.
 *                        It does not affect the outcome of this function.
 *            Callparm -- This parameter is here to provide compatibility
 *                        with the hardware version of this library.
 *                        It does not affect the outcome of this function.
 *            XORByte  -- A pointer to a uint8.  If decompression succeeds
 *                        immediately, the LCB (longitudinal check byte)
 *                        of the output will be stored at this address.
 *                        Set to 0 to decline this option.
 *
 *
 * Returns:   0 if an error occurred;
 *            Otherwise, a mblk_t pointer which points to the
 *            output of the decompression operation.
 *
 * Notes:    This function will place the decompressed data in a single
 *           mblk_t data buffer.  It is possible that the decompression
 *           operation itself will succeed, but no memory is available
 *           for the output.
 *
 *           If this function fails, or the user has managed to detect lost
 *           information in the data stream, the user MUST order the peer
 *           entity to reset its history if and only if the peer entity is
 *           utilizing a history that spans multiple packets (i.e. the peer
 *           entity is utilizing the KeepHist feature).
 *
 *           This function does NOT free the buffers pointed to by Source.
 */

uint3264
StacDecompress(Context, Source, Callback, Callparm, XORByte)
StacContext_t *Context ;
mblk_t *Source ;
void (*Callback)() ;
uint32 Callparm ;
uint8 *XORByte ;
{
	uint32 DestCount = STAC_DECOMP_BUFFER_SIZE + STAC_PREPEND_MARGIN ;
	register uint8 LocalXOR = 0xFF ;
	mblk_t *Localmp ;
	mblk_t *Destmp ;
	uint8 *SourcePtrCopy ;
	uint32 SourceCount ;
	uint16 rval ;

	/* Error check */
	if (!Context->State) return 0 ;

	/* Allocate output buffer */
	if (!(Destmp = allocb(STAC_DECOMP_BUFFER_SIZE + STAC_PREPEND_MARGIN, BPRI_MED))) {
		return 0 ;
	}

#if STAC_PREPEND_MARGIN
	Destmp->b_rptr += STAC_PREPEND_MARGIN ;
	Destmp->b_wptr += STAC_PREPEND_MARGIN ;
#endif

	/* Decompress all data buffers into output buffer */
	for(Localmp = Source; Localmp; Localmp = Localmp->b_cont) {
		SourceCount = (uint32)(Localmp->b_wptr - Localmp->b_rptr) ;
		SourcePtrCopy = Localmp->b_rptr ;
		rval = LZS_Decompress(&SourcePtrCopy, &Destmp->b_wptr,
			&SourceCount, &DestCount, (void *) Context->DecompHist,
			LZS_SAVE_HISTORY) ;
		if (!rval || (rval & LZS_DEST_EXHAUSTED)) {
			LZS_InitDecompressionHistory((void *) Context->DecompHist) ;
			freemsg(Destmp) ;
			return 0 ;
		}
	}

	/* Calculate and save LCB if required */
	if (XORByte) {
		SourcePtrCopy = Destmp->b_rptr ;
		while(SourcePtrCopy != Destmp->b_wptr)
			LocalXOR ^= *SourcePtrCopy++ ;
		*XORByte = LocalXOR ;
	}

	return (uint3264) Destmp ;
}

/****************************************************************************
 * StacGetCompressResults  --  API Call
 *
 * Purpose:  Provides compatibility with the hardware version of this
 *           library.  In this library, this function does nothing.
 *
 * Paramters: Context  -- A pointer to a StacContext entry.
 *            XORByte  -- A pointer to a uint8.
 *
 * Returns:   0 always
 *
 * Notes:   NONE
 */

uint32
StacGetCompressResults(Context, XORByte)
StacContext_t *Context ;
uint8 *XORByte ;
{
	return 0 ;
}

/****************************************************************************
 * StacGetDecompressResults  --  API Call
 *
 * Purpose:  Provides compatibility with the hardware version of this
 *           library.  In this library, this function does nothing.
 *
 * Paramters: Context  -- A pointer to a StacContext entry.
 *            XORByte  -- A pointer to a uint8.
 *
 * Returns:   0 always
 *
 * Notes:   NONE
 */

uint32
StacGetDecompressResults(Context, XORByte)
StacContext_t *Context ;
uint8 *XORByte ;
{
	return 0 ;
}

/****************************************************************************
 * StacScan  --  Polling function
 *
 * Purpose:  Provides compatibility with the hardware version of this
 *           library.  In this library, this function does nothing.
 *
 * Paramters: NONE
 *
 * Returns:   N/A
 */

void
StacScan()
{
}

