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.
 
 
 
 
 
 

764 lines
19 KiB

/*
* Microsoft Confidential
* Copyright (C) Microsoft Corporation 1994
* Copyright (c) 1993,1994 Cinematronics
* All Rights Reserved.
*
* DCOMP.C: decompressor core
*
* History:
* 08-Jul-1994 msliger Added disk-based ring buffer support.
* 14-Jul-1994 msliger Fixed build of UNPAQ app.
* 30-Aug-1994 msliger Fixed marking buffer dirty if newest.
* 01-Feb-1995 msliger Fixed reporting ring init failures.
*/
// DCOMP.C
//
// Quantum file archiver and compressor
// Advanced data compression
//
// Copyright (c) 1993,1994 Cinematronics
// All rights reserved.
//
// This file contains trade secrets of Cinematronics.
// Do NOT distribute!
#include <stdio.h>
#include <stdlib.h>
#ifdef STAFFORD
#include <alloc.h>
#endif // STAFFORD
#include "quantum.h"
#ifndef UNPAQLIB //msliger
#include "arc.h"
#endif //msliger
#include "dcomp.h"
#include "lz.h"
#include "rtl.h"
#ifndef UNPAQLIB //msliger
extern ARC Arc;
#endif //msliger
#ifdef UNPAQLIB //msliger
#include "arith.h"
#endif
#ifdef UNPAQLIB
#define DISK_RING /* enable DISK_RING support code */
#endif
#ifdef DISK_RING
#include <fcntl.h> /* for disk ring buffer code */
#include <sys\stat.h>
#include "qdi.h" /* for RINGNAME, file functions */
#include "qdi_int.h" /* lastContext */
#endif //msliger
typedef struct
{
BYTE HUGE *Buf; // history buffer: NULL -> using disk ring buffer
BYTE HUGE *BufEnd; // last byte in history buffer + 1
BYTE HUGE *CurPtr; // pointer to oldest byte in history buffer
unsigned long Cur; // current position in the history buffer
long WindowMask; // used to normalize Cur for wrapping
long WindowSize; // size of the history window
#ifndef UNPAQLIB //msliger
long NumBytes; // total number of bytes to decompress
FILE *OutFile; // the output file
WORD Checksum;
#else //msliger
unsigned short NumBytes; // total number of bytes to decompress
BYTE *OutBuffer; //msliger the output buffer
int fOutOverflow; //msliger if too little space in output buffer
BYTE WindowBits; //msliger needed in DComp_Reset()
int fRingFault; // if disk callbacks fail
#endif //msliger
} DCOMP;
DCOMP DComp;
void (FAST2 NEAR *DComp_Token_Match)( MATCH Match );
void (FAST2 NEAR *DComp_Token_Literal)( int Chr );
static void FAST2 DComp_Internal_Match( MATCH Match );
static void FAST2 DComp_Internal_Literal( int Chr );
#ifdef DISK_RING /* virtual ring manager */
#define BUFFER_SIZE (4096) /* must be 2^Nth */
#define MIN_BUFFERS 3 /* minimum number we want */
typedef struct aBuffer
{
struct aBuffer FAR *pLinkNewer; /* link to more recently used */
struct aBuffer FAR *pLinkOlder; /* link to less recently used */
int BufferPage; /* what page this is, -1 -> invalid */
int BufferDirty; /* NZ -> needs to be written */
BYTE Buffer[BUFFER_SIZE]; /* content */
} BUFFER, FAR *PBUFFER;
typedef struct
{
PBUFFER pBuffer; /* pointer to buffer, NULL if not present */
int fDiskValid; /* NZ -> this page has been written to disk */
} PAGETABLEENTRY;
static struct
{
int Handle; /* ring file handle */
PBUFFER RingBuffer; /* current output ring buffer */
BYTE FAR *RingPointer; /* current output pointer (into RingBuffer) */
BYTE FAR *RingPointerLimit; /* address of last byte of RingBuffer + 1 */
int RingPages; /* how many pages there are total */
PBUFFER pNewest; /* pointer to most recently used buffer */
PBUFFER pOldest; /* pointer to least recently used buffer */
PAGETABLEENTRY FAR *PageTable; /* pointer to array of pointers */
} Disk;
static int FAST DComp_Ring_Init(void);
static void FAST DComp_Ring_Reset(void);
static PBUFFER FAST DComp_Ring_Load(int page,int fWrite);
static void FAST2 DComp_Ring_Match( MATCH Match );
static void FAST2 DComp_Ring_Literal( int Chr );
static void FAST DComp_Ring_Close(void);
#endif /* DISK_RING */
int FAST DComp_Init( BYTE WindowBits ) //msliger
{
DComp.WindowSize = 1L << WindowBits; //msliger
DComp.WindowMask = DComp.WindowSize - 1;
DComp.Cur = 0;
#ifdef UNPAQLIB //msliger
DComp.fRingFault = 0;
DComp.WindowBits = WindowBits; //msliger
#endif //msliger
if( (DComp.Buf = Rtl_Malloc( DComp.WindowSize )) != NULL )
{
DComp_Token_Match = DComp_Internal_Match; /* use internal buffering */
DComp_Token_Literal = DComp_Internal_Literal;
DComp.CurPtr = DComp.Buf;
DComp.BufEnd = DComp.Buf + DComp.WindowSize;
}
#ifdef DISK_RING
else if (DComp_Ring_Init()) /* try disk ring buffer */
{
DComp_Token_Match = DComp_Ring_Match; /* use disk buffering */
DComp_Token_Literal = DComp_Ring_Literal;
}
#endif
else
{
return(1); /* if can't create ring buffer */
}
Lz_Init( WindowBits ); //msliger
return(0);
}
void FAST2 DComp_Internal_Match( MATCH Match )
{
BYTE HUGE *SrcPtr;
register BYTE Chr;
if (DComp.NumBytes >= (unsigned) Match.Len)
{
SrcPtr = DComp.Buf + ((DComp.Cur - Match.Dist) & DComp.WindowMask);
DComp.NumBytes -= Match.Len;
DComp.Cur += Match.Len;
while (Match.Len--)
{
#ifdef UNPAQLIB
Chr = *SrcPtr;
*DComp.CurPtr = Chr;
*DComp.OutBuffer++ = Chr;
#else
Chr = *SrcPtr;
*DComp.CurPtr = Chr;
putc( Chr, DComp.OutFile );
DComp.Checksum ^= Chr;
if( DComp.Checksum & 0x8000 ) // simulate a ROL in C, yucky!
{
DComp.Checksum <<= 1;
DComp.Checksum++;
}
else
{
DComp.Checksum <<= 1;
}
#endif
if (++SrcPtr == DComp.BufEnd)
{
SrcPtr = DComp.Buf;
}
if (++DComp.CurPtr == DComp.BufEnd)
{
DComp.CurPtr = DComp.Buf;
}
}
}
else /* match too large to fit */
{
DComp.NumBytes = 0;
#ifdef UNPAQLIB
DComp.fOutOverflow = 1;
#endif
}
}
void FAST2 DComp_Internal_Literal( int Chr )
{
DComp.NumBytes--;
DComp.Cur++;
#ifndef UNPAQLIB
putc( (BYTE) Chr, DComp.OutFile );
DComp.Checksum ^= (BYTE) Chr;
if( DComp.Checksum & 0x8000 ) // simulate a ROL in C, yucky!
{
DComp.Checksum <<= 1;
DComp.Checksum++;
}
else
{
DComp.Checksum <<= 1;
}
#else
*DComp.OutBuffer++ = (BYTE) Chr;
#endif
*DComp.CurPtr = (BYTE) Chr;
if (++DComp.CurPtr == DComp.BufEnd)
{
DComp.CurPtr = DComp.Buf;
}
}
#ifndef UNPAQLIB
WORD FAST DComp_Decompress( FILE *OutputFile, long NumBytes )
{
DComp.OutFile = OutputFile;
DComp.NumBytes = NumBytes;
DComp.Checksum = 0;
{
while( DComp.NumBytes )
{
Lz_NextToken();
}
}
if( DComp.NumBytes < 0 )
{
puts( "ERR: Incorrect file size." );
exit( -1 );
}
return( DComp.Checksum );
}
#endif /* not UNPAQLIB */ //msliger
#ifdef UNPAQLIB
char *pbSource;
int cbSource;
int fSourceOverflow;
WORD FAST DComp_DecompressBlock( void *pbSrc,UINT cbSrc,void *pbDst,UINT cbDst )
{
DComp.NumBytes = cbDst;
DComp.OutBuffer = pbDst;
DComp.fOutOverflow = 0;
pbSource = pbSrc; // pass these along to BIT.C
cbSource = cbSrc;
fSourceOverflow = 0;
Arith_Init();
while( (DComp.NumBytes) && (!fSourceOverflow) )
{
Lz_NextToken();
}
Arith_Close();
return( fSourceOverflow || DComp.fOutOverflow || DComp.fRingFault);
}
#endif
void FAST DComp_Close( void )
{
#ifdef DISK_RING
if (DComp.Buf == NULL)
{
DComp_Ring_Close(); /* if using a disk-based ring buffer */
}
else
{
Rtl_Free( DComp.Buf ); /* if using memory-based ring buffer */
}
#else
Rtl_Free( DComp.Buf ); /* always memory-based */
#endif
Lz_Close();
}
#ifdef UNPAQLIB
// this code is only for use with DComp_DecompressBlock()
void FAST DComp_Reset( void )
{
Lz_Close();
DComp.Cur = 0;
DComp.CurPtr = DComp.Buf;
DComp.fRingFault = 0;
#ifdef DISK_RING
if (DComp.Buf == NULL)
{
DComp_Ring_Reset();
}
#endif
Lz_Init( DComp.WindowBits );
}
#endif /* UNPAQLIB */
#ifdef DISK_RING
// disk-based ring buffer support code
static int FAST DComp_Ring_Init(void)
{
RINGNAME ringName;
PBUFFER pBuffer;
int cBuffers;
if (lastContext->pfnOpen == NULL)
{
return(0); /* failed, no disk services */
}
ringName.wildName[0] = '*';
ringName.wildName[1] = '\0';
ringName.fileSize = DComp.WindowSize;
Disk.Handle = lastContext->pfnOpen((char FAR *) &ringName,
(_O_BINARY|_O_RDWR|_O_CREAT),(_S_IREAD|_S_IWRITE));
if (Disk.Handle == -1)
{
return(0); /* failed, can't make disk file */
}
Disk.RingPages = (int) (DComp.WindowSize / BUFFER_SIZE);
if (Disk.RingPages < MIN_BUFFERS)
{
Disk.RingPages = MIN_BUFFERS; /* if DComp.WindowSize < BUFFER_SIZE */
}
Disk.PageTable = Rtl_Malloc(sizeof(PAGETABLEENTRY) * Disk.RingPages);
if (Disk.PageTable == NULL)
{
lastContext->pfnClose(Disk.Handle); /* close the file */
return(0); /* failed, can't get page table */
}
Disk.pNewest = NULL;
/* DComp_Ring_Close() can be used to abort from this point on */
for (cBuffers = 0; cBuffers < Disk.RingPages; cBuffers++)
{
pBuffer = Rtl_Malloc(sizeof(BUFFER));
if (pBuffer != NULL)
{
pBuffer->pLinkNewer = NULL; /* none are newer */
pBuffer->pLinkOlder = Disk.pNewest; /* all the others older now */
if (Disk.pNewest != NULL)
{
Disk.pNewest->pLinkNewer = pBuffer; /* old guy now knows about new */
}
else /* if nobody else */
{
Disk.pOldest = pBuffer; /* guess I'm the oldest too */
}
Disk.pNewest = pBuffer; /* I'm the newest */
}
else /* if pBuffer == NULL */
{
if (cBuffers < MIN_BUFFERS) /* less than minimum? */
{
DComp_Ring_Close(); /* give it up */
return(0); /* failed, can't get min buffers */
}
else /* if we got the minimum */
{
break; /* got enough, quit trying */
}
}
}
DComp_Ring_Reset(); /* init everything else */
return(1); /* ring buffer created */
}
static void FAST DComp_Ring_Reset(void)
{
PBUFFER walker;
int iPage;
for (walker = Disk.pNewest; walker != NULL; walker = walker->pLinkOlder)
{
walker->BufferPage = -1; /* buffer is not valid */
walker->BufferDirty = 0; /* and doesn't need writing */
}
for (iPage = 0; iPage < Disk.RingPages; iPage++)
{
Disk.PageTable[iPage].pBuffer = NULL; /* not in memory */
Disk.PageTable[iPage].fDiskValid = 0; /* not on disk */
}
Disk.RingBuffer = DComp_Ring_Load(0,1); /* make a page 0 for writing */
if (Disk.RingBuffer != NULL) /* always will pass */
{
Disk.RingPointer = Disk.RingBuffer->Buffer;
Disk.RingPointerLimit = Disk.RingPointer + BUFFER_SIZE;
}
}
static void FAST2 DComp_Ring_Match( MATCH Match )
{
long SrcOffset; /* offset into output ring */
int SrcPage; /* page # where that offset lies */
int Chunk; /* number of bytes this pass */
BYTE FAR *SrcPtr; /* pointer to source bytes */
BYTE Chr; /* data character */
PBUFFER SrcBuffer; /* buffer where source data is */
int SrcBufferOffset; /* offset within the buffer */
int newPage;
if (DComp.NumBytes >= (unsigned) Match.Len)
{
SrcOffset = (DComp.Cur - Match.Dist) & DComp.WindowMask;
DComp.NumBytes -= Match.Len;
DComp.Cur += Match.Len;
/* promote current output page to make sure it's never discarded */
if (DComp_Ring_Load(Disk.RingBuffer->BufferPage,0) == NULL)
{
DComp.NumBytes = 0;
DComp.fRingFault = 1;
return;
}
while (Match.Len)
{
/* Limit: number of bytes requested */
Chunk = Match.Len; /* try for everything */
/* Limit: space remaining on current output page */
if ((Disk.RingPointerLimit - Disk.RingPointer) < Chunk)
{
Chunk = Disk.RingPointerLimit - Disk.RingPointer;
}
SrcPage = (int) (SrcOffset / BUFFER_SIZE);
SrcBufferOffset = (int) (SrcOffset % BUFFER_SIZE);
SrcBuffer = DComp_Ring_Load(SrcPage,0); /* for reading */
if (SrcBuffer == NULL)
{
DComp.NumBytes = 0;
DComp.fRingFault = 1;
return;
}
SrcPtr = SrcBuffer->Buffer + SrcBufferOffset;
/* Limit: number of source bytes on current output page */
if ((BUFFER_SIZE - SrcBufferOffset) < Chunk)
{
Chunk = (BUFFER_SIZE - SrcBufferOffset);
}
SrcOffset += Chunk;
SrcOffset &= DComp.WindowMask;
Match.Len -= Chunk;
while (Chunk--) /* copy this chunk */
{
Chr = *SrcPtr++;
*Disk.RingPointer++ = Chr;
*DComp.OutBuffer++ = Chr;
}
if (Disk.RingPointer == Disk.RingPointerLimit)
{
newPage = (Disk.RingBuffer->BufferPage + 1);
if (newPage >= Disk.RingPages)
{
newPage = 0;
}
Disk.RingBuffer = DComp_Ring_Load(newPage,1); /* for writing */
if (Disk.RingBuffer == NULL)
{
DComp.NumBytes = 0;
DComp.fRingFault = 1;
return;
}
Disk.RingPointer = Disk.RingBuffer->Buffer;
Disk.RingPointerLimit = Disk.RingPointer + BUFFER_SIZE;
}
} /* while Match.Len */
} /* if Match.Len size OK */
else /* match too large to fit */
{
DComp.NumBytes = 0;
DComp.fOutOverflow = 1;
}
}
static void FAST2 DComp_Ring_Literal( int Chr )
{
int newPage;
DComp.NumBytes--;
DComp.Cur++;
*DComp.OutBuffer++ = (BYTE) Chr;
*Disk.RingPointer = (BYTE) Chr;
if (++Disk.RingPointer == Disk.RingPointerLimit)
{
newPage = (Disk.RingBuffer->BufferPage + 1);
if (newPage >= Disk.RingPages)
{
newPage = 0;
}
Disk.RingBuffer = DComp_Ring_Load(newPage,1); /* for writing */
if (Disk.RingBuffer == NULL)
{
DComp.NumBytes = 0;
DComp.fRingFault = 1;
return;
}
Disk.RingPointer = Disk.RingBuffer->Buffer;
Disk.RingPointerLimit = Disk.RingPointer + BUFFER_SIZE;
}
}
/* Bring page into a buffer, return a pointer to that buffer. fWrite */
/* indicates the caller's intentions for this buffer, NZ->consider it */
/* dirty now. Returns NULL if there is a paging fault (callback */
/* failed) or if any internal assertions fail. */
static PBUFFER FAST DComp_Ring_Load(int page,int fWrite)
{
PBUFFER pBuffer;
long iPagefileOffset;
pBuffer = Disk.PageTable[page].pBuffer; /* look up this page */
if (pBuffer != NULL) /* if it's in the table */
{
if (pBuffer != Disk.pNewest) /* promote if not newest */
{
pBuffer->pLinkNewer->pLinkOlder = pBuffer->pLinkOlder;
if (pBuffer->pLinkOlder != NULL) /* if there is someone older */
{
pBuffer->pLinkOlder->pLinkNewer = pBuffer->pLinkNewer;
}
else
{
Disk.pOldest = pBuffer->pLinkNewer;
}
/* link into head of chain */
Disk.pNewest->pLinkNewer = pBuffer; /* newest now knows one newer */
pBuffer->pLinkNewer = NULL; /* nobody's newer */
pBuffer->pLinkOlder = Disk.pNewest; /* everybody's older */
Disk.pNewest = pBuffer; /* I'm the newest */
}
pBuffer->BufferDirty |= fWrite; /* might already be dirty */
return(pBuffer); /* return my handle */
}
/* desired page is not in the table; discard oldest & use it */
/* assertion check: current output buffer appears to be the oldest */
if (Disk.pOldest == Disk.RingBuffer)
{
return(NULL);
}
pBuffer = Disk.pOldest; /* choose the oldest buffer */
if (pBuffer->BufferPage != -1) /* take it out of page table */
{
Disk.PageTable[pBuffer->BufferPage].pBuffer = NULL; /* not here now */
if (pBuffer->BufferDirty) /* write on eject, if dirty */
{
iPagefileOffset = (long) pBuffer->BufferPage * BUFFER_SIZE;
if (lastContext->pfnSeek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
iPagefileOffset)
{
return(NULL);
}
if (lastContext->pfnWrite(Disk.Handle,pBuffer->Buffer,BUFFER_SIZE) !=
BUFFER_SIZE)
{
return(NULL);
}
Disk.PageTable[pBuffer->BufferPage].fDiskValid = 1;
}
}
Disk.pOldest = Disk.pOldest->pLinkNewer; /* newer is now oldest */
Disk.pOldest->pLinkOlder = NULL; /* oldest knows none older */
Disk.pNewest->pLinkNewer = pBuffer;
pBuffer->pLinkNewer = NULL; /* link into head of chain */
pBuffer->pLinkOlder = Disk.pNewest;
Disk.pNewest = pBuffer;
/* add new buffer to paging table */
Disk.PageTable[page].pBuffer = pBuffer; /* add new to paging table */
/* if this disk page is valid, load it */
if (Disk.PageTable[page].fDiskValid)
{
iPagefileOffset = (long) page * BUFFER_SIZE;
if (lastContext->pfnSeek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
iPagefileOffset)
{
return(NULL);
}
if (lastContext->pfnRead(Disk.Handle,pBuffer->Buffer,BUFFER_SIZE) !=
BUFFER_SIZE)
{
return(NULL);
}
}
else if (!fWrite)
{
/* assertion failure, trying to load a never-written page from disk */
return(NULL);
}
pBuffer->BufferDirty = fWrite; /* might be dirty now */
pBuffer->BufferPage = page; /* our new page number */
return(pBuffer); /* return new handle */
}
static void FAST DComp_Ring_Close(void)
{
PBUFFER pBuffer, pNext; /* buffer walk pointer */
Rtl_Free(Disk.PageTable); /* discard page table */
pBuffer = Disk.pNewest;
while (pBuffer != NULL) /* discard buffer chain */
{
pNext = pBuffer->pLinkOlder;
Rtl_Free(pBuffer);
pBuffer = pNext;
}
lastContext->pfnClose(Disk.Handle); /* close that file (and delete) */
}
#endif /* DISK_RING */