chmtypes.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. { Copyright (C) <2005> <Andrew Haines> chmtypes.pas
  2. This library is free software; you can redistribute it and/or modify it
  3. under the terms of the GNU Library General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at your
  5. option) any later version.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  9. for more details.
  10. You should have received a copy of the GNU Library General Public License
  11. along with this library; if not, write to the Free Software Foundation,
  12. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  13. }
  14. {
  15. See the file COPYING.FPC, included in this distribution,
  16. for details about the copyright.
  17. }
  18. unit chmtypes;
  19. {$mode objfpc}{$H+}
  20. interface
  21. uses
  22. Classes, SysUtils,xmlcfg;
  23. type
  24. TSectionName = (snMSCompressed, snUnCompressed);
  25. TSectionNames = set of TSectionName;
  26. { TDirectoryChunk }
  27. TDirectoryChunk = class(TObject)
  28. private
  29. FHeaderSize: Integer;
  30. FQuickRefEntries: Word;
  31. Buffer: array[0..$1000-1] of byte;
  32. CurrentPos: Integer;
  33. FItemCount: Word;
  34. FClearCount: Integer;
  35. public
  36. function CanHold(ASize: Integer): Boolean;
  37. function FreeSpace: Integer;
  38. procedure WriteHeader(AHeader: Pointer);
  39. procedure WriteEntry(Size: Integer; Data: Pointer);
  40. procedure WriteChunkToStream(Stream: TStream); overload;
  41. procedure Clear;
  42. property ItemCount: Word read FItemCount;
  43. constructor Create(AHeaderSize: Integer);
  44. end;
  45. { TPMGIDirectoryChunk }
  46. TPMGIDirectoryChunk = class(TDirectoryChunk)
  47. private
  48. FChunkLevelCount: Integer;
  49. FParentChunk: TPMGIDirectoryChunk;
  50. public
  51. procedure WriteChunkToStream(Stream: TStream; var AIndex: Integer; Final: Boolean = False); overload;
  52. property ParentChunk: TPMGIDirectoryChunk read FParentChunk write FParentChunk;
  53. property ChunkLevelCount: Integer read FChunkLevelCount write FChunkLevelCount;
  54. end;
  55. PFileEntryRec = ^TFileEntryRec;
  56. TFileEntryRec = record
  57. Path: String;
  58. Name: String;
  59. DecompressedOffset: QWord;
  60. DecompressedSize: QWord;
  61. Compressed: Boolean; // True means it goes in section1 False means section0
  62. end;
  63. { TFileEntryList }
  64. TFileEntryList = class(TList)
  65. private
  66. FPaths: TStringList;
  67. function GetFileEntry(Index: Integer): TFileEntryRec;
  68. procedure SetFileEntry(Index: Integer; const AValue: TFileEntryRec);
  69. public
  70. function AddEntry(AFileEntry: TFileEntryRec; CheckPathIsAdded: Boolean = True): Integer;
  71. procedure Delete(Index: Integer);
  72. property FileEntry[Index: Integer]: TFileEntryRec read GetFileEntry write SetFileEntry;
  73. procedure Sort;
  74. constructor Create;
  75. destructor Destroy; override;
  76. end;
  77. TValidWindowFieldsEnum = (valid_Unknown1 {:=1},
  78. valid_Navigation_pane_style {:= 2},
  79. valid_Window_style_flags {:= 4},
  80. valid_Window_extended_style_flags {:= 8},
  81. valid_Initial_window_position {:= $10},
  82. valid_Navigation_pane_width {:= $20},
  83. valid_Window_show_state {:= $40},
  84. valid_Info_types {:= $80},
  85. valid_Buttons {:= $100},
  86. valid_Navigation_Pane_initially_closed_state {:= $200},
  87. valid_Tab_position {:= $400},
  88. valid_Tab_order {:= $800},
  89. valid_History_count{ := $1000},
  90. valid_Default_Pane {:= $2000});
  91. TValidWindowFields = Set Of TValidWindowFieldsEnum;
  92. TCHMWindow = Class
  93. window_type,
  94. Title_bar_text,
  95. Toc_file,
  96. index_file,
  97. Default_File,
  98. Home_button_file,
  99. Jumpbutton_1_File,
  100. Jumpbutton_1_Text,
  101. Jumpbutton_2_File,
  102. Jumpbutton_2_Text : string;
  103. nav_style : integer; // overlay with bitfields (next 2 also)
  104. navpanewidth : integer;
  105. buttons : integer;
  106. left,
  107. top,
  108. right,
  109. bottom : integer;
  110. styleflags ,
  111. xtdstyleflags,
  112. window_show_state,
  113. navpane_initially_closed,
  114. navpane_default,
  115. navpane_location,
  116. wm_notify_id : integer;
  117. flags : TValidWindowFields; // bitset that keeps track of which fields are filled.
  118. // of certain fields. Needs to be inserted into #windows stream
  119. Constructor create(s:string='');
  120. procedure load_from_ini(txt:string);
  121. procedure savetoxml(cfg:TXMLConfig;key:string);
  122. procedure loadfromxml(cfg:TXMLConfig;key:string);
  123. procedure assign(obj : TCHMWindow);
  124. end;
  125. TTOCIdxHeader = record
  126. BlockSize: DWord; // 4096
  127. EntriesOffset: DWord;
  128. EntriesCount: DWord;
  129. TopicsOffset: DWord;
  130. EmptyBytes: array[0..4079] of byte;
  131. end;
  132. const
  133. TOC_ENTRY_HAS_NEW = 2;
  134. TOC_ENTRY_HAS_CHILDREN = 4;
  135. TOC_ENTRY_HAS_LOCAL = 8;
  136. type
  137. PTOCEntryPageBookInfo = ^TTOCEntryPageBookInfo;
  138. TTOCEntryPageBookInfo = record
  139. Unknown1: Word; // = 0
  140. EntryIndex: Word; // multiple entry info's can have this value but the TTocEntry it points to points back to the first item with this number. Wierd.
  141. Props: DWord; // BitField. See TOC_ENTRY_*
  142. TopicsIndexOrStringsOffset: DWord; // if TOC_ENTRY_HAS_LOCAL is in props it's the Topics Index
  143. // else it's the Offset In Strings of the Item Text
  144. ParentPageBookInfoOffset: DWord;
  145. NextPageBookOffset: DWord; // same level of tree only
  146. // Only if TOC_ENTRY_HAS_CHILDREN is set are these written
  147. FirstChildOffset: DWord;
  148. Unknown3: DWord; // = 0
  149. end;
  150. TTocEntry = record
  151. PageBookInfoOffset: DWord;
  152. IncrementedInt: DWord; // first is $29A
  153. TopicsIndex: DWord; // Index of Entry in #TOPICS file
  154. end;
  155. TTopicEntry = record
  156. TocOffset,
  157. StringsOffset,
  158. URLTableOffset: DWord;
  159. InContents: Word;// 2 = in contents 6 = not in contents
  160. Unknown: Word; // 0,2,4,8,10,12,16,32
  161. end;
  162. TBtreeHeader = packed record
  163. ident : array[0..1] of ansichar; // $3B $29
  164. flags : word; // bit $2 is always 1, bit $0400 1 if dir? (always on)
  165. blocksize : word; // size of blocks (2048)
  166. dataformat : array[0..15] of ansichar; // "X44" always the same, see specs.
  167. unknown0 : dword; // always 0
  168. lastlstblock : dword; // index of last listing block in the file;
  169. indexrootblock : dword; // Index of the root block in the file.
  170. unknown1 : dword; // always -1
  171. nrblock : dword; // Number of blocks
  172. treedepth : word; // The depth of the tree of blocks (1 if no index blocks, 2 one level of index blocks, ...)
  173. nrkeywords : dword; // number of keywords in the file.
  174. codepage : dword; // Windows code page identifier (usually 1252 - Windows 3.1 US (ANSI))
  175. lcid : dword; // LCID from the HHP file.
  176. ischm : dword; // 0 if this a BTREE and is part of a CHW file, 1 if it is a BTree and is part of a CHI or CHM file
  177. unknown2 : dword; // Unknown. Almost always 10031. Also 66631 (accessib.chm, ieeula.chm, iesupp.chm, iexplore.chm, msoe.chm, mstask.chm, ratings.chm, wab.chm).
  178. unknown3 : dword; // unknown 0
  179. unknown4 : dword; // unknown 0
  180. unknown5 : dword; // unknown 0
  181. end;
  182. PBTreeBlockHeader = ^TBtreeBlockHeader;
  183. TBtreeBlockHeader = packed record
  184. Length : word; // Length of free space at the end of the block.
  185. NumberOfEntries : word; // Number of entries in the block.
  186. IndexOfPrevBlock : dword; // Index of the previous block. -1 if this is the first listing block.
  187. IndexOfNextBlock : dword; // Index of the next block. -1 if this is the last listing block.
  188. end;
  189. PBtreeBlockEntry = ^TBtreeBlockEntry;
  190. TBtreeBlockEntry = packed record
  191. isseealso : word; // 2 if this keyword is a See Also keyword, 0 if it is not.
  192. entrydepth : word; // Depth of this entry into the tree.
  193. charindex : dword;// Character index of the last keyword in the ", " separated list.
  194. unknown0 : dword;// 0 (unknown)
  195. NrPairs : dword;// Number of Name, Local pairs
  196. end;
  197. PBtreeIndexBlockHeader = ^TBtreeIndexBlockHeader;
  198. TBtreeIndexBlockHeader = packed record
  199. length : word; // Length of free space at the end of the block.
  200. NumberOfEntries : word; // Number of entries in the block.
  201. IndexOfChildBlock : dword; // Index of Child Block
  202. end;
  203. PBtreeIndexBlockEntry = ^TBtreeIndexBlockEntry;
  204. TBtreeIndexBlockEntry = packed record
  205. isseealso : word; // 2 if this keyword is a See Also keyword, 0 if it is not.
  206. entrydepth : word; // Depth of this entry into the tree.
  207. charindex : dword;// Character index of the last keyword in the ", " separated list.
  208. unknown0 : dword;// 0 (unknown)
  209. NrPairs : dword;// Number of Name, Local pairs
  210. end;
  211. function PageBookInfoRecordSize(ARecord: PTOCEntryPageBookInfo): Integer;
  212. Const defvalidflags = [valid_Navigation_pane_style,valid_Window_style_flags,valid_Initial_window_position,valid_Navigation_pane_width,valid_Buttons,valid_Tab_position];
  213. implementation
  214. uses chmbase;
  215. function PageBookInfoRecordSize(ARecord: PTOCEntryPageBookInfo): Integer;
  216. begin
  217. if (TOC_ENTRY_HAS_CHILDREN and ARecord^.Props) > 0 then
  218. Result := 28
  219. else
  220. Result := 20;
  221. end;
  222. { TDirectoryChunk }
  223. function TDirectoryChunk.CanHold(ASize: Integer): Boolean;
  224. begin
  225. Result := CurrentPos < $1000 - ASize - (SizeOf(Word) * (FQuickRefEntries+2));
  226. end;
  227. function TDirectoryChunk.FreeSpace: Integer;
  228. begin
  229. Result := $1000 - CurrentPos;
  230. end;
  231. procedure TDirectoryChunk.WriteHeader(AHeader: Pointer);
  232. begin
  233. Move(AHeader^, Buffer[0], FHeaderSize);
  234. end;
  235. procedure TDirectoryChunk.WriteEntry(Size: Integer; Data: Pointer);
  236. var
  237. ReversePos: Integer;
  238. Value: Word;
  239. begin
  240. if not CanHold(Size) then Raise Exception.Create('Trying to write past the end of the buffer');
  241. Move(Data^, Buffer[CurrentPos], Size);
  242. Inc(CurrentPos, Size);
  243. Inc(FItemCount);
  244. // now put a quickref entry if needed
  245. if ItemCount mod 5 = 0 then begin
  246. Inc(FQuickRefEntries);
  247. ReversePos := ($1000) - SizeOf(Word) - (SizeOf(Word)*FQuickRefEntries);
  248. Value := NtoLE(Word(CurrentPos - Size - FHeaderSize));
  249. Move(Value, Buffer[ReversePos], SizeOf(Word));
  250. end;
  251. end;
  252. procedure TDirectoryChunk.WriteChunkToStream(Stream: TStream);
  253. var
  254. ReversePos: Integer;
  255. TmpItemCount: Word;
  256. begin
  257. ReversePos := $1000 - SizeOf(Word);
  258. TmpItemCount := NtoLE(Word(FItemCount));
  259. Move(TmpItemCount, Buffer[ReversePos], SizeOf(Word));
  260. Stream.Write(Buffer[0], $1000);
  261. {$IFDEF DEBUG_CHM_CHUNKS}
  262. WriteLn('Writing ', Copy(PChar(@Buffer[0]),0,4),' ChunkToStream');
  263. {$ENDIF}
  264. end;
  265. procedure TDirectoryChunk.Clear;
  266. begin
  267. FillChar(Buffer, $1000, 0);
  268. FItemCount := 0;
  269. CurrentPos := FHeaderSize;
  270. FQuickRefEntries := 0;
  271. Inc(FClearCount);
  272. end;
  273. constructor TDirectoryChunk.Create(AHeaderSize: Integer);
  274. begin
  275. FHeaderSize := AHeaderSize;
  276. CurrentPos := FHeaderSize;
  277. end;
  278. { TFileEntryList }
  279. function TFileEntryList.GetFileEntry(Index: Integer): TFileEntryRec;
  280. begin
  281. Result := PFileEntryRec(Items[Index])^;
  282. end;
  283. procedure TFileEntryList.SetFileEntry(Index: Integer; const AValue: TFileEntryRec);
  284. begin
  285. PFileEntryRec(Items[Index])^ := AValue;
  286. end;
  287. function TFileEntryList.AddEntry(AFileEntry: TFileEntryRec; CheckPathIsAdded: Boolean = True): Integer;
  288. var
  289. TmpEntry: PFileEntryRec;
  290. begin
  291. New(TmpEntry);
  292. //WriteLn('Adding: ', AFileEntry.Path+AFileEntry.Name,' Size = ', AFileEntry.DecompressedSize,' Offset = ', AFileEntry.DecompressedOffset);
  293. if CheckPathIsAdded and (FPaths.IndexOf(AFileEntry.Path) < 0) then begin
  294. // all paths are included in the list of files in section 0 with a size and offset of 0
  295. FPaths.Add(AFileEntry.Path);
  296. TmpEntry^.Path := AFileEntry.Path;
  297. TmpEntry^.Name := '';
  298. TmpEntry^.DecompressedOffset := 0;
  299. TmpEntry^.DecompressedSize := 0;
  300. TmpEntry^.Compressed := False;
  301. (Self as TList).Add(TmpEntry);
  302. New(TmpEntry);
  303. end;
  304. TmpEntry^ := AFileEntry;
  305. Result := (Self as TList).Add(TmpEntry);
  306. end;
  307. procedure TFileEntryList.Delete(Index: Integer);
  308. begin
  309. Dispose(PFileEntryRec(Items[Index]));
  310. Inherited Delete(Index);
  311. end;
  312. function FileEntrySortFunc(Item1, Item2: PFileEntryRec): Integer;
  313. var
  314. Str1, Str2: String;
  315. begin
  316. Str1 := Item1^.Path + Item1^.Name;
  317. Str2 := Item2^.Path + Item2^.Name;
  318. Result := ChmCompareText(Str1, Str2);
  319. end;
  320. procedure TFileEntryList.Sort;
  321. begin
  322. Inherited Sort(TListSortCompare(@FileEntrySortFunc));
  323. end;
  324. constructor TFileEntryList.Create;
  325. begin
  326. Inherited Create;
  327. FPaths := TStringList.Create;
  328. end;
  329. destructor TFileEntryList.Destroy;
  330. var
  331. I: Integer;
  332. begin
  333. for I := Count-1 downto 0 do
  334. Delete(I);
  335. FPaths.Free;
  336. inherited Destroy;
  337. end;
  338. { TPMGIDirectoryChunk }
  339. procedure TPMGIDirectoryChunk.WriteChunkToStream(Stream: TStream; var AIndex: Integer
  340. ; Final: Boolean = False);
  341. var
  342. NewBuffer: array[0..512] of byte;
  343. EntryLength,
  344. WriteSize: Integer;
  345. OldPos, NewPos, NewStart: Int64;
  346. procedure FinishBlock;
  347. var
  348. Header: TPMGIIndexChunk;
  349. begin
  350. Inc(AIndex);
  351. Header.PMGIsig := 'PMGI';
  352. Header.UnusedSpace := FParentChunk.FreeSpace;
  353. FParentChunk.WriteHeader(@Header);
  354. FParentChunk.WriteChunkToStream(Stream, AIndex, Final);
  355. FParentChunk.Clear;
  356. end;
  357. begin
  358. if FItemCount < 1 then begin
  359. {$ifdef chm_debug}
  360. WriteLn('WHAT ARE YOU DOING!!');
  361. {$endif}
  362. Dec(AIndex);
  363. Exit;
  364. end;
  365. OldPos := Stream.Position;
  366. WriteChunkToStream(Stream);
  367. NewPos := Stream.Position;
  368. Inc(FChunkLevelCount);
  369. if Final and (ChunkLevelCount < 2) then begin
  370. FParentChunk.Free;
  371. FParentChunk := nil;
  372. Exit;
  373. end;
  374. if FParentChunk = nil then FParentChunk := TPMGIDirectoryChunk.Create(FHeaderSize);
  375. NewStart := OldPos+FHeaderSize;
  376. Stream.Position := NewStart;
  377. EntryLength := GetCompressedInteger(Stream);
  378. WriteSize := (Stream.Position - NewStart) + EntryLength;
  379. Move(Buffer[FHeaderSize], NewBuffer[0], WriteSize);
  380. Inc(WriteSize, WriteCompressedInteger(@NewBuffer[WriteSize], AIndex));
  381. Stream.Position := NewPos;
  382. if not FParentChunk.CanHold(WriteSize) then begin
  383. FinishBlock;
  384. end;
  385. FParentChunk.WriteEntry(WriteSize, @NewBuffer[0]);
  386. if Final then FinishBlock;
  387. //WriteLn(ChunkLevelCount);
  388. end;
  389. function getnext(const s:string;var i: integer;len:integer):string;
  390. var
  391. ind : integer;
  392. begin
  393. if i>len then exit('');
  394. ind:=i;
  395. if s[ind]='"' then
  396. begin
  397. inc(ind);
  398. while (ind<=len) and (s[ind]<>'"') do inc(ind);
  399. result:=copy(s,i+1,ind-i-1);
  400. inc(ind); // skip "
  401. end
  402. else
  403. begin
  404. while (ind<=len) and (s[ind]<>',') do inc(ind);
  405. result:=copy(s,i,ind-i);
  406. end;
  407. i:=ind+1; // skip ,
  408. end;
  409. function getnextint(const txt:string;var ind: integer;len:integer;var flags : TValidWindowFields;x:TValidWindowFieldsEnum):integer;
  410. var s : string;
  411. i:integer;
  412. begin
  413. i:=ind;
  414. s:=getnext(txt,ind,len);
  415. // set a flag if the field was empty (,,)
  416. if (ind=(i+1)) and (x<>valid_unknown1) then
  417. include(flags,x);
  418. result:=strtointdef(s,0); // I think this does C style hex, if not fixup here.
  419. end;
  420. procedure TCHMWindow.load_from_ini(txt:string);
  421. var ind,len,
  422. j,k : integer;
  423. arr : array[0..3] of integer;
  424. s2 : string;
  425. bArr : Boolean;
  426. begin
  427. j:=pos('=',txt);
  428. if j>0 then
  429. txt[j]:=',';
  430. ind:=1; len:=length(txt);
  431. window_type :=getnext(txt,ind,len);
  432. Title_bar_text :=getnext(txt,ind,len);
  433. Toc_file :=getnext(txt,ind,len);
  434. index_file :=getnext(txt,ind,len);
  435. Default_File :=getnext(txt,ind,len);
  436. Home_button_file :=getnext(txt,ind,len);
  437. Jumpbutton_1_File :=getnext(txt,ind,len);
  438. Jumpbutton_1_Text :=getnext(txt,ind,len);
  439. Jumpbutton_2_File :=getnext(txt,ind,len);
  440. Jumpbutton_2_Text :=getnext(txt,ind,len);
  441. nav_style :=getnextint(txt,ind,len,flags,valid_navigation_pane_style);
  442. navpanewidth :=getnextint(txt,ind,len,flags,valid_navigation_pane_width);
  443. buttons :=getnextint(txt,ind,len,flags,valid_buttons);
  444. (* initialize arr[] *)
  445. arr[0] :=0;
  446. arr[1] :=0;
  447. arr[2] :=0;
  448. arr[3] :=0;
  449. k:=0;
  450. bArr := False;
  451. (* "[" int,int,int,int "]", |, *)
  452. s2:=getnext(txt,ind,len);
  453. if length(s2)>0 then begin
  454. (* check if first chart is "[" *)
  455. if (s2[1]='[') then begin
  456. delete(s2,1,1);
  457. bArr := True;
  458. end;
  459. (* looking for a max 4 int followed by a closing "]" *)
  460. repeat
  461. if k > 0 then s2:=getnext(txt,ind,len);
  462. j:=pos(']',s2);
  463. if j>0 then delete(s2,j,1);
  464. if length(trim(s2))>0 then
  465. include(flags,valid_tab_position);
  466. arr[k]:=strtointdef(s2,0);
  467. inc(k);
  468. until (bArr <> True) or (j<>0) or (ind>len);
  469. end;
  470. left :=arr[0];
  471. top :=arr[1];
  472. right :=arr[2];
  473. bottom:=arr[3];
  474. styleflags :=getnextint(txt,ind,len,flags,valid_buttons);
  475. xtdstyleflags :=getnextint(txt,ind,len,flags,valid_window_style_flags);
  476. window_show_state :=getnextint(txt,ind,len,flags,valid_window_extended_style_flags);
  477. navpane_initially_closed :=getnextint(txt,ind,len,flags,valid_navigation_pane_initially_closed_state);
  478. navpane_default :=getnextint(txt,ind,len,flags,valid_default_pane);
  479. navpane_location :=getnextint(txt,ind,len,flags,valid_tab_position);
  480. wm_notify_id :=getnextint(txt,ind,len,flags,valid_unknown1);
  481. end;
  482. procedure TCHMWindow.savetoxml(cfg:TXMLConfig;key:string);
  483. begin
  484. cfg.setvalue(key+'window_type',window_type);
  485. cfg.setvalue(key+'title_bar_text',title_bar_text);
  486. cfg.setvalue(key+'toc_file', Toc_file );
  487. cfg.setvalue(key+'index_file', index_file );
  488. cfg.setvalue(key+'default_file', Default_File );
  489. cfg.setvalue(key+'home_button_file', Home_button_file);
  490. cfg.setvalue(key+'jumpbutton_1_file', Jumpbutton_1_File );
  491. cfg.setvalue(key+'jumpbutton_1_text', Jumpbutton_1_Text );
  492. cfg.setvalue(key+'jumpbutton_2_file', Jumpbutton_2_File );
  493. cfg.setvalue(key+'jumpbutton_2_text', Jumpbutton_2_Text );
  494. cfg.setvalue(key+'nav_style', nav_style );
  495. cfg.setvalue(key+'navpanewidth', navpanewidth );
  496. cfg.setvalue(key+'buttons', buttons );
  497. cfg.setvalue(key+'left', left);
  498. cfg.setvalue(key+'top', top );
  499. cfg.setvalue(key+'right', right );
  500. cfg.setvalue(key+'bottom', bottom );
  501. cfg.setvalue(key+'styleflags', styleflags);
  502. cfg.setvalue(key+'xtdstyleflags', xtdstyleflags );
  503. cfg.setvalue(key+'window_show_state', window_show_state );
  504. cfg.setvalue(key+'navpane_initially_closed',navpane_initially_closed );
  505. cfg.setvalue(key+'navpane_default',navpane_default);
  506. cfg.setvalue(key+'navpane_location',navpane_location );
  507. cfg.setvalue(key+'wm_notify_id',wm_notify_id );
  508. end;
  509. procedure TCHMWindow.loadfromxml(cfg:TXMLConfig;key:string);
  510. begin
  511. window_type :=cfg.getvalue(key+'window_type','');
  512. Title_bar_text :=cfg.getvalue(key+'title_bar_text','');
  513. Toc_file :=cfg.getvalue(key+'toc_file','');
  514. Index_file :=cfg.getvalue(key+'index_file','');
  515. Default_File :=cfg.getvalue(key+'default_file','');
  516. Home_button_file :=cfg.getvalue(key+'home_button_file','');
  517. Jumpbutton_1_File :=cfg.getvalue(key+'jumpbutton_1_file','');
  518. Jumpbutton_1_Text :=cfg.getvalue(key+'jumpbutton_1_text','');
  519. Jumpbutton_2_File :=cfg.getvalue(key+'jumpbutton_2_file','');
  520. Jumpbutton_2_Text :=cfg.getvalue(key+'jumpbutton_2_text','');
  521. nav_style :=cfg.getvalue(key+'nav_style',0);
  522. navpanewidth :=cfg.getvalue(key+'navpanewidth',0);
  523. buttons :=cfg.getvalue(key+'buttons',0);
  524. left :=cfg.getvalue(key+'left',0);
  525. top :=cfg.getvalue(key+'top',0);
  526. right :=cfg.getvalue(key+'right',0);
  527. bottom :=cfg.getvalue(key+'bottom',0);
  528. styleflags :=cfg.getvalue(key+'styleflags',0);
  529. xtdstyleflags :=cfg.getvalue(key+'xtdstyleflags',0);
  530. window_show_state :=cfg.getvalue(key+'window_show_state',0);
  531. navpane_initially_closed :=cfg.getvalue(key+'navpane_initially_closed',0);
  532. navpane_default :=cfg.getvalue(key+'navpane_default',0);
  533. navpane_location :=cfg.getvalue(key+'navpane_location',0);
  534. wm_notify_id :=cfg.getvalue(key+'wm_notify_id',0);
  535. end;
  536. Constructor TCHMWindow.create(s:string='');
  537. begin
  538. flags:=defvalidflags;
  539. if s<>'' then
  540. load_from_ini(s);
  541. end;
  542. procedure TCHMWindow.assign(obj : TCHMWindow);
  543. begin
  544. window_type :=obj.window_type;
  545. Title_bar_text :=obj.Title_bar_text;
  546. Toc_file :=obj.Toc_file;
  547. Index_file :=obj.Index_file;
  548. Default_File :=obj.Default_File;
  549. Home_button_file :=obj.Home_button_file;
  550. Jumpbutton_1_File:=obj.Jumpbutton_1_File;
  551. Jumpbutton_1_Text:=obj.Jumpbutton_1_Text;
  552. Jumpbutton_2_File:=obj.Jumpbutton_2_File;
  553. Jumpbutton_2_Text:=obj.Jumpbutton_2_Text;
  554. nav_style :=obj.nav_style;
  555. navpanewidth :=obj.navpanewidth;
  556. buttons :=obj.buttons;
  557. left :=obj.left;
  558. top :=obj.top;
  559. right :=obj.right;
  560. bottom :=obj.bottom;
  561. styleflags :=obj.styleflags;
  562. xtdstyleflags :=obj.xtdstyleflags;
  563. window_show_state:=obj.window_show_state;
  564. navpane_initially_closed :=obj.navpane_initially_closed;
  565. navpane_default :=obj.navpane_default;
  566. navpane_location :=obj.navpane_location;
  567. wm_notify_id :=obj.wm_notify_id;
  568. end;
  569. end.