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