123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- program chmsearch;
- { Fulltext search demo by Reinier Olislagers}
- {$mode objfpc}{$H+}
- uses
- Classes, SysUtils, ChmReader, chmfiftimain;
- type
- TChmWLCTopic = record
- TopicIndex: DWord;
- LocationCodes: array of DWord;
- end;
- TChmWLCTopicArray = array of TChmWLCTopic;
- procedure DoSearch(CHMFileName: string; Keyword: string);
- type
- TTopicEntry = record
- Topic:Integer;
- Hits: Integer;
- TitleHits: Integer;
- FoundForThisRound: Boolean;
- end;
- TFoundTopics = array of TTopicEntry;
- var
- FoundTopics: TFoundTopics;
- procedure DeleteTopic(ATopicIndex: Integer);
- var
- MoveSize: DWord;
- begin
- WriteLn('Deleting Topic');
- if ATopicIndex < High(FoundTopics) then
- begin
- MoveSize := SizeOf(TTopicEntry) * (High(FoundTopics) - (ATopicIndex+1));
- Move(FoundTopics[ATopicIndex+1], FoundTopics[ATopicIndex], MoveSize);
- end;
- SetLength(FoundTopics, Length(FoundTopics) -1);
- end;
- function GetTopicIndex(ATopicID: Integer): Integer;
- var
- i: Integer;
- begin
- Result := -1;
- for i := 0 to High(FoundTopics) do
- begin
- if FoundTopics[i].Topic = ATopicID then
- Exit(i);
- end;
- end;
- procedure UpdateTopic(TopicID: Integer; NewHits: Integer; NewTitleHits: Integer; AddNewTopic: Boolean);
- var
- TopicIndex: Integer;
- begin
- //WriteLn('Updating topic');
- TopicIndex := GetTopicIndex(TopicID);
- if TopicIndex = -1 then
- begin
- if AddNewTopic = False then
- Exit;
- SetLength(FoundTopics, Length(FoundTopics)+1);
- TopicIndex := High(FoundTopics);
- FoundTopics[TopicIndex].Topic := TopicID;
- end;
- FoundTopics[TopicIndex].FoundForThisRound := True;
- if NewHits > 0 then
- Inc(FoundTopics[TopicIndex].Hits, NewHits);
- if NewTitleHits > 0 then
- Inc(FoundTopics[TopicIndex].TitleHits, NewTitleHits);
- end;
- var
- CHMRead: TCHMReader;
- CHMStream: TFileStream;
- TopicResults: chmfiftimain.TChmWLCTopicArray;
- TitleResults: chmfiftimain.TChmWLCTopicArray;
- FIftiMainStream: TMemoryStream;
- SearchReader: TChmSearchReader;
- DocTitle: String;
- DocURL: String;
- CurrTopic: Integer;
- k: Integer;
- begin
- CHMStream := TFileStream.Create(CHMFileName, fmOpenRead or fmShareDenyWrite);
- ChmRead := TChmReader.Create(CHMStream,false);
- try
- FIftiMainStream := CHMRead.GetObject('/$FIftiMain');
- if FIftiMainStream = nil then
- begin
- writeln('Could not assign fiftimainstream. Aborting.');
- halt(3);
- end;
- SearchReader := TChmSearchReader.Create(FIftiMainStream, True); //frees the stream when done
- CHMRead.SearchReader := SearchReader;
- TopicResults := SearchReader.LookupWord(Keyword, TitleResults);
- //TopicResults := SearchReader.LookupWord(SearchWords[CurrTopic], TitleResults);
- // Body results
- for k := 0 to High(TopicResults) do
- begin
- UpdateTopic(TopicResults[k].TopicIndex, High(TopicResults[k].LocationCodes), 0, CurrTopic = 0);
- writeln('Updated topic body with index '+inttostr(TopicResults[k].TopicIndex));
- end;
- // Title results
- for k := 0 to High(TitleResults) do
- begin
- UpdateTopic(TitleResults[k].TopicIndex, 0, High(TitleResults[k].LocationCodes), CurrTopic = 0);
- writeln('Updated title topic with index '+inttostr(TitleResults[k].TopicIndex));
- end;
- // Remove documents that don't have results
- k := 0;
- writeln('Going to remove docs without results; count: '+Inttostr(Length(FoundTopics)));
- while k <= High(FoundTopics) do
- begin
- if FoundTopics[k].FoundForThisRound = False then
- DeleteTopic(k)
- else
- begin
- FoundTopics[k].FoundForThisRound := False;
- Inc(k);
- end;
- end;
- // Clear out results that don't contain all the words we are looking for
- // Now lookup titles and urls to add to final search results
- writeln('Found '+inttostr(Length(FoundTopics))+' topics');
- for CurrTopic := 0 to High(FoundTopics) do
- begin
- try
- DocURL := CHMRead.LookupTopicByID(FoundTopics[CurrTopic].Topic, DocTitle);
- if (Length(DocURL) > 0) and (DocURL[1] <> '/') then
- Insert('/', DocURL, 1);
- if DocTitle = '' then
- DocTitle := 'untitled';
- writeln('DocURL : '+DocURL);
- writeln('DocTitle : '+DocTitle);
- except
- on E: Exception do
- begin
- WriteLn('Exception');
- writeln(E.Message);
- end;
- end;
- end;
- finally
- CHMRead.Free;
- CHMStream.Free;
- //SearchReader.Free; //apparently not needed?!?!
- end;
- end;
- var
- SearchFor: string;
- begin
- if paramstr(1)='' then
- begin
- writeln('No .chm file specified.');
- writeln('Substituting hardcoded value lcl.chm');
- end;
- writeln('Enter search keyword or blank to exit:');
- readln(SearchFor);
- while (trim(SearchFor)<>'') do
- begin
- if paramstr(1)='' then
- DoSearch('lcl.chm',SearchFor)
- else
- DoSearch(paramstr(1),SearchFor);
- writeln('Enter search keyword or blank to exit:');
- readln(SearchFor);
- end;
- end.
|