[18] | 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.
|
---|