/* * Help Access Library * A Library to access the contents of Windows Help files. * * Copyright (C) 1995-2000 Bernd Herd, http://www.herdsoft.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* PHRASES.C ------------------------------------------ * @doc * @module PHRASES.C | * Handling of Phrases and PhrIndex, PhrImage etc. Files. * * Help Access Library Project. * *-----------------------------------------------------*/ #include #include #include #include #include #include "hlpacces.h" #include "top.h" //------------ Local fucntion-Prototypes ----------------------------- void LOCAL nLoadOldPhrasesFile(NPTOPIC topic, HIFSFILE hPhrases); void LOCAL nLoadNewPhrasesFile(NPTOPIC topic, HIFSFILE hPhrImage, HIFSFILE hPhrIndex); /* iPhrasesLoad * * Handling of Phrases-Data. */ void iPhrasesLoad(NPTOPIC topic) { HIFSFILE hPhrases, hPhrIndex, hPhrImage; /* New-style phrases ? */ if (NULL!=(hPhrImage=IFSOpenFile(topic->ifs, "|PhrImage")) && NULL!=(hPhrIndex=IFSOpenFile(topic->ifs, "|PhrIndex")) ) { nLoadNewPhrasesFile(topic, hPhrImage, hPhrIndex); IFSCloseFile(hPhrImage); IFSCloseFile(hPhrIndex); } else /* No new-style phrases found, Old stale Windows 3.0 / Windows 3.1 / Media Viewer |Phrases - File ? */ if (NULL!=(hPhrases=IFSOpenFile(topic->ifs, "|Phrases"))) { nLoadOldPhrasesFile(topic, hPhrases); IFSCloseFile(hPhrases); } } /* iPhrasesFree * * Free up memory blocks required to hold phrases */ void iPhrasesFree(NPTOPIC topic) { if (topic->PhrImage) Hlpfree(topic->PhrImage); if (topic->PhrIndex) Hlpfree(topic->PhrIndex); if (topic->PhrasesPtr) Hlpfree(topic->PhrasesPtr); } /* nLoadOldPhrasesFile -----------------------------------------* * Load Phrases-Table * HC31 Version *--------------------------------------------------------------*/ void LOCAL nLoadOldPhrasesFile(NPTOPIC topic, HIFSFILE hPhrases) { PHRASEHDR PhraseHdr; short *Offsets; char *Phrases; LONG DeCompSize, PhrasesLength; PhrasesLength = IFSSeekFile(hPhrases, 0, SEEK_END); IFSSeekFile(hPhrases, 0, SEEK_SET); /* Load Phraeses-File header */ IFSReadFile(hPhrases, &PhraseHdr, sizeof(PhraseHdr)); /* Test if MVCC-File */ if (ledword(PhraseHdr.PhrasesSize) > 0x10000L && !ISV30(topic) ) {// Offensichtlich was faul... Wird ein MVCC-File sein IFSSeekFile(hPhrases, 2, SEEK_SET); IFSReadFile(hPhrases, &PhraseHdr, sizeof(PhraseHdr)); IFSSeekFile(hPhrases, 30, SEEK_CUR); } /* Allocate space and decompress if it's compressed, else read in. */ if (((topic->tit->Flags & COMPRESSION_310 ) || (topic->tit->Flags & COMPRESSION_UNKN) || ledword(PhraseHdr.PhrasesSize) > PhrasesLength - (sizeof(PhraseHdr) + 2*leword(PhraseHdr.NumPhrases))+10 ) && !ISV30(topic)) // When HC30 it's not LZ-Compressed { Offsets = Hlpmalloc((WORD) (ledword(PhraseHdr.PhrasesSize) + 600 + (leword(PhraseHdr.NumPhrases) + 1) * 2)); Phrases = (LPSTR) (Offsets + IFSReadFile(hPhrases, Offsets,2*(leword(PhraseHdr.NumPhrases)+1))/2); DeCompSize = iLZDecompress(hPhrases, PhrasesLength - (sizeof(PhraseHdr) + 2 * (leword(PhraseHdr.NumPhrases)+1)), Phrases); } else { /* Backup 4 bytes for uncompressed Phrases (no PhrasesSize) */ Offsets=Hlpmalloc((WORD)(PhrasesLength-4)); IFSSeekFile(hPhrases, -4, SEEK_CUR); IFSReadFile(hPhrases, Offsets, (WORD) (PhrasesLength - 4)); } topic->PhrasesPtr = Phrases = (char *) Offsets; } /* Phrase header In uncompressed, last field is empty */ #pragma pack(1) typedef struct PHRINDEXHDR { LEDWORD One; /* Seems to be allways 1 */ LEDWORD PhrasesCount, /* Number of Phrases */ PhrIndexSizeCompr;/* Phrases Index Size Compressed ? */ LEDWORD PhrasesSize, /* Amount of space uncompressed phrases requires. */ PhrasesSizeCompr, /* Compressed PhrImage Data Block size */ Zero; /* Seems to be always 0 */ } PACKED PHRINDEXHDR; #pragma pack() /* nHlpDecompressPhrIndex40 -------------------------------------* * Decompress Phrases Index-Data for WinHelp 4.0 File * * The PhrIndex-File is stored in a Huffman-Compressed Manner * Bits are evaluated in a LSB-First manner. *--------------------------------------------------------------*/ /*static struct { int nobits, bits, val } huff[] = { // { 0xf, 0x2, 2}, // 0010 { 3, 0x04, 3}, // 001 { 3, 0x06, 4}, // 011 { 4, 0x01, 5}, // 1000 { 4, 0x05, 6}, // 1010 { 4, 0x09, 7}, // 1001 { 4, 0x0d, 8}, // 1011 { 5, 0x03, 9}, // 11000 { 5, 0x0b,10}, // 11010 { 5, 0x13,11}, // 11001 { 5, 0x1b,12}, // 11011 { 6, 0x07,13}, // 111000 { 6, 0x17,14}, // 111010 { 6, 0x27,15}, // 111001 { 6, 0x37,16}, // 111011 { 7, 0x0f,17}, // 1111000 };*/ /* Jede führende 1 bedeutet: +4, bis eine 0 folgt. Anschließend: 00 = +1 10 = +2 01 = +3 11 = +4 Wobei hier die binärschreibweise von Rechts nach links dargestellt ist. D.h. praktisch, daß die folgenden 2 Bits dann die Länge angeben. Komischerweise wird auf diese Weise die Bitkombinatione"000" verschwendet, vielleicht hat sie eine Sonderfunktion ? In den unteren 4 Bits des 1. Bytes auf das "PhrIndex" zeigt steht die Anzahl der Bits, die mindestens für einen Entry reserviert sind. */ void LOCAL nHlpDecompressPhrIndex40(PHRINDEXHDR *PhrIndexHdr, LPSTR PhrIndex, LPINT PhrIndexDeComp) { int PhraseNo, PhraseLength, MinBits, BitNo=8; unsigned BitBuf, BitShft, PhrasePosition=0; MinBits = *PhrIndex & 0xf; PhrIndex += 4; /* Die ersten 4 Bytes haben eine besondere Bedeutung */ for (PhraseNo=0; PhraseNoPhrasesCount); PhraseNo++) { // -------- Get Next Bits -------------------------------- PhraseLength = 1; do { // ----- Fetch next Byte into BitBuf ------------------ if (BitNo>7) { BitNo-=8; // BitBuf=*((LPINT) (PhrIndex++)); BitBuf=(((LPBYTE)PhrIndex)[0])+(((LPBYTE)PhrIndex)[1]<<8)+(((LPBYTE)PhrIndex)[2]<<16); PhrIndex++; } BitShft = BitBuf >> BitNo; if (BitShft & 1) PhraseLength+=(1<> BitNo; PhraseLength += (BitShft & ((1<= 0x10000L-501) HlpDisplayError("Phrase Image %s", Use32); */ // HAck # endif DeCompData = (LPSTR) Hlpmalloc(ledword(PhrIndexHdr.PhrasesSize) + 500); /**/ DeCompSize = CompSize != ledword(PhrIndexHdr.PhrasesSize) ? iLZDecompress (hPhrImage, CompSize, DeCompData) : IFSReadFile(hPhrImage, DeCompData, CompSize); /* if (abs(DeCompSize - PhrIndexHdr.PhrasesSize)>10) HlpDisplayWarning(ifs, IDS_PHRASESSIZE, PhrIndexHdr.PhrasesSize, DeCompSize); */ // ----------- Store Result Pointers --------------------- topic->PhrImage = DeCompData; topic->PhrIndex = PhrIndexDeComp; } // nLoadNewPhrasesFile /* HlpGetPhrase ------------------------------------------------* * Get a Memory-Block with a Phrase (like strdup) * *--------------------------------------------------------------*/ LPSTR LOCAL nHlpGetPhrase3(HTOPIC topic, int PhraseNum) // Return Memory Block with a Phrase { LPSTR Phrases = topic->PhrasesPtr, NewBuf; int Length; LEWORD *Offsets = (LEWORD *)Phrases; char *p = Phrases+leword(Offsets[PhraseNum]); Length = leword(Offsets[PhraseNum+1]) - leword(Offsets[PhraseNum]); NewBuf = (LPSTR) Hlpcalloc(Length+1,1); memcpy(NewBuf, p, Length); return NewBuf; } LPSTR LOCAL nHlpGetPhrase4(HTOPIC topic, int PhraseNum) // Return Memory Block with a Phrase { unsigned Length = topic->PhrIndex[PhraseNum+1] - topic->PhrIndex[PhraseNum]; LPCSTR Source = topic->PhrImage + topic->PhrIndex[PhraseNum]; LPSTR Dest = Hlpcalloc(Length+1,1); memcpy(Dest, Source, Length); return Dest; } LPSTR iGetPhrase(HTOPIC topic, int PhraseNum) // Return Memory Block with a Phrase { if (topic->PhrImage) return nHlpGetPhrase4(topic, PhraseNum); else return nHlpGetPhrase3(topic, PhraseNum); }