chmsearch.lpr 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. program chmsearch;
  2. { Fulltext search demo by Reinier Olislagers}
  3. {$mode objfpc}{$H+}
  4. uses
  5. Classes, SysUtils, ChmReader, chmfiftimain;
  6. type
  7. TChmWLCTopic = record
  8. TopicIndex: DWord;
  9. LocationCodes: array of DWord;
  10. end;
  11. TChmWLCTopicArray = array of TChmWLCTopic;
  12. procedure DoSearch(CHMFileName: string; Keyword: string);
  13. type
  14. TTopicEntry = record
  15. Topic:Integer;
  16. Hits: Integer;
  17. TitleHits: Integer;
  18. FoundForThisRound: Boolean;
  19. end;
  20. TFoundTopics = array of TTopicEntry;
  21. var
  22. FoundTopics: TFoundTopics;
  23. procedure DeleteTopic(ATopicIndex: Integer);
  24. var
  25. MoveSize: DWord;
  26. begin
  27. WriteLn('Deleting Topic');
  28. if ATopicIndex < High(FoundTopics) then
  29. begin
  30. MoveSize := SizeOf(TTopicEntry) * (High(FoundTopics) - (ATopicIndex+1));
  31. Move(FoundTopics[ATopicIndex+1], FoundTopics[ATopicIndex], MoveSize);
  32. end;
  33. SetLength(FoundTopics, Length(FoundTopics) -1);
  34. end;
  35. function GetTopicIndex(ATopicID: Integer): Integer;
  36. var
  37. i: Integer;
  38. begin
  39. Result := -1;
  40. for i := 0 to High(FoundTopics) do
  41. begin
  42. if FoundTopics[i].Topic = ATopicID then
  43. Exit(i);
  44. end;
  45. end;
  46. procedure UpdateTopic(TopicID: Integer; NewHits: Integer; NewTitleHits: Integer; AddNewTopic: Boolean);
  47. var
  48. TopicIndex: Integer;
  49. begin
  50. //WriteLn('Updating topic');
  51. TopicIndex := GetTopicIndex(TopicID);
  52. if TopicIndex = -1 then
  53. begin
  54. if AddNewTopic = False then
  55. Exit;
  56. SetLength(FoundTopics, Length(FoundTopics)+1);
  57. TopicIndex := High(FoundTopics);
  58. FoundTopics[TopicIndex].Topic := TopicID;
  59. end;
  60. FoundTopics[TopicIndex].FoundForThisRound := True;
  61. if NewHits > 0 then
  62. Inc(FoundTopics[TopicIndex].Hits, NewHits);
  63. if NewTitleHits > 0 then
  64. Inc(FoundTopics[TopicIndex].TitleHits, NewTitleHits);
  65. end;
  66. var
  67. CHMRead: TCHMReader;
  68. CHMStream: TFileStream;
  69. TopicResults: chmfiftimain.TChmWLCTopicArray;
  70. TitleResults: chmfiftimain.TChmWLCTopicArray;
  71. FIftiMainStream: TMemoryStream;
  72. SearchReader: TChmSearchReader;
  73. DocTitle: String;
  74. DocURL: String;
  75. CurrTopic: Integer;
  76. k: Integer;
  77. begin
  78. CHMStream := TFileStream.Create(CHMFileName, fmOpenRead or fmShareDenyWrite);
  79. ChmRead := TChmReader.Create(CHMStream,false);
  80. try
  81. FIftiMainStream := CHMRead.GetObject('/$FIftiMain');
  82. if FIftiMainStream = nil then
  83. begin
  84. writeln('Could not assign fiftimainstream. Aborting.');
  85. halt(3);
  86. end;
  87. SearchReader := TChmSearchReader.Create(FIftiMainStream, True); //frees the stream when done
  88. CHMRead.SearchReader := SearchReader;
  89. TopicResults := SearchReader.LookupWord(Keyword, TitleResults);
  90. //TopicResults := SearchReader.LookupWord(SearchWords[CurrTopic], TitleResults);
  91. // Body results
  92. for k := 0 to High(TopicResults) do
  93. begin
  94. UpdateTopic(TopicResults[k].TopicIndex, High(TopicResults[k].LocationCodes), 0, CurrTopic = 0);
  95. writeln('Updated topic body with index '+inttostr(TopicResults[k].TopicIndex));
  96. end;
  97. // Title results
  98. for k := 0 to High(TitleResults) do
  99. begin
  100. UpdateTopic(TitleResults[k].TopicIndex, 0, High(TitleResults[k].LocationCodes), CurrTopic = 0);
  101. writeln('Updated title topic with index '+inttostr(TitleResults[k].TopicIndex));
  102. end;
  103. // Remove documents that don't have results
  104. k := 0;
  105. writeln('Going to remove docs without results; count: '+Inttostr(Length(FoundTopics)));
  106. while k <= High(FoundTopics) do
  107. begin
  108. if FoundTopics[k].FoundForThisRound = False then
  109. DeleteTopic(k)
  110. else
  111. begin
  112. FoundTopics[k].FoundForThisRound := False;
  113. Inc(k);
  114. end;
  115. end;
  116. // Clear out results that don't contain all the words we are looking for
  117. // Now lookup titles and urls to add to final search results
  118. writeln('Found '+inttostr(Length(FoundTopics))+' topics');
  119. for CurrTopic := 0 to High(FoundTopics) do
  120. begin
  121. try
  122. DocURL := CHMRead.LookupTopicByID(FoundTopics[CurrTopic].Topic, DocTitle);
  123. if (Length(DocURL) > 0) and (DocURL[1] <> '/') then
  124. Insert('/', DocURL, 1);
  125. if DocTitle = '' then
  126. DocTitle := 'untitled';
  127. writeln('DocURL : '+DocURL);
  128. writeln('DocTitle : '+DocTitle);
  129. except
  130. on E: Exception do
  131. begin
  132. WriteLn('Exception');
  133. writeln(E.Message);
  134. end;
  135. end;
  136. end;
  137. finally
  138. CHMRead.Free;
  139. CHMStream.Free;
  140. //SearchReader.Free; //apparently not needed?!?!
  141. end;
  142. end;
  143. var
  144. SearchFor: string;
  145. begin
  146. if paramstr(1)='' then
  147. begin
  148. writeln('No .chm file specified.');
  149. writeln('Substituting hardcoded value lcl.chm');
  150. end;
  151. writeln('Enter search keyword or blank to exit:');
  152. readln(SearchFor);
  153. while (trim(SearchFor)<>'') do
  154. begin
  155. if paramstr(1)='' then
  156. DoSearch('lcl.chm',SearchFor)
  157. else
  158. DoSearch(paramstr(1),SearchFor);
  159. writeln('Enter search keyword or blank to exit:');
  160. readln(SearchFor);
  161. end;
  162. end.