Import TechBot
[reactos.git] / irc / TechBot / CHMLibrary / CHMDecoding / CHMFile.cs
1 using System;
2 using System.Diagnostics;
3 using System.Collections;
4 using System.Collections.Specialized;
5 using System.IO;
6 using System.Text;
7 using System.Runtime.InteropServices;
8 using System.Globalization;
9 // using HtmlHelp.Storage;
10
11 namespace HtmlHelp.ChmDecoding
12 {
13 /// <summary>
14 /// Internal enumeration for specifying the type of the html-help file
15 /// </summary>
16 internal enum HtmlHelpFileType
17 {
18 /// <summary>
19 /// CHM - compiled contents file
20 /// </summary>
21 /// <remarks>A file with this extension must always exist. If the file would be too long, some parts
22 /// can be splitted into the filestypes below.</remarks>
23 CHM = 0,
24 /// <summary>
25 /// CHI - compiled system file
26 /// </summary>
27 CHI = 1,
28 /// <summary>
29 /// CHQ - compiled fulltext search file
30 /// </summary>
31 CHQ = 2,
32 /// <summary>
33 /// CHW - compiled index file
34 /// </summary>
35 CHW = 3
36
37 }
38
39 /// <summary>
40 /// The class <c>CHMFile</c> implemts methods and properties for handling a single chmfile.
41 /// </summary>
42 public sealed class CHMFile : IDisposable
43 {
44 /// <summary>
45 /// Internal member storing a reference to the hosting HtmlHelpSystem instance
46 /// </summary>
47 private HtmlHelpSystem _systemInstance = null;
48 /// <summary>
49 /// Internal flag specifying if only system data has been loaded
50 /// </summary>
51 private bool _onlySystem = false;
52 /// <summary>
53 /// Internal flag specifying if the object is going to be disposed
54 /// </summary>
55 private bool disposed = false;
56 /// <summary>
57 /// Internal arraylist containing the table of contents
58 /// </summary>
59 private ArrayList _toc = new ArrayList();
60 /// <summary>
61 /// Internal arraylist containing items of the toc which are merge-Links
62 /// </summary>
63 private ArrayList _mergeLinks = new ArrayList();
64 /// <summary>
65 /// Internal member storing the read information types
66 /// </summary>
67 private ArrayList _informationTypes = new ArrayList();
68 /// <summary>
69 /// Internal member storing the read categories
70 /// </summary>
71 private ArrayList _categories = new ArrayList();
72 /// <summary>
73 /// Internal arraylist containing the index (klinks)
74 /// </summary>
75 private ArrayList _indexKLinks = new ArrayList();
76 /// <summary>
77 /// Internal arraylist containing the index (alinks)
78 /// </summary>
79 private ArrayList _indexALinks = new ArrayList();
80 /// <summary>
81 /// Internal member storing the full filename
82 /// </summary>
83 private string _chmFileName = "";
84 /// <summary>
85 /// Internal member storing the full filename of the chi-file (includes all system files)
86 /// The file name is zero-length if there is no chi-file
87 /// </summary>
88 private string _chiFileName = "";
89 /// <summary>
90 /// Internal member storing the full filename of the chw-file (includes the help index)
91 /// The file name is zero-length if there is no chw-file
92 /// </summary>
93 private string _chwFileName = "";
94 /// <summary>
95 /// Internal member storing the full filename of the chq-file (includes the fulltext contents)
96 /// The file name is zero-length if there is no chq-file
97 /// </summary>
98 private string _chqFileName = "";
99 /// <summary>
100 /// Internal member storing the decoded information from the internal #SYSTEM file
101 /// </summary>
102 private CHMSystem _systemFile = null;
103 /// <summary>
104 /// Internal member storing the decoded information from the internal #IDXHDR file
105 /// </summary>
106 private CHMIdxhdr _idxhdrFile = null;
107 /// <summary>
108 /// Internal member storing the decoded information from the internal #STRINGS file
109 /// </summary>
110 private CHMStrings _stringsFile = null;
111 /// <summary>
112 /// Internal member storing the decoded information from the internal #URLSTR file
113 /// </summary>
114 private CHMUrlstr _urlstrFile = null;
115 /// <summary>
116 /// Internal member storing the decoded information from the internal #URLTBL file
117 /// </summary>
118 private CHMUrltable _urltblFile = null;
119 /// <summary>
120 /// Internal member storing the decoded information from the internal #TOPICS file
121 /// </summary>
122 private CHMTopics _topicsFile = null;
123 /// <summary>
124 /// Internal member storing the decoded information from the internal #TOCIDX file
125 /// </summary>
126 private CHMTocidx _tocidxFile = null;
127 /// <summary>
128 /// Internal member storing the decoded information from the internal binary index file (KLinks).
129 /// </summary>
130 private CHMBtree _kLinks = null;
131 /// <summary>
132 /// Internal member storing the decoded information from the internal binary index file (ALinks).
133 /// </summary>
134 private CHMBtree _aLinks = null;
135 /// <summary>
136 /// Internal member storing the fulltext searcher for this file
137 /// </summary>
138 private FullTextEngine _ftSearcher = null;
139 /// <summary>
140 /// Internal member storing the default encoder
141 /// </summary>
142 private Encoding _textEncoding = Encoding.GetEncoding(1252); // standard windows-1252 encoder
143 /// <summary>
144 /// Internal memebr storing the chm file info
145 /// </summary>
146 private ChmFileInfo _chmFileInfo = null;
147 /// <summary>
148 /// Internal flag specifying if the dump must be written (if enabled)
149 /// </summary>
150 private bool _mustWriteDump = false;
151 /// <summary>
152 /// Internal flag specifying if data was read using the dump
153 /// </summary>
154 private bool _dumpRead = false;
155 /// <summary>
156 /// Internal member for specifying the number of dump-reading trys.
157 /// If dump-reading fails, this is used that it will not be opened a second time
158 /// (in CHM-Systems with CHM, CHI, etc. files)
159 /// </summary>
160 private int _dumpReadTrys = 0;
161 /// <summary>
162 /// Internal member storing the dumping info instance
163 /// </summary>
164 private DumpingInfo _dmpInfo = null;
165
166 private CHMStream.CHMStream _currentWrapper;
167 private CHMStream.CHMStream _baseStream=null;
168 public CHMStream.CHMStream BaseStream
169 {
170 get
171 {
172 if (_baseStream==null)
173 _baseStream=new CHMStream.CHMStream(this.ChmFilePath);
174 return _baseStream;
175 }
176 }
177
178 /// <summary>
179 /// Creates a new instance of the class
180 /// </summary>
181 /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>
182 /// <param name="chmFile">chm file to read</param>
183 public CHMFile(HtmlHelpSystem systemInstance, string chmFile) : this(systemInstance, chmFile, false, null)
184 {
185 }
186
187 /// <summary>
188 /// Creates a new instance of the class
189 /// </summary>
190 /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>
191 /// <param name="chmFile">chm file to read</param>
192 /// <param name="dmpInfo">A dumping info class</param>
193 public CHMFile(HtmlHelpSystem systemInstance, string chmFile, DumpingInfo dmpInfo) : this(systemInstance, chmFile, false, dmpInfo)
194 {
195 }
196
197 /// <summary>
198 /// Creates a new instance of the class
199 /// </summary>
200 /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>
201 /// <param name="chmFile">chm file to read</param>
202 /// <param name="onlySystemData">true if only system data should be extracted (no index or toc)</param>
203 internal CHMFile(HtmlHelpSystem systemInstance, string chmFile, bool onlySystemData) : this(systemInstance, chmFile, onlySystemData, null)
204 {
205 }
206
207 /// <summary>
208 /// Creates a new instance of the class
209 /// </summary>
210 /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>
211 /// <param name="chmFile">chm file to read</param>
212 /// <param name="onlySystemData">true if only system data should be extracted (no index or toc)</param>
213 /// <param name="dmpInfo">A dumping info class</param>
214 internal CHMFile(HtmlHelpSystem systemInstance, string chmFile, bool onlySystemData, DumpingInfo dmpInfo)
215 {
216 _systemInstance = systemInstance;
217 _dumpReadTrys=0;
218
219 _dmpInfo = dmpInfo;
220 if(dmpInfo != null)
221 {
222 dmpInfo.ChmFile = this;
223 }
224
225 if( ! chmFile.ToLower().EndsWith(".chm") )
226 {
227 throw new ArgumentException("HtmlHelp file must have the extension .chm !", "chmFile");
228 }
229
230 _chmFileName = chmFile;
231 _chiFileName = "";
232
233 // Read the IStorage file system
234 if( File.Exists(chmFile) )
235 {
236 _onlySystem = onlySystemData;
237
238 DateTime dtStartHH = DateTime.Now;
239
240 string sCHIName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chi";
241 string sCHQName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chq";
242 string sCHWName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chw";
243
244 // If there is a CHI file present (this file includes the internal system files for the current chm file)
245 if( File.Exists(sCHIName) )
246 {
247 _chiFileName = sCHIName;
248
249 ReadFile(_chiFileName, HtmlHelpFileType.CHI);
250 }
251
252 // If there is a CHW file present (this file includes the internal binary index of the help)
253 if(( File.Exists(sCHWName) ) && (!_onlySystem) )
254 {
255 _chwFileName = sCHWName;
256
257 ReadFile(_chwFileName, HtmlHelpFileType.CHW);
258 }
259
260 // If there is a CHQ file present (this file includes the fulltext-search data)
261 if(( File.Exists(sCHQName) ) && (!_onlySystem) )
262 {
263 _chqFileName = sCHQName;
264
265 ReadFile(_chqFileName, HtmlHelpFileType.CHQ);
266 }
267
268 ReadFile(chmFile, HtmlHelpFileType.CHM);
269
270 if(_mustWriteDump)
271 {
272 _mustWriteDump = !SaveDump(dmpInfo);
273
274 }
275
276 // check the default-topic setting
277 if(_systemFile.DefaultTopic.Length > 0)
278 {
279 CHMStream.CHMStream iw=null;
280 iw = new CHMStream.CHMStream(chmFile);
281 _currentWrapper=iw;
282
283 // tryo to open the topic file
284 MemoryStream fileObject = iw.OpenStream( _systemFile.DefaultTopic);
285 if( fileObject != null)
286 {
287 // if succeed, the topic default topic is OK
288 fileObject.Close();
289 }
290 else
291 {
292 // set the first topic of the toc-tree as default topic
293 if(_toc.Count > 0)
294 {
295 _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local );
296 }
297 }
298 _currentWrapper=null;
299 }
300 else
301 {
302 // set the first topic of the toc-tree as default topic
303 if(_toc.Count > 0)
304 {
305 _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local );
306 }
307 }
308
309 _chmFileInfo = new ChmFileInfo(this);
310 }
311 else
312 {
313 throw new ArgumentException("File '" + chmFile + "' not found !", "chmFile");
314 }
315 }
316
317 /// <summary>
318 /// Read a IStorage file
319 /// </summary>
320 /// <param name="fname">filename</param>
321 /// <param name="type">type of file</param>
322 private void ReadFile(string fname, HtmlHelpFileType type)
323 {
324 CHMStream.CHMStream iw=null;
325 iw=new CHMStream.CHMStream();
326 iw.OpenCHM(fname);
327 _currentWrapper=iw;
328 MemoryStream fileObject=null;
329
330 // ITStorageWrapper iw = null;
331
332 // Open the internal chm system files and parse their content
333 // FileObject fileObject = null;
334 // iw = new ITStorageWrapper(fname, false);
335
336 if( (type != HtmlHelpFileType.CHQ) && (type != HtmlHelpFileType.CHW) )
337 {
338 fileObject = iw.OpenStream("#SYSTEM");
339 if ((fileObject != null) && (fileObject.Length>0))
340 _systemFile = new CHMSystem(fileObject.ToArray(), this);
341
342 fileObject = iw.OpenStream("#IDXHDR");
343 if ((fileObject != null) && (fileObject.Length>0))
344 _idxhdrFile = new CHMIdxhdr(fileObject.ToArray(), this);
345
346 // try to read Dump
347 if((!_dumpRead)&&(CheckDump(_dmpInfo))&&(_dumpReadTrys==0))
348 {
349 _dumpReadTrys++;
350 _dumpRead = LoadDump(_dmpInfo);
351 }
352
353 if( (!_dumpRead)||(!_dmpInfo.DumpStrings) )
354 {
355 fileObject = iw.OpenStream( "#STRINGS");
356 if ((fileObject != null) && (fileObject.Length>0))
357 _stringsFile = new CHMStrings(fileObject.ToArray(), this);
358 }
359
360 if( (!_dumpRead)||(!_dmpInfo.DumpUrlStr) )
361 {
362 fileObject = iw.OpenStream( "#URLSTR");
363 if ((fileObject != null) && (fileObject.Length>0))
364 _urlstrFile = new CHMUrlstr(fileObject.ToArray(), this);
365 }
366
367 if( (!_dumpRead)||(!_dmpInfo.DumpUrlTbl) )
368 {
369 fileObject = iw.OpenStream( "#URLTBL");
370 if ((fileObject != null) && (fileObject.Length>0))
371 _urltblFile = new CHMUrltable(fileObject.ToArray(), this);
372 }
373
374 if( (!_dumpRead)||(!_dmpInfo.DumpTopics) )
375 {
376 fileObject = iw.OpenStream( "#TOPICS");
377 if ((fileObject != null) && (fileObject.Length>0))
378 _topicsFile = new CHMTopics(fileObject.ToArray(), this);
379 }
380
381 if(!_onlySystem)
382 {
383 if( (!_dumpRead)||(!_dmpInfo.DumpBinaryTOC) )
384 {
385 fileObject = iw.OpenStream( "#TOCIDX");
386 if( (fileObject != null) && (fileObject.Length>0) && (_systemFile.BinaryTOC) )
387 {
388 _tocidxFile = new CHMTocidx(fileObject.ToArray(), this);
389 _toc = _tocidxFile.TOC;
390 }
391 }
392 }
393
394 if( (_systemFile != null) && (!_onlySystem) )
395 {
396 if(!_systemFile.BinaryTOC)
397 {
398 if( (!_dumpRead)||(!_dmpInfo.DumpTextTOC) )
399 {
400 CHMStream.chmUnitInfo HHCInfo=iw.GetFileInfoByExtension(".hhc");
401 if (HHCInfo!=null)
402 {
403 fileObject = iw.OpenStream(HHCInfo);
404 if ((fileObject != null) && (fileObject.Length>0))
405 {
406 ASCIIEncoding ascii=new ASCIIEncoding();
407 string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
408
409 _toc = HHCParser.ParseHHC(fileString, this);
410 }
411
412 if(HHCParser.HasMergeLinks)
413 _mergeLinks = HHCParser.MergeItems;
414 }
415 }
416 }
417 }
418 }
419
420 if( type != HtmlHelpFileType.CHQ ) // no index information in CHQ files (only fulltext search)
421 {
422 if( (_systemFile != null) && (!_onlySystem) )
423 {
424 if( ! _systemFile.BinaryIndex )
425 {
426 if( (!_dumpRead)||(!_dmpInfo.DumpTextIndex) )
427 {
428 fileObject = iw.OpenStream( _systemFile.IndexFile);
429 if ((fileObject != null) && (fileObject.Length>0))
430 {
431
432 string fileString = this.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
433 // string fileString = fileObject.ReadFromFile(this.TextEncoding);
434 fileObject.Close();
435
436 _indexKLinks = HHKParser.ParseHHK(fileString, this);
437 _indexKLinks.Sort();
438 }
439 }
440 }
441 else
442 {
443 if( (!_dumpRead)||(!_dmpInfo.DumpBinaryIndex) )
444 {
445 fileObject=iw.OpenStream(@"$WWKeywordLinks\BTree");
446 if ((fileObject != null) && (fileObject.Length>0))
447 {
448 _kLinks = new CHMBtree(fileObject.ToArray(), this);
449 _indexKLinks = _kLinks.IndexList;
450 }
451
452 fileObject =iw.OpenStream(@"$WWAssociativeLinks\BTree");
453 if ((fileObject != null) && (fileObject.Length>0))
454 {
455 _aLinks = new CHMBtree(fileObject.ToArray(), this);
456 _indexALinks = _aLinks.IndexList;
457 _indexALinks.Sort();
458 }
459 }
460 }
461 }
462 }
463
464 if( (type != HtmlHelpFileType.CHI) && (type != HtmlHelpFileType.CHW) )
465 {
466 if( (_systemFile != null) && (!_onlySystem) )
467 {
468 if( _systemFile.FullTextSearch)
469 {
470 if( (!_dumpRead)||(!_dmpInfo.DumpFullText) )
471 {
472 fileObject = iw.OpenStream("$FIftiMain");
473 if(( fileObject != null) && (fileObject .Length>0))
474 _ftSearcher = new FullTextEngine(fileObject .ToArray(), this);
475 }
476 }
477 }
478 }
479 _currentWrapper=null;
480 }
481
482 /// <summary>
483 /// Enumerates the files in the chm storage and gets all files matching a given extension.
484 /// </summary>
485 /// <param name="extension">extension to return</param>
486 /// <returns>Returns an arraylist of filenames or null if nothing found</returns>
487 /// <remarks>On large CHMs, enumerations are very slow. Only use it if necessary !</remarks>
488 internal ArrayList EnumFilesByExtension(string extension)
489 {
490 ArrayList arrRet = new ArrayList();
491
492 CHMStream.CHMStream iw = null;
493 if(_currentWrapper == null)
494 iw = new CHMStream.CHMStream(_chmFileName);
495 else
496 iw = _currentWrapper;
497
498 arrRet=iw.GetFileListByExtenstion(extension);
499
500 if(arrRet.Count > 0)
501 return arrRet;
502
503 return null;
504 }
505
506 /// <summary>
507 /// Searches an TOC entry using the local
508 /// </summary>
509 /// <param name="local">local to search</param>
510 /// <returns>Returns the TOC item</returns>
511 internal TOCItem GetTOCItemByLocal(string local)
512 {
513 return GetTOCItemByLocal(this.TOC, local);
514 }
515
516 /// <summary>
517 /// Recursively searches an TOC entry using its local
518 /// </summary>
519 /// <param name="arrTOC">toc level list</param>
520 /// <param name="local">local to search</param>
521 /// <returns>Returns the TOC item</returns>
522 private TOCItem GetTOCItemByLocal(ArrayList arrTOC, string local)
523 {
524 TOCItem ret = null;
525 foreach(TOCItem curItem in arrTOC)
526 {
527 string scL = curItem.Local.ToLower();
528 string sL = local.ToLower();
529
530 while(scL[0]=='/') // delete prefixing '/'
531 scL = scL.Substring(1);
532
533 while(sL[0]=='/') // delete prefixing '/'
534 sL = sL.Substring(1);
535
536 if(scL == sL)
537 return curItem;
538
539 if(curItem.Children.Count > 0)
540 {
541 ret = GetTOCItemByLocal(curItem.Children, local);
542 if(ret != null)
543 return ret;
544 }
545 }
546
547 return ret;
548 }
549
550 /// <summary>
551 /// Removes a TOCItem from the toc
552 /// </summary>
553 /// <param name="rem">item to remove</param>
554 /// <returns>Returns true if removed</returns>
555 internal bool RemoveTOCItem(TOCItem rem)
556 {
557 if(rem == null)
558 return false;
559
560 return RemoveTOCItem(this.TOC, rem);
561 }
562
563 /// <summary>
564 /// Recursively searches a TOCItem and removes it if found
565 /// </summary>
566 /// <param name="arrTOC">toc level list</param>
567 /// <param name="rem">item to remove</param>
568 /// <returns>Returns true if removed</returns>
569 private bool RemoveTOCItem(ArrayList arrTOC, TOCItem rem)
570 {
571 for(int i=0; i<arrTOC.Count;i++)
572 {
573 TOCItem curItem = arrTOC[i] as TOCItem;
574
575 if(curItem == rem)
576 {
577 arrTOC.RemoveAt(i);
578 return true;
579 }
580
581 if(curItem.Children.Count > 0)
582 {
583 bool bRem = RemoveTOCItem(curItem.Children, rem);
584 if(bRem)
585 return true;
586 }
587 }
588
589 return false;
590 }
591
592 /// <summary>
593 /// Returns true if the HtmlHelpSystem instance contains 1 or more information types
594 /// </summary>
595 public bool HasInformationTypes
596 {
597 get { return (_informationTypes.Count>0); }
598 }
599
600 /// <summary>
601 /// Returns true if the HtmlHelpSystem instance contains 1 or more categories
602 /// </summary>
603 public bool HasCategories
604 {
605 get { return (_categories.Count>0); }
606 }
607
608 /// <summary>
609 /// Gets an ArrayList of <see cref="InformationType">InformationType</see> items
610 /// </summary>
611 public ArrayList InformationTypes
612 {
613 get { return _informationTypes; }
614 }
615
616 /// <summary>
617 /// Gets an ArrayList of <see cref="Category">Category</see> items
618 /// </summary>
619 public ArrayList Categories
620 {
621 get { return _categories; }
622 }
623
624 /// <summary>
625 /// Gets the information type specified by its name
626 /// </summary>
627 /// <param name="name">name of the information type to receive</param>
628 /// <returns>Returns the Instance for the name or null if not found</returns>
629 public InformationType GetInformationType(string name)
630 {
631 if(HasInformationTypes)
632 {
633 for(int i=0; i<_informationTypes.Count;i++)
634 {
635 InformationType iT = _informationTypes[i] as InformationType;
636
637 if(iT.Name == name)
638 return iT;
639 }
640 }
641
642 return null;
643 }
644
645 /// <summary>
646 /// Gets the category specifiyd by its name
647 /// </summary>
648 /// <param name="name">name of the category</param>
649 /// <returns>Returns the Instance for the name or null if not found</returns>
650 public Category GetCategory(string name)
651 {
652 if(HasCategories)
653 {
654 for(int i=0; i<_categories.Count;i++)
655 {
656 Category cat = _categories[i] as Category;
657
658 if(cat.Name == name)
659 return cat;
660 }
661 }
662
663 return null;
664 }
665
666 #region Dumping methods
667
668 /// <summary>
669 /// Checks if a dump for this file exists and if it can be read
670 /// </summary>
671 /// <param name="dmpInfo">dumping info class</param>
672 /// <returns>true if it can be read</returns>
673 private bool CheckDump(DumpingInfo dmpInfo)
674 {
675 if(_dumpReadTrys<=0)
676 _mustWriteDump = false;
677
678 if(_onlySystem)
679 return false;
680
681 if( dmpInfo != null )
682 {
683 if(_dumpReadTrys > 0)
684 return _mustWriteDump;
685
686 _mustWriteDump = !dmpInfo.DumpExists;
687 return !_mustWriteDump;
688 }
689
690 return false;
691 }
692
693 /// <summary>
694 /// Saves the the toc and index into a data dump
695 /// </summary>
696 /// <param name="dmpInfo">dumping info</param>
697 /// <returns>true if succeed</returns>
698 private bool SaveDump(DumpingInfo dmpInfo)
699 {
700 if(dmpInfo == null)
701 return false;
702
703 bool bRet = false;
704
705
706 BinaryWriter writer = dmpInfo.Writer;
707
708 int nCnt = 0;
709 try
710 {
711 Debug.WriteLine("writing dump-file header");
712 FileInfo fi = new FileInfo(_chmFileName);
713 string ftime = fi.LastWriteTime.ToString("dd.MM.yyyy HH:mm:ss.ffffff");
714
715 writer.Write("HtmlHelpSystem dump file 1.0");
716 writer.Write(ftime);
717 writer.Write(_textEncoding.CodePage);
718
719 // strings dumping
720 if(dmpInfo.DumpStrings)
721 {
722 writer.Write(true); // data should be in dump
723
724 if(_stringsFile==null)
725 {
726 writer.Write(false); // data not supported by the chm
727 }
728 else
729 {
730 Debug.WriteLine("writing #STRINGS");
731 writer.Write(true); // data supported and following
732 _stringsFile.Dump(ref writer);
733 }
734 }
735 else
736 {
737 writer.Write(false); // data is not in dump
738 }
739
740 // urlstr dumping
741 if(dmpInfo.DumpUrlStr)
742 {
743 writer.Write(true);
744
745 if(_urlstrFile==null)
746 {
747 writer.Write(false);
748 }
749 else
750 {
751 Debug.WriteLine("writing #URLSTR");
752 writer.Write(true);
753 _urlstrFile.Dump(ref writer);
754 }
755 }
756 else
757 {
758 writer.Write(false);
759 }
760
761 // urltbl dumping
762 if(dmpInfo.DumpUrlTbl)
763 {
764 writer.Write(true);
765
766 if(_urltblFile==null)
767 {
768 writer.Write(false);
769 }
770 else
771 {
772 Debug.WriteLine("writing #URLTBL");
773 writer.Write(true);
774 _urltblFile.Dump(ref writer);
775 }
776 }
777 else
778 {
779 writer.Write(false);
780 }
781
782 // topics dumping
783 if(dmpInfo.DumpTopics)
784 {
785 writer.Write(true);
786
787 if(_topicsFile==null)
788 {
789 writer.Write(false);
790 }
791 else
792 {
793 Debug.WriteLine("writing #TOPICS");
794 writer.Write(true);
795 _topicsFile.Dump(ref writer);
796 }
797 }
798 else
799 {
800 writer.Write(false);
801 }
802
803 // ftsearch dumping
804 if(dmpInfo.DumpFullText)
805 {
806 writer.Write(true);
807
808 if(_ftSearcher==null)
809 {
810 writer.Write(false);
811 }
812 else
813 {
814 Debug.WriteLine("writing $FIftiMain");
815 writer.Write(true);
816 _ftSearcher.Dump(ref writer);
817 }
818 }
819 else
820 {
821 writer.Write(false);
822 }
823
824 // TOC dumping
825 bool bWriteTOC = false;
826
827 if( (_systemFile.BinaryTOC) && (dmpInfo.DumpBinaryTOC) )
828 {
829 Debug.WriteLine("writing binary TOC");
830 bWriteTOC = true;
831 }
832
833 if( (!_systemFile.BinaryTOC) && (dmpInfo.DumpTextTOC) )
834 {
835 Debug.WriteLine("writing text-based TOC");
836 bWriteTOC = true;
837 }
838
839 writer.Write(bWriteTOC);
840
841 if(bWriteTOC)
842 {
843 // write table of contents
844 writer.Write( _toc.Count );
845
846 for(nCnt=0; nCnt < _toc.Count; nCnt++)
847 {
848 TOCItem curItem = ((TOCItem)(_toc[nCnt]));
849 curItem.Dump( ref writer );
850 }
851 }
852
853 // Index dumping
854 bool bWriteIdx = false;
855
856 if( (_systemFile.BinaryIndex) && (dmpInfo.DumpBinaryIndex) )
857 {
858 Debug.WriteLine("writing binary index");
859 bWriteIdx = true;
860 }
861
862 if( (!_systemFile.BinaryIndex) && (dmpInfo.DumpTextIndex) )
863 {
864 Debug.WriteLine("writing text-based index");
865 bWriteIdx = true;
866 }
867
868 writer.Write(bWriteIdx);
869
870 if(bWriteIdx)
871 {
872 // write index
873 writer.Write( _indexALinks.Count );
874 for(nCnt=0; nCnt < _indexALinks.Count; nCnt++)
875 {
876 IndexItem curItem = ((IndexItem)(_indexALinks[nCnt]));
877 curItem.Dump( ref writer );
878 }
879
880 writer.Write( _indexKLinks.Count );
881 for(nCnt=0; nCnt < _indexKLinks.Count; nCnt++)
882 {
883 IndexItem curItem = ((IndexItem)(_indexKLinks[nCnt]));
884 curItem.Dump( ref writer );
885 }
886 }
887
888 // Information types dumping
889 writer.Write( _informationTypes.Count );
890
891 Debug.WriteLine("writing " + _informationTypes.Count.ToString() + " information types");
892
893 for(nCnt=0; nCnt<_informationTypes.Count;nCnt++)
894 {
895 InformationType curType = _informationTypes[nCnt] as InformationType;
896
897 curType.Dump(ref writer);
898 }
899
900 // Categories dumping
901 writer.Write( _categories.Count );
902
903 Debug.WriteLine("writing " + _categories.Count.ToString() + " categories");
904
905 for(nCnt=0; nCnt<_categories.Count; nCnt++)
906 {
907 Category curCat = _categories[nCnt] as Category;
908
909 curCat.Dump( ref writer);
910 }
911
912 bRet=true;
913 }
914 finally
915 {
916 dmpInfo.SaveData();
917 }
918
919 return bRet;
920 }
921
922 /// <summary>
923 /// Parses a HHC file which is located in the current CHM.
924 /// </summary>
925 /// <param name="hhcFile">hhc file to parse</param>
926 /// <returns>an arraylist with toc items</returns>
927 public ArrayList ParseHHC(string hhcFile)
928 {
929 ArrayList arrRet = new ArrayList();
930
931 CHMStream.CHMStream iw=null;
932 iw=new CHMStream.CHMStream();
933 iw.OpenCHM(_chmFileName);
934 MemoryStream fileObject=null;
935
936 fileObject = iw.OpenStream(hhcFile);
937 if( fileObject != null)
938 {
939 ASCIIEncoding ascii=new ASCIIEncoding();
940 string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
941 fileObject.Close();
942
943 arrRet = HHCParser.ParseHHC(fileString, this);
944
945 if(HHCParser.HasMergeLinks)
946 {
947 foreach(TOCItem curItem in HHCParser.MergeItems)
948 {
949 _mergeLinks.Add(curItem);
950 }
951 }
952 }
953
954 return arrRet;
955 }
956
957 /// <summary>
958 /// Loads the toc and index from a data dump
959 /// </summary>
960 /// <param name="dmpInfo">dumping info</param>
961 /// <returns>true if succeed</returns>
962 private bool LoadDump(DumpingInfo dmpInfo)
963 {
964 if(dmpInfo == null)
965 return false;
966
967 bool bRet = false;
968
969 try
970 {
971 BinaryReader reader = dmpInfo.Reader;
972
973 if(reader == null)
974 {
975 Debug.WriteLine("No reader returned !");
976 dmpInfo.SaveData(); // closes the dump
977 _mustWriteDump = true;
978 return false;
979 }
980
981 int nCnt = 0;
982
983 Debug.WriteLine("reading dump-file header");
984 FileInfo fi = new FileInfo(_chmFileName);
985 string ftime = fi.LastWriteTime.ToString("dd.MM.yyyy HH:mm:ss.ffffff");
986
987 string header = reader.ReadString();
988
989 if( header != "HtmlHelpSystem dump file 1.0")
990 {
991 Debug.WriteLine("Unsupported dump-file format !");
992 dmpInfo.SaveData(); // closes the dump
993 _mustWriteDump = true;
994 return false;
995 }
996
997 string ftimecheck = reader.ReadString();
998
999 reader.ReadInt32(); // codepage, we'll use the same as for the chm file which is already set.
1000
1001 // if(ftimecheck != ftime)
1002 // {
1003 // Debug.WriteLine("Dump is out of date (CHM file changed during last dump creation) !");
1004 // dmpInfo.SaveData(); // closes the dump
1005 // _mustWriteDump = true;
1006 // return false; // force reload
1007 // }
1008
1009
1010 bool bFlag=false; // true if data should be in dump
1011 bool bFlagSupp=false; // false if data is not supported by the chm
1012
1013 bFlag = reader.ReadBoolean();
1014
1015 if(bFlag)
1016 {
1017 bFlagSupp = reader.ReadBoolean();
1018
1019 if(!dmpInfo.DumpStrings)
1020 {
1021 Debug.WriteLine("Dumped #STRINGS found but not expected !");
1022 dmpInfo.SaveData(); // closes the dump
1023 _mustWriteDump = true;
1024 return false; // force reload
1025 }
1026
1027 if(bFlagSupp)
1028 {
1029 Debug.WriteLine("reading #STRINGS");
1030 _stringsFile = new CHMStrings();
1031 _stringsFile.SetCHMFile(this);
1032 _stringsFile.ReadDump(ref reader);
1033 }
1034 }
1035 else
1036 {
1037 if(dmpInfo.DumpStrings)
1038 {
1039 Debug.WriteLine("Dumped #STRINGS expected but not found !");
1040 dmpInfo.SaveData(); // closes the dump
1041 _mustWriteDump = true;
1042 return false; // force reload
1043 }
1044 }
1045
1046 bFlag = reader.ReadBoolean();
1047
1048 if(bFlag)
1049 {
1050 bFlagSupp = reader.ReadBoolean();
1051
1052 if(!dmpInfo.DumpUrlStr)
1053 {
1054 Debug.WriteLine("Dumped #URLSTR found but not expected !");
1055 dmpInfo.SaveData(); // closes the dump
1056 _mustWriteDump = true;
1057 return false; // force reload
1058 }
1059
1060 if(bFlagSupp)
1061 {
1062 Debug.WriteLine("reading #URLSTR");
1063 _urlstrFile = new CHMUrlstr();
1064 _urlstrFile.SetCHMFile(this);
1065 _urlstrFile.ReadDump(ref reader);
1066 }
1067 }
1068 else
1069 {
1070 if(dmpInfo.DumpUrlStr)
1071 {
1072 Debug.WriteLine("Dumped #URLSTR expected but not found !");
1073 dmpInfo.SaveData(); // closes the dump
1074 _mustWriteDump = true;
1075 return false; // force reload
1076 }
1077 }
1078
1079 bFlag = reader.ReadBoolean();
1080
1081 if(bFlag)
1082 {
1083 bFlagSupp = reader.ReadBoolean();
1084
1085 if(!dmpInfo.DumpUrlTbl)
1086 {
1087 Debug.WriteLine("Dumped #URLTBL found but not expected !");
1088 dmpInfo.SaveData(); // closes the dump
1089 _mustWriteDump = true;
1090 return false; // force reload
1091 }
1092
1093 if(bFlagSupp)
1094 {
1095 Debug.WriteLine("reading #URLTBL");
1096 _urltblFile = new CHMUrltable();
1097 _urltblFile.SetCHMFile(this);
1098 _urltblFile.ReadDump(ref reader);
1099 }
1100 }
1101 else
1102 {
1103 if(dmpInfo.DumpUrlTbl)
1104 {
1105 Debug.WriteLine("Dumped #URLTBL expected but not found !");
1106 dmpInfo.SaveData(); // closes the dump
1107 _mustWriteDump = true;
1108 return false; // force reload
1109 }
1110 }
1111
1112 bFlag = reader.ReadBoolean();
1113
1114 if(bFlag)
1115 {
1116 bFlagSupp = reader.ReadBoolean();
1117
1118 if(!dmpInfo.DumpTopics)
1119 {
1120 Debug.WriteLine("Dumped #TOPICS found but not expected !");
1121 dmpInfo.SaveData(); // closes the dump
1122 _mustWriteDump = true;
1123 return false; // force reload
1124 }
1125
1126 if(bFlagSupp)
1127 {
1128 Debug.WriteLine("reading #TOPICS");
1129 _topicsFile = new CHMTopics();
1130 _topicsFile.SetCHMFile(this);
1131 _topicsFile.ReadDump(ref reader);
1132 }
1133 }
1134 else
1135 {
1136 if(dmpInfo.DumpTopics)
1137 {
1138 Debug.WriteLine("Dumped #TOPICS expected but not found !");
1139 dmpInfo.SaveData(); // closes the dump
1140 _mustWriteDump = true;
1141 return false; // force reload
1142 }
1143 }
1144
1145 bFlag = reader.ReadBoolean();
1146
1147 if(bFlag)
1148 {
1149 bFlagSupp = reader.ReadBoolean();
1150
1151 if(!dmpInfo.DumpFullText)
1152 {
1153 Debug.WriteLine("Dumped $FIftiMain found but not expected !");
1154 dmpInfo.SaveData(); // closes the dump
1155 _mustWriteDump = true;
1156 return false; // force reload
1157 }
1158
1159 if(bFlagSupp)
1160 {
1161 Debug.WriteLine("reading $FIftiMain");
1162 _ftSearcher = new FullTextEngine();
1163 _ftSearcher.SetCHMFile(this);
1164 _ftSearcher.ReadDump(ref reader);
1165 }
1166 }
1167 else
1168 {
1169 if(dmpInfo.DumpFullText)
1170 {
1171 Debug.WriteLine("Dumped $FIftiMain expected but not found !");
1172 dmpInfo.SaveData(); // closes the dump
1173 _mustWriteDump = true;
1174 return false; // force reload
1175 }
1176 }
1177
1178 // read table of contents
1179 _toc.Clear();
1180 bFlag = reader.ReadBoolean();
1181
1182 if(bFlag)
1183 {
1184 if((_systemFile.BinaryTOC)&&(!dmpInfo.DumpBinaryTOC))
1185 {
1186 Debug.WriteLine("Binary TOC expected but not found !");
1187 dmpInfo.SaveData(); // closes the dump
1188 _mustWriteDump = true;
1189 return false; // force reload
1190 }
1191
1192 if((!_systemFile.BinaryTOC)&&(!dmpInfo.DumpTextTOC))
1193 {
1194 Debug.WriteLine("Text-based TOC expected but not found !");
1195 dmpInfo.SaveData(); // closes the dump
1196 _mustWriteDump = true;
1197 return false; // force reload
1198 }
1199
1200 if(_systemFile.BinaryTOC)
1201 Debug.WriteLine("reading binary TOC");
1202 else
1203 Debug.WriteLine("reading text-based TOC");
1204
1205 int nTocCnt = reader.ReadInt32();
1206
1207 for(nCnt=0; nCnt < nTocCnt; nCnt++)
1208 {
1209 TOCItem item = new TOCItem();
1210 item.AssociatedFile = this;
1211 item.ChmFile = _chmFileName;
1212 item.ReadDump(ref reader);
1213 if(item.MergeLink.Length > 0)
1214 _mergeLinks.Add(item);
1215
1216 _toc.Add(item);
1217 }
1218 }
1219 else
1220 {
1221 if((_systemFile.BinaryTOC)&&(dmpInfo.DumpBinaryTOC))
1222 {
1223 Debug.WriteLine("Binary TOC expected but no TOC dump !");
1224 dmpInfo.SaveData(); // closes the dump
1225 _mustWriteDump = true;
1226 return false; // force reload
1227 }
1228
1229 if((!_systemFile.BinaryTOC)&&(dmpInfo.DumpTextTOC))
1230 {
1231 Debug.WriteLine("Text-based TOC expected but no TOC dump !");
1232 dmpInfo.SaveData(); // closes the dump
1233 _mustWriteDump = true;
1234 return false; // force reload
1235 }
1236 }
1237
1238 // read index
1239 _indexALinks.Clear();
1240 _indexKLinks.Clear();
1241
1242 bFlag = reader.ReadBoolean();
1243
1244 if(bFlag)
1245 {
1246 if((_systemFile.BinaryIndex)&&(!dmpInfo.DumpBinaryIndex))
1247 {
1248 Debug.WriteLine("Binary index expected but not found !");
1249 dmpInfo.SaveData(); // closes the dump
1250 _mustWriteDump = true;
1251 return false; // force reload
1252 }
1253
1254 if((!_systemFile.BinaryIndex)&&(!dmpInfo.DumpTextIndex))
1255 {
1256 Debug.WriteLine("Binary index expected but not found !");
1257 dmpInfo.SaveData(); // closes the dump
1258 _mustWriteDump = true;
1259 return false; // force reload
1260 }
1261
1262 if(_systemFile.BinaryIndex)
1263 Debug.WriteLine("reading binary index");
1264 else
1265 Debug.WriteLine("reading text-based index");
1266
1267 int nIndxaCnt = reader.ReadInt32();
1268
1269 for(nCnt=0; nCnt < nIndxaCnt; nCnt++)
1270 {
1271 IndexItem item = new IndexItem();
1272 item.ChmFile = this;
1273 item.ReadDump(ref reader);
1274 _indexALinks.Add(item);
1275 }
1276
1277
1278 int nIndxkCnt = reader.ReadInt32();
1279
1280 for(nCnt=0; nCnt < nIndxkCnt; nCnt++)
1281 {
1282 IndexItem item = new IndexItem();
1283 item.ChmFile = this;
1284 item.ReadDump(ref reader);
1285 _indexKLinks.Add(item);
1286 }
1287 }
1288 else
1289 {
1290 if((_systemFile.BinaryIndex)&&(dmpInfo.DumpBinaryIndex))
1291 {
1292 Debug.WriteLine("Binary index expected but no index in dump !");
1293 dmpInfo.SaveData(); // closes the dump
1294 _mustWriteDump = true;
1295 return false; // force reload
1296 }
1297
1298 if((!_systemFile.BinaryIndex)&&(dmpInfo.DumpTextIndex))
1299 {
1300 Debug.WriteLine("Text-based index expected but no index dump !");
1301 dmpInfo.SaveData(); // closes the dump
1302 _mustWriteDump = true;
1303 return false; // force reload
1304 }
1305 }
1306
1307 // read information types from dump
1308 int nITCnt = reader.ReadInt32();
1309
1310 Debug.WriteLine("Reading " + nITCnt.ToString() + " information types from dump !");
1311
1312 for(nCnt=0; nCnt<nITCnt; nCnt++)
1313 {
1314 InformationType newType = new InformationType();
1315 newType.ReadDump(ref reader);
1316
1317 if( SystemInstance.GetInformationType( newType.Name ) != null)
1318 {
1319 // information type of this name already exists in the helpsystem
1320 InformationType sysType = SystemInstance.GetInformationType( newType.Name );
1321 _informationTypes.Add(sysType);
1322 }
1323 else
1324 {
1325 _informationTypes.Add( newType );
1326 }
1327 }
1328
1329 // read categories from dump
1330 int nCCnt = reader.ReadInt32();
1331
1332 Debug.WriteLine("Reading " + nITCnt.ToString() + " categories from dump !");
1333
1334 for(nCnt=0; nCnt<nCCnt; nCnt++)
1335 {
1336 Category newCat = new Category();
1337 newCat.ReadDump(ref reader, this);
1338
1339 if( SystemInstance.GetCategory( newCat.Name ) != null)
1340 {
1341 // category of this name already exists in the helpsystem
1342 Category sysCat = SystemInstance.GetCategory( newCat.Name );
1343
1344 sysCat.MergeInfoTypes( newCat );
1345 _categories.Add( sysCat );
1346 }
1347 else
1348 {
1349 _categories.Add( newCat );
1350 }
1351 }
1352
1353 _dumpRead = true;
1354 bRet = true;
1355 }
1356 catch(Exception ex)
1357 {
1358 Debug.WriteLine("###ERROR :" + ex.Message);
1359 _mustWriteDump = true;
1360 }
1361 finally
1362 {
1363 dmpInfo.SaveData(); // closes the dump
1364 }
1365
1366 return bRet;
1367 }
1368
1369 #endregion
1370
1371 #region Internal properties
1372 /// <summary>
1373 /// Gets the current storage wrapper.
1374 /// </summary>
1375 /// <remarks>This property will return not null, if there are currently file read actions running !</remarks>
1376 internal CHMStream.CHMStream CurrentStorageWrapper
1377 {
1378 get { return _currentWrapper;}
1379 }
1380 /// <summary>
1381 /// Gets/sets the hosting HtmlHelpSystem instance
1382 /// </summary>
1383 internal HtmlHelpSystem SystemInstance
1384 {
1385 get { return _systemInstance; }
1386 set { _systemInstance = value; }
1387 }
1388 /// <summary>
1389 /// Gets an arraylist of TOC items which contains merg-links to other CHMs
1390 /// </summary>
1391 internal ArrayList MergLinks
1392 {
1393 get { return _mergeLinks; }
1394 }
1395
1396 /// <summary>
1397 /// Gets the internal system file instance
1398 /// </summary>
1399 internal CHMSystem SystemFile
1400 {
1401 get { return _systemFile; }
1402 }
1403
1404 /// <summary>
1405 /// Gets the internal idxhdr file instance
1406 /// </summary>
1407 internal CHMIdxhdr IdxHdrFile
1408 {
1409 get { return _idxhdrFile; }
1410 }
1411
1412 /// <summary>
1413 /// Gets the internal strings file instance
1414 /// </summary>
1415 internal CHMStrings StringsFile
1416 {
1417 get { return _stringsFile; }
1418 }
1419
1420 /// <summary>
1421 /// Gets the internal urlstr file instance
1422 /// </summary>
1423 internal CHMUrlstr UrlstrFile
1424 {
1425 get { return _urlstrFile; }
1426 }
1427
1428 /// <summary>
1429 /// Gets the internal urltbl file instance
1430 /// </summary>
1431 internal CHMUrltable UrltblFile
1432 {
1433 get { return _urltblFile; }
1434 }
1435
1436 /// <summary>
1437 /// Gets the internal topics file instance
1438 /// </summary>
1439 internal CHMTopics TopicsFile
1440 {
1441 get { return _topicsFile; }
1442 }
1443
1444 /// <summary>
1445 /// Gets the internal tocidx file instance
1446 /// </summary>
1447 internal CHMTocidx TocidxFile
1448 {
1449 get { return _tocidxFile; }
1450 }
1451
1452 /// <summary>
1453 /// Gets the internal btree file instance for alinks
1454 /// </summary>
1455 internal CHMBtree ALinksFile
1456 {
1457 get { return _aLinks; }
1458 }
1459
1460 /// <summary>
1461 /// Gets the internal btree file instance for klinks
1462 /// </summary>
1463 internal CHMBtree KLinksFile
1464 {
1465 get { return _kLinks; }
1466 }
1467
1468 /// <summary>
1469 /// Gets/Sets the text encoding
1470 /// </summary>
1471 internal Encoding TextEncoding
1472 {
1473 get { return _textEncoding; }
1474 set { _textEncoding = value; }
1475 }
1476
1477 #endregion
1478
1479 #region Properties from the #SYSTEM file
1480 /// <summary>
1481 /// Gets the file version of the chm file.
1482 /// 2 for Compatibility=1.0, 3 for Compatibility=1.1
1483 /// </summary>
1484 internal int FileVersion
1485 {
1486 get
1487 {
1488 if(_systemFile==null)
1489 return 0;
1490
1491 return _systemFile.FileVersion;
1492 }
1493 }
1494
1495 /// <summary>
1496 /// Gets the contents file name
1497 /// </summary>
1498 internal string ContentsFile
1499 {
1500 get
1501 {
1502 if(_systemFile==null)
1503 return String.Empty;
1504
1505 return _systemFile.ContentsFile;
1506 }
1507 }
1508
1509 /// <summary>
1510 /// Gets the index file name
1511 /// </summary>
1512 internal string IndexFile
1513 {
1514 get
1515 {
1516 if(_systemFile==null)
1517 return String.Empty;
1518
1519 return _systemFile.IndexFile;
1520 }
1521 }
1522
1523 /// <summary>
1524 /// Gets the default help topic
1525 /// </summary>
1526 internal string DefaultTopic
1527 {
1528 get
1529 {
1530 if(_systemFile==null)
1531 return String.Empty;
1532
1533 return _systemFile.DefaultTopic;
1534 }
1535 }
1536
1537 /// <summary>
1538 /// Gets the title of the help window
1539 /// </summary>
1540 internal string HelpWindowTitle
1541 {
1542 get
1543 {
1544 if(_systemFile==null)
1545 return String.Empty;
1546
1547 return _systemFile.Title;
1548 }
1549 }
1550
1551 /// <summary>
1552 /// Gets the flag if DBCS is in use
1553 /// </summary>
1554 internal bool DBCS
1555 {
1556 get
1557 {
1558 if(_systemFile==null)
1559 return false;
1560
1561 return _systemFile.DBCS;
1562 }
1563 }
1564
1565 /// <summary>
1566 /// Gets the flag if full-text-search is available
1567 /// </summary>
1568 internal bool FullTextSearch
1569 {
1570 get
1571 {
1572 if(_systemFile==null)
1573 return false;
1574
1575 return _systemFile.FullTextSearch;
1576 }
1577 }
1578
1579 /// <summary>
1580 /// Gets the flag if the file has ALinks
1581 /// </summary>
1582 internal bool HasALinks
1583 {
1584 get
1585 {
1586 if(_systemFile==null)
1587 return false;
1588
1589 return _systemFile.HasALinks;
1590 }
1591 }
1592
1593 /// <summary>
1594 /// Gets the flag if the file has KLinks
1595 /// </summary>
1596 internal bool HasKLinks
1597 {
1598 get
1599 {
1600 if(_systemFile==null)
1601 return false;
1602
1603 return _systemFile.HasKLinks;
1604 }
1605 }
1606
1607 /// <summary>
1608 /// Gets the default window name
1609 /// </summary>
1610 internal string DefaultWindow
1611 {
1612 get
1613 {
1614 if(_systemFile==null)
1615 return String.Empty;
1616
1617 return _systemFile.DefaultWindow;
1618 }
1619 }
1620
1621 /// <summary>
1622 /// Gets the file name of the compile file
1623 /// </summary>
1624 internal string CompileFile
1625 {
1626 get
1627 {
1628 if(_systemFile==null)
1629 return String.Empty;
1630
1631 return _systemFile.CompileFile;
1632 }
1633 }
1634
1635 /// <summary>
1636 /// Gets the flag if the chm has a binary index file
1637 /// </summary>
1638 internal bool BinaryIndex
1639 {
1640 get
1641 {
1642 if(_systemFile==null)
1643 return false;
1644
1645 return _systemFile.BinaryIndex;
1646 }
1647 }
1648
1649 /// <summary>
1650 /// Gets the flag if the chm has a binary index file
1651 /// </summary>
1652 internal string CompilerVersion
1653 {
1654 get
1655 {
1656 if(_systemFile==null)
1657 return String.Empty;
1658
1659 return _systemFile.CompilerVersion;
1660 }
1661 }
1662
1663 /// <summary>
1664 /// Gets the flag if the chm has a binary toc file
1665 /// </summary>
1666 internal bool BinaryTOC
1667 {
1668 get
1669 {
1670 if(_systemFile==null)
1671 return false;
1672
1673 return _systemFile.BinaryTOC;
1674 }
1675 }
1676
1677 /// <summary>
1678 /// Gets the font face of the read font property.
1679 /// Empty string for default font.
1680 /// </summary>
1681 internal string FontFace
1682 {
1683 get
1684 {
1685 if(_systemFile==null)
1686 return "";
1687
1688 return _systemFile.FontFace;
1689 }
1690 }
1691
1692 /// <summary>
1693 /// Gets the font size of the read font property.
1694 /// 0 for default font size
1695 /// </summary>
1696 internal double FontSize
1697 {
1698 get
1699 {
1700 if(_systemFile==null)
1701 return 0;
1702
1703 return _systemFile.FontSize;
1704 }
1705 }
1706
1707 /// <summary>
1708 /// Gets the character set of the read font property
1709 /// 1 for default
1710 /// </summary>
1711 internal int CharacterSet
1712 {
1713 get
1714 {
1715 if(_systemFile==null)
1716 return 1;
1717
1718 return _systemFile.CharacterSet;
1719 }
1720 }
1721
1722 /// <summary>
1723 /// Gets the codepage depending on the read font property
1724 /// </summary>
1725 internal int CodePage
1726 {
1727 get
1728 {
1729 if(_systemFile==null)
1730 return CultureInfo.CurrentCulture.TextInfo.ANSICodePage;
1731
1732 return _systemFile.CodePage;
1733 }
1734 }
1735
1736 /// <summary>
1737 /// Gets the assiciated culture info
1738 /// </summary>
1739 internal CultureInfo Culture
1740 {
1741 get
1742 {
1743 if(_systemFile==null)
1744 return CultureInfo.CurrentCulture;
1745
1746 return _systemFile.Culture;
1747 }
1748 }
1749
1750 #endregion
1751
1752 #region Properties from the #IDXHDR file
1753 /// <summary>
1754 /// Gets the number of topic nodes including the contents and index files
1755 /// </summary>
1756 internal int NumberOfTopicNodes
1757 {
1758 get
1759 {
1760 if(_idxhdrFile==null)
1761 return 0;
1762
1763 return _idxhdrFile.NumberOfTopicNodes;
1764 }
1765 }
1766
1767 /// <summary>
1768 /// Gets the ImageList string specyfied in the #IDXHDR file.
1769 /// </summary>
1770 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1771 internal string ImageList
1772 {
1773 get
1774 {
1775 if( (_stringsFile == null) || (_idxhdrFile == null) )
1776 return "";
1777
1778 return _stringsFile[ _idxhdrFile.ImageListOffset ];
1779 }
1780 }
1781
1782 /// <summary>
1783 /// True if the value of the ImageType param of the
1784 /// "text/site properties" object of the sitemap contents is "Folder".
1785 /// </summary>
1786 /// <remarks>If this is set to true, the help will display folders instead of books</remarks>
1787 internal bool ImageTypeFolder
1788 {
1789 get
1790 {
1791 if(_idxhdrFile==null)
1792 return false;
1793
1794 return _idxhdrFile.ImageTypeFolder;
1795 }
1796 }
1797
1798 /// <summary>
1799 /// Gets the background setting
1800 /// </summary>
1801 internal int Background
1802 {
1803 get
1804 {
1805 if(_idxhdrFile==null)
1806 return 0;
1807
1808 return _idxhdrFile.Background;
1809 }
1810 }
1811
1812 /// <summary>
1813 /// Gets the foreground setting
1814 /// </summary>
1815 internal int Foreground
1816 {
1817 get
1818 {
1819 if(_idxhdrFile==null)
1820 return 0;
1821
1822 return _idxhdrFile.Foreground;
1823 }
1824 }
1825
1826 /// <summary>
1827 /// Gets the Font string specyfied in the #IDXHDR file.
1828 /// </summary>
1829 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1830 internal string FontName
1831 {
1832 get
1833 {
1834 if( (_stringsFile == null) || (_idxhdrFile == null) )
1835 return "";
1836
1837 return _stringsFile[ _idxhdrFile.FontOffset ];
1838 }
1839 }
1840
1841 /// <summary>
1842 /// Gets the FrameName string specyfied in the #IDXHDR file.
1843 /// </summary>
1844 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1845 internal string FrameName
1846 {
1847 get
1848 {
1849 if( (_stringsFile == null) || (_idxhdrFile == null) )
1850 return "";
1851
1852 return _stringsFile[ _idxhdrFile.FrameNameOffset ];
1853 }
1854 }
1855
1856 /// <summary>
1857 /// Gets the WindowName string specyfied in the #IDXHDR file.
1858 /// </summary>
1859 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1860 internal string WindowName
1861 {
1862 get
1863 {
1864 if( (_stringsFile == null) || (_idxhdrFile == null) )
1865 return "";
1866
1867 return _stringsFile[ _idxhdrFile.WindowNameOffset ];
1868 }
1869 }
1870
1871 /// <summary>
1872 /// Gets a string array containing the merged file names
1873 /// </summary>
1874 internal string[] MergedFiles
1875 {
1876 get
1877 {
1878 if( (_stringsFile == null) || (_idxhdrFile == null) )
1879 return new string[0];
1880
1881 string[] saRet = new string[ _idxhdrFile.MergedFileOffsets.Count ];
1882
1883 for(int i=0; i < _idxhdrFile.MergedFileOffsets.Count; i++)
1884 {
1885 saRet[i] = _stringsFile[ (int)_idxhdrFile.MergedFileOffsets[i] ];
1886 }
1887
1888 return saRet;
1889 }
1890 }
1891 #endregion
1892
1893 /// <summary>
1894 /// Gets the file info associated with this instance
1895 /// </summary>
1896 public ChmFileInfo FileInfo
1897 {
1898 get { return _chmFileInfo; }
1899 }
1900
1901 /// <summary>
1902 /// Gets the internal toc read from the text-based hhc file
1903 /// </summary>
1904 public ArrayList TOC
1905 {
1906 get { return _toc; }
1907 }
1908
1909 /// <summary>
1910 /// Gets the internal index read from the chm file.
1911 /// </summary>
1912 public ArrayList IndexKLinks
1913 {
1914 get { return _indexKLinks; }
1915 }
1916
1917 /// <summary>
1918 /// Gets the internal index read from the chm file.
1919 /// </summary>
1920 public ArrayList IndexALinks
1921 {
1922 get { return _indexALinks; }
1923 }
1924
1925 /// <summary>
1926 /// Gets the full-text search engine for this file
1927 /// </summary>
1928 internal FullTextEngine FullTextSearchEngine
1929 {
1930 get { return _ftSearcher; }
1931 }
1932
1933 /// <summary>
1934 /// Gets the full pathname of the file
1935 /// </summary>
1936 public string ChmFilePath
1937 {
1938 get { return _chmFileName; }
1939 }
1940
1941 /// <summary>
1942 /// Gets the full pathname of the chi-file
1943 /// The file name is zero-length if there is no chi-file
1944 /// </summary>
1945 public string ChiFilePath
1946 {
1947 get { return _chiFileName; }
1948 }
1949
1950 /// <summary>
1951 /// Gets the full pathname of the chw-file
1952 /// The file name is zero-length if there is no chw-file
1953 /// </summary>
1954 public string ChwFilePath
1955 {
1956 get { return _chwFileName; }
1957 }
1958
1959 /// <summary>
1960 /// Gets the full pathname of the chq-file
1961 /// The file name is zero-length if there is no chq-file
1962 /// </summary>
1963 public string ChqFilePath
1964 {
1965 get { return _chqFileName; }
1966 }
1967
1968 /// <summary>
1969 /// Forms an URL for the web browser
1970 /// </summary>
1971 /// <param name="local">local resource</param>
1972 /// <returns>a url for the web-browser</returns>
1973 internal string FormURL(string local)
1974 {
1975 if( (local.ToLower().IndexOf("http://") >= 0) ||
1976 (local.ToLower().IndexOf("https://") >= 0) ||
1977 (local.ToLower().IndexOf("mailto:") >= 0) ||
1978 (local.ToLower().IndexOf("ftp://") >= 0) ||
1979 (local.ToLower().IndexOf("ms-its:") >= 0))
1980 return local;
1981
1982 return HtmlHelpSystem.UrlPrefix + _chmFileName + "::/" + local;
1983 }
1984
1985 /// <summary>
1986 /// Implement IDisposable.
1987 /// </summary>
1988 public void Dispose()
1989 {
1990 Dispose(true);
1991 // This object will be cleaned up by the Dispose method.
1992 // Therefore, you should call GC.SupressFinalize to
1993 // take this object off the finalization queue
1994 // and prevent finalization code for this object
1995 // from executing a second time.
1996 GC.SuppressFinalize(this);
1997 }
1998
1999 /// <summary>
2000 /// Dispose(bool disposing) executes in two distinct scenarios.
2001 /// If disposing equals true, the method has been called directly
2002 /// or indirectly by a user's code. Managed and unmanaged resources
2003 /// can be disposed.
2004 /// If disposing equals false, the method has been called by the
2005 /// runtime from inside the finalizer and you should not reference
2006 /// other objects. Only unmanaged resources can be disposed.
2007 /// </summary>
2008 /// <param name="disposing">disposing flag</param>
2009 private void Dispose(bool disposing)
2010 {
2011 // Check to see if Dispose has already been called.
2012 if(!this.disposed)
2013 {
2014 // If disposing equals true, dispose all managed
2015 // and unmanaged resources.
2016 if(disposing)
2017 {
2018 // Dispose managed resources.
2019 _toc.Clear();
2020 _indexKLinks.Clear();
2021 _indexALinks.Clear();
2022
2023 if(_systemFile!=null)
2024 _systemFile.Dispose();
2025
2026 if(_idxhdrFile != null)
2027 _idxhdrFile.Dispose();
2028
2029 if(_stringsFile != null)
2030 _stringsFile.Dispose();
2031
2032 if(_urlstrFile != null)
2033 _urlstrFile.Dispose();
2034
2035 if(_urltblFile != null)
2036 _urltblFile.Dispose();
2037
2038 if(_topicsFile != null)
2039 _topicsFile.Dispose();
2040
2041 if(_tocidxFile != null)
2042 _tocidxFile.Dispose();
2043
2044 if(_kLinks != null)
2045 _kLinks.Dispose();
2046
2047 if(_aLinks != null)
2048 _aLinks.Dispose();
2049
2050 if(_ftSearcher != null)
2051 _ftSearcher.Dispose();
2052
2053 if(_chmFileInfo != null)
2054 _chmFileInfo = null;
2055 }
2056 }
2057 disposed = true;
2058 }
2059
2060 }
2061 }