/* * 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. */ /* GETTOP.C ------------------------------------------- * @doc * * @module GETTOP.C | * Code to go thru the TOPICLINKENTRIES and enumerate their * contents. * * Help Access Library Project. * *-----------------------------------------------------*/ #include #include #include #include #include #include "hlpacces.h" #include "top.h" LPBYTE LOCAL nDeCompTopic( HTOPIC topic, BYTE *InputBlock, UINT InputLength, UINT OutputLength, UINT *ResultLength, BOOL NibbleMode); void LOCAL nTopicTitle(HTOPIC topic, TOPICENUMPROC fnenum, LPARAM lParam, BYTE* String, UINT Length); void LOCAL nSearchContextAndKeyWord(HTOPIC topic, TOPICENUMPROC fnenum, DWORD TopicOffset, LPARAM lParam); /* iGetTopics --------------------------------------------------* * Get Topic Text *--------------------------------------------------------------*/ // Dump |TOPIC file, doing decompression and phrase substitution void iGetTopics(HTOPIC topic, TOPICENUMPROC fnenum, LPARAM lParam) { TOPICHEADER *TopicHdr; TOPICLINK TopicLink; DWORD ThisTopicOffset; BOOL InNonScrollingRegion, TextEndReached = FALSE; DWORD OriginalDataLen2, CurrentDataLen2, EndNonScrollingRegion; FORMATHEADER FormatHeader; BYTE *FormatData , *TextData, *TempString; UINT FormatLength , TextLength, GroupNumber; // --------------- Loop thru our source Data blocks --------------------- do { if (ISV30(topic)) ThisTopicOffset = (topic->CurrBlockLoc>=topic->DecompSize ? 0x800 : 0) + (topic->BlkNum) * 0x800 + sizeof(TOPICBLOCKHEADER) +topic->CurrBlockLoc; else ThisTopicOffset = topic->TopicOffset; //--------------- Read TopicLink header -------------------------------- iTopicRead(topic, (BYTE *) &TopicLink, sizeof(TopicLink) - 2*sizeof(BYTE *)); CurrentDataLen2 = OriginalDataLen2 = ledword(TopicLink.DataLen2); if (TopicLink.RecordType == TL_DISPLAY || TopicLink.RecordType == TL_DISPLAY30 || TopicLink.RecordType == TL_TABLE) { topic->TopicOffset += OriginalDataLen2; InNonScrollingRegion = ledword(TopicLink.NextBlock) <= EndNonScrollingRegion; } if (topic->PhrasesPtr || topic->PhrIndex) CurrentDataLen2 = ledword(TopicLink.BlockSize) - ledword(TopicLink.DataLen1); TopicLink.LinkData1=(BYTE *) Hlpcalloc((WORD)(ledword(TopicLink.DataLen1)-21+16),1); iTopicRead(topic, TopicLink.LinkData1, ledword(TopicLink.DataLen1) - 21); if (CurrentDataLen2 > 0) { TopicLink.LinkData2=(BYTE*)Hlpcalloc((WORD)(CurrentDataLen2+16),1); iTopicRead(topic, TopicLink.LinkData2, CurrentDataLen2); //---------------- 3.1.96: Decompress Phrases ------------ TextData = nDeCompTopic(topic, TopicLink.LinkData2, min(CurrentDataLen2, OriginalDataLen2), 0xff00U, &TextLength, topic->PhrIndex && !(CurrentDataLen2 >= OriginalDataLen2) ); Hlpfree(TopicLink.LinkData2); TopicLink.LinkData2 = TextData; CurrentDataLen2 = TextLength; } // --------------- Base for Pointer-References ----------- FormatData = TopicLink.LinkData1; FormatLength = ledword(TopicLink.DataLen1)-21; // --------------- Act depending on RecordType------------ switch (TopicLink.RecordType) { case TL_TOPICHDR: { TopicHdr = (TOPICHEADER *)TopicLink.LinkData1; /*printf("TopicHdr.BrowseBck:%d TopicHdr.BrowseFor:%d", ledword(TopicHdr->BrowseBck), ledword(TopicHdr->BrowseFor));*/ if (ISV30(topic) && // Find End of File for HC30 ledword(TopicHdr->BlockSize) <= 8) TextEndReached = TRUE; EndNonScrollingRegion = ledword(TopicHdr->Scroll); InNonScrollingRegion = EndNonScrollingRegion > ledword(TopicHdr->NonScroll); /* Transfer Topic Title */ if (CurrentDataLen2 > 0 /* && !ForPrint*/) nTopicTitle(topic, fnenum, lParam, TopicLink.LinkData2, (UINT) CurrentDataLen2); /* Transfer Group-Name Informations */ if (ledword(TopicLink.DataLen1)-21 > sizeof(TOPICHEADER)) { GroupNumber=*((LPWORD) (TopicHdr+1))-1; if (GroupNumbertit->GroupCount) { TempString=topic->tit->GroupNames[GroupNumber]; iTopicString(topic, fnenum, lParam, &TempString, NULL, TOPIC_TITLE_GROUP); } } /* Transfer informations about the browse sequence */ { char szBuffer[30]; sprintf(szBuffer, "%08X", ledword(TopicHdr->BrowseBck)); TempString = szBuffer; iTopicString(topic, fnenum, lParam, &TempString, NULL, TOPIC_BROWSE_BACK); sprintf(szBuffer, "%08x", ledword(TopicHdr->BrowseFor)); TempString = szBuffer; iTopicString(topic, fnenum, lParam, &TempString, NULL, TOPIC_BROWSE_FORWARD); } /* Handle Keywords etc. for WinHelp 3.0 */ if (ISV30(topic)) nSearchContextAndKeyWord(topic, fnenum, ThisTopicOffset, lParam); } break; case TL_DISPLAY30: case TL_DISPLAY: { /* Show a 'text' type record. */ if (!ISV30(topic)) nSearchContextAndKeyWord(topic, fnenum, ThisTopicOffset, lParam); FormatHeader.DoubleOfFormatLength = iGetLongValue(&FormatData, &FormatLength); // Bernd 15.2.96: When {bmlwd} with > 32 KByte we need a long-Value FormatHeader.DoubleDataLength = TopicLink.RecordType == TL_DISPLAY30 ? (short) 0 : iGetWordValue(&FormatData, &FormatLength); iTopicParagraph(topic, fnenum, lParam, &TextData , &TextLength, &FormatData, &FormatLength, ThisTopicOffset, InNonScrollingRegion, FALSE); } break; case TL_TABLE: { /* Show a 'Table' type record */ if (!ISV30(topic)) nSearchContextAndKeyWord(topic, fnenum, ThisTopicOffset, lParam); FormatHeader.DoubleOfFormatLength = iGetLongValue(&FormatData, &FormatLength); FormatHeader.DoubleDataLength = iGetWordValue(&FormatData, &FormatLength); iTopicTable(topic, fnenum, lParam, TextData , TextLength, FormatData, FormatLength, topic->TopicOffset, InNonScrollingRegion); } break; } // of switch Hlpfree(TopicLink.LinkData1); if (CurrentDataLen2 > 0) Hlpfree(TopicLink.LinkData2); TextEndReached |= ledword(TopicLink.NextBlock) == -1; // Works with HC31 } while(!TextEndReached && !topic->CancelEnumeration); } /* nDeCompTopic ----------------------------------------------* * Decompresses a Compressed Topic into a new memory Block * InputBlock - Pointer to the memory Block containing the * Phrase-Replacement Coded Input String. * InputLength- Size of this Memory Block * OutputLength-Initial Size of Output Memory Block * ResultLength-Pointer to Variale that will receive the Resulting * Block Length * Returns: A Pointer to the new Memory Block containing the * decompressed Data. *--------------------------------------------------------------*/ LPBYTE LOCAL nDeCompTopic( HTOPIC topic, BYTE *InputBlock, UINT InputLength, UINT OutputLength, UINT *ResultLength, BOOL NibbleMode) { BYTE Byte1, Byte2; BYTE * OutBlock = Hlpmalloc(OutputLength+1), * Dest = OutBlock; short CurChar; UINT PhraseNum; UINT counter, BlkLen, OutBytes=0; LPSTR Phrase/*, p*/; // BOOL NibbleMode = FALSE; // = InputLength>0x18; /* Hack */ // -------- Winhelp 4.x Phrase Replacement --------------- for (counter = 0; counter < InputLength; ++counter ) { CurChar = *InputBlock++; // ---- Depend on Mode... -------------------------------- /* if (CurChar < ' ' && CurChar >= 0xf) NibbleMode = TRUE; */ if (NibbleMode) { // ----------- We're in Nibble-Mode ---------------------- if (CurChar & 1) { switch (CurChar & 0xf) { case 0xf: BlkLen = ((CurChar & 0xf0) >> 4)+1; memset(Dest, 0 , BlkLen); Dest += BlkLen; OutBytes += BlkLen; break; case 0x7: BlkLen = ((CurChar & 0xf0) >> 4)+1; memset(Dest, ' ', BlkLen); Dest += BlkLen; OutBytes += BlkLen; break; case 0xb: case 0x3: BlkLen = ((CurChar & 0xf8) >> 3) +1; memcpy(Dest, InputBlock, BlkLen); InputBlock+= BlkLen; Dest += BlkLen; OutBytes += BlkLen; counter += BlkLen; break; case 0x1: case 0x5: case 0x9: case 0xd: Byte1 =(BYTE) ((CurChar & 0xfc) >> 2); CurChar = *InputBlock++; counter++; Byte2 = (BYTE) CurChar; PhraseNum = Byte1 * 256 + Byte2 + 128; /* If there's a remainder, we have a space after the phrase */ Phrase = iGetPhrase(topic, PhraseNum); BlkLen = strlen(Phrase); memcpy(Dest, Phrase, BlkLen ); Dest += BlkLen; OutBytes += BlkLen; Hlpfree(Phrase); break; } } else { // --------- Get a Phrase -------------------------------- PhraseNum = CurChar/2; /* If there's a remainder, we have a space after the phrase */ Phrase = iGetPhrase(topic, PhraseNum); BlkLen = strlen(Phrase); memcpy(Dest, Phrase, BlkLen ); Dest += BlkLen; OutBytes += BlkLen; Hlpfree(Phrase); } } else { if ((CurChar > 0) && (CurChar <= 15)) { Byte1 = (BYTE) CurChar; CurChar = *InputBlock++; counter++; Byte2 = (BYTE) CurChar; PhraseNum = (256 * (Byte1 - 1) + Byte2); /* If there's a remainder, we have a space after the phrase */ Phrase = iGetPhrase(topic, PhraseNum / 2); BlkLen = strlen(Phrase); memcpy(Dest, Phrase, BlkLen ); Dest += BlkLen; OutBytes += BlkLen; Hlpfree(Phrase); if (PhraseNum % 2) { *Dest++= ' '; OutBytes++; } } else { *Dest++= CurChar; OutBytes++; } // } } } // for *Dest=0; if (ResultLength != NULL) *ResultLength = OutBytes; return OutBlock; } /* nTopicTitle -------------------------------------------------* * Write Title of Topic(And eventually Macro) * *--------------------------------------------------------------*/ void LOCAL nTopicTitle(HTOPIC topic, TOPICENUMPROC fnenum, LPARAM lParam, BYTE* String, UINT Length) { if (Length && String[0]) // do we have a Titel ($)-Footnote? iTopicString(topic, fnenum, lParam, &String, &Length, TOPIC_TITLE); else { String++; Length--; } if (Length && String[0]) // do we have a Macro (!)-Footnote ? iTopicString(topic, fnenum, lParam, &String, &Length, TOPIC_MACRO_ENTRY); } /* nSearchContextAndKeyWord ------------------------------------* * Search KeyWord-Tables and Context-Ids for references * to the current TopicOffset *--------------------------------------------------------------*/ void LOCAL nSearchContextAndKeyWord(HTOPIC topic, TOPICENUMPROC fnenum, DWORD TopicOffset, LPARAM lParam) { LPSTR ContextStr, p; /* ------- Handle the Context-Strings -------------------------*/ if (NULL!=(ContextStr = p = iContextFind(topic, TopicOffset))) { iTopicString(topic, fnenum, lParam, (LPBYTE *)&p, NULL, TOPIC_CONTEXTID); Hlpfree(ContextStr); } /* ------- Handle the Keyword-Strings -------------------------*/ iKeyWordsForTopic(topic, fnenum, TopicOffset, lParam); }