Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

446 lines
15 KiB

/*
* Microsoft Confidential
* Copyright (C) Microsoft Corporation 1994
* All Rights Reserved.
*
* QDI.C: Quantum Decompression Interface
*
* History:
* 20-Jan-1994 msliger Initial version.
* 11-Feb-1994 msliger Changed M*ICreate() to adjust size.
* 13-Feb-1994 msliger revised type names, ie, UINT16 -> UINT.
* changed handles to HANDLEs.
* 24-Feb-1994 msliger Changed alloc,free to common typedefs.
* 22-Mar-1994 msliger Changed interface USHORT to UINT.
* 28-May-1994 msliger Created from MDI.C for Quantum.
* Added configuration parameter.
* 30-May-1994 msliger Changed to QDI* names.
* 08-Jul-1994 msliger Support for disk-based ring buffer.
* 27-Jul-1994 msliger Changed to allow ASM decompressor.
* 10-Aug-1994 msliger Changed to assert the requested decompress
* size for improved resistance to corrupted
* input data.
* 18-Aug-1994 msliger Implemented 286 decompress option.
* 31-Jan-1995 msliger Supported QDICreateDecompression query.
* 01-Feb-1995 msliger QDICreate no longer reserves memory.
*/
/* --- preprocessor ------------------------------------------------------- */
/*
* Quantum Decompression is a very complicated, time consuming process, so
* we wrote a hand tuned 386 version. Unfortunately, some environments
* (80286 Win3.x machines and the Windows NT x86 emulation for Mips, Alpha,
* etc.) cannot run 386 code. So, we need to build different flavors of
* QDI.LIB:
* 16-bit QDI.LIB - has 286 & 386 versions
* 16-bit QDI3.LIB - 386-only version
* 32-bit QDI.LIB - 32-bit only version (for Win32 apps)
*
* There are two symbols which can be defined to affect how this code is
* built, USE_C_SRC and USE_386_ASM:
*
* USE_386_ASM Links the 386 assembler source (for i386+ non-Win32 only!)
*
* USE_C_SRC Links the C source. For any application. For
* 16-bit applications, this forces use of large memory model,
* and will generate externs for certain compiler run-time
* helpers, like __aFulmul.
* This is the DEFAULT if neither symbol is defined.
*
* These symbols can be defined in the following combinations:
* USE_386_ASM Only the 386 ASM code for 16-bit environments is available.
* ==> This is intended for Chicago setup, since Chicago only
* runs on i386 or better CPUs.
*
* USE_C_SRC Only the "portable" C code is available.
* ==> For Win32 builds, used by NT setup and Win32 EXTRACT.EXE,
* and Win32 ACME Setup.
*
* <both> Both "portable" C and the 16-bit 386 are available. The
* caller can force the use of the C code (compiled for 286,
* for compatibility purposes) or the 386 code, *or* can allow
* QDI to detect the CPU type and select the appropriate code.
* For 16-bit applications, this forces use of large memory
* model, and will generate externs for certain compiler run-
* time helpers, like __aNulshr.
* ==> For 16-bit ACME, which has to pass down the CPU type as
* determined by calling the Win16 API, since our CPU
* detection code is not reliable in 286-prot mode!
* ==> For 16-bit EXTRACT.EXE, which will rely upon the CPU
* detection code!
*
* <neither> Same as USE_C_SRC
*/
#include <stdio.h> /* for NULL */
#ifdef USE_386_ASM
#ifdef USE_C_SRC
#define USE_BOTH /* means both are present */
#endif
#else /* if not USE_386_ASM */
#ifndef USE_C_SRC
#define USE_C_SRC /* make sure USE_C_SRC is defined if not USE_386_ASM */
#endif
#endif
#include "qdi.h" /* types, prototype verification, error codes */
#include "qdi_int.h" /* QDI internal structures */
#ifdef USE_C_SRC
#include "dcomp.h" /* features in DCOMP.C */
#include "rtl.h" /* functions we gotta do for you */
#endif
#ifdef USE_386_ASM
#include "decomp.h" /* features in DECOMP.ASM */
#endif
#ifdef USE_BOTH
static int GetCPUtype(void); /* internal CPU determination */
#endif
#define MAX_GROWTH 10240 /* don't know what it will really be */
#pragma warning(disable:4704) /* because of in-line asm code */
/* MAKE_SIGNATURE - Construct a structure signature
*
* Entry:
* a,b,c,d - four characters
*
* Exit:
* Returns constructed SIGNATURE
*
* Example:
* strct->signature = MAKE_SIGNATURE('b','e','n','s')
*/
#define MAKE_SIGNATURE(a,b,c,d) (a + (b<<8) + (c<<16) + (d<<24))
#define BAD_SIGNATURE (0L)
#define QDI_SIGNATURE MAKE_SIGNATURE('Q','D','I','C')
/* --- QDI context structure ---------------------------------------------- */
PMDC_CONTEXT lastContext; /* needed for callbacks */
#define PMDCfromHMD(h) ((PMDC_CONTEXT)(h)) /* handle to pointer */
#define HMDfromPMDC(p) ((QDI_CONTEXT_HANDLE)(p)) /* pointer to handle */
/* --- QDICreateDecompression() ------------------------------------------- */
int FAR DIAMONDAPI QDICreateDecompression(
UINT FAR * pcbDataBlockMax, /* max uncompressed data block */
void FAR * pvConfiguration, /* implementation-defined */
PFNALLOC pfnma, /* Memory allocation function */
PFNFREE pfnmf, /* Memory free function */
UINT FAR * pcbSrcBufferMin, /* gets required input buffer */
QDI_CONTEXT_HANDLE FAR * pmdhHandle, /* gets newly-created handle */
PFNOPEN pfnopen, /* open a file callback */
PFNREAD pfnread, /* read a file callback */
PFNWRITE pfnwrite, /* write a file callback */
PFNCLOSE pfnclose, /* close a file callback */
PFNSEEK pfnseek) /* seek in file callback */
{
PMDC_CONTEXT context; /* new context */
PFQUANTUMDECOMPRESS pConfig; /* to get configuration details */
pConfig = pvConfiguration; /* get a pointer we can use */
if ((pConfig->WindowBits < 10) || (pConfig->WindowBits > 21))
{
return(MDI_ERROR_CONFIGURATION); /* can't accept that */
}
if ((*pcbDataBlockMax == 0) || (*pcbDataBlockMax > 32768u))
{
*pcbDataBlockMax = 32768u; /* help with source block size */
}
*pcbSrcBufferMin = /* we'll expand sometimes */
*pcbDataBlockMax + MAX_GROWTH;
if (pmdhHandle == NULL) /* if no context requested, */
{
return(MDI_ERROR_NO_ERROR); /* return from query mode */
}
#ifdef USE_BOTH
if (pConfig->fCPUtype == QDI_CPU_UNKNOWN)
{
pConfig->fCPUtype = GetCPUtype(); /* figure out if not told */
}
else if ((pConfig->fCPUtype != QDI_CPU_80286) &&
(pConfig->fCPUtype != QDI_CPU_80386))
{
return(MDI_ERROR_CONFIGURATION); /* bogus parameter used */
}
#else /* not USE_BOTH */
#ifdef USE_386_ASM
if (pConfig->fCPUtype == QDI_CPU_UNKNOWN)
{
pConfig->fCPUtype = QDI_CPU_80386;
}
else if (pConfig->fCPUtype != QDI_CPU_80386)
{
return(MDI_ERROR_CONFIGURATION); /* bogus parameter used */
}
#else /* must be USE_C_SRC only */
/** Nothing to do -- we just call the C code, which was either compiled */
/* 16-bit or 32-bit. We could validate the parms, but no real need to */
#endif /* USE_386_ASM */
#endif /* USE_BOTH */
*pmdhHandle = (QDI_CONTEXT_HANDLE) 0; /* wait until it's valid */
context = pfnma(sizeof(struct QDI_CONTEXT));
if (context == NULL)
{
return(MDI_ERROR_NOT_ENOUGH_MEMORY); /* if can't allocate */
}
context->pfnAlloc = pfnma; /* remember where alloc() is */
context->pfnFree = pfnmf; /* remember where free() is */
context->pfnOpen = pfnopen; /* remember where pfnopen() is */
context->pfnRead = pfnread; /* remember where pfnread() is */
context->pfnWrite = pfnwrite; /* remember where pfnwrite() is */
context->pfnClose = pfnclose; /* remember where pfnclose() is */
context->pfnSeek = pfnseek; /* remember where pfnseek() is */
context->cbDataBlockMax = *pcbDataBlockMax; /* remember agreement */
context->fCPUtype = pConfig->fCPUtype; /* remember CPU type */
context->signature = QDI_SIGNATURE; /* install signature */
lastContext = context; /* hand off to memory wrapper */
#ifdef USE_C_SRC
#ifdef USE_BOTH
if (context->fCPUtype == QDI_CPU_80286)
#endif /* USE_BOTH */
{
/** Do the C source init **/
if (DComp_Init((BYTE) (pConfig->WindowBits)) != 0) /* setup decompressor */
{
pfnmf(context); /* self-destruct */
return(MDI_ERROR_NOT_ENOUGH_MEMORY);
}
}
#endif /* USE_C_SRC */
#ifdef USE_386_ASM
#ifdef USE_BOTH
else /* if (context->fCPUtype == QDI_CPU_80386) */
#endif /* USE_BOTH */
{
/** Do the 386 ASM init **/
if (DComp386_Init((BYTE) (pConfig->WindowBits)) != 0) /* setup decompressor */
{
pfnmf(context); /* self-destruct */
return(MDI_ERROR_NOT_ENOUGH_MEMORY);
}
}
#endif /* USE_386_ASM */
/* pass context back to caller */
*pmdhHandle = HMDfromPMDC(context);
return(MDI_ERROR_NO_ERROR); /* tell caller all is well */
}
/* --- QDIDecompress() ---------------------------------------------------- */
int FAR DIAMONDAPI QDIDecompress(
QDI_CONTEXT_HANDLE hmd, /* decompression context */
void FAR * pbSrc, /* source buffer */
UINT cbSrc, /* source actual size */
void FAR * pbDst, /* target buffer */
UINT FAR * pcbResult) /* gets actual target size */
{
PMDC_CONTEXT context; /* pointer to the context */
int result; /* return code */
context = PMDCfromHMD(hmd); /* get pointer from handle */
if (context->signature != QDI_SIGNATURE)
{
return(MDI_ERROR_BAD_PARAMETERS); /* missing signature */
}
lastContext = context; /* hand off to memory wrapper */
if (*pcbResult > context->cbDataBlockMax)
{
return(MDI_ERROR_BUFFER_OVERFLOW); /* violated max block promise */
}
#ifdef USE_C_SRC
#ifdef USE_BOTH
if (context->fCPUtype == QDI_CPU_80286)
#endif /* USE_BOTH */
{
result = DComp_DecompressBlock(pbSrc,cbSrc,pbDst,*pcbResult);
}
#endif /* USE_C_SRC */
#ifdef USE_386_ASM
#ifdef USE_BOTH
else /* (context->fCPUtype == QDI_CPU_80386) */
#endif /* USE_BOTH */
{
result = DComp386_DecompressBlock(pbSrc,cbSrc,pbDst,*pcbResult);
}
#endif /* USE_386_ASM */
if (result == 0)
{
return(MDI_ERROR_NO_ERROR); /* report no failure */
}
else
{
return(MDI_ERROR_FAILED); /* report failure */
}
}
/* --- QDIResetDecompression() -------------------------------------------- */
int FAR DIAMONDAPI QDIResetDecompression(QDI_CONTEXT_HANDLE hmd)
{
PMDC_CONTEXT context; /* pointer to the context */
context = PMDCfromHMD(hmd); /* get pointer from handle */
if (context->signature != QDI_SIGNATURE)
{
return(MDI_ERROR_BAD_PARAMETERS); /* missing signature */
}
lastContext = context; /* hand off to memory wrapper */
#ifdef USE_C_SRC
#ifdef USE_BOTH
if (context->fCPUtype == QDI_CPU_80286)
#endif /* USE_BOTH */
{
DComp_Reset(); /* do it */
}
#endif /* USE_C_SRC */
#ifdef USE_386_ASM
#ifdef USE_BOTH
else /* if (context->fCPUtype == QDI_CPU_80386) */
#endif /* USE_BOTH */
{
DComp386_Reset(); /* do it */
}
#endif /* USE_386_ASM */
return(MDI_ERROR_NO_ERROR); /* if tag is OK */
}
/* --- QDIDestroyDecompression() ------------------------------------------ */
int FAR DIAMONDAPI QDIDestroyDecompression(QDI_CONTEXT_HANDLE hmd)
{
PMDC_CONTEXT context; /* pointer to the context */
context = PMDCfromHMD(hmd); /* get pointer from handle */
if (context->signature != QDI_SIGNATURE)
{
return(MDI_ERROR_BAD_PARAMETERS); /* missing signature */
}
lastContext = context; /* hand off to memory wrapper */
#ifdef USE_C_SRC
#ifdef USE_BOTH
if (context->fCPUtype == QDI_CPU_80286)
#endif /* USE_BOTH */
{
DComp_Close(); /* shut down decompressor */
}
#endif /* USE_C_SRC */
#ifdef USE_386_ASM
#ifdef USE_BOTH
else /* if (context->fCPUtype == QDI_CPU_80386) */
#endif /* USE_BOTH */
{
DComp386_Close(); /* shut down decompressor */
}
#endif /* USE_386_ASM */
context->signature = BAD_SIGNATURE; /* destroy signature */
context->pfnFree(context); /* self-destruct */
return(MDI_ERROR_NO_ERROR); /* success */
}
#ifdef USE_C_SRC
/* --- Rtl_Malloc() ------------------------------------------------------- */
void * FAST Rtl_Malloc( long x )
{
return(lastContext->pfnAlloc((ULONG) x));
}
/* --- Rtl_Free() --------------------------------------------------------- */
void FAST Rtl_Free( void *x )
{
lastContext->pfnFree(x);
}
#endif /* USE_C_SRC */
#ifdef USE_BOTH
/* --- GetCPUtype() ------------------------------------------------------- */
#define ASM __asm
/*** GetCPUtype - Determine CPU type (286 vs. 386 or better)
*
* [Logic taken from emm386/smartdrv.]
*
* Entry:
* none:
*
* Exit:
* Returns QDI_CPU_80286 if on i286 or compatible.
* Returns QDI_CPU_80386 if on i386 or better (or compatible).
*/
static int GetCPUtype(void)
{
int f286;
ASM pushf /* preserve original flags */
ASM mov ax,7000h /* try to set some special flags bits */
ASM push ax /* put up for popf */
ASM popf /* pull number into flags */
ASM pushf /* push flags back */
ASM pop ax /* pull flags into AX */
ASM popf /* restore original flags */
ASM and ax,7000h /* check for 386-specific bits */
ASM mov f286,ax /* return the result */
if (f286 != 0)
{
return(QDI_CPU_80386);
}
else
{
return(QDI_CPU_80286);
}
}
#endif /* USE_BOTH */
/* ------------------------------------------------------------------------ */