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.
 
 
 
 
 
 

345 lines
9.1 KiB

/*****************************************************************************
* *
* COMPRESS.C *
* *
* Copyright (C) Microsoft Corporation 1990. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* This module performs text compression at compile time and *
* decompression at run time using a list of phrases to be suppressed. *
* This list gets put in to the |Phrases file in the filesystem, which is *
* read in at runtime. *
* *
*****************************************************************************/
#include "help.h"
#include "inc\_compres.h"
#include "inc\compress.h"
INLINE static LPSTR STDCALL QchDecompressW(DWORD, LPSTR, QPHR);
INLINE static RC STDCALL RcLoadPhrases(HF hf, QPHR qphr, WORD wVersionNo);
/***************************************************************************
*
- Name HphrLoadTableHfs
-
* Purpose
* Loads the phrase table from the given help file.
*
* Arguments
* hfs -- A handle to the help file filesystem.
* wVersionNo - help ver no., needed to know whether to decompress.
*
* Returns
* A handle to the phrase table to be used for decompression. Returns
* NULL if the help file is not compressed, and hphrOOM on out of memory,
* meaning that the help file cannot be displayed properly.
*
***************************************************************************/
#ifndef NO_PRAGMAS
#pragma data_seg(".text", "CODE")
#endif
const char txtPhraseTable[] = "|Phrases";
#ifndef NO_PRAGMAS
#pragma data_seg()
#endif
HPHR STDCALL HphrLoadTableHfs(HFS hfs, WORD wVersionNo)
{
QPHR qphr;
HF hf;
ASSERT(hfs);
hf = HfOpenHfs(hfs, txtPhraseTable, fFSOpenReadOnly);
if (hf == NULL) {
if (RcGetFSError() != rcNoExists)
return hphrOOM;
return NULL;
}
qphr = (QPHR) GhAlloc(GMEM_FIXED, sizeof(PHR));
if (qphr == NULL) {
RcCloseHf(hf);
return hphrOOM;
}
qphr->hfs = hfs;
{
LONG cbHdrTmp =
(LONG) (wVersionNo == wVersion3_0 ? cbPhrHeader3_0 : cbPhrHeader);
if (LcbReadHf(hf, qphr, cbHdrTmp) != cbHdrTmp) {
ASSERT(FALSE);
// 16-Feb-1994 [ralphw]
// Return value is wrong, but 3.1 didn't return at all!
goto Fail;
}
}
#ifndef _X86_
/* SDFF map the phrase table header: */
LcbMapSDFF( ISdffFileIdHf( hf ),
(wVersionNo == wVersion3_0 ? SE_PHRASE_HEADER_30 : SE_PHRASE_HEADER),
qphr, qphr );
#endif
if (rcSuccess != RcLoadPhrases(hf, qphr, wVersionNo)) {
Fail:
RcCloseHf(hf);
FreeGh((GH) qphr);
return hphrOOM;
}
RcCloseHf(hf);
return (HPHR) qphr;
}
INLINE static RC STDCALL NEAR RcLoadPhrases(HF hf, QPHR qphr, WORD wVersionNo)
{
HANDLE hrgcb;
DWORD lcbRgcb, lcbCompressed, lcbOffsets;
INT16* qcb;
PBYTE pbCompressed;
if (wVersionNo == wVersion3_0) { // not zeck block compressed:
lcbRgcb = LcbSizeHf(hf) - cbPhrHeader3_0;
if (!(hrgcb = GhAlloc(GPTR, lcbRgcb)))
return(rcOutOfMemory);
qphr->hrgcb = hrgcb;
if (LcbReadHf(hf, PtrFromGh(hrgcb), lcbRgcb) != (LONG) lcbRgcb) {
ASSERT(FALSE);
}
}
else {
ASSERT(wVersionNo == wVersion3_1 || wVersionNo == wVersion40);
/*
* The memory-size of the table is the size of the offset table +
* the size of the decompressed phrase listing. The size of the
* offset table is given by sizeof(INT)*cPhrases:
*/
lcbOffsets = (qphr->cPhrases + 1) * sizeof(INT16); // offset table size
lcbRgcb = lcbOffsets + qphr->cbPhrases; // Whole phrase table size
lcbCompressed = LcbSizeHf(hf) - cbPhrHeader - lcbOffsets;
// the compressed size may be GREATER (when small phrase tables), so
// use the max of compressed or decompressed sizes (ptr 558):
if (!(hrgcb = GhAlloc(GPTR, max(lcbRgcb, lcbCompressed + lcbOffsets))))
return rcOutOfMemory;
qphr->hrgcb = hrgcb;
qcb = PtrFromGh(hrgcb);
if (LcbReadHf(hf, qcb, lcbCompressed + lcbOffsets) !=
(LONG) (lcbCompressed + lcbOffsets)) {
// REVIEW: File is corrupted or cannot be read. We should die.
ASSERT(FALSE);
}
/*
* Now must decompress raw phrase listing. Allocate another
* buffer, copy compressed data into it, then decompress it into the
* std dest buffer in hrgcb:
*
* +1 because lcbCompressed may == 0, and GhAlloc asserts on that.
*/
if (!(pbCompressed = (PBYTE) GhAlloc(GMEM_FIXED, lcbCompressed + 1)))
return(rcOutOfMemory);
MoveMemory(pbCompressed, ((PBYTE) qcb) + lcbOffsets, lcbCompressed);
LcbUncompressZeck(pbCompressed, ((PBYTE) qcb) + lcbOffsets,
lcbCompressed);
FreeGh((GH) pbCompressed);
#ifndef _X86_
/* Perform SDFF mapping on the offsets table. SDFF does not do the whole
* table automatically on it's own because the size of the table is
* determined via cPhrases, thus it does not fall into any of SDFF's
* "word size preceded" table types. Thus this loop.
*/
{
/* Assumes: qcb is a locked pointer to qhpr->hrgcb */
unsigned int i;
SDFF_FILEID fileid = ISdffFileIdHf( hf );
for( i = 0; i <= (unsigned int) qphr->cPhrases; i++ ) {
qcb[i] = WQuickMapSDFF( fileid, TE_WORD, &qcb[i] );
}
}
#endif
}
return rcSuccess;
}
/***************************************************************************
*
- Name DestroyHphr
-
* Purpose
* Destroys resources allocated for the phrase table.
*
* Arguments
* A handle to the phrase table.
*
* Returns
* nothing.
*
***************************************************************************/
void STDCALL DestroyHphr(HPHR hphr)
{
if (hphr == NULL)
return; // No hphr to destroy!
FreeGh(((QPHR) PtrFromGh(hphr))->hrgcb);
FreeGh(hphr);
}
/***************************************************************************
*
- Name QchDecompressW
-
* Purpose
* Given a phrase token and a pointer to a buffer, copies the
* corresponding phrase to that buffer
*
* Arguments
* wPhraseToken -- phrase token to be inserted.
* qch -- buffer to place phrase.
* qphr -- pointer to phrase table.
*
* Returns
* A pointer to the character past the last character of the phrase
* placed in the buffer. Returns NULL if unable to load the phrase
* due to out of memory.
*
* +++
*
* Notes
* The phrase token includes an index into the phrase table, as
* well as a flag indicating whether or not a space should be
* appended to the phrase.
*
***************************************************************************/
INLINE static PSTR STDCALL QchDecompressW(DWORD wPhraseToken,
LPSTR pszDst, QPHR qphr)
{
DWORD iPhrase;
BOOL fSpace;
WORD* pi;
int cbPhrase;
#ifdef _DEBUG
PSTR pszPhrases;
#endif
ASSERT(qphr != NULL);
pi = PtrFromGh(qphr->hrgcb);
// Calculate iPhrase and fSpace:
iPhrase = (DWORD) (wPhraseToken - qphr->wBaseToken);
fSpace = iPhrase & 1;
iPhrase >>= 1;
ASSERT(iPhrase < (WORD) qphr->cPhrases);
#ifdef _DEBUG
pszPhrases = QFromQCb(pi, pi[iPhrase]);
#endif
cbPhrase = (int) pi[iPhrase + 1] - (int) pi[iPhrase];
MoveMemory(pszDst, QFromQCb(pi, pi[iPhrase]), cbPhrase);
pszDst += cbPhrase;
if (fSpace)
*pszDst++ = ' ';
return pszDst;
}
/***************************************************************************
*
- Name CbDecompressQch
-
* Purpose
* Decompresses the given string.
*
* Arguments
* qchSrc -- String to be decompressed.
* lcb -- size of string to be decompressed.
* qchDest -- place to put decompressed string.
* hphr -- handle to phrase table.
*
* Returns
* Number of characters placed into the decompressed string. Returns
* DECOMPRESS_NIL if it fails due to OOM.
*
* +++
*
* Notes
* Does not use huge pointers, so the source and destination buffers
* cannot cross segment boundaries. Then why is the size of the
* source passed as a long? I don't know.
*
***************************************************************************/
int STDCALL CbDecompressQch(PCSTR pszSrc, int lcb, LPSTR pszDest,
HPHR hphr, DWORD wVersionNo)
{
DWORD wPhraseToken, wTokenMin, wTokenMax;
PSTR pszStart;
PCSTR pszLast;
QPHR qphr;
/*
* If hphr is NULL, then GetQFCINFO() should have thought we were
* uncompressed and not called us. If GetQFCINFO() thinks we're
* compressed, it means the uncompressed size is larger then the
* compressed size, which almost certainly means we will break here
* without hphr.
*/
ASSERT(hphr);
if (hphr == NULL) {
MoveMemory(pszDest, pszSrc, lcb);
return lcb;
}
qphr = PtrFromGh(hphr);
wTokenMin = qphr->wBaseToken;
wTokenMax = qphr->wBaseToken + 2 * qphr->cPhrases;
pszLast = pszSrc + lcb - 1; // Last possible position of a phrase token
pszStart = pszDest;
while (pszSrc < pszLast) {
wPhraseToken = (((WORD) pszSrc[0]) << 8) + (BYTE) pszSrc[1];
if (wPhraseToken >= wTokenMin && wPhraseToken < wTokenMax) {
pszDest = QchDecompressW(wPhraseToken, pszDest, qphr);
if (pszDest == NULL) {
return DECOMPRESS_NIL;
}
pszSrc += 2;
ASSERT( pszSrc <= pszLast + 1 );
}
else
*pszDest++ = *pszSrc++;
}
// Check for last character
if (pszSrc == pszLast)
*pszDest++ = *pszSrc++;
return (pszDest - pszStart);
}