1 | Unit SearchTable;
|
---|
2 |
|
---|
3 | // NewView - a new OS/2 Help Viewer
|
---|
4 | // Copyright 2003 Aaron Lawrence (aaronl at consultant dot com)
|
---|
5 | // This software is released under the Gnu Public License - see readme.txt
|
---|
6 |
|
---|
7 | Interface
|
---|
8 |
|
---|
9 | uses
|
---|
10 | Classes, IPFFileFormatUnit, OS2Def;
|
---|
11 |
|
---|
12 | // Code to read and use IPF search tables
|
---|
13 | // NB The RLE decompression was arrived at by trial and error
|
---|
14 | // it seems to be correct but it's difficult to test.
|
---|
15 |
|
---|
16 | type
|
---|
17 | TSearchTable = class
|
---|
18 | protected
|
---|
19 | _Data: pointer;
|
---|
20 | _Entries: TList; // pointers to panel flag records
|
---|
21 | _RecordLengthIs16Bit: boolean;
|
---|
22 | _DictionaryCount: longint;
|
---|
23 | _TopicCount: longint;
|
---|
24 |
|
---|
25 | procedure ReadEntries;
|
---|
26 |
|
---|
27 | Procedure Check1ByteOfFlags( b: byte;
|
---|
28 | StartingIndex: longint;
|
---|
29 | Results: UInt32ArrayPointer );
|
---|
30 |
|
---|
31 | procedure DoRLESearch( p: pbyte;
|
---|
32 | pDataEnd: pointer;
|
---|
33 | Results: UInt32ArrayPointer );
|
---|
34 |
|
---|
35 | public
|
---|
36 | constructor Create( Data: pointer;
|
---|
37 | RecordLengthIs16Bit: boolean;
|
---|
38 | DictionaryCount: longint;
|
---|
39 | TopicCount: longint );
|
---|
40 | destructor Destroy; override;
|
---|
41 |
|
---|
42 | // Sets Results to 1 for occurrences of DictIndex
|
---|
43 | procedure Search( DictIndex: uint16;
|
---|
44 | Results: UInt32ArrayPointer );
|
---|
45 |
|
---|
46 | end;
|
---|
47 |
|
---|
48 | Implementation
|
---|
49 |
|
---|
50 | constructor TSearchTable.Create( Data: pointer;
|
---|
51 | RecordLengthIs16Bit: boolean;
|
---|
52 | DictionaryCount: longint;
|
---|
53 | TopicCount: longint );
|
---|
54 | begin
|
---|
55 | _Data := Data;
|
---|
56 | _RecordLengthIs16Bit :=
|
---|
57 | RecordLengthIs16Bit;
|
---|
58 | _Entries := TList.Create;
|
---|
59 | _DictionaryCount := DictionaryCount;
|
---|
60 | _TopicCount := TopicCount;
|
---|
61 | ReadEntries;
|
---|
62 | end;
|
---|
63 |
|
---|
64 | destructor TSearchTable.Destroy;
|
---|
65 | begin
|
---|
66 | _Entries.Destroy;
|
---|
67 | end;
|
---|
68 |
|
---|
69 | procedure TSearchTable.ReadEntries;
|
---|
70 | var
|
---|
71 | pWordRecord: pointer;
|
---|
72 | RecordLen: uint16;
|
---|
73 | WordIndex: uint16;
|
---|
74 | begin
|
---|
75 | pWordRecord:= _Data;
|
---|
76 |
|
---|
77 | for WordIndex:= 0 to _DictionaryCount - 1 do
|
---|
78 | begin
|
---|
79 | _Entries.Add( pWordRecord );
|
---|
80 |
|
---|
81 | if _RecordLengthIs16Bit then
|
---|
82 | RecordLen:= pUInt16( pWordRecord )^
|
---|
83 | else // 8 bit
|
---|
84 | RecordLen:= pUInt8( pWordRecord )^;
|
---|
85 | inc( pWordRecord, RecordLen );
|
---|
86 | end;
|
---|
87 | end;
|
---|
88 |
|
---|
89 |
|
---|
90 | // Search table decompression
|
---|
91 |
|
---|
92 | // Looks through a single byte of 8 flags, given by b,
|
---|
93 | // and updates topic entries within results for any flags
|
---|
94 | // that are set.
|
---|
95 | Procedure TSearchTable.Check1ByteOfFlags( b: byte;
|
---|
96 | StartingIndex: longint;
|
---|
97 | Results: UInt32ArrayPointer );
|
---|
98 | var
|
---|
99 | TopicIndex: longint;
|
---|
100 | begin
|
---|
101 | TopicIndex:= StartingIndex;
|
---|
102 | while b > 0 do
|
---|
103 | begin
|
---|
104 | if b and $80 > 0 then
|
---|
105 | Results[ TopicIndex ] := 1;
|
---|
106 | inc( TopicIndex );
|
---|
107 | b:= b shl 1;
|
---|
108 | end;
|
---|
109 | end;
|
---|
110 |
|
---|
111 | // Decompress RLE compressed data starting at p,
|
---|
112 | // running til pDataEnd. Update topic entries in Results.
|
---|
113 | procedure TSearchTable.DoRLESearch( p: pbyte;
|
---|
114 | pDataEnd: pointer;
|
---|
115 | Results: UInt32ArrayPointer );
|
---|
116 | var
|
---|
117 | TopicIndex: integer;
|
---|
118 |
|
---|
119 | N: integer;
|
---|
120 | thebyte: byte;
|
---|
121 | byte1, byte2: byte;
|
---|
122 | begin
|
---|
123 | assert( pbyte( p )^ = 1, 'Unexpected RLE type' );
|
---|
124 | inc( p ); // skip header, always 1?
|
---|
125 |
|
---|
126 | TopicIndex:= 0;
|
---|
127 |
|
---|
128 | while p < pDataEnd do
|
---|
129 | begin
|
---|
130 | thebyte:= p^;
|
---|
131 | inc( p );
|
---|
132 |
|
---|
133 | if thebyte = $80 then
|
---|
134 | begin
|
---|
135 | // escape
|
---|
136 | thebyte := p^;
|
---|
137 | inc( p );
|
---|
138 |
|
---|
139 | if thebyte = 0 then
|
---|
140 | begin
|
---|
141 | // 16 bit repeat of zeroes??
|
---|
142 | N := pUInt16( p )^ + 1;
|
---|
143 | inc( p, 2 );
|
---|
144 | inc( TopicIndex, N );
|
---|
145 | end
|
---|
146 | else
|
---|
147 | begin
|
---|
148 | // n+1 repeats of next 2 bytes???
|
---|
149 | N := thebyte + 1;
|
---|
150 | byte1 := p^;
|
---|
151 | inc( p );
|
---|
152 | byte2 := p^;
|
---|
153 | inc( p );
|
---|
154 | while N > 0 do
|
---|
155 | begin
|
---|
156 | Check1ByteOfFlags( byte1,
|
---|
157 | TopicIndex,
|
---|
158 | Results );
|
---|
159 | inc( TopicIndex, 8 );
|
---|
160 | Check1ByteOfFlags( byte2,
|
---|
161 | TopicIndex,
|
---|
162 | Results );
|
---|
163 | inc( TopicIndex, 8 );
|
---|
164 | dec( N );
|
---|
165 | end;
|
---|
166 | end;
|
---|
167 | end
|
---|
168 | else
|
---|
169 | begin
|
---|
170 | N:= thebyte and $7f + 1;
|
---|
171 |
|
---|
172 | if thebyte and $80 > 0 then
|
---|
173 | begin
|
---|
174 | // literal data
|
---|
175 | while N > 0 do
|
---|
176 | begin
|
---|
177 | Check1ByteOfFlags( p^,
|
---|
178 | TopicIndex,
|
---|
179 | Results );
|
---|
180 | inc( TopicIndex, 8 );
|
---|
181 | inc( p );
|
---|
182 | dec( N );
|
---|
183 | end;
|
---|
184 | end
|
---|
185 | else
|
---|
186 | begin
|
---|
187 | // repeat of next byte
|
---|
188 | thebyte := p^;
|
---|
189 | inc( p );
|
---|
190 | while N > 0 do
|
---|
191 | begin
|
---|
192 | Check1ByteOfFlags( thebyte,
|
---|
193 | TopicIndex,
|
---|
194 | Results );
|
---|
195 | inc( TopicIndex, 8 );
|
---|
196 | dec( N );
|
---|
197 | end;
|
---|
198 | end;
|
---|
199 | end;
|
---|
200 | end;
|
---|
201 | end;
|
---|
202 |
|
---|
203 | // This function finds uses of the given word (DictIndex)
|
---|
204 | // using the search table. Results[ topic ] is set to
|
---|
205 | // non-zero for topics which contain the word.
|
---|
206 | procedure TSearchTable.Search( DictIndex: uint16;
|
---|
207 | Results: UInt32ArrayPointer );
|
---|
208 | var
|
---|
209 | TopicIndex: integer;
|
---|
210 | pWordRecord: pointer;
|
---|
211 | RecordLen: uint16;
|
---|
212 | CompressionCode: uint8;
|
---|
213 | pData: pointer;
|
---|
214 | pDataEnd: pointer;
|
---|
215 | Flags: uint8;
|
---|
216 | begin
|
---|
217 | pWordRecord:= _Entries[ DictIndex ];
|
---|
218 |
|
---|
219 | // Check search table format
|
---|
220 | if _RecordLengthIs16Bit then
|
---|
221 | begin
|
---|
222 | RecordLen:= pUInt16( pWordRecord )^;
|
---|
223 | CompressionCode:= pUInt8( pWordRecord + 2 )^;
|
---|
224 | pData:= pWordRecord + 3;
|
---|
225 | end
|
---|
226 | else // 8 bit
|
---|
227 | begin
|
---|
228 | RecordLen:= pUInt8( pWordRecord )^;
|
---|
229 | CompressionCode:= pUInt8( pWordRecord + 1 )^;
|
---|
230 | pData:= pWordRecord + 2;
|
---|
231 | end;
|
---|
232 |
|
---|
233 | // Decompress the search table for this word
|
---|
234 | pDataEnd:= pWordRecord + RecordLen;
|
---|
235 | case CompressionCode of
|
---|
236 | 0: // word not used anywhere.
|
---|
237 | ClearUInt32Array( Results, _TopicCount );
|
---|
238 |
|
---|
239 | 1: // used in all panels
|
---|
240 | FillUInt32Array( Results, _TopicCount, 1 );
|
---|
241 |
|
---|
242 | 2: // RLE
|
---|
243 | begin
|
---|
244 | ClearUInt32Array( Results, _TopicCount );
|
---|
245 | DoRLESearch( pData,
|
---|
246 | pDataEnd,
|
---|
247 | Results );
|
---|
248 | end;
|
---|
249 |
|
---|
250 | 3: // list of topics containing word
|
---|
251 | begin
|
---|
252 | ClearUInt32Array( Results, _TopicCount );
|
---|
253 | while pData < pDataEnd do
|
---|
254 | begin
|
---|
255 | TopicIndex:= pUInt16( pData )^;
|
---|
256 | Results^[ TopicIndex ] := 1;
|
---|
257 | inc( pData, 2 );
|
---|
258 | end;
|
---|
259 | end;
|
---|
260 |
|
---|
261 | 4: // list of topics NOT containing word
|
---|
262 | begin
|
---|
263 | FillUInt32Array( Results, _TopicCount, 1 );
|
---|
264 |
|
---|
265 | while pData < pDataEnd do
|
---|
266 | begin
|
---|
267 | TopicIndex:= pUInt16( pData )^;
|
---|
268 | Results^[ TopicIndex ] := 0;
|
---|
269 | inc( pData, 2 );
|
---|
270 | end;
|
---|
271 | end;
|
---|
272 |
|
---|
273 | 5, // compressed by truncating bit stream at last byte containing a set bit.
|
---|
274 | 6: // same as above but starting at non-zero byte (first word contains start topic)
|
---|
275 | begin
|
---|
276 | ClearUInt32Array( Results, _TopicCount );
|
---|
277 | if CompressionCode = 5 then
|
---|
278 | begin
|
---|
279 | TopicIndex:= 0
|
---|
280 | end
|
---|
281 | else
|
---|
282 | begin
|
---|
283 | TopicIndex:= pUInt16( pData )^ * 8;
|
---|
284 | inc( pData, 2 );
|
---|
285 | end;
|
---|
286 |
|
---|
287 | while pData < pDataEnd do
|
---|
288 | begin
|
---|
289 | Flags:= pUInt8( pData )^;
|
---|
290 | Check1ByteOfFlags( Flags,
|
---|
291 | TopicIndex,
|
---|
292 | Results );
|
---|
293 | inc( TopicIndex, 8 );
|
---|
294 | inc( pData );
|
---|
295 | end;
|
---|
296 | end;
|
---|
297 |
|
---|
298 | else
|
---|
299 | // unknown method
|
---|
300 | ClearUInt32Array( Results, _TopicCount );
|
---|
301 | end;
|
---|
302 | end;
|
---|
303 |
|
---|
304 | Initialization
|
---|
305 | End.
|
---|