1 | Unit IPFFileFormatUnit;
|
---|
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 | // Definition of IPF file header and other structures
|
---|
10 |
|
---|
11 | uses
|
---|
12 | SysUtils;
|
---|
13 |
|
---|
14 | type
|
---|
15 | uint32 = longword;
|
---|
16 | uint16 = word;
|
---|
17 | uint8 = byte;
|
---|
18 | pUInt16 = ^ uint16;
|
---|
19 | pUInt32 = ^ uint32;
|
---|
20 | pUInt8 = ^ uint8;
|
---|
21 |
|
---|
22 | PCharArray = array[ 0..0 ] of PCHar;
|
---|
23 | UInt32Array = array[ 0..0 ] of UInt32;
|
---|
24 | UInt16Array = array[ 0..0 ] of UInt16;
|
---|
25 | UInt8Array = array[ 0..0 ] of UInt8;
|
---|
26 |
|
---|
27 | PCharArrayPointer = ^ PCharArray;
|
---|
28 | UInt32ArrayPointer = ^ UInt32Array;
|
---|
29 | UInt16ArrayPointer = ^ UInt16Array;
|
---|
30 | UInt8ArrayPointer = ^ UInt8Array;
|
---|
31 |
|
---|
32 | TBooleanArray = array[ 0..0 ] of boolean;
|
---|
33 | BooleanArrayPointer = ^TBooleanArray;
|
---|
34 |
|
---|
35 | EHelpFileException = class( Exception )
|
---|
36 | end;
|
---|
37 |
|
---|
38 | EWindowsHelpFormatException = class( Exception )
|
---|
39 | end;
|
---|
40 |
|
---|
41 | var
|
---|
42 | ErrorCorruptHelpFile: string;
|
---|
43 |
|
---|
44 | const
|
---|
45 | INF_HEADER_ID = $5348;
|
---|
46 |
|
---|
47 | Type
|
---|
48 | THelpFileHeader = record
|
---|
49 | ID: uint16; // ID magic word (5348h = "HS")
|
---|
50 | unknown1: uint8; // unknown purpose, could be third letter of ID
|
---|
51 | flags: uint8; // probably a flag word...
|
---|
52 | // bit 0: set if INF style file
|
---|
53 | // bit 4: set if HLP style file
|
---|
54 | // patching this byte allows reading HLP files
|
---|
55 | // using the VIEW command, while help files
|
---|
56 | // seem to work with INF settings here as well.
|
---|
57 | hdrsize: uint16; // total size of header
|
---|
58 | unknown2: uint16; // unknown purpose
|
---|
59 |
|
---|
60 | ntoc: uint16; // number of entries in the tocarray
|
---|
61 | tocstart: uint32; // file offset of the start of the toc
|
---|
62 | toclen: uint32; // number of bytes in file occupied by the toc
|
---|
63 | tocoffsetsstart: uint32; // file offset of the start of array of toc offsets
|
---|
64 | nres: uint16; // number of panels with ressource numbers
|
---|
65 | resstart: uint32; // 32 bit file offset of ressource number table
|
---|
66 | nname: uint16; // number of panels with textual name
|
---|
67 | namestart: uint32; // 32 bit file offset to panel name table
|
---|
68 | nindex: uint16; // number of index entries
|
---|
69 | indexstart: uint32; // 32 bit file offset to index table
|
---|
70 | indexlen: uint32; // size of index table
|
---|
71 | unknown3: array[ 0..9 ] of uint8; // unknown purpose
|
---|
72 | searchstart: uint32; // 31 bit file offset of full text search table
|
---|
73 | // Note: top bit indicates 32 bit search record!
|
---|
74 | searchlen: uint32; // size of full text search table
|
---|
75 | nslots: uint16; // number of "slots"
|
---|
76 | slotsstart: uint32; // file offset of the slots array
|
---|
77 | dictlen: uint32; // number of bytes occupied by the "dictionary"
|
---|
78 | ndict: uint16; // number of entries in the dictionary
|
---|
79 | dictstart: uint32; // file offset of the start of the dictionary
|
---|
80 | imgstart: uint32; // file offset of image data
|
---|
81 | unknown4: uint8; // unknown purpose
|
---|
82 | nlsstart: uint32; // 32 bit file offset of NLS table
|
---|
83 | nlslen: uint32; // size of NLS table
|
---|
84 | extstart: uint32; // 32 bit file offset of extended data block
|
---|
85 | reserved: array[ 0..2 ] of uint32; // for future use. set to zero.
|
---|
86 | title: array[ 0..47 ] of char; // ASCII title of database
|
---|
87 | end;
|
---|
88 | TPHelpFileHeader = ^ THelpFileHeader;
|
---|
89 |
|
---|
90 | TExtendedHelpFileHeader = record
|
---|
91 | NumFontEntry: uint16; // FONT TABLE: Number entries
|
---|
92 | FontTableOffset: uint32; // FONT TABLE: Offset in file
|
---|
93 | NumDataBase: uint16; // DATA BASE: Number of files
|
---|
94 | DataBaseOffset: uint32; // DATA BASE: Offset in file
|
---|
95 | DataBaseSize: uint32; // DATA BASE: Size in bytes
|
---|
96 | EntryInGNameTable: uint16; // GLOBAL NAMES: Number entries
|
---|
97 | HelpPanelGNameTblOffset: uint32; // GLOBAL NAMES: Offset in file
|
---|
98 | StringsOffset: uint32; // STRINGS : Offset in file
|
---|
99 | StringsSize: uint16; // STRINGS : Total bytes of all strings
|
---|
100 | ChildPagesOffset: uint32; // CHILDPAGES : Offset in file
|
---|
101 | ChildPagesSize: uint32; // CHILDPAGES : Total bytes of all strings
|
---|
102 | NumGIndexEntry: uint32; // Total number of Global Index items
|
---|
103 | CtrlOffset: uint32; // CTRL BUTTONS : offset in file
|
---|
104 | CtrlSize: uint32; // CTRL BUTTONS : size in bytes
|
---|
105 | Reserved: array[0..3] of uint32; // For future use. Set to zero
|
---|
106 | end;
|
---|
107 | TPExtendedHelpFileHeader = ^ TExtendedHelpFileHeader;
|
---|
108 |
|
---|
109 | Type
|
---|
110 | TTOCEntryStart = record
|
---|
111 | length: uint8; // length of the entry including this byte
|
---|
112 | flags: uint8; // flag byte, description folows (MSB first)
|
---|
113 | // bit1 haschildren; // following nodes are a higher level
|
---|
114 | // bit1 hidden; // this entry doesn't appear in VIEW.EXE's
|
---|
115 | // presentation of the toc
|
---|
116 | // bit1 extended; // extended entry format
|
---|
117 | // bit1 stuff; // ??
|
---|
118 | // int4 level; // nesting level
|
---|
119 | numSlots: uint8; // number of "slots" occupied by the text for
|
---|
120 | // this toc entry
|
---|
121 | end;
|
---|
122 | pTTOCEntryStart = ^TTOCEntryStart;
|
---|
123 |
|
---|
124 | TExtendedTOCEntry = record
|
---|
125 | w1: uint8;
|
---|
126 | w2: uint8;
|
---|
127 | end;
|
---|
128 | pExtendedTOCEntry = ^TExtendedTOCEntry;
|
---|
129 |
|
---|
130 | TTOCEntryOffsetArray = array[ 0..0 ] of uint32;
|
---|
131 | pTTOCEntryOffsetArray = ^ TTOCEntryOffsetArray;
|
---|
132 |
|
---|
133 | Const
|
---|
134 | TOCEntryExtended = 32;
|
---|
135 | TOCEntryHidden = 64;
|
---|
136 | TOCEntryHasChildren = 128;
|
---|
137 |
|
---|
138 | type
|
---|
139 | THelpXYPair = record
|
---|
140 | Flags: uint8;
|
---|
141 | X: uint16;
|
---|
142 | Y: uint16;
|
---|
143 | end;
|
---|
144 | pHelpXYPair = ^ THelpXYPair;
|
---|
145 |
|
---|
146 | TSlotHeader = record
|
---|
147 | stuff: uint8; // always 0??
|
---|
148 | localdictpos: uint32; // file offset of the local dictionary
|
---|
149 | nlocaldict: uint8; // number of entries in the local dict
|
---|
150 | ntext: uint16; // number of bytes in the text
|
---|
151 | end;
|
---|
152 | pSlotHeader = ^TSlotHeader;
|
---|
153 |
|
---|
154 | THelpFontSpec = record
|
---|
155 | FaceName: array[ 0..32 ] of char;
|
---|
156 | Height: uint16;
|
---|
157 | Width: uint16;
|
---|
158 | Codepage: uint16;
|
---|
159 | end;
|
---|
160 | pTHelpFontSpec = ^ THelpFontSpec;
|
---|
161 |
|
---|
162 | // List of IPF escape codes.
|
---|
163 |
|
---|
164 | const
|
---|
165 | // Basic byte codes
|
---|
166 | IPF_END_PARA = $fa;
|
---|
167 | IPF_CENTER = $fb;
|
---|
168 | IPF_INVERT_SPACING = $fc;
|
---|
169 | IPF_LINEBREAK = $fd;
|
---|
170 | IPF_SPACE = $fe;
|
---|
171 | IPF_ESC = $ff; // followed by one of the ecXXX codes below
|
---|
172 |
|
---|
173 | // FF XX
|
---|
174 | ecSetLeftMargin = $02;
|
---|
175 | ecHighlight1 = $04; // hp1,2,3,5,6,7
|
---|
176 | ecLinkStart = $05;
|
---|
177 | ecFootnoteLinkStart = $07;
|
---|
178 | ecLinkEnd = $08;
|
---|
179 | ecStartCharGraphics = $0b;
|
---|
180 | ecEndCharGraphics = $0c;
|
---|
181 | ecHighlight2 = $0d; // hp4,8,9
|
---|
182 | ecImage = $0e;
|
---|
183 | ecLinkedImage = $0f;
|
---|
184 | ecProgramLink = $10;
|
---|
185 | ecSetLeftMarginNewLine = $11;
|
---|
186 | ecSetLeftMarginFit = $12;
|
---|
187 | ecForegroundColor = $13;
|
---|
188 | ecBackgroundColor = $14;
|
---|
189 | ecFontChange = $19;
|
---|
190 | ecStartLines = $1a;
|
---|
191 | ecEndLines = $1b;
|
---|
192 | ecSetLeftMarginHere = $1c;
|
---|
193 | ecStartLinkByResourceID = $1d;
|
---|
194 | ecExternalLink = $1f;
|
---|
195 |
|
---|
196 | // Subescape codes of
|
---|
197 | HPART_DEFINE = 0;
|
---|
198 | HPART_PT_HDREF = 1;
|
---|
199 | HPART_PT_FNREF = 2;
|
---|
200 | HPART_PT_SPREF = 3;
|
---|
201 | HPART_HDREF = 4;
|
---|
202 | HPART_FNREF = 5;
|
---|
203 | HPART_SPREF = 6;
|
---|
204 | HPART_LAUNCH = 7;
|
---|
205 | HPART_PT_LAUNCH = 8;
|
---|
206 | HPART_INFORM = 9;
|
---|
207 | HPART_PT_INFORM = 10;
|
---|
208 | // ?? 11 ??
|
---|
209 | HPART_EXTERN_PT_HDREF = 12;
|
---|
210 | HPART_EXTERN_PT_SPREF = 13;
|
---|
211 | HPART_EXTERN_HDREF = 14;
|
---|
212 | HPART_EXTERN_SPREF = 15;
|
---|
213 | HPART_GLOBAL_HDREF = 16;
|
---|
214 | HPART_GLOBAL_PT_HDREF = 17;
|
---|
215 |
|
---|
216 | // -----------------------------------------------------------
|
---|
217 | // Operations on Int32 arrays, used for searching
|
---|
218 | // These could be optimised heavily if needed.
|
---|
219 | procedure AllocUInt32Array( Var pArray: UInt32ArrayPointer;
|
---|
220 | Size: longint );
|
---|
221 | procedure FreeUInt32Array( Var pArray: UInt32ArrayPointer;
|
---|
222 | Size: longint );
|
---|
223 |
|
---|
224 | procedure FillUInt32Array( pArray: UInt32ArrayPointer;
|
---|
225 | Size: longint;
|
---|
226 | Value: UInt32 );
|
---|
227 |
|
---|
228 | procedure AddUInt32Array( pSource: UInt32ArrayPointer;
|
---|
229 | pDest: UInt32ArrayPointer;
|
---|
230 | Size: longint );
|
---|
231 |
|
---|
232 | // Dest = Dest + source * Multiplier
|
---|
233 | procedure AddMultConstUInt32Array( pSource: UInt32ArrayPointer;
|
---|
234 | Multiplier: longint;
|
---|
235 | pDest: UInt32ArrayPointer;
|
---|
236 | Size: longint );
|
---|
237 |
|
---|
238 | procedure AndUInt32Array( pSource: UInt32ArrayPointer;
|
---|
239 | pDest: UInt32ArrayPointer;
|
---|
240 | Size: longint );
|
---|
241 |
|
---|
242 | // If both source and dest > 0 then
|
---|
243 | // add source to dest
|
---|
244 | procedure AndAddUInt32Array( pSource: UInt32ArrayPointer;
|
---|
245 | pDest: UInt32ArrayPointer;
|
---|
246 | Size: longint );
|
---|
247 |
|
---|
248 | // if Source > 0 then dest is set to 0
|
---|
249 | procedure AndNotUInt32Array( pSource: UInt32ArrayPointer;
|
---|
250 | pDest: UInt32ArrayPointer;
|
---|
251 | Size: longint );
|
---|
252 |
|
---|
253 | // dest = dest or source;
|
---|
254 | // if source > 0 then set dest to > 0
|
---|
255 | procedure OrUInt32Array( pSource: UInt32ArrayPointer;
|
---|
256 | pDest: UInt32ArrayPointer;
|
---|
257 | Size: longint );
|
---|
258 |
|
---|
259 | // if source = 0 then dest set to >0
|
---|
260 | procedure NotOrUInt32Array( pSource: UInt32ArrayPointer;
|
---|
261 | pDest: UInt32ArrayPointer;
|
---|
262 | Size: longint );
|
---|
263 |
|
---|
264 | procedure CopyUInt32Array( pSource: UInt32ArrayPointer;
|
---|
265 | pDest: UInt32ArrayPointer;
|
---|
266 | Size: longint );
|
---|
267 |
|
---|
268 | procedure ClearUInt32Array( pArray: UInt32ArrayPointer;
|
---|
269 | Size: longint );
|
---|
270 | procedure SetUInt32Array( pArray: UInt32ArrayPointer;
|
---|
271 | Size: longint );
|
---|
272 |
|
---|
273 | // returns the result of ORing every array element.
|
---|
274 | // Can be useful for debugging e.g. seeing at a glance
|
---|
275 | // if any element is non-zero
|
---|
276 | function OrAllUInt32Array( pArray: UInt32ArrayPointer;
|
---|
277 | Size: longint ): longint;
|
---|
278 |
|
---|
279 |
|
---|
280 | Implementation
|
---|
281 |
|
---|
282 | uses
|
---|
283 | ACLUtility;
|
---|
284 |
|
---|
285 | // Operations on int32 arrays
|
---|
286 | // -----------------------------------------------------------
|
---|
287 |
|
---|
288 | procedure AllocUInt32Array( Var pArray: UInt32ArrayPointer;
|
---|
289 | Size: longint );
|
---|
290 | begin
|
---|
291 | GetMem( pArray,
|
---|
292 | Size
|
---|
293 | * sizeof( UInt32 ) );
|
---|
294 | end;
|
---|
295 |
|
---|
296 | procedure FreeUInt32Array( Var pArray: UInt32ArrayPointer;
|
---|
297 | Size: longint );
|
---|
298 | begin
|
---|
299 | FreeMem( pArray,
|
---|
300 | Size
|
---|
301 | * sizeof( UInt32 ) );
|
---|
302 | end;
|
---|
303 |
|
---|
304 | // This is a nice fast implementation of filling an
|
---|
305 | // array of dwords (Int32/longword)
|
---|
306 | procedure FillUInt32Array( pArray: UInt32ArrayPointer;
|
---|
307 | Size: longint;
|
---|
308 | Value: UInt32 );
|
---|
309 | begin
|
---|
310 | assert( Size >= 0 );
|
---|
311 | Asm
|
---|
312 | Mov EAX, Value
|
---|
313 | Mov EDI, pArray
|
---|
314 | Mov ECX, Size
|
---|
315 | CLD // direction = up
|
---|
316 | REP STOSD // store double word, until ECX = 0
|
---|
317 | End;
|
---|
318 | end;
|
---|
319 |
|
---|
320 | procedure ClearUInt32Array( pArray: UInt32ArrayPointer;
|
---|
321 | Size: longint );
|
---|
322 | begin
|
---|
323 | FillUInt32Array( pArray, Size, 0 );
|
---|
324 | end;
|
---|
325 |
|
---|
326 | procedure SetUInt32Array( pArray: UInt32ArrayPointer;
|
---|
327 | Size: longint );
|
---|
328 | begin
|
---|
329 | FillUInt32Array( pArray, Size, $ffffffff );
|
---|
330 | end;
|
---|
331 |
|
---|
332 | procedure AddUInt32Array( pSource: UInt32ArrayPointer;
|
---|
333 | pDest: UInt32ArrayPointer;
|
---|
334 | Size: longint );
|
---|
335 | var
|
---|
336 | i: longint;
|
---|
337 | begin
|
---|
338 | for i := 0 to Size - 1 do
|
---|
339 | inc( pDest^[ i ], pSource^[ i ] );
|
---|
340 | end;
|
---|
341 |
|
---|
342 | procedure AddMultConstUInt32Array( pSource: UInt32ArrayPointer;
|
---|
343 | Multiplier: longint;
|
---|
344 | pDest: UInt32ArrayPointer;
|
---|
345 | Size: longint );
|
---|
346 | var
|
---|
347 | i: longint;
|
---|
348 | begin
|
---|
349 | for i := 0 to Size - 1 do
|
---|
350 | inc( pDest^[ i ], pSource^[ i ] * Multiplier );
|
---|
351 | end;
|
---|
352 |
|
---|
353 | procedure OrUInt32Array( pSource: UInt32ArrayPointer;
|
---|
354 | pDest: UInt32ArrayPointer;
|
---|
355 | Size: longint );
|
---|
356 | var
|
---|
357 | i: longint;
|
---|
358 | begin
|
---|
359 | for i := 0 to Size - 1 do
|
---|
360 | pDest^[ i ] := pDest^[ i ] or pSource^[ i ];
|
---|
361 | end;
|
---|
362 |
|
---|
363 | procedure CopyUInt32Array( pSource: UInt32ArrayPointer;
|
---|
364 | pDest: UInt32ArrayPointer;
|
---|
365 | Size: longint );
|
---|
366 | begin
|
---|
367 | MemCopy( pSource, pDest, Size * sizeof( uint32 ) );
|
---|
368 | end;
|
---|
369 |
|
---|
370 | procedure NotOrUInt32Array( pSource: UInt32ArrayPointer;
|
---|
371 | pDest: UInt32ArrayPointer;
|
---|
372 | Size: longint );
|
---|
373 | var
|
---|
374 | i: longint;
|
---|
375 | begin
|
---|
376 | for i := 0 to Size - 1 do
|
---|
377 | if pSource^[ i ] = 0 then
|
---|
378 | pDest^[ i ] := 1;
|
---|
379 | end;
|
---|
380 |
|
---|
381 | procedure AndUInt32Array( pSource: UInt32ArrayPointer;
|
---|
382 | pDest: UInt32ArrayPointer;
|
---|
383 | Size: longint );
|
---|
384 | var
|
---|
385 | i: longint;
|
---|
386 | begin
|
---|
387 | for i := 0 to Size - 1 do
|
---|
388 | pDest^[ i ] := pDest^[ i ] and pSource^[ i ];
|
---|
389 | end;
|
---|
390 |
|
---|
391 | procedure AndAddUInt32Array( pSource: UInt32ArrayPointer;
|
---|
392 | pDest: UInt32ArrayPointer;
|
---|
393 | Size: longint );
|
---|
394 | var
|
---|
395 | i: longint;
|
---|
396 | begin
|
---|
397 | for i := 0 to Size - 1 do
|
---|
398 | if ( pSource^[ i ] > 0 )
|
---|
399 | and ( pDest^[ i ] > 0 ) then
|
---|
400 | inc( pDest^[ i ], pSource^[ i ] )
|
---|
401 | else
|
---|
402 | pDest^[ i ] := 0;
|
---|
403 | end;
|
---|
404 |
|
---|
405 | procedure AndNotUInt32Array( pSource: UInt32ArrayPointer;
|
---|
406 | pDest: UInt32ArrayPointer;
|
---|
407 | Size: longint );
|
---|
408 | var
|
---|
409 | i: longint;
|
---|
410 | begin
|
---|
411 | for i := 0 to Size - 1 do
|
---|
412 | if pSource^[ i ] > 0 then
|
---|
413 | pDest^[ i ] := 0;
|
---|
414 | end;
|
---|
415 |
|
---|
416 | function OrAllUInt32Array( pArray: UInt32ArrayPointer;
|
---|
417 | Size: longint ): longint;
|
---|
418 | var
|
---|
419 | i: longint;
|
---|
420 | begin
|
---|
421 | Result := 0;
|
---|
422 | for i := 0 to Size - 1 do
|
---|
423 | Result := Result or pArray^[ i ];
|
---|
424 | end;
|
---|
425 |
|
---|
426 | Initialization
|
---|
427 | End.
|
---|