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.
 
 
 
 
 
 

522 lines
13 KiB

// SaveLoad.cpp -- Implementation for the class CPersist
#include "stdafx.h"
#include "SaveLoad.h"
#include "Memex.h"
#include "String.h"
#include "stdlib.h"
#include "search.h"
#include "memory.h"
#include "Except.h"
CPersist::CPersist()
{
m_puio = NULL;
m_pios = NULL;
m_pdwImage = NULL;
m_pdwNextTable = NULL;
m_szFile[0] = 0;
m_fExceptionCleanup = FALSE;
ZeroMemory(&m_vb, sizeof(m_vb));
}
CPersist::~CPersist()
{
if (m_pios)
{
if (m_fExceptionCleanup)
{
m_pios->ExceptionDestructor(); m_pios= NULL;
}
else
{
if (m_vb.Base && m_pdwNextTable > PUINT(m_vb.Base))
CompleteDiskImage();
delete m_pios; m_pios= NULL;
}
}
if (m_pdwImage) ReleaseImage();
ASSERT(!m_pdwImage);
if (m_puio) delete m_puio;
if (m_vb.Base) FreeVirtualBuffer(&m_vb);
}
void CPersist::CompleteDiskImage()
{
// ASSERT(m_vb.Base && m_pdwNextTable > PUINT(m_vb.Base)); //rmk
ASSERT(m_pios);
UINT offTable= NextOffset();
WriteDWords(PUINT(m_vb.Base), m_pdwNextTable - PUINT(m_vb.Base));
m_pdwNextTable= PUINT(m_vb.Base);
m_pios->FlushOutput(TRUE);
UINT cdwFile= m_pios->CdwStream();
delete m_pios; m_pios= NULL;
UINT cbSector= m_puio->CbSector();
if (cbSector < CSLOTS * sizeof(UINT))
cbSector = cbSector * ((CSLOTS * sizeof(UINT) + cbSector - 1) / cbSector);
PUINT pdwSector = NULL;
__try
{
pdwSector= (PUINT) m_puio->GetBuffer(&cbSector);
m_puio->Read(pdwSector, 0, 0, cbSector);
pdwSector[ISLOT_TABLE_OFFSET]= offTable;
m_puio->Write(pdwSector, 0, 0, cbSector);
m_puio->MakePermanent(m_szFile, TRUE, cdwFile * sizeof(UINT));
}
__finally
{
if (pdwSector) m_puio->FreeBuffer(pdwSector);
}
}
CPersist *CPersist::CreateDiskImage(PSZ pszFileName, UINT dwOptions, UINT usSignature, UINT usVersion)
{
ASSERT(pszFileName);
ASSERT(strlen(pszFileName) <= MAX_PATH);
// BugBug: Should verify the syntax of pszFileName here.
// We may be able to use GetFullPathName to do this.
CPersist *pp= NULL;
__try
{
pp= New CPersist;
strcpy(pp->m_szFile, pszFileName);
CreateVirtualBuffer(&(pp->m_vb), 0x10000, 0x800000);
pp->m_pdwNextTable= (PUINT) (pp->m_vb.Base);
pp->m_puio= CUnbufferedIO::NewTempFile(pszFileName, TRUE);
pp->m_pios= CIOStream::NewIOStream(pp->m_puio);
pp->m_pios->AttachStream(TRUE, 0, 0);
pp->m_pios->PutDWordOut(usSignature); // To identify this as a Full-Text index
pp->m_pios->PutDWordOut(usVersion ); // Version number for this file layout
pp->m_pios->PutDWordOut(dwOptions ); // Place holder for Index creation options
pp->m_pios->PutDWordOut(UINT(-1) ); // Place holder for offset to content directory
}
__finally
{
if (_abnormal_termination() && pp)
{
pp->m_fExceptionCleanup= TRUE; delete pp; pp= NULL;
}
}
return pp;
}
void CPersist::ExceptionDestructor()
{
m_fExceptionCleanup= TRUE; delete this;
}
BOOL CPersist::IsValidIndex(PSZ pszFileName, UINT dwOptions)
{
CPersist *pPersist = NULL;
UINT fOptions = 0;
__try
{
pPersist= OpenDiskImage(pszFileName);
fOptions= pPersist->m_pdwImage[ISLOT_OPTIONS];
delete pPersist; pPersist= NULL;
}
__except(FilterFTExceptions(_exception_code()))
{
if (pPersist) delete pPersist;
return FALSE;
}
return fOptions == dwOptions;
}
CPersist *CPersist::OpenDiskImage(PSZ pszFileName, UINT usSignature, UINT usVersion, UINT usMinVersion)
{
ASSERT(pszFileName);
ASSERT(strlen(pszFileName) <= MAX_PATH);
CPersist *pp = NULL;
BOOL fOpenFailed = FALSE;
__try
{
pp= New CPersist();
strcpy(pp->m_szFile, pszFileName);
for (;;)
{
pp->m_puio= CUnbufferedIO::OpenExistingFile(pszFileName);
if (!(pp->m_puio)) { fOpenFailed= TRUE; __leave; }
pp->m_pdwImage= PUINT(pp->m_puio->MappedImage());
if ( pp->m_pdwImage
&& pp->m_pdwImage[ISLOT_SIGNATURE ] == usSignature
&& pp->m_pdwImage[ISLOT_FTS_VERSION ] <= usVersion
&& pp->m_pdwImage[ISLOT_FTS_VERSION ] >= usMinVersion
&& pp->m_pdwImage[ISLOT_TABLE_OFFSET] != UINT(-1)
) break;
#ifdef _DEBUG
char ac[500];
if (!(pp->m_pdwImage)) wsprintf(ac, "Can't map file \"%s\" into memory!", pp->m_szFile);
else if ( pp->m_pdwImage[ISLOT_SIGNATURE ] != usSignature
|| pp->m_pdwImage[ISLOT_FTS_VERSION] != usVersion
)
wsprintf(ac, "Signature == 0x%08x, should be 0x%08x; File Version == 0x%08x, should be 0x%08x",
pp->m_pdwImage[ISLOT_SIGNATURE], usSignature, pp->m_pdwImage[ISLOT_FTS_VERSION], usVersion
);
else if (pp->m_pdwImage[ISLOT_TABLE_OFFSET] == UINT(-1))
wsprintf(ac, "Damaged index file: Table Offset == 0x%08x",
pp->m_pdwImage[ISLOT_TABLE_OFFSET]
);
::MessageBox(::hwndMain, ac, "Invalid Index File!", MB_OK);
#endif // _DEBUG
SetLastError( (!pp->m_pdwImage) ? ERR_FILE_MAP_FAILED :
( pp->m_pdwImage[ISLOT_SIGNATURE ] != usSignature
|| pp->m_pdwImage[ISLOT_FTS_VERSION] < usMinVersion
) ? ERR_INVALID_FILE_TYPE :
(pp->m_pdwImage[ISLOT_FTS_VERSION] > usVersion)
? ERR_FUTURE_VERSION : ERR_DAMAGED_FILE
);
delete pp->m_puio; pp->m_puio= NULL; pp->m_pdwImage= NULL;
fOpenFailed= TRUE; __leave;
}
pp->m_pdwNextTable= pp->m_pdwImage + pp->m_pdwImage[ISLOT_TABLE_OFFSET];
}
__finally
{
if ((fOpenFailed || _abnormal_termination()) && pp)
{
pp->m_fExceptionCleanup= TRUE; delete pp; pp= NULL;
}
}
return pp;
}
void CPersist::ReleaseImage()
{
ASSERT(m_pdwImage && m_puio && !m_pios);
m_puio->UnmapImage(); m_pdwImage= NULL;
delete m_puio; m_puio= NULL;
}
PVOID CPersist::ReserveTableSpace(UINT cbTable)
{
UINT cdw= (cbTable + sizeof(UINT) - 1) / sizeof(UINT);
PUINT pdw= m_pdwNextTable + cdw;
if (m_vb.Base) // Non-null when we're saving to disk
// Null when we're reloading from disk
if (PBYTE(pdw) - 1 > PBYTE(m_vb.CommitLimit))
ExtendVirtualBuffer(&m_vb, PBYTE(pdw) - 1);
m_pdwNextTable= pdw;
return (PVOID) (pdw - cdw);
}
int __cdecl comparer (const void *pvL, const void *pvR)
{
return *((LPINT) pvR) - *((LPINT)pvL);
}
UINT CPersist::Encode(const BYTE *pbData, UINT cbData)
{
enum {MAX_WORK_BUFFER = 0x4000};
enum {BREAK_POINT = 3};
enum {SHIFT_BITS = 2};
enum {NUMBITS = sizeof(UINT)<<3};
UINT i, j, n;
UINT nBitsRemain;
UINT nWriteCount = 0;
UINT nCode, nCodeLen;
UINT nBits, nStart;
BYTE (*pbLookup)[16];
pbLookup = NULL;
PUINT pnCode = NULL;
PUINT table = NULL;
PBYTE pattern = NULL;
PBYTE bitcount = NULL;
ValidateHeap();
__try
{
table = New UINT[512];
pattern = New BYTE[256];
bitcount = New BYTE[256];
ValidateHeap();
for (j = 0; j < cbData; j++) // count byte frequencies in
table[2 * pbData[j]]++; // ... first entry of pair
ValidateHeap();
for (i = 0; i < 256; i++) // note character byte in
{ // ... second entry of pair
table[2*i+1] = i;
pattern[i] = bitcount[i] = 0; // initialization
}
ValidateHeap();
qsort(table, 256, 2*sizeof(UINT), comparer); // sort by byte frequency
ValidateHeap();
for (n = 0; n < 256 && table[n]; n += 2) {}; // count of non-zero frequencies
nBits = SHIFT_BITS; // start with smallest number of bits
nStart = BREAK_POINT; // start with break pattern
for (i = 1; i < 2 * n; i += 2)
{
bitcount[table[i]] = nBits; // bitcount and pattern for next
pattern [table[i]] = nStart; // ... most frequently used byte
if (nStart-- == BREAK_POINT) // reduce pattern until at break point
{
nBits += SHIFT_BITS; // pattern increases in number of bits
nStart = (++nStart << SHIFT_BITS) - 1; // maximum value for number of bits
}
}
ValidateHeap();
pbLookup = New BYTE[nBits>>1][16]; // alloc Huffman lookup table
ValidateHeap();
for (i = 0; i < 256; i++) // setup Huffman lookup table
if (bitcount[i])
pbLookup[(bitcount[i]>>1)-1][pattern[i]] = i;
ValidateHeap();
UINT nBufSize = min(2 + (nBits << 3) + cbData, MAX_WORK_BUFFER);
pnCode = New UINT[nBufSize];
PUINT pnLoc = pnCode;
PUINT pnEnd = pnCode + nBufSize;
*pnLoc++ = nBits>>1;
memcpy(pnLoc, pbLookup, nBits<<3);
pnLoc += nBits<<1;
nBitsRemain = NUMBITS; // start with empty UINT
*pnLoc = 0; // ... and initialized
ValidateHeap();
for (i = 0; i < cbData; i++)
{
nCode = pattern [pbData[i]];
nCodeLen = bitcount[pbData[i]];
if (nBitsRemain >= nCodeLen) // room for pattern in current UINT
{
nBitsRemain -= nCodeLen;
*pnLoc |= nCode << nBitsRemain;
}
else if (nCodeLen < nBitsRemain + NUMBITS) // patterns overflows into next UINT
{
*pnLoc |= nCode >> (nCodeLen - nBitsRemain);
if (++pnLoc >= pnEnd)
{ // at end of buffer, write to disk
WriteDWords(pnCode, pnLoc - pnCode);
nWriteCount += pnLoc - pnCode;
pnLoc = pnCode;
}
nBitsRemain += NUMBITS - nCodeLen;
*pnLoc = nCode << nBitsRemain;
}
else if (nCodeLen > nBitsRemain + NUMBITS) // pattern spans next two UINT's
{
if (++pnLoc >= pnEnd - 1) // we're filling two UINT's this cycle
{
WriteDWords(pnCode, pnLoc - pnCode);
nWriteCount += pnLoc - pnCode;
pnLoc = pnCode; // at end of buffer, write to disk
}
*pnLoc++ = nCode >> (nCodeLen - nBitsRemain - NUMBITS);
nBitsRemain += (NUMBITS<<1) - nCodeLen;
*pnLoc = nCode << nBitsRemain;
}
else // pattern evenly fills next UINT
{
if (++pnLoc >= pnEnd)
{ // at end of buffer, write to disk
WriteDWords(pnCode, pnLoc - pnCode);
nWriteCount += pnLoc - pnCode;
pnLoc = pnCode;
}
nBitsRemain = 0;
*pnLoc = nCode;
}
}
ValidateHeap();
WriteDWords(pnCode, ++pnLoc - pnCode);
nWriteCount += pnLoc - pnCode;
}
__finally
{
ValidateHeap();
if (table ) { delete []table; table = NULL; }
ValidateHeap();
if (pattern ) { delete []pattern; pattern = NULL; }
ValidateHeap();
if (bitcount) { delete []bitcount; bitcount = NULL; }
ValidateHeap();
if (pbLookup) { delete []pbLookup; pbLookup = NULL; }
ValidateHeap();
if (pnCode ) { delete []pnCode; pnCode = NULL; }
}
ValidateHeap();
return nWriteCount;
}
void CPersist::WriteBytes(const BYTE *pb, UINT cb)
{
UINT cdw= (cb + sizeof(UINT) - 1) / sizeof(UINT);
for (; cdw; )
{
UINT cdwChunk= cdw;
PUINT pdw= m_pios->NextDWordsOut(&cdwChunk);
ASSERT(pdw && cdwChunk > 0);
UINT cbChunk= cdwChunk * sizeof(UINT);
if (cbChunk > cb) cbChunk= cb;
CopyMemory(pdw, pb, cbChunk);
pb += cbChunk;
cb -= cbChunk;
cdw -= cdwChunk;
}
}
UINT CPersist::SaveData(const BYTE *pbData, UINT cbData)
{
UINT off= NextOffset();
WriteBytes(pbData, cbData);
return off;
}
void CPersist::WriteWords (const WORD *pw, UINT cw )
{
UINT cWordsPerDWord= sizeof(UINT) / sizeof(USHORT);
UINT cdw= (cw + cWordsPerDWord - 1) / cWordsPerDWord;
for (; cdw; )
{
UINT cdwChunk= cdw;
PUINT pdw= m_pios->NextDWordsOut(&cdwChunk);
ASSERT(pdw && cdwChunk > 0);
UINT cwChunk= cdwChunk * cWordsPerDWord;
if (cwChunk > cw) cwChunk= cw;
CopyMemory(pdw, pw, cwChunk * sizeof(USHORT));
pw += cwChunk;
cw -= cwChunk;
cdw -= cdwChunk;
}
}
void CPersist::WriteDWords(const UINT *pdw, UINT cdw)
{
for (; cdw; )
{
UINT cdwChunk= cdw;
PUINT pdwOut= m_pios->NextDWordsOut(&cdwChunk);
ASSERT(pdwOut && cdwChunk > 0);
CopyMemory(pdwOut, pdw, cdwChunk * sizeof(UINT));
pdw += cdwChunk;
cdw -= cdwChunk;
}
}