2 using System.Diagnostics;
3 using System.Collections;
4 using System.Collections.Specialized;
7 using System.Runtime.InteropServices;
8 using System.Globalization;
9 // using HtmlHelp.Storage;
11 namespace HtmlHelp.ChmDecoding
14 /// Internal enumeration for specifying the type of the html-help file
16 internal enum HtmlHelpFileType
19 /// CHM - compiled contents file
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>
25 /// CHI - compiled system file
29 /// CHQ - compiled fulltext search file
33 /// CHW - compiled index file
40 /// The class <c>CHMFile</c> implemts methods and properties for handling a single chmfile.
42 public sealed class CHMFile : IDisposable
45 /// Internal member storing a reference to the hosting HtmlHelpSystem instance
47 private HtmlHelpSystem _systemInstance = null;
49 /// Internal flag specifying if only system data has been loaded
51 private bool _onlySystem = false;
53 /// Internal flag specifying if the object is going to be disposed
55 private bool disposed = false;
57 /// Internal arraylist containing the table of contents
59 private ArrayList _toc = new ArrayList();
61 /// Internal arraylist containing items of the toc which are merge-Links
63 private ArrayList _mergeLinks = new ArrayList();
65 /// Internal member storing the read information types
67 private ArrayList _informationTypes = new ArrayList();
69 /// Internal member storing the read categories
71 private ArrayList _categories = new ArrayList();
73 /// Internal arraylist containing the index (klinks)
75 private ArrayList _indexKLinks = new ArrayList();
77 /// Internal arraylist containing the index (alinks)
79 private ArrayList _indexALinks = new ArrayList();
81 /// Internal member storing the full filename
83 private string _chmFileName = "";
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
88 private string _chiFileName = "";
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
93 private string _chwFileName = "";
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
98 private string _chqFileName = "";
100 /// Internal member storing the decoded information from the internal #SYSTEM file
102 private CHMSystem _systemFile = null;
104 /// Internal member storing the decoded information from the internal #IDXHDR file
106 private CHMIdxhdr _idxhdrFile = null;
108 /// Internal member storing the decoded information from the internal #STRINGS file
110 private CHMStrings _stringsFile = null;
112 /// Internal member storing the decoded information from the internal #URLSTR file
114 private CHMUrlstr _urlstrFile = null;
116 /// Internal member storing the decoded information from the internal #URLTBL file
118 private CHMUrltable _urltblFile = null;
120 /// Internal member storing the decoded information from the internal #TOPICS file
122 private CHMTopics _topicsFile = null;
124 /// Internal member storing the decoded information from the internal #TOCIDX file
126 private CHMTocidx _tocidxFile = null;
128 /// Internal member storing the decoded information from the internal binary index file (KLinks).
130 private CHMBtree _kLinks = null;
132 /// Internal member storing the decoded information from the internal binary index file (ALinks).
134 private CHMBtree _aLinks = null;
136 /// Internal member storing the fulltext searcher for this file
138 private FullTextEngine _ftSearcher = null;
140 /// Internal member storing the default encoder
142 private Encoding _textEncoding = Encoding.GetEncoding(1252); // standard windows-1252 encoder
144 /// Internal memebr storing the chm file info
146 private ChmFileInfo _chmFileInfo = null;
148 /// Internal flag specifying if the dump must be written (if enabled)
150 private bool _mustWriteDump = false;
152 /// Internal flag specifying if data was read using the dump
154 private bool _dumpRead = false;
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)
160 private int _dumpReadTrys = 0;
162 /// Internal member storing the dumping info instance
164 private DumpingInfo _dmpInfo = null;
166 private CHMStream.CHMStream _currentWrapper;
167 private CHMStream.CHMStream _baseStream=null;
168 public CHMStream.CHMStream BaseStream
172 if (_baseStream==null)
173 _baseStream=new CHMStream.CHMStream(this.ChmFilePath);
179 /// Creates a new instance of the class
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)
188 /// Creates a new instance of the class
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)
198 /// Creates a new instance of the class
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)
208 /// Creates a new instance of the class
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)
216 _systemInstance = systemInstance;
222 dmpInfo.ChmFile = this;
225 if( ! chmFile.ToLower().EndsWith(".chm") )
227 throw new ArgumentException("HtmlHelp file must have the extension .chm !", "chmFile");
230 _chmFileName = chmFile;
233 // Read the IStorage file system
234 if( File.Exists(chmFile) )
236 _onlySystem = onlySystemData;
238 DateTime dtStartHH = DateTime.Now;
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";
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) )
247 _chiFileName = sCHIName;
249 ReadFile(_chiFileName, HtmlHelpFileType.CHI);
252 // If there is a CHW file present (this file includes the internal binary index of the help)
253 if(( File.Exists(sCHWName) ) && (!_onlySystem) )
255 _chwFileName = sCHWName;
257 ReadFile(_chwFileName, HtmlHelpFileType.CHW);
260 // If there is a CHQ file present (this file includes the fulltext-search data)
261 if(( File.Exists(sCHQName) ) && (!_onlySystem) )
263 _chqFileName = sCHQName;
265 ReadFile(_chqFileName, HtmlHelpFileType.CHQ);
268 ReadFile(chmFile, HtmlHelpFileType.CHM);
272 _mustWriteDump = !SaveDump(dmpInfo);
276 // check the default-topic setting
277 if(_systemFile.DefaultTopic.Length > 0)
279 CHMStream.CHMStream iw=null;
280 iw = new CHMStream.CHMStream(chmFile);
283 // tryo to open the topic file
284 MemoryStream fileObject = iw.OpenStream( _systemFile.DefaultTopic);
285 if( fileObject != null)
287 // if succeed, the topic default topic is OK
292 // set the first topic of the toc-tree as default topic
295 _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local );
298 _currentWrapper=null;
302 // set the first topic of the toc-tree as default topic
305 _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local );
309 _chmFileInfo = new ChmFileInfo(this);
313 throw new ArgumentException("File '" + chmFile + "' not found !", "chmFile");
318 /// Read a IStorage file
320 /// <param name="fname">filename</param>
321 /// <param name="type">type of file</param>
322 private void ReadFile(string fname, HtmlHelpFileType type)
324 CHMStream.CHMStream iw=null;
325 iw=new CHMStream.CHMStream();
328 MemoryStream fileObject=null;
330 // ITStorageWrapper iw = null;
332 // Open the internal chm system files and parse their content
333 // FileObject fileObject = null;
334 // iw = new ITStorageWrapper(fname, false);
336 if( (type != HtmlHelpFileType.CHQ) && (type != HtmlHelpFileType.CHW) )
338 fileObject = iw.OpenStream("#SYSTEM");
339 if ((fileObject != null) && (fileObject.Length>0))
340 _systemFile = new CHMSystem(fileObject.ToArray(), this);
342 fileObject = iw.OpenStream("#IDXHDR");
343 if ((fileObject != null) && (fileObject.Length>0))
344 _idxhdrFile = new CHMIdxhdr(fileObject.ToArray(), this);
347 if((!_dumpRead)&&(CheckDump(_dmpInfo))&&(_dumpReadTrys==0))
350 _dumpRead = LoadDump(_dmpInfo);
353 if( (!_dumpRead)||(!_dmpInfo.DumpStrings) )
355 fileObject = iw.OpenStream( "#STRINGS");
356 if ((fileObject != null) && (fileObject.Length>0))
357 _stringsFile = new CHMStrings(fileObject.ToArray(), this);
360 if( (!_dumpRead)||(!_dmpInfo.DumpUrlStr) )
362 fileObject = iw.OpenStream( "#URLSTR");
363 if ((fileObject != null) && (fileObject.Length>0))
364 _urlstrFile = new CHMUrlstr(fileObject.ToArray(), this);
367 if( (!_dumpRead)||(!_dmpInfo.DumpUrlTbl) )
369 fileObject = iw.OpenStream( "#URLTBL");
370 if ((fileObject != null) && (fileObject.Length>0))
371 _urltblFile = new CHMUrltable(fileObject.ToArray(), this);
374 if( (!_dumpRead)||(!_dmpInfo.DumpTopics) )
376 fileObject = iw.OpenStream( "#TOPICS");
377 if ((fileObject != null) && (fileObject.Length>0))
378 _topicsFile = new CHMTopics(fileObject.ToArray(), this);
383 if( (!_dumpRead)||(!_dmpInfo.DumpBinaryTOC) )
385 fileObject = iw.OpenStream( "#TOCIDX");
386 if( (fileObject != null) && (fileObject.Length>0) && (_systemFile.BinaryTOC) )
388 _tocidxFile = new CHMTocidx(fileObject.ToArray(), this);
389 _toc = _tocidxFile.TOC;
394 if( (_systemFile != null) && (!_onlySystem) )
396 if(!_systemFile.BinaryTOC)
398 if( (!_dumpRead)||(!_dmpInfo.DumpTextTOC) )
400 CHMStream.chmUnitInfo HHCInfo=iw.GetFileInfoByExtension(".hhc");
403 fileObject = iw.OpenStream(HHCInfo);
404 if ((fileObject != null) && (fileObject.Length>0))
406 ASCIIEncoding ascii=new ASCIIEncoding();
407 string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
409 _toc = HHCParser.ParseHHC(fileString, this);
412 if(HHCParser.HasMergeLinks)
413 _mergeLinks = HHCParser.MergeItems;
420 if( type != HtmlHelpFileType.CHQ ) // no index information in CHQ files (only fulltext search)
422 if( (_systemFile != null) && (!_onlySystem) )
424 if( ! _systemFile.BinaryIndex )
426 if( (!_dumpRead)||(!_dmpInfo.DumpTextIndex) )
428 fileObject = iw.OpenStream( _systemFile.IndexFile);
429 if ((fileObject != null) && (fileObject.Length>0))
432 string fileString = this.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
433 // string fileString = fileObject.ReadFromFile(this.TextEncoding);
436 _indexKLinks = HHKParser.ParseHHK(fileString, this);
443 if( (!_dumpRead)||(!_dmpInfo.DumpBinaryIndex) )
445 fileObject=iw.OpenStream(@"$WWKeywordLinks\BTree");
446 if ((fileObject != null) && (fileObject.Length>0))
448 _kLinks = new CHMBtree(fileObject.ToArray(), this);
449 _indexKLinks = _kLinks.IndexList;
452 fileObject =iw.OpenStream(@"$WWAssociativeLinks\BTree");
453 if ((fileObject != null) && (fileObject.Length>0))
455 _aLinks = new CHMBtree(fileObject.ToArray(), this);
456 _indexALinks = _aLinks.IndexList;
464 if( (type != HtmlHelpFileType.CHI) && (type != HtmlHelpFileType.CHW) )
466 if( (_systemFile != null) && (!_onlySystem) )
468 if( _systemFile.FullTextSearch)
470 if( (!_dumpRead)||(!_dmpInfo.DumpFullText) )
472 fileObject = iw.OpenStream("$FIftiMain");
473 if(( fileObject != null) && (fileObject .Length>0))
474 _ftSearcher = new FullTextEngine(fileObject .ToArray(), this);
479 _currentWrapper=null;
483 /// Enumerates the files in the chm storage and gets all files matching a given extension.
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)
490 ArrayList arrRet = new ArrayList();
492 CHMStream.CHMStream iw = null;
493 if(_currentWrapper == null)
494 iw = new CHMStream.CHMStream(_chmFileName);
496 iw = _currentWrapper;
498 arrRet=iw.GetFileListByExtenstion(extension);
507 /// Searches an TOC entry using the local
509 /// <param name="local">local to search</param>
510 /// <returns>Returns the TOC item</returns>
511 internal TOCItem GetTOCItemByLocal(string local)
513 return GetTOCItemByLocal(this.TOC, local);
517 /// Recursively searches an TOC entry using its local
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)
525 foreach(TOCItem curItem in arrTOC)
527 string scL = curItem.Local.ToLower();
528 string sL = local.ToLower();
530 while(scL[0]=='/') // delete prefixing '/'
531 scL = scL.Substring(1);
533 while(sL[0]=='/') // delete prefixing '/'
534 sL = sL.Substring(1);
539 if(curItem.Children.Count > 0)
541 ret = GetTOCItemByLocal(curItem.Children, local);
551 /// Removes a TOCItem from the toc
553 /// <param name="rem">item to remove</param>
554 /// <returns>Returns true if removed</returns>
555 internal bool RemoveTOCItem(TOCItem rem)
560 return RemoveTOCItem(this.TOC, rem);
564 /// Recursively searches a TOCItem and removes it if found
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)
571 for(int i=0; i<arrTOC.Count;i++)
573 TOCItem curItem = arrTOC[i] as TOCItem;
581 if(curItem.Children.Count > 0)
583 bool bRem = RemoveTOCItem(curItem.Children, rem);
593 /// Returns true if the HtmlHelpSystem instance contains 1 or more information types
595 public bool HasInformationTypes
597 get { return (_informationTypes.Count>0); }
601 /// Returns true if the HtmlHelpSystem instance contains 1 or more categories
603 public bool HasCategories
605 get { return (_categories.Count>0); }
609 /// Gets an ArrayList of <see cref="InformationType">InformationType</see> items
611 public ArrayList InformationTypes
613 get { return _informationTypes; }
617 /// Gets an ArrayList of <see cref="Category">Category</see> items
619 public ArrayList Categories
621 get { return _categories; }
625 /// Gets the information type specified by its name
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)
631 if(HasInformationTypes)
633 for(int i=0; i<_informationTypes.Count;i++)
635 InformationType iT = _informationTypes[i] as InformationType;
646 /// Gets the category specifiyd by its name
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)
654 for(int i=0; i<_categories.Count;i++)
656 Category cat = _categories[i] as Category;
666 #region Dumping methods
669 /// Checks if a dump for this file exists and if it can be read
671 /// <param name="dmpInfo">dumping info class</param>
672 /// <returns>true if it can be read</returns>
673 private bool CheckDump(DumpingInfo dmpInfo)
676 _mustWriteDump = false;
681 if( dmpInfo != null )
683 if(_dumpReadTrys > 0)
684 return _mustWriteDump;
686 _mustWriteDump = !dmpInfo.DumpExists;
687 return !_mustWriteDump;
694 /// Saves the the toc and index into a data dump
696 /// <param name="dmpInfo">dumping info</param>
697 /// <returns>true if succeed</returns>
698 private bool SaveDump(DumpingInfo dmpInfo)
706 BinaryWriter writer = dmpInfo.Writer;
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");
715 writer.Write("HtmlHelpSystem dump file 1.0");
717 writer.Write(_textEncoding.CodePage);
720 if(dmpInfo.DumpStrings)
722 writer.Write(true); // data should be in dump
724 if(_stringsFile==null)
726 writer.Write(false); // data not supported by the chm
730 Debug.WriteLine("writing #STRINGS");
731 writer.Write(true); // data supported and following
732 _stringsFile.Dump(ref writer);
737 writer.Write(false); // data is not in dump
741 if(dmpInfo.DumpUrlStr)
745 if(_urlstrFile==null)
751 Debug.WriteLine("writing #URLSTR");
753 _urlstrFile.Dump(ref writer);
762 if(dmpInfo.DumpUrlTbl)
766 if(_urltblFile==null)
772 Debug.WriteLine("writing #URLTBL");
774 _urltblFile.Dump(ref writer);
783 if(dmpInfo.DumpTopics)
787 if(_topicsFile==null)
793 Debug.WriteLine("writing #TOPICS");
795 _topicsFile.Dump(ref writer);
804 if(dmpInfo.DumpFullText)
808 if(_ftSearcher==null)
814 Debug.WriteLine("writing $FIftiMain");
816 _ftSearcher.Dump(ref writer);
825 bool bWriteTOC = false;
827 if( (_systemFile.BinaryTOC) && (dmpInfo.DumpBinaryTOC) )
829 Debug.WriteLine("writing binary TOC");
833 if( (!_systemFile.BinaryTOC) && (dmpInfo.DumpTextTOC) )
835 Debug.WriteLine("writing text-based TOC");
839 writer.Write(bWriteTOC);
843 // write table of contents
844 writer.Write( _toc.Count );
846 for(nCnt=0; nCnt < _toc.Count; nCnt++)
848 TOCItem curItem = ((TOCItem)(_toc[nCnt]));
849 curItem.Dump( ref writer );
854 bool bWriteIdx = false;
856 if( (_systemFile.BinaryIndex) && (dmpInfo.DumpBinaryIndex) )
858 Debug.WriteLine("writing binary index");
862 if( (!_systemFile.BinaryIndex) && (dmpInfo.DumpTextIndex) )
864 Debug.WriteLine("writing text-based index");
868 writer.Write(bWriteIdx);
873 writer.Write( _indexALinks.Count );
874 for(nCnt=0; nCnt < _indexALinks.Count; nCnt++)
876 IndexItem curItem = ((IndexItem)(_indexALinks[nCnt]));
877 curItem.Dump( ref writer );
880 writer.Write( _indexKLinks.Count );
881 for(nCnt=0; nCnt < _indexKLinks.Count; nCnt++)
883 IndexItem curItem = ((IndexItem)(_indexKLinks[nCnt]));
884 curItem.Dump( ref writer );
888 // Information types dumping
889 writer.Write( _informationTypes.Count );
891 Debug.WriteLine("writing " + _informationTypes.Count.ToString() + " information types");
893 for(nCnt=0; nCnt<_informationTypes.Count;nCnt++)
895 InformationType curType = _informationTypes[nCnt] as InformationType;
897 curType.Dump(ref writer);
900 // Categories dumping
901 writer.Write( _categories.Count );
903 Debug.WriteLine("writing " + _categories.Count.ToString() + " categories");
905 for(nCnt=0; nCnt<_categories.Count; nCnt++)
907 Category curCat = _categories[nCnt] as Category;
909 curCat.Dump( ref writer);
923 /// Parses a HHC file which is located in the current CHM.
925 /// <param name="hhcFile">hhc file to parse</param>
926 /// <returns>an arraylist with toc items</returns>
927 public ArrayList ParseHHC(string hhcFile)
929 ArrayList arrRet = new ArrayList();
931 CHMStream.CHMStream iw=null;
932 iw=new CHMStream.CHMStream();
933 iw.OpenCHM(_chmFileName);
934 MemoryStream fileObject=null;
936 fileObject = iw.OpenStream(hhcFile);
937 if( fileObject != null)
939 ASCIIEncoding ascii=new ASCIIEncoding();
940 string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length);
943 arrRet = HHCParser.ParseHHC(fileString, this);
945 if(HHCParser.HasMergeLinks)
947 foreach(TOCItem curItem in HHCParser.MergeItems)
949 _mergeLinks.Add(curItem);
958 /// Loads the toc and index from a data dump
960 /// <param name="dmpInfo">dumping info</param>
961 /// <returns>true if succeed</returns>
962 private bool LoadDump(DumpingInfo dmpInfo)
971 BinaryReader reader = dmpInfo.Reader;
975 Debug.WriteLine("No reader returned !");
976 dmpInfo.SaveData(); // closes the dump
977 _mustWriteDump = true;
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");
987 string header = reader.ReadString();
989 if( header != "HtmlHelpSystem dump file 1.0")
991 Debug.WriteLine("Unsupported dump-file format !");
992 dmpInfo.SaveData(); // closes the dump
993 _mustWriteDump = true;
997 string ftimecheck = reader.ReadString();
999 reader.ReadInt32(); // codepage, we'll use the same as for the chm file which is already set.
1001 // if(ftimecheck != ftime)
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
1010 bool bFlag=false; // true if data should be in dump
1011 bool bFlagSupp=false; // false if data is not supported by the chm
1013 bFlag = reader.ReadBoolean();
1017 bFlagSupp = reader.ReadBoolean();
1019 if(!dmpInfo.DumpStrings)
1021 Debug.WriteLine("Dumped #STRINGS found but not expected !");
1022 dmpInfo.SaveData(); // closes the dump
1023 _mustWriteDump = true;
1024 return false; // force reload
1029 Debug.WriteLine("reading #STRINGS");
1030 _stringsFile = new CHMStrings();
1031 _stringsFile.SetCHMFile(this);
1032 _stringsFile.ReadDump(ref reader);
1037 if(dmpInfo.DumpStrings)
1039 Debug.WriteLine("Dumped #STRINGS expected but not found !");
1040 dmpInfo.SaveData(); // closes the dump
1041 _mustWriteDump = true;
1042 return false; // force reload
1046 bFlag = reader.ReadBoolean();
1050 bFlagSupp = reader.ReadBoolean();
1052 if(!dmpInfo.DumpUrlStr)
1054 Debug.WriteLine("Dumped #URLSTR found but not expected !");
1055 dmpInfo.SaveData(); // closes the dump
1056 _mustWriteDump = true;
1057 return false; // force reload
1062 Debug.WriteLine("reading #URLSTR");
1063 _urlstrFile = new CHMUrlstr();
1064 _urlstrFile.SetCHMFile(this);
1065 _urlstrFile.ReadDump(ref reader);
1070 if(dmpInfo.DumpUrlStr)
1072 Debug.WriteLine("Dumped #URLSTR expected but not found !");
1073 dmpInfo.SaveData(); // closes the dump
1074 _mustWriteDump = true;
1075 return false; // force reload
1079 bFlag = reader.ReadBoolean();
1083 bFlagSupp = reader.ReadBoolean();
1085 if(!dmpInfo.DumpUrlTbl)
1087 Debug.WriteLine("Dumped #URLTBL found but not expected !");
1088 dmpInfo.SaveData(); // closes the dump
1089 _mustWriteDump = true;
1090 return false; // force reload
1095 Debug.WriteLine("reading #URLTBL");
1096 _urltblFile = new CHMUrltable();
1097 _urltblFile.SetCHMFile(this);
1098 _urltblFile.ReadDump(ref reader);
1103 if(dmpInfo.DumpUrlTbl)
1105 Debug.WriteLine("Dumped #URLTBL expected but not found !");
1106 dmpInfo.SaveData(); // closes the dump
1107 _mustWriteDump = true;
1108 return false; // force reload
1112 bFlag = reader.ReadBoolean();
1116 bFlagSupp = reader.ReadBoolean();
1118 if(!dmpInfo.DumpTopics)
1120 Debug.WriteLine("Dumped #TOPICS found but not expected !");
1121 dmpInfo.SaveData(); // closes the dump
1122 _mustWriteDump = true;
1123 return false; // force reload
1128 Debug.WriteLine("reading #TOPICS");
1129 _topicsFile = new CHMTopics();
1130 _topicsFile.SetCHMFile(this);
1131 _topicsFile.ReadDump(ref reader);
1136 if(dmpInfo.DumpTopics)
1138 Debug.WriteLine("Dumped #TOPICS expected but not found !");
1139 dmpInfo.SaveData(); // closes the dump
1140 _mustWriteDump = true;
1141 return false; // force reload
1145 bFlag = reader.ReadBoolean();
1149 bFlagSupp = reader.ReadBoolean();
1151 if(!dmpInfo.DumpFullText)
1153 Debug.WriteLine("Dumped $FIftiMain found but not expected !");
1154 dmpInfo.SaveData(); // closes the dump
1155 _mustWriteDump = true;
1156 return false; // force reload
1161 Debug.WriteLine("reading $FIftiMain");
1162 _ftSearcher = new FullTextEngine();
1163 _ftSearcher.SetCHMFile(this);
1164 _ftSearcher.ReadDump(ref reader);
1169 if(dmpInfo.DumpFullText)
1171 Debug.WriteLine("Dumped $FIftiMain expected but not found !");
1172 dmpInfo.SaveData(); // closes the dump
1173 _mustWriteDump = true;
1174 return false; // force reload
1178 // read table of contents
1180 bFlag = reader.ReadBoolean();
1184 if((_systemFile.BinaryTOC)&&(!dmpInfo.DumpBinaryTOC))
1186 Debug.WriteLine("Binary TOC expected but not found !");
1187 dmpInfo.SaveData(); // closes the dump
1188 _mustWriteDump = true;
1189 return false; // force reload
1192 if((!_systemFile.BinaryTOC)&&(!dmpInfo.DumpTextTOC))
1194 Debug.WriteLine("Text-based TOC expected but not found !");
1195 dmpInfo.SaveData(); // closes the dump
1196 _mustWriteDump = true;
1197 return false; // force reload
1200 if(_systemFile.BinaryTOC)
1201 Debug.WriteLine("reading binary TOC");
1203 Debug.WriteLine("reading text-based TOC");
1205 int nTocCnt = reader.ReadInt32();
1207 for(nCnt=0; nCnt < nTocCnt; nCnt++)
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);
1221 if((_systemFile.BinaryTOC)&&(dmpInfo.DumpBinaryTOC))
1223 Debug.WriteLine("Binary TOC expected but no TOC dump !");
1224 dmpInfo.SaveData(); // closes the dump
1225 _mustWriteDump = true;
1226 return false; // force reload
1229 if((!_systemFile.BinaryTOC)&&(dmpInfo.DumpTextTOC))
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
1239 _indexALinks.Clear();
1240 _indexKLinks.Clear();
1242 bFlag = reader.ReadBoolean();
1246 if((_systemFile.BinaryIndex)&&(!dmpInfo.DumpBinaryIndex))
1248 Debug.WriteLine("Binary index expected but not found !");
1249 dmpInfo.SaveData(); // closes the dump
1250 _mustWriteDump = true;
1251 return false; // force reload
1254 if((!_systemFile.BinaryIndex)&&(!dmpInfo.DumpTextIndex))
1256 Debug.WriteLine("Binary index expected but not found !");
1257 dmpInfo.SaveData(); // closes the dump
1258 _mustWriteDump = true;
1259 return false; // force reload
1262 if(_systemFile.BinaryIndex)
1263 Debug.WriteLine("reading binary index");
1265 Debug.WriteLine("reading text-based index");
1267 int nIndxaCnt = reader.ReadInt32();
1269 for(nCnt=0; nCnt < nIndxaCnt; nCnt++)
1271 IndexItem item = new IndexItem();
1272 item.ChmFile = this;
1273 item.ReadDump(ref reader);
1274 _indexALinks.Add(item);
1278 int nIndxkCnt = reader.ReadInt32();
1280 for(nCnt=0; nCnt < nIndxkCnt; nCnt++)
1282 IndexItem item = new IndexItem();
1283 item.ChmFile = this;
1284 item.ReadDump(ref reader);
1285 _indexKLinks.Add(item);
1290 if((_systemFile.BinaryIndex)&&(dmpInfo.DumpBinaryIndex))
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
1298 if((!_systemFile.BinaryIndex)&&(dmpInfo.DumpTextIndex))
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
1307 // read information types from dump
1308 int nITCnt = reader.ReadInt32();
1310 Debug.WriteLine("Reading " + nITCnt.ToString() + " information types from dump !");
1312 for(nCnt=0; nCnt<nITCnt; nCnt++)
1314 InformationType newType = new InformationType();
1315 newType.ReadDump(ref reader);
1317 if( SystemInstance.GetInformationType( newType.Name ) != null)
1319 // information type of this name already exists in the helpsystem
1320 InformationType sysType = SystemInstance.GetInformationType( newType.Name );
1321 _informationTypes.Add(sysType);
1325 _informationTypes.Add( newType );
1329 // read categories from dump
1330 int nCCnt = reader.ReadInt32();
1332 Debug.WriteLine("Reading " + nITCnt.ToString() + " categories from dump !");
1334 for(nCnt=0; nCnt<nCCnt; nCnt++)
1336 Category newCat = new Category();
1337 newCat.ReadDump(ref reader, this);
1339 if( SystemInstance.GetCategory( newCat.Name ) != null)
1341 // category of this name already exists in the helpsystem
1342 Category sysCat = SystemInstance.GetCategory( newCat.Name );
1344 sysCat.MergeInfoTypes( newCat );
1345 _categories.Add( sysCat );
1349 _categories.Add( newCat );
1358 Debug.WriteLine("###ERROR :" + ex.Message);
1359 _mustWriteDump = true;
1363 dmpInfo.SaveData(); // closes the dump
1371 #region Internal properties
1373 /// Gets the current storage wrapper.
1375 /// <remarks>This property will return not null, if there are currently file read actions running !</remarks>
1376 internal CHMStream.CHMStream CurrentStorageWrapper
1378 get { return _currentWrapper;}
1381 /// Gets/sets the hosting HtmlHelpSystem instance
1383 internal HtmlHelpSystem SystemInstance
1385 get { return _systemInstance; }
1386 set { _systemInstance = value; }
1389 /// Gets an arraylist of TOC items which contains merg-links to other CHMs
1391 internal ArrayList MergLinks
1393 get { return _mergeLinks; }
1397 /// Gets the internal system file instance
1399 internal CHMSystem SystemFile
1401 get { return _systemFile; }
1405 /// Gets the internal idxhdr file instance
1407 internal CHMIdxhdr IdxHdrFile
1409 get { return _idxhdrFile; }
1413 /// Gets the internal strings file instance
1415 internal CHMStrings StringsFile
1417 get { return _stringsFile; }
1421 /// Gets the internal urlstr file instance
1423 internal CHMUrlstr UrlstrFile
1425 get { return _urlstrFile; }
1429 /// Gets the internal urltbl file instance
1431 internal CHMUrltable UrltblFile
1433 get { return _urltblFile; }
1437 /// Gets the internal topics file instance
1439 internal CHMTopics TopicsFile
1441 get { return _topicsFile; }
1445 /// Gets the internal tocidx file instance
1447 internal CHMTocidx TocidxFile
1449 get { return _tocidxFile; }
1453 /// Gets the internal btree file instance for alinks
1455 internal CHMBtree ALinksFile
1457 get { return _aLinks; }
1461 /// Gets the internal btree file instance for klinks
1463 internal CHMBtree KLinksFile
1465 get { return _kLinks; }
1469 /// Gets/Sets the text encoding
1471 internal Encoding TextEncoding
1473 get { return _textEncoding; }
1474 set { _textEncoding = value; }
1479 #region Properties from the #SYSTEM file
1481 /// Gets the file version of the chm file.
1482 /// 2 for Compatibility=1.0, 3 for Compatibility=1.1
1484 internal int FileVersion
1488 if(_systemFile==null)
1491 return _systemFile.FileVersion;
1496 /// Gets the contents file name
1498 internal string ContentsFile
1502 if(_systemFile==null)
1503 return String.Empty;
1505 return _systemFile.ContentsFile;
1510 /// Gets the index file name
1512 internal string IndexFile
1516 if(_systemFile==null)
1517 return String.Empty;
1519 return _systemFile.IndexFile;
1524 /// Gets the default help topic
1526 internal string DefaultTopic
1530 if(_systemFile==null)
1531 return String.Empty;
1533 return _systemFile.DefaultTopic;
1538 /// Gets the title of the help window
1540 internal string HelpWindowTitle
1544 if(_systemFile==null)
1545 return String.Empty;
1547 return _systemFile.Title;
1552 /// Gets the flag if DBCS is in use
1558 if(_systemFile==null)
1561 return _systemFile.DBCS;
1566 /// Gets the flag if full-text-search is available
1568 internal bool FullTextSearch
1572 if(_systemFile==null)
1575 return _systemFile.FullTextSearch;
1580 /// Gets the flag if the file has ALinks
1582 internal bool HasALinks
1586 if(_systemFile==null)
1589 return _systemFile.HasALinks;
1594 /// Gets the flag if the file has KLinks
1596 internal bool HasKLinks
1600 if(_systemFile==null)
1603 return _systemFile.HasKLinks;
1608 /// Gets the default window name
1610 internal string DefaultWindow
1614 if(_systemFile==null)
1615 return String.Empty;
1617 return _systemFile.DefaultWindow;
1622 /// Gets the file name of the compile file
1624 internal string CompileFile
1628 if(_systemFile==null)
1629 return String.Empty;
1631 return _systemFile.CompileFile;
1636 /// Gets the flag if the chm has a binary index file
1638 internal bool BinaryIndex
1642 if(_systemFile==null)
1645 return _systemFile.BinaryIndex;
1650 /// Gets the flag if the chm has a binary index file
1652 internal string CompilerVersion
1656 if(_systemFile==null)
1657 return String.Empty;
1659 return _systemFile.CompilerVersion;
1664 /// Gets the flag if the chm has a binary toc file
1666 internal bool BinaryTOC
1670 if(_systemFile==null)
1673 return _systemFile.BinaryTOC;
1678 /// Gets the font face of the read font property.
1679 /// Empty string for default font.
1681 internal string FontFace
1685 if(_systemFile==null)
1688 return _systemFile.FontFace;
1693 /// Gets the font size of the read font property.
1694 /// 0 for default font size
1696 internal double FontSize
1700 if(_systemFile==null)
1703 return _systemFile.FontSize;
1708 /// Gets the character set of the read font property
1711 internal int CharacterSet
1715 if(_systemFile==null)
1718 return _systemFile.CharacterSet;
1723 /// Gets the codepage depending on the read font property
1725 internal int CodePage
1729 if(_systemFile==null)
1730 return CultureInfo.CurrentCulture.TextInfo.ANSICodePage;
1732 return _systemFile.CodePage;
1737 /// Gets the assiciated culture info
1739 internal CultureInfo Culture
1743 if(_systemFile==null)
1744 return CultureInfo.CurrentCulture;
1746 return _systemFile.Culture;
1752 #region Properties from the #IDXHDR file
1754 /// Gets the number of topic nodes including the contents and index files
1756 internal int NumberOfTopicNodes
1760 if(_idxhdrFile==null)
1763 return _idxhdrFile.NumberOfTopicNodes;
1768 /// Gets the ImageList string specyfied in the #IDXHDR file.
1770 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1771 internal string ImageList
1775 if( (_stringsFile == null) || (_idxhdrFile == null) )
1778 return _stringsFile[ _idxhdrFile.ImageListOffset ];
1783 /// True if the value of the ImageType param of the
1784 /// "text/site properties" object of the sitemap contents is "Folder".
1786 /// <remarks>If this is set to true, the help will display folders instead of books</remarks>
1787 internal bool ImageTypeFolder
1791 if(_idxhdrFile==null)
1794 return _idxhdrFile.ImageTypeFolder;
1799 /// Gets the background setting
1801 internal int Background
1805 if(_idxhdrFile==null)
1808 return _idxhdrFile.Background;
1813 /// Gets the foreground setting
1815 internal int Foreground
1819 if(_idxhdrFile==null)
1822 return _idxhdrFile.Foreground;
1827 /// Gets the Font string specyfied in the #IDXHDR file.
1829 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1830 internal string FontName
1834 if( (_stringsFile == null) || (_idxhdrFile == null) )
1837 return _stringsFile[ _idxhdrFile.FontOffset ];
1842 /// Gets the FrameName string specyfied in the #IDXHDR file.
1844 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1845 internal string FrameName
1849 if( (_stringsFile == null) || (_idxhdrFile == null) )
1852 return _stringsFile[ _idxhdrFile.FrameNameOffset ];
1857 /// Gets the WindowName string specyfied in the #IDXHDR file.
1859 /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>
1860 internal string WindowName
1864 if( (_stringsFile == null) || (_idxhdrFile == null) )
1867 return _stringsFile[ _idxhdrFile.WindowNameOffset ];
1872 /// Gets a string array containing the merged file names
1874 internal string[] MergedFiles
1878 if( (_stringsFile == null) || (_idxhdrFile == null) )
1879 return new string[0];
1881 string[] saRet = new string[ _idxhdrFile.MergedFileOffsets.Count ];
1883 for(int i=0; i < _idxhdrFile.MergedFileOffsets.Count; i++)
1885 saRet[i] = _stringsFile[ (int)_idxhdrFile.MergedFileOffsets[i] ];
1894 /// Gets the file info associated with this instance
1896 public ChmFileInfo FileInfo
1898 get { return _chmFileInfo; }
1902 /// Gets the internal toc read from the text-based hhc file
1904 public ArrayList TOC
1906 get { return _toc; }
1910 /// Gets the internal index read from the chm file.
1912 public ArrayList IndexKLinks
1914 get { return _indexKLinks; }
1918 /// Gets the internal index read from the chm file.
1920 public ArrayList IndexALinks
1922 get { return _indexALinks; }
1926 /// Gets the full-text search engine for this file
1928 internal FullTextEngine FullTextSearchEngine
1930 get { return _ftSearcher; }
1934 /// Gets the full pathname of the file
1936 public string ChmFilePath
1938 get { return _chmFileName; }
1942 /// Gets the full pathname of the chi-file
1943 /// The file name is zero-length if there is no chi-file
1945 public string ChiFilePath
1947 get { return _chiFileName; }
1951 /// Gets the full pathname of the chw-file
1952 /// The file name is zero-length if there is no chw-file
1954 public string ChwFilePath
1956 get { return _chwFileName; }
1960 /// Gets the full pathname of the chq-file
1961 /// The file name is zero-length if there is no chq-file
1963 public string ChqFilePath
1965 get { return _chqFileName; }
1969 /// Forms an URL for the web browser
1971 /// <param name="local">local resource</param>
1972 /// <returns>a url for the web-browser</returns>
1973 internal string FormURL(string local)
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))
1982 return HtmlHelpSystem.UrlPrefix + _chmFileName + "::/" + local;
1986 /// Implement IDisposable.
1988 public void Dispose()
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);
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.
2008 /// <param name="disposing">disposing flag</param>
2009 private void Dispose(bool disposing)
2011 // Check to see if Dispose has already been called.
2014 // If disposing equals true, dispose all managed
2015 // and unmanaged resources.
2018 // Dispose managed resources.
2020 _indexKLinks.Clear();
2021 _indexALinks.Clear();
2023 if(_systemFile!=null)
2024 _systemFile.Dispose();
2026 if(_idxhdrFile != null)
2027 _idxhdrFile.Dispose();
2029 if(_stringsFile != null)
2030 _stringsFile.Dispose();
2032 if(_urlstrFile != null)
2033 _urlstrFile.Dispose();
2035 if(_urltblFile != null)
2036 _urltblFile.Dispose();
2038 if(_topicsFile != null)
2039 _topicsFile.Dispose();
2041 if(_tocidxFile != null)
2042 _tocidxFile.Dispose();
2050 if(_ftSearcher != null)
2051 _ftSearcher.Dispose();
2053 if(_chmFileInfo != null)
2054 _chmFileInfo = null;