/* File: C:\WACKER\xfer\cmprs2.c (Created: 20-Jan-1994) * created from HAWIN source file * cmprs2.c -- Routines to implement data decompression * * Copyright 1989,1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 1 $ * $Date: 10/05/98 1:16p $ */ #include #include #if !defined(BYTE) #define BYTE unsigned char #endif #include "cmprs.h" #include "cmprs.hh" #if SHOW // #include #endif /* * * * * * * * * * * * * * * Decompression routines * * * * * * * * * * * * * * */ typedef struct s_dcmp_node DCMP_NODE; struct s_dcmp_node { DCMP_NODE *pstLinkBack; DCMP_NODE *pstLinkFwd; BYTE ucChar; }; #define NODE_CAST DCMP_NODE * DCMP_NODE *pstDcmpTbl; // pointer to lookup table DCMP_NODE *pstCode = NULL; // used to scan table for output int (**ppfDcmpPutfunc)(void *, int); /* ptr. to ptr. to function used by calling func */ int (*pfDcmpPutChar)(void *, int); /* ptr. to function used internally to get data */ void *pPsave; DCMP_NODE *pstTblLimit = NULL; /* pointer to table beyond 1st 256 nodes */ DCMP_NODE *pstExtraNode = NULL; /* pointer to additional node used in spec. case */ int fDcmpError; /* set TRUE if illegal code is received */ int fStartFresh = FALSE; unsigned int usCodeMask; /* mask to isolate varible sized codes */ unsigned int usOldCode; /* last code received */ int mcFirstChar; /* final character of pattern readout, actually, the FIRST character of pattern (characters are read out in reverse order */ // #pragma optimize("lgea",on) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: decompress_start * * DESCRIPTION: * * * ARGUMENTS: * * * RETURNS: * */ int decompress_start(int (**put_func)(void *, int), void *pP, int fPauses) { unsigned int usCount; DCMP_NODE *pstTmp; if (!compress_enable()) return(FALSE); pPsave = pP; fFlushable = fPauses; // Due to the use of based pointers, we must use compress_tblspace + 1 // in the following code. Otherwise, node 0 (which could have an offset // of 0 looks like a NULL pointer. // pstDcmpTbl = (DCMP_NODE *)(OFFSETOF(compress_tblspace) + 1); pstDcmpTbl = (DCMP_NODE *)(compress_tblspace); pstCode = NULL; pstExtraNode = (NODE_CAST)&pstDcmpTbl[MAXNODES]; /* last node */ pstExtraNode->pstLinkFwd = NULL; pstTblLimit = (NODE_CAST)&pstDcmpTbl[256]; for (usCount = 0, pstTmp = pstDcmpTbl; usCount < 256; ++usCount) { pstTmp->ucChar = (BYTE)usCount; ++pstTmp; } ulHoldReg = 0; sBitsLeft = 0; sCodeBits = 9; usMaxCode = 512; usCodeMask = (1 << sCodeBits) - 1; usFreeCode = FIRSTFREE; fDcmpError = FALSE; fStartFresh = FALSE; ppfDcmpPutfunc = put_func; pfDcmpPutChar = *ppfDcmpPutfunc; *ppfDcmpPutfunc = dcmp_putc; usxCmprsStatus = COMPRESS_ACTIVE; #if SHOW printf("D decompress_start, sCodeBits=%d\n", sCodeBits); #endif return(TRUE); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: decompress_error * * DESCRIPTION: * * * ARGUMENTS: * * * RETURNS: * */ int decompress_error(void) { return(fDcmpError); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: dcmp_start * * DESCRIPTION: * * * ARGUMENTS: * * * RETURNS: * */ int dcmp_start(void *pX, int mcStartChar) { unsigned int usCode; ulHoldReg |= ((unsigned long)mcStartChar << sBitsLeft); sBitsLeft += 8; #if SHOW printf("D %02X %08lX,%2d dcmp_start\n", mcStartChar, ulHoldReg, sBitsLeft); #endif if (sBitsLeft >= sCodeBits) { usCode = (unsigned int)ulHoldReg & usCodeMask; ulHoldReg >>= sCodeBits; sBitsLeft -= sCodeBits; #if SHOW printf("D >> %03X %08lX,%2d sCodeBits=%d dcmp_start\n", usCode, ulHoldReg, sBitsLeft, sCodeBits); #endif /* Table has just been cleared, code must be in range of 0 - 255 */ if (!IN_RANGE((INT)usCode, 0, 255)) { #if SHOW printf("D >> %03X ERROR: out of range\n", usCode); #endif return(dcmp_abort()); } else { #if SHOW printf("D %02X dcmp_start\n", usCode); #endif mcStartChar = (*pfDcmpPutChar)(pPsave, mcFirstChar = (INT)(usOldCode = usCode)); *ppfDcmpPutfunc = dcmp_putc; } } return(mcStartChar); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: dcmp_putc * * DESCRIPTION: * * * ARGUMENTS: * * * RETURNS: * */ int dcmp_putc(void *pX, int mcInput) { unsigned int usCode; unsigned int usInCode; int mcPutResult; DCMP_NODE *pstTmp; ulHoldReg |= ((unsigned long)mcInput << sBitsLeft); sBitsLeft += 8; #if SHOW printf("D %02X %08lX,%2d\n", mcInput, ulHoldReg, sBitsLeft); #endif if (sBitsLeft >= sCodeBits) { usCode = (unsigned int)ulHoldReg & usCodeMask; ulHoldReg >>= sCodeBits; sBitsLeft -= sCodeBits; #if SHOW printf("D >> %03X %08lX,%2d sCodeBits=%d\n", usCode, ulHoldReg, sBitsLeft, sCodeBits); #endif if (usCode == STOPCODE) { if (!fFlushable) decompress_stop(); else { // Pause in the data, leave lookup table intact but start // receiving a fresh stream. sBitsLeft = 0; ulHoldReg = 0L; fStartFresh = TRUE; #if SHOW printf("D %08lX,%2d setting fFreshStart\n", ulHoldReg, sBitsLeft); #endif } } else if (usCode == CLEARCODE) { sCodeBits = 9; usMaxCode = 512; usCodeMask = (1 << sCodeBits) - 1; usFreeCode = FIRSTFREE; *ppfDcmpPutfunc = dcmp_start; #if SHOW printf("D CLEARCODE, sCodeBits=%d\n", sCodeBits); #endif } else if (usCode > (unsigned int)usFreeCode) { #if SHOW printf("D ERROR: usCode > usFreeCode of %03X\n", usFreeCode); #endif return(dcmp_abort()); } else { pstCode = (NODE_CAST)&pstDcmpTbl[usInCode = usCode]; if (usCode == usFreeCode) /* spec. case kkk */ { pstCode = (NODE_CAST)&pstDcmpTbl[usCode = usOldCode]; pstExtraNode->ucChar = (BYTE)mcFirstChar; pstCode->pstLinkFwd = pstExtraNode; #if SHOW printf("D Special case: kkk\n"); #endif } else pstCode->pstLinkFwd = NULL; while(pstCode > pstTblLimit) { pstCode->pstLinkBack->pstLinkFwd = pstCode; pstCode = pstCode->pstLinkBack; } mcFirstChar = pstCode->ucChar; if (!fStartFresh) { #if SHOW printf("D D Added %03X = %03X + %02X\n", usFreeCode, usOldCode, mcFirstChar); #endif if (usFreeCode < MAXNODES) { pstTmp = (NODE_CAST)&pstDcmpTbl[usFreeCode++]; pstTmp->ucChar = (BYTE)mcFirstChar; pstTmp->pstLinkBack = (NODE_CAST)&pstDcmpTbl[usOldCode]; } } fStartFresh = FALSE; usOldCode = usInCode; if (usFreeCode >= usMaxCode && sCodeBits < MAXCODEBITS) { ++sCodeBits; usCodeMask = (1 << sCodeBits) - 1; usMaxCode *= 2; #if SHOW printf("D D New sCodeBits = %d\n", sCodeBits); #endif } while (pstCode != NULL) { #if SHOW printf("D %02X ", pstCode->ucChar); #endif if ((mcPutResult = (*pfDcmpPutChar)(pPsave, pstCode->ucChar)) < 0) { if (mcPutResult == DCMP_UNFINISHED) { #if SHOW printf("Interrupted"); #endif pstCode = pstCode->pstLinkFwd; // to pick up later mcInput = DCMP_UNFINISHED; break; } else { #if SHOW printf("ERROR: putc returned -1"); #endif pstCode = NULL; mcInput = ERROR; break; } } #if SHOW printf("\n"); #endif pstCode = pstCode->pstLinkFwd; } } } return(mcInput); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: decompress_continue * * DESCRIPTION: * Needed for compression in remote control. Picks up expansion of an * output string after it has been interrupted. * * ARGUMENTS: * * * RETURNS: * */ int decompress_continue(void) { int mcPutResult; int mcRetCode; // Deliver an initial unfinished code so routines downstream can pick // up midstream if necessary if ((*pfDcmpPutChar)(pPsave, DCMP_UNFINISHED) == DCMP_UNFINISHED) return DCMP_UNFINISHED; // Now continue delivering any remaining expansion codes unless // interrupted again while (pstCode != NULL) { if ((mcPutResult = (*pfDcmpPutChar)(pPsave, pstCode->ucChar)) < 0) { if (mcPutResult == DCMP_UNFINISHED) { pstCode = pstCode->pstLinkFwd; // to pick up later mcRetCode = DCMP_UNFINISHED; break; } else { pstCode = NULL; mcRetCode = ERROR; break; } } pstCode = pstCode->pstLinkFwd; } return mcRetCode; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: dcmp_abort * * DESCRIPTION: * * * ARGUMENTS: * * * RETURNS: * */ int dcmp_abort(void) { /* print error message or whatever */ fDcmpError = TRUE; decompress_stop(); return(ERROR); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: decompress_stop * * DESCRIPTION: * * * ARGUMENTS: * * * RETURNS: * */ void decompress_stop(void) { #if SHOW printf("D Decompress_stop\n"); #endif if (ppfDcmpPutfunc != NULL) { *ppfDcmpPutfunc = pfDcmpPutChar; ppfDcmpPutfunc = NULL; } usxCmprsStatus = COMPRESS_IDLE; } /* end of cmprs2.c */