/* * 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. */ /* PTOPCRD.C -------------------------------------------- * @doc * @module PTOPCRD.C | * Code to read a Data-Block from TOPIC-File * * Help Access Library Project. * *-----------------------------------------------------*/ #include #include #include #include #include #include "hlpacces.h" #include "top.h" /* nReadTopicBlock ---------------------------------------------- * * Read the next Topic Data block from the Input file, decompress * it and maintain Pointers * * --------------------------------------------------------------*/ void LOCAL nReadTopicBlock(HTOPIC topic) { int BytesToRead; // ---------- Data Block is empty, get new Data. --------- topic->TopicOffset = (topic->BlkNum) << (topic->BlockNoShift +1); // Warum +1? // ---- Align to 4k Boundary ----------------------------- IFSSeekFile(topic->topicfile, (topic->BlockSize * topic->BlkNum), SEEK_SET); // Align to 4k Boundary IFSReadFile(topic->topicfile, &topic->TopicBlockHeader, sizeof(TOPICBLOCKHEADER)); // Get the Topic Block Header // ---- Get Input Data Block from File ------------------- BytesToRead = (topic->BlockSize * topic->BlkNum) + topic->NettoBlockSize-1 < topic->TopicFileLength ? topic->NettoBlockSize/*-1*/ : topic->TopicFileLength - (topic->BlockSize * topic->BlkNum) - sizeof(TOPICBLOCKHEADER); topic->DecompSize = ISCOMPRESSED(topic) ? iLZDecompress(topic->topicfile, BytesToRead, (char *)topic->DCmpBlock) : IFSReadFile(topic->topicfile, topic->DCmpBlock,(WORD) topic->NettoBlockSize); topic->CurrBlockLoc = 0; // ---- Data-Block in ifs->DCmpBlock is now available ---- } /* iTopicRead ---------------------------------------------------* * The |TOPIC-File is separated into Blocks of equal Size that * have to be decompressed on a Block-By-Block bases. The BlockSize of one * Block is 0x800 fir WinHelp 3.0 and 0x1000 for anything else. * * At the start of every Block there is a TOPICBLOCKHEADER- * Structure. The rest (BlockSize-sizeof(TOPICBLOCKHEADER)) is filled * with compressed Data. * * The Topic-Links are combined into a List. Every TOPICLINK-Structure * includes a Pointer to the next TOPICLINK-Structure as a "TopicOffset" * DWORD. * * Every TOPICLINK-Entry contains the Number of Bytes to the next Topiclink, * Sometimes a Block is not used up to the last byte. In This case the * DWORD-Pointer to the next TOPICLINK shows where to get the next data block, * and the BytesCount shows how Many bytes are available in this Block. *--------------------------------------------------------------*/ /* // ------- Data for RtfTopicRead ------------------------- BYTE *DCmpBlock; // Block of decompressed data LONG CurrBlockLoc; // Where we are in the DCmpBlock LONG DecompSize; // Size of DCmpBlock after decomp LONG BlkNum; // Blocknumber since Start of |TOPIC file LONG NextTopicLink; // Offset where the next TOPICLINK is to be found LONG BytesInLink; // Number of Bytes in one Topic Link Block */ LONG iTopicRead( HTOPIC topic, // TOPIC-File reference Handle BYTE *Dest, // Pointer to buffer receiving Data read LONG NumBytes) // Number of Bytes to read { LONG BytesLeft; /* # Bytes left to return */ TOPICLINK *TopicLink; LONG LinkOffset; // BYTE-LOOP: Loop thru the OUTPUT Byte Counter ---------- for (BytesLeft=NumBytes; BytesLeft; BytesLeft--) { // ------- If no more Data in Buffer, get next Data block --- if (topic->DecompSize == topic->CurrBlockLoc || // All data Read from 4K-Block? (!topic->BytesInLink && (topic->NextTopicLink >> topic->BlockNoShift) != topic->BlkNum) // Next TopicLink in another Block? ) { topic->BlkNum++; nReadTopicBlock(topic); } // ------- Get Data from TopicLink-Block -------------------- if (!topic->BytesInLink) { // ---- Get new Topic Link ------------------------------- LinkOffset = topic->NextTopicLink & topic->BlockOffsetMask; // Isolate Block Offset if (LinkOffset > topic->DecompSize) return 0; // Pessimistische Prüfung TopicLink = (TOPICLINK*)(topic->DCmpBlock + LinkOffset-sizeof(TOPICBLOCKHEADER)); // ---- Compute Address of next Topic Link --------------- topic->NextTopicLink = ledword(TopicLink->NextBlock) + (ISV30(topic) ? topic->NextTopicLink : 0); // ---- Get Size of this Topic Link ---------------------- topic->BytesInLink = ledword(TopicLink->BlockSize); // ---- Control TopicOffset... --------------------------- // *TopicOffset = (ifs->BlkNum << BlockNoShift+1) + ifs->CurrBlockLoc + sizeof(TOPICBLOCKHEADER); // ---- We now have controlled NextTopicLink and BytesInLink --- } // ------- Copy Byte from Source to Dest ----------------- *(Dest++) = *(topic->DCmpBlock + (topic->CurrBlockLoc++) ); topic->BytesInLink--; } /* While (BytesLeft) */ return NumBytes; } /* HlpTopicSeek ------------------------------------------------* * @func void | HlpTopicSeek | * * Positions the TOPIC-File to the TopicOffset address given * as the Parameter. This TopicOffset will be the Address for * subsequent calls to and * * @comm This is not a simple seek-operation, as the Topiclink * chains have to be maintained. * * If the given TopicOffset is invalid, a GPF may occur. * * @return -1 on error * *--------------------------------------------------------------*/ int WINAPI DLLEXP HlpTopicSeek( HTOPIC topic, // @parm TOPIC-File reference Handle DWORD TopicOffset) // @parm TopicOffset value retrieved by { UINT NewBlkNum = TopicOffset >> (topic->BlockNoShift +1), dummy; DWORD StartOfScan, ExpandedSize; UINT TopicOffsetAdd; TOPICLINK *TopicLink; LPBYTE LinkData1; // -------- If the new TopicOffset is in another block, we have to load the block -------- if (topic->BlkNum != NewBlkNum) { if (NewBlkNum * topic->BlockSize > topic->TopicFileLength) { return -1; } topic->BlkNum = NewBlkNum; nReadTopicBlock(topic); } // -------- Position Read-Pointer inside of the Block... --------------------------------- topic->TopicOffset = (topic->BlkNum) << (topic->BlockNoShift +1); // Warum +1? // Get offset of first Topic in this Block. StartOfScan = (ledword(topic->TopicBlockHeader.TopicData) & topic->BlockOffsetMask); // Build pointer to the first Topic Title entry. TopicLink = (TOPICLINK*)(topic->DCmpBlock + StartOfScan-sizeof(TOPICBLOCKHEADER)); while (topic->TopicOffset < TopicOffset) { /* vprintf("TopicLink:\n" "BlockSize : 0x%08lx\n" "DataLen2 : 0x%08lx\n" "PrevBlock : 0x%08lx\n" "NextBlock : 0x%08lx\n" "DataLen1 : 0x%08lx\n", TopicLink); printf("RecordType: 0x%02x\n", TopicLink->RecordType); */ LinkData1 = ((LPBYTE) TopicLink)+sizeof(TOPICLINK)-2*sizeof(LPBYTE); if (TopicLink->RecordType==TL_DISPLAY || TopicLink->RecordType==TL_TABLE) { ExpandedSize = iGetLongValue(&LinkData1, &dummy); TopicOffsetAdd= iGetWordValue(&LinkData1, &dummy); // printf("SCAN: TopicOffset: 0x%08lx ExpandedSize: 0x%08lx TopicOffsetAdd: 0x%04x\n", topic->TopicOffset, ExpandedSize, TopicOffsetAdd); topic->TopicOffset += TopicOffsetAdd; } TopicLink = (TOPICLINK FAR *)(topic->DCmpBlock + (ledword(TopicLink->NextBlock) & topic->BlockOffsetMask)-sizeof(TOPICBLOCKHEADER)); } // printf("FOUND: TopicOffset: 0x%08lx ExpandedSize: 0x%08lx TopicOffsetAdd: 0x%04x\n", topic->TopicOffset, ExpandedSize, TopicOffsetAdd); topic->CurrBlockLoc = ( (LPBYTE) TopicLink) - ( (LPBYTE) topic->DCmpBlock); topic->NextTopicLink = ledword(TopicLink->NextBlock) ; topic->BytesInLink = ledword(TopicLink->BlockSize); return 0; } /* iTopicReadInit -----------------------------------------------* * Prepares data blocks for the iTopicRead-Function *--------------------------------------------------------------*/ void iTopicReadInit(HTOPIC topic) { topic->BlockSize = ISV30(topic) ? 0x0800 : 0x1000; topic->BlockNoShift = ISV30(topic) ? 11 : 14; /* Block-Number shifted into topic-Offset... */ topic->BlockOffsetMask= (1<BlockNoShift)-1; /* 0x3fff or 0x07ff */ topic->NettoBlockSize = topic->BlockSize-sizeof(TOPICBLOCKHEADER); /* Size of netto-Datablock to read */ topic->CurrBlockLoc = 0L; topic->BlkNum = -1; topic->TopicOffset = 0; topic->DCmpBlock = Hlpmalloc(topic->NettoBlockSize * (ISCOMPRESSED(topic) ? 6:1)); topic->DecompSize = 0; /* Set initial size to 0 */ topic->NextTopicLink = sizeof(TOPICBLOCKHEADER); topic->BytesInLink = 0; /* Force Load of first Topic Block */ topic->TopicFileLength= IFSSeekFile(topic->topicfile, 0, SEEK_END); IFSSeekFile(topic->topicfile, 0, SEEK_SET); // Redundand, only to get for shure } /* iTopicReadFree -----------------------------------------------* * Free up data blocks for the iTopicRead-Function *--------------------------------------------------------------*/ void iTopicReadFree(HTOPIC topic) { /* CLEAN-UP: If NumBytes = 0, then we're done and need to Hlpfree memory */ if (topic->DCmpBlock) { Hlpfree(topic->DCmpBlock); topic->DCmpBlock=NULL; } /* topic->DCmpBlock=NULL; topic->BlkNum=0; topic->DecompSize=topic->CurrBlockLoc=0; */ }