using System; using System.Diagnostics; using System.Collections; using System.Collections.Specialized; using System.IO; using System.Text; using System.Runtime.InteropServices; using System.Globalization; // using HtmlHelp.Storage; namespace HtmlHelp.ChmDecoding { /// /// Internal enumeration for specifying the type of the html-help file /// internal enum HtmlHelpFileType { /// /// CHM - compiled contents file /// /// A file with this extension must always exist. If the file would be too long, some parts /// can be splitted into the filestypes below. CHM = 0, /// /// CHI - compiled system file /// CHI = 1, /// /// CHQ - compiled fulltext search file /// CHQ = 2, /// /// CHW - compiled index file /// CHW = 3 } /// /// The class CHMFile implemts methods and properties for handling a single chmfile. /// public sealed class CHMFile : IDisposable { /// /// Internal member storing a reference to the hosting HtmlHelpSystem instance /// private HtmlHelpSystem _systemInstance = null; /// /// Internal flag specifying if only system data has been loaded /// private bool _onlySystem = false; /// /// Internal flag specifying if the object is going to be disposed /// private bool disposed = false; /// /// Internal arraylist containing the table of contents /// private ArrayList _toc = new ArrayList(); /// /// Internal arraylist containing items of the toc which are merge-Links /// private ArrayList _mergeLinks = new ArrayList(); /// /// Internal member storing the read information types /// private ArrayList _informationTypes = new ArrayList(); /// /// Internal member storing the read categories /// private ArrayList _categories = new ArrayList(); /// /// Internal arraylist containing the index (klinks) /// private ArrayList _indexKLinks = new ArrayList(); /// /// Internal arraylist containing the index (alinks) /// private ArrayList _indexALinks = new ArrayList(); /// /// Internal member storing the full filename /// private string _chmFileName = ""; /// /// Internal member storing the full filename of the chi-file (includes all system files) /// The file name is zero-length if there is no chi-file /// private string _chiFileName = ""; /// /// Internal member storing the full filename of the chw-file (includes the help index) /// The file name is zero-length if there is no chw-file /// private string _chwFileName = ""; /// /// Internal member storing the full filename of the chq-file (includes the fulltext contents) /// The file name is zero-length if there is no chq-file /// private string _chqFileName = ""; /// /// Internal member storing the decoded information from the internal #SYSTEM file /// private CHMSystem _systemFile = null; /// /// Internal member storing the decoded information from the internal #IDXHDR file /// private CHMIdxhdr _idxhdrFile = null; /// /// Internal member storing the decoded information from the internal #STRINGS file /// private CHMStrings _stringsFile = null; /// /// Internal member storing the decoded information from the internal #URLSTR file /// private CHMUrlstr _urlstrFile = null; /// /// Internal member storing the decoded information from the internal #URLTBL file /// private CHMUrltable _urltblFile = null; /// /// Internal member storing the decoded information from the internal #TOPICS file /// private CHMTopics _topicsFile = null; /// /// Internal member storing the decoded information from the internal #TOCIDX file /// private CHMTocidx _tocidxFile = null; /// /// Internal member storing the decoded information from the internal binary index file (KLinks). /// private CHMBtree _kLinks = null; /// /// Internal member storing the decoded information from the internal binary index file (ALinks). /// private CHMBtree _aLinks = null; /// /// Internal member storing the fulltext searcher for this file /// private FullTextEngine _ftSearcher = null; /// /// Internal member storing the default encoder /// private Encoding _textEncoding = Encoding.GetEncoding(1252); // standard windows-1252 encoder /// /// Internal memebr storing the chm file info /// private ChmFileInfo _chmFileInfo = null; /// /// Internal flag specifying if the dump must be written (if enabled) /// private bool _mustWriteDump = false; /// /// Internal flag specifying if data was read using the dump /// private bool _dumpRead = false; /// /// Internal member for specifying the number of dump-reading trys. /// If dump-reading fails, this is used that it will not be opened a second time /// (in CHM-Systems with CHM, CHI, etc. files) /// private int _dumpReadTrys = 0; /// /// Internal member storing the dumping info instance /// private DumpingInfo _dmpInfo = null; private CHMStream.CHMStream _currentWrapper; private CHMStream.CHMStream _baseStream=null; public CHMStream.CHMStream BaseStream { get { if (_baseStream==null) _baseStream=new CHMStream.CHMStream(this.ChmFilePath); return _baseStream; } } /// /// Creates a new instance of the class /// /// a reference to the hosting HtmlHelpSystem instance /// chm file to read public CHMFile(HtmlHelpSystem systemInstance, string chmFile) : this(systemInstance, chmFile, false, null) { } /// /// Creates a new instance of the class /// /// a reference to the hosting HtmlHelpSystem instance /// chm file to read /// A dumping info class public CHMFile(HtmlHelpSystem systemInstance, string chmFile, DumpingInfo dmpInfo) : this(systemInstance, chmFile, false, dmpInfo) { } /// /// Creates a new instance of the class /// /// a reference to the hosting HtmlHelpSystem instance /// chm file to read /// true if only system data should be extracted (no index or toc) internal CHMFile(HtmlHelpSystem systemInstance, string chmFile, bool onlySystemData) : this(systemInstance, chmFile, onlySystemData, null) { } /// /// Creates a new instance of the class /// /// a reference to the hosting HtmlHelpSystem instance /// chm file to read /// true if only system data should be extracted (no index or toc) /// A dumping info class internal CHMFile(HtmlHelpSystem systemInstance, string chmFile, bool onlySystemData, DumpingInfo dmpInfo) { _systemInstance = systemInstance; _dumpReadTrys=0; _dmpInfo = dmpInfo; if(dmpInfo != null) { dmpInfo.ChmFile = this; } if( ! chmFile.ToLower().EndsWith(".chm") ) { throw new ArgumentException("HtmlHelp file must have the extension .chm !", "chmFile"); } _chmFileName = chmFile; _chiFileName = ""; // Read the IStorage file system if( File.Exists(chmFile) ) { _onlySystem = onlySystemData; DateTime dtStartHH = DateTime.Now; string sCHIName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chi"; string sCHQName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chq"; string sCHWName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chw"; // If there is a CHI file present (this file includes the internal system files for the current chm file) if( File.Exists(sCHIName) ) { _chiFileName = sCHIName; ReadFile(_chiFileName, HtmlHelpFileType.CHI); } // If there is a CHW file present (this file includes the internal binary index of the help) if(( File.Exists(sCHWName) ) && (!_onlySystem) ) { _chwFileName = sCHWName; ReadFile(_chwFileName, HtmlHelpFileType.CHW); } // If there is a CHQ file present (this file includes the fulltext-search data) if(( File.Exists(sCHQName) ) && (!_onlySystem) ) { _chqFileName = sCHQName; ReadFile(_chqFileName, HtmlHelpFileType.CHQ); } ReadFile(chmFile, HtmlHelpFileType.CHM); if(_mustWriteDump) { _mustWriteDump = !SaveDump(dmpInfo); } // check the default-topic setting if(_systemFile.DefaultTopic.Length > 0) { CHMStream.CHMStream iw=null; iw = new CHMStream.CHMStream(chmFile); _currentWrapper=iw; // tryo to open the topic file MemoryStream fileObject = iw.OpenStream( _systemFile.DefaultTopic); if( fileObject != null) { // if succeed, the topic default topic is OK fileObject.Close(); } else { // set the first topic of the toc-tree as default topic if(_toc.Count > 0) { _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local ); } } _currentWrapper=null; } else { // set the first topic of the toc-tree as default topic if(_toc.Count > 0) { _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local ); } } _chmFileInfo = new ChmFileInfo(this); } else { throw new ArgumentException("File '" + chmFile + "' not found !", "chmFile"); } } /// /// Read a IStorage file /// /// filename /// type of file private void ReadFile(string fname, HtmlHelpFileType type) { CHMStream.CHMStream iw=null; iw=new CHMStream.CHMStream(); iw.OpenCHM(fname); _currentWrapper=iw; MemoryStream fileObject=null; // ITStorageWrapper iw = null; // Open the internal chm system files and parse their content // FileObject fileObject = null; // iw = new ITStorageWrapper(fname, false); if( (type != HtmlHelpFileType.CHQ) && (type != HtmlHelpFileType.CHW) ) { fileObject = iw.OpenStream("#SYSTEM"); if ((fileObject != null) && (fileObject.Length>0)) _systemFile = new CHMSystem(fileObject.ToArray(), this); fileObject = iw.OpenStream("#IDXHDR"); if ((fileObject != null) && (fileObject.Length>0)) _idxhdrFile = new CHMIdxhdr(fileObject.ToArray(), this); // try to read Dump if((!_dumpRead)&&(CheckDump(_dmpInfo))&&(_dumpReadTrys==0)) { _dumpReadTrys++; _dumpRead = LoadDump(_dmpInfo); } if( (!_dumpRead)||(!_dmpInfo.DumpStrings) ) { fileObject = iw.OpenStream( "#STRINGS"); if ((fileObject != null) && (fileObject.Length>0)) _stringsFile = new CHMStrings(fileObject.ToArray(), this); } if( (!_dumpRead)||(!_dmpInfo.DumpUrlStr) ) { fileObject = iw.OpenStream( "#URLSTR"); if ((fileObject != null) && (fileObject.Length>0)) _urlstrFile = new CHMUrlstr(fileObject.ToArray(), this); } if( (!_dumpRead)||(!_dmpInfo.DumpUrlTbl) ) { fileObject = iw.OpenStream( "#URLTBL"); if ((fileObject != null) && (fileObject.Length>0)) _urltblFile = new CHMUrltable(fileObject.ToArray(), this); } if( (!_dumpRead)||(!_dmpInfo.DumpTopics) ) { fileObject = iw.OpenStream( "#TOPICS"); if ((fileObject != null) && (fileObject.Length>0)) _topicsFile = new CHMTopics(fileObject.ToArray(), this); } if(!_onlySystem) { if( (!_dumpRead)||(!_dmpInfo.DumpBinaryTOC) ) { fileObject = iw.OpenStream( "#TOCIDX"); if( (fileObject != null) && (fileObject.Length>0) && (_systemFile.BinaryTOC) ) { _tocidxFile = new CHMTocidx(fileObject.ToArray(), this); _toc = _tocidxFile.TOC; } } } if( (_systemFile != null) && (!_onlySystem) ) { if(!_systemFile.BinaryTOC) { if( (!_dumpRead)||(!_dmpInfo.DumpTextTOC) ) { CHMStream.chmUnitInfo HHCInfo=iw.GetFileInfoByExtension(".hhc"); if (HHCInfo!=null) { fileObject = iw.OpenStream(HHCInfo); if ((fileObject != null) && (fileObject.Length>0)) { ASCIIEncoding ascii=new ASCIIEncoding(); string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length); _toc = HHCParser.ParseHHC(fileString, this); } if(HHCParser.HasMergeLinks) _mergeLinks = HHCParser.MergeItems; } } } } } if( type != HtmlHelpFileType.CHQ ) // no index information in CHQ files (only fulltext search) { if( (_systemFile != null) && (!_onlySystem) ) { if( ! _systemFile.BinaryIndex ) { if( (!_dumpRead)||(!_dmpInfo.DumpTextIndex) ) { fileObject = iw.OpenStream( _systemFile.IndexFile); if ((fileObject != null) && (fileObject.Length>0)) { string fileString = this.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length); // string fileString = fileObject.ReadFromFile(this.TextEncoding); fileObject.Close(); _indexKLinks = HHKParser.ParseHHK(fileString, this); _indexKLinks.Sort(); } } } else { if( (!_dumpRead)||(!_dmpInfo.DumpBinaryIndex) ) { fileObject=iw.OpenStream(@"$WWKeywordLinks\BTree"); if ((fileObject != null) && (fileObject.Length>0)) { _kLinks = new CHMBtree(fileObject.ToArray(), this); _indexKLinks = _kLinks.IndexList; } fileObject =iw.OpenStream(@"$WWAssociativeLinks\BTree"); if ((fileObject != null) && (fileObject.Length>0)) { _aLinks = new CHMBtree(fileObject.ToArray(), this); _indexALinks = _aLinks.IndexList; _indexALinks.Sort(); } } } } } if( (type != HtmlHelpFileType.CHI) && (type != HtmlHelpFileType.CHW) ) { if( (_systemFile != null) && (!_onlySystem) ) { if( _systemFile.FullTextSearch) { if( (!_dumpRead)||(!_dmpInfo.DumpFullText) ) { fileObject = iw.OpenStream("$FIftiMain"); if(( fileObject != null) && (fileObject .Length>0)) _ftSearcher = new FullTextEngine(fileObject .ToArray(), this); } } } } _currentWrapper=null; } /// /// Enumerates the files in the chm storage and gets all files matching a given extension. /// /// extension to return /// Returns an arraylist of filenames or null if nothing found /// On large CHMs, enumerations are very slow. Only use it if necessary ! internal ArrayList EnumFilesByExtension(string extension) { ArrayList arrRet = new ArrayList(); CHMStream.CHMStream iw = null; if(_currentWrapper == null) iw = new CHMStream.CHMStream(_chmFileName); else iw = _currentWrapper; arrRet=iw.GetFileListByExtenstion(extension); if(arrRet.Count > 0) return arrRet; return null; } /// /// Searches an TOC entry using the local /// /// local to search /// Returns the TOC item internal TOCItem GetTOCItemByLocal(string local) { return GetTOCItemByLocal(this.TOC, local); } /// /// Recursively searches an TOC entry using its local /// /// toc level list /// local to search /// Returns the TOC item private TOCItem GetTOCItemByLocal(ArrayList arrTOC, string local) { TOCItem ret = null; foreach(TOCItem curItem in arrTOC) { string scL = curItem.Local.ToLower(); string sL = local.ToLower(); while(scL[0]=='/') // delete prefixing '/' scL = scL.Substring(1); while(sL[0]=='/') // delete prefixing '/' sL = sL.Substring(1); if(scL == sL) return curItem; if(curItem.Children.Count > 0) { ret = GetTOCItemByLocal(curItem.Children, local); if(ret != null) return ret; } } return ret; } /// /// Removes a TOCItem from the toc /// /// item to remove /// Returns true if removed internal bool RemoveTOCItem(TOCItem rem) { if(rem == null) return false; return RemoveTOCItem(this.TOC, rem); } /// /// Recursively searches a TOCItem and removes it if found /// /// toc level list /// item to remove /// Returns true if removed private bool RemoveTOCItem(ArrayList arrTOC, TOCItem rem) { for(int i=0; i 0) { bool bRem = RemoveTOCItem(curItem.Children, rem); if(bRem) return true; } } return false; } /// /// Returns true if the HtmlHelpSystem instance contains 1 or more information types /// public bool HasInformationTypes { get { return (_informationTypes.Count>0); } } /// /// Returns true if the HtmlHelpSystem instance contains 1 or more categories /// public bool HasCategories { get { return (_categories.Count>0); } } /// /// Gets an ArrayList of InformationType items /// public ArrayList InformationTypes { get { return _informationTypes; } } /// /// Gets an ArrayList of Category items /// public ArrayList Categories { get { return _categories; } } /// /// Gets the information type specified by its name /// /// name of the information type to receive /// Returns the Instance for the name or null if not found public InformationType GetInformationType(string name) { if(HasInformationTypes) { for(int i=0; i<_informationTypes.Count;i++) { InformationType iT = _informationTypes[i] as InformationType; if(iT.Name == name) return iT; } } return null; } /// /// Gets the category specifiyd by its name /// /// name of the category /// Returns the Instance for the name or null if not found public Category GetCategory(string name) { if(HasCategories) { for(int i=0; i<_categories.Count;i++) { Category cat = _categories[i] as Category; if(cat.Name == name) return cat; } } return null; } #region Dumping methods /// /// Checks if a dump for this file exists and if it can be read /// /// dumping info class /// true if it can be read private bool CheckDump(DumpingInfo dmpInfo) { if(_dumpReadTrys<=0) _mustWriteDump = false; if(_onlySystem) return false; if( dmpInfo != null ) { if(_dumpReadTrys > 0) return _mustWriteDump; _mustWriteDump = !dmpInfo.DumpExists; return !_mustWriteDump; } return false; } /// /// Saves the the toc and index into a data dump /// /// dumping info /// true if succeed private bool SaveDump(DumpingInfo dmpInfo) { if(dmpInfo == null) return false; bool bRet = false; BinaryWriter writer = dmpInfo.Writer; int nCnt = 0; try { Debug.WriteLine("writing dump-file header"); FileInfo fi = new FileInfo(_chmFileName); string ftime = fi.LastWriteTime.ToString("dd.MM.yyyy HH:mm:ss.ffffff"); writer.Write("HtmlHelpSystem dump file 1.0"); writer.Write(ftime); writer.Write(_textEncoding.CodePage); // strings dumping if(dmpInfo.DumpStrings) { writer.Write(true); // data should be in dump if(_stringsFile==null) { writer.Write(false); // data not supported by the chm } else { Debug.WriteLine("writing #STRINGS"); writer.Write(true); // data supported and following _stringsFile.Dump(ref writer); } } else { writer.Write(false); // data is not in dump } // urlstr dumping if(dmpInfo.DumpUrlStr) { writer.Write(true); if(_urlstrFile==null) { writer.Write(false); } else { Debug.WriteLine("writing #URLSTR"); writer.Write(true); _urlstrFile.Dump(ref writer); } } else { writer.Write(false); } // urltbl dumping if(dmpInfo.DumpUrlTbl) { writer.Write(true); if(_urltblFile==null) { writer.Write(false); } else { Debug.WriteLine("writing #URLTBL"); writer.Write(true); _urltblFile.Dump(ref writer); } } else { writer.Write(false); } // topics dumping if(dmpInfo.DumpTopics) { writer.Write(true); if(_topicsFile==null) { writer.Write(false); } else { Debug.WriteLine("writing #TOPICS"); writer.Write(true); _topicsFile.Dump(ref writer); } } else { writer.Write(false); } // ftsearch dumping if(dmpInfo.DumpFullText) { writer.Write(true); if(_ftSearcher==null) { writer.Write(false); } else { Debug.WriteLine("writing $FIftiMain"); writer.Write(true); _ftSearcher.Dump(ref writer); } } else { writer.Write(false); } // TOC dumping bool bWriteTOC = false; if( (_systemFile.BinaryTOC) && (dmpInfo.DumpBinaryTOC) ) { Debug.WriteLine("writing binary TOC"); bWriteTOC = true; } if( (!_systemFile.BinaryTOC) && (dmpInfo.DumpTextTOC) ) { Debug.WriteLine("writing text-based TOC"); bWriteTOC = true; } writer.Write(bWriteTOC); if(bWriteTOC) { // write table of contents writer.Write( _toc.Count ); for(nCnt=0; nCnt < _toc.Count; nCnt++) { TOCItem curItem = ((TOCItem)(_toc[nCnt])); curItem.Dump( ref writer ); } } // Index dumping bool bWriteIdx = false; if( (_systemFile.BinaryIndex) && (dmpInfo.DumpBinaryIndex) ) { Debug.WriteLine("writing binary index"); bWriteIdx = true; } if( (!_systemFile.BinaryIndex) && (dmpInfo.DumpTextIndex) ) { Debug.WriteLine("writing text-based index"); bWriteIdx = true; } writer.Write(bWriteIdx); if(bWriteIdx) { // write index writer.Write( _indexALinks.Count ); for(nCnt=0; nCnt < _indexALinks.Count; nCnt++) { IndexItem curItem = ((IndexItem)(_indexALinks[nCnt])); curItem.Dump( ref writer ); } writer.Write( _indexKLinks.Count ); for(nCnt=0; nCnt < _indexKLinks.Count; nCnt++) { IndexItem curItem = ((IndexItem)(_indexKLinks[nCnt])); curItem.Dump( ref writer ); } } // Information types dumping writer.Write( _informationTypes.Count ); Debug.WriteLine("writing " + _informationTypes.Count.ToString() + " information types"); for(nCnt=0; nCnt<_informationTypes.Count;nCnt++) { InformationType curType = _informationTypes[nCnt] as InformationType; curType.Dump(ref writer); } // Categories dumping writer.Write( _categories.Count ); Debug.WriteLine("writing " + _categories.Count.ToString() + " categories"); for(nCnt=0; nCnt<_categories.Count; nCnt++) { Category curCat = _categories[nCnt] as Category; curCat.Dump( ref writer); } bRet=true; } finally { dmpInfo.SaveData(); } return bRet; } /// /// Parses a HHC file which is located in the current CHM. /// /// hhc file to parse /// an arraylist with toc items public ArrayList ParseHHC(string hhcFile) { ArrayList arrRet = new ArrayList(); CHMStream.CHMStream iw=null; iw=new CHMStream.CHMStream(); iw.OpenCHM(_chmFileName); MemoryStream fileObject=null; fileObject = iw.OpenStream(hhcFile); if( fileObject != null) { ASCIIEncoding ascii=new ASCIIEncoding(); string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length); fileObject.Close(); arrRet = HHCParser.ParseHHC(fileString, this); if(HHCParser.HasMergeLinks) { foreach(TOCItem curItem in HHCParser.MergeItems) { _mergeLinks.Add(curItem); } } } return arrRet; } /// /// Loads the toc and index from a data dump /// /// dumping info /// true if succeed private bool LoadDump(DumpingInfo dmpInfo) { if(dmpInfo == null) return false; bool bRet = false; try { BinaryReader reader = dmpInfo.Reader; if(reader == null) { Debug.WriteLine("No reader returned !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; } int nCnt = 0; Debug.WriteLine("reading dump-file header"); FileInfo fi = new FileInfo(_chmFileName); string ftime = fi.LastWriteTime.ToString("dd.MM.yyyy HH:mm:ss.ffffff"); string header = reader.ReadString(); if( header != "HtmlHelpSystem dump file 1.0") { Debug.WriteLine("Unsupported dump-file format !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; } string ftimecheck = reader.ReadString(); reader.ReadInt32(); // codepage, we'll use the same as for the chm file which is already set. // if(ftimecheck != ftime) // { // Debug.WriteLine("Dump is out of date (CHM file changed during last dump creation) !"); // dmpInfo.SaveData(); // closes the dump // _mustWriteDump = true; // return false; // force reload // } bool bFlag=false; // true if data should be in dump bool bFlagSupp=false; // false if data is not supported by the chm bFlag = reader.ReadBoolean(); if(bFlag) { bFlagSupp = reader.ReadBoolean(); if(!dmpInfo.DumpStrings) { Debug.WriteLine("Dumped #STRINGS found but not expected !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(bFlagSupp) { Debug.WriteLine("reading #STRINGS"); _stringsFile = new CHMStrings(); _stringsFile.SetCHMFile(this); _stringsFile.ReadDump(ref reader); } } else { if(dmpInfo.DumpStrings) { Debug.WriteLine("Dumped #STRINGS expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } bFlag = reader.ReadBoolean(); if(bFlag) { bFlagSupp = reader.ReadBoolean(); if(!dmpInfo.DumpUrlStr) { Debug.WriteLine("Dumped #URLSTR found but not expected !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(bFlagSupp) { Debug.WriteLine("reading #URLSTR"); _urlstrFile = new CHMUrlstr(); _urlstrFile.SetCHMFile(this); _urlstrFile.ReadDump(ref reader); } } else { if(dmpInfo.DumpUrlStr) { Debug.WriteLine("Dumped #URLSTR expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } bFlag = reader.ReadBoolean(); if(bFlag) { bFlagSupp = reader.ReadBoolean(); if(!dmpInfo.DumpUrlTbl) { Debug.WriteLine("Dumped #URLTBL found but not expected !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(bFlagSupp) { Debug.WriteLine("reading #URLTBL"); _urltblFile = new CHMUrltable(); _urltblFile.SetCHMFile(this); _urltblFile.ReadDump(ref reader); } } else { if(dmpInfo.DumpUrlTbl) { Debug.WriteLine("Dumped #URLTBL expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } bFlag = reader.ReadBoolean(); if(bFlag) { bFlagSupp = reader.ReadBoolean(); if(!dmpInfo.DumpTopics) { Debug.WriteLine("Dumped #TOPICS found but not expected !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(bFlagSupp) { Debug.WriteLine("reading #TOPICS"); _topicsFile = new CHMTopics(); _topicsFile.SetCHMFile(this); _topicsFile.ReadDump(ref reader); } } else { if(dmpInfo.DumpTopics) { Debug.WriteLine("Dumped #TOPICS expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } bFlag = reader.ReadBoolean(); if(bFlag) { bFlagSupp = reader.ReadBoolean(); if(!dmpInfo.DumpFullText) { Debug.WriteLine("Dumped $FIftiMain found but not expected !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(bFlagSupp) { Debug.WriteLine("reading $FIftiMain"); _ftSearcher = new FullTextEngine(); _ftSearcher.SetCHMFile(this); _ftSearcher.ReadDump(ref reader); } } else { if(dmpInfo.DumpFullText) { Debug.WriteLine("Dumped $FIftiMain expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } // read table of contents _toc.Clear(); bFlag = reader.ReadBoolean(); if(bFlag) { if((_systemFile.BinaryTOC)&&(!dmpInfo.DumpBinaryTOC)) { Debug.WriteLine("Binary TOC expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if((!_systemFile.BinaryTOC)&&(!dmpInfo.DumpTextTOC)) { Debug.WriteLine("Text-based TOC expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(_systemFile.BinaryTOC) Debug.WriteLine("reading binary TOC"); else Debug.WriteLine("reading text-based TOC"); int nTocCnt = reader.ReadInt32(); for(nCnt=0; nCnt < nTocCnt; nCnt++) { TOCItem item = new TOCItem(); item.AssociatedFile = this; item.ChmFile = _chmFileName; item.ReadDump(ref reader); if(item.MergeLink.Length > 0) _mergeLinks.Add(item); _toc.Add(item); } } else { if((_systemFile.BinaryTOC)&&(dmpInfo.DumpBinaryTOC)) { Debug.WriteLine("Binary TOC expected but no TOC dump !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if((!_systemFile.BinaryTOC)&&(dmpInfo.DumpTextTOC)) { Debug.WriteLine("Text-based TOC expected but no TOC dump !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } // read index _indexALinks.Clear(); _indexKLinks.Clear(); bFlag = reader.ReadBoolean(); if(bFlag) { if((_systemFile.BinaryIndex)&&(!dmpInfo.DumpBinaryIndex)) { Debug.WriteLine("Binary index expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if((!_systemFile.BinaryIndex)&&(!dmpInfo.DumpTextIndex)) { Debug.WriteLine("Binary index expected but not found !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if(_systemFile.BinaryIndex) Debug.WriteLine("reading binary index"); else Debug.WriteLine("reading text-based index"); int nIndxaCnt = reader.ReadInt32(); for(nCnt=0; nCnt < nIndxaCnt; nCnt++) { IndexItem item = new IndexItem(); item.ChmFile = this; item.ReadDump(ref reader); _indexALinks.Add(item); } int nIndxkCnt = reader.ReadInt32(); for(nCnt=0; nCnt < nIndxkCnt; nCnt++) { IndexItem item = new IndexItem(); item.ChmFile = this; item.ReadDump(ref reader); _indexKLinks.Add(item); } } else { if((_systemFile.BinaryIndex)&&(dmpInfo.DumpBinaryIndex)) { Debug.WriteLine("Binary index expected but no index in dump !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } if((!_systemFile.BinaryIndex)&&(dmpInfo.DumpTextIndex)) { Debug.WriteLine("Text-based index expected but no index dump !"); dmpInfo.SaveData(); // closes the dump _mustWriteDump = true; return false; // force reload } } // read information types from dump int nITCnt = reader.ReadInt32(); Debug.WriteLine("Reading " + nITCnt.ToString() + " information types from dump !"); for(nCnt=0; nCnt /// Gets the current storage wrapper. /// /// This property will return not null, if there are currently file read actions running ! internal CHMStream.CHMStream CurrentStorageWrapper { get { return _currentWrapper;} } /// /// Gets/sets the hosting HtmlHelpSystem instance /// internal HtmlHelpSystem SystemInstance { get { return _systemInstance; } set { _systemInstance = value; } } /// /// Gets an arraylist of TOC items which contains merg-links to other CHMs /// internal ArrayList MergLinks { get { return _mergeLinks; } } /// /// Gets the internal system file instance /// internal CHMSystem SystemFile { get { return _systemFile; } } /// /// Gets the internal idxhdr file instance /// internal CHMIdxhdr IdxHdrFile { get { return _idxhdrFile; } } /// /// Gets the internal strings file instance /// internal CHMStrings StringsFile { get { return _stringsFile; } } /// /// Gets the internal urlstr file instance /// internal CHMUrlstr UrlstrFile { get { return _urlstrFile; } } /// /// Gets the internal urltbl file instance /// internal CHMUrltable UrltblFile { get { return _urltblFile; } } /// /// Gets the internal topics file instance /// internal CHMTopics TopicsFile { get { return _topicsFile; } } /// /// Gets the internal tocidx file instance /// internal CHMTocidx TocidxFile { get { return _tocidxFile; } } /// /// Gets the internal btree file instance for alinks /// internal CHMBtree ALinksFile { get { return _aLinks; } } /// /// Gets the internal btree file instance for klinks /// internal CHMBtree KLinksFile { get { return _kLinks; } } /// /// Gets/Sets the text encoding /// internal Encoding TextEncoding { get { return _textEncoding; } set { _textEncoding = value; } } #endregion #region Properties from the #SYSTEM file /// /// Gets the file version of the chm file. /// 2 for Compatibility=1.0, 3 for Compatibility=1.1 /// internal int FileVersion { get { if(_systemFile==null) return 0; return _systemFile.FileVersion; } } /// /// Gets the contents file name /// internal string ContentsFile { get { if(_systemFile==null) return String.Empty; return _systemFile.ContentsFile; } } /// /// Gets the index file name /// internal string IndexFile { get { if(_systemFile==null) return String.Empty; return _systemFile.IndexFile; } } /// /// Gets the default help topic /// internal string DefaultTopic { get { if(_systemFile==null) return String.Empty; return _systemFile.DefaultTopic; } } /// /// Gets the title of the help window /// internal string HelpWindowTitle { get { if(_systemFile==null) return String.Empty; return _systemFile.Title; } } /// /// Gets the flag if DBCS is in use /// internal bool DBCS { get { if(_systemFile==null) return false; return _systemFile.DBCS; } } /// /// Gets the flag if full-text-search is available /// internal bool FullTextSearch { get { if(_systemFile==null) return false; return _systemFile.FullTextSearch; } } /// /// Gets the flag if the file has ALinks /// internal bool HasALinks { get { if(_systemFile==null) return false; return _systemFile.HasALinks; } } /// /// Gets the flag if the file has KLinks /// internal bool HasKLinks { get { if(_systemFile==null) return false; return _systemFile.HasKLinks; } } /// /// Gets the default window name /// internal string DefaultWindow { get { if(_systemFile==null) return String.Empty; return _systemFile.DefaultWindow; } } /// /// Gets the file name of the compile file /// internal string CompileFile { get { if(_systemFile==null) return String.Empty; return _systemFile.CompileFile; } } /// /// Gets the flag if the chm has a binary index file /// internal bool BinaryIndex { get { if(_systemFile==null) return false; return _systemFile.BinaryIndex; } } /// /// Gets the flag if the chm has a binary index file /// internal string CompilerVersion { get { if(_systemFile==null) return String.Empty; return _systemFile.CompilerVersion; } } /// /// Gets the flag if the chm has a binary toc file /// internal bool BinaryTOC { get { if(_systemFile==null) return false; return _systemFile.BinaryTOC; } } /// /// Gets the font face of the read font property. /// Empty string for default font. /// internal string FontFace { get { if(_systemFile==null) return ""; return _systemFile.FontFace; } } /// /// Gets the font size of the read font property. /// 0 for default font size /// internal double FontSize { get { if(_systemFile==null) return 0; return _systemFile.FontSize; } } /// /// Gets the character set of the read font property /// 1 for default /// internal int CharacterSet { get { if(_systemFile==null) return 1; return _systemFile.CharacterSet; } } /// /// Gets the codepage depending on the read font property /// internal int CodePage { get { if(_systemFile==null) return CultureInfo.CurrentCulture.TextInfo.ANSICodePage; return _systemFile.CodePage; } } /// /// Gets the assiciated culture info /// internal CultureInfo Culture { get { if(_systemFile==null) return CultureInfo.CurrentCulture; return _systemFile.Culture; } } #endregion #region Properties from the #IDXHDR file /// /// Gets the number of topic nodes including the contents and index files /// internal int NumberOfTopicNodes { get { if(_idxhdrFile==null) return 0; return _idxhdrFile.NumberOfTopicNodes; } } /// /// Gets the ImageList string specyfied in the #IDXHDR file. /// /// This property uses the #STRINGS file to extract the string at a given offset. internal string ImageList { get { if( (_stringsFile == null) || (_idxhdrFile == null) ) return ""; return _stringsFile[ _idxhdrFile.ImageListOffset ]; } } /// /// True if the value of the ImageType param of the /// "text/site properties" object of the sitemap contents is "Folder". /// /// If this is set to true, the help will display folders instead of books internal bool ImageTypeFolder { get { if(_idxhdrFile==null) return false; return _idxhdrFile.ImageTypeFolder; } } /// /// Gets the background setting /// internal int Background { get { if(_idxhdrFile==null) return 0; return _idxhdrFile.Background; } } /// /// Gets the foreground setting /// internal int Foreground { get { if(_idxhdrFile==null) return 0; return _idxhdrFile.Foreground; } } /// /// Gets the Font string specyfied in the #IDXHDR file. /// /// This property uses the #STRINGS file to extract the string at a given offset. internal string FontName { get { if( (_stringsFile == null) || (_idxhdrFile == null) ) return ""; return _stringsFile[ _idxhdrFile.FontOffset ]; } } /// /// Gets the FrameName string specyfied in the #IDXHDR file. /// /// This property uses the #STRINGS file to extract the string at a given offset. internal string FrameName { get { if( (_stringsFile == null) || (_idxhdrFile == null) ) return ""; return _stringsFile[ _idxhdrFile.FrameNameOffset ]; } } /// /// Gets the WindowName string specyfied in the #IDXHDR file. /// /// This property uses the #STRINGS file to extract the string at a given offset. internal string WindowName { get { if( (_stringsFile == null) || (_idxhdrFile == null) ) return ""; return _stringsFile[ _idxhdrFile.WindowNameOffset ]; } } /// /// Gets a string array containing the merged file names /// internal string[] MergedFiles { get { if( (_stringsFile == null) || (_idxhdrFile == null) ) return new string[0]; string[] saRet = new string[ _idxhdrFile.MergedFileOffsets.Count ]; for(int i=0; i < _idxhdrFile.MergedFileOffsets.Count; i++) { saRet[i] = _stringsFile[ (int)_idxhdrFile.MergedFileOffsets[i] ]; } return saRet; } } #endregion /// /// Gets the file info associated with this instance /// public ChmFileInfo FileInfo { get { return _chmFileInfo; } } /// /// Gets the internal toc read from the text-based hhc file /// public ArrayList TOC { get { return _toc; } } /// /// Gets the internal index read from the chm file. /// public ArrayList IndexKLinks { get { return _indexKLinks; } } /// /// Gets the internal index read from the chm file. /// public ArrayList IndexALinks { get { return _indexALinks; } } /// /// Gets the full-text search engine for this file /// internal FullTextEngine FullTextSearchEngine { get { return _ftSearcher; } } /// /// Gets the full pathname of the file /// public string ChmFilePath { get { return _chmFileName; } } /// /// Gets the full pathname of the chi-file /// The file name is zero-length if there is no chi-file /// public string ChiFilePath { get { return _chiFileName; } } /// /// Gets the full pathname of the chw-file /// The file name is zero-length if there is no chw-file /// public string ChwFilePath { get { return _chwFileName; } } /// /// Gets the full pathname of the chq-file /// The file name is zero-length if there is no chq-file /// public string ChqFilePath { get { return _chqFileName; } } /// /// Forms an URL for the web browser /// /// local resource /// a url for the web-browser internal string FormURL(string local) { if( (local.ToLower().IndexOf("http://") >= 0) || (local.ToLower().IndexOf("https://") >= 0) || (local.ToLower().IndexOf("mailto:") >= 0) || (local.ToLower().IndexOf("ftp://") >= 0) || (local.ToLower().IndexOf("ms-its:") >= 0)) return local; return HtmlHelpSystem.UrlPrefix + _chmFileName + "::/" + local; } /// /// Implement IDisposable. /// public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } /// /// Dispose(bool disposing) executes in two distinct scenarios. /// If disposing equals true, the method has been called directly /// or indirectly by a user's code. Managed and unmanaged resources /// can be disposed. /// If disposing equals false, the method has been called by the /// runtime from inside the finalizer and you should not reference /// other objects. Only unmanaged resources can be disposed. /// /// disposing flag private void Dispose(bool disposing) { // Check to see if Dispose has already been called. if(!this.disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if(disposing) { // Dispose managed resources. _toc.Clear(); _indexKLinks.Clear(); _indexALinks.Clear(); if(_systemFile!=null) _systemFile.Dispose(); if(_idxhdrFile != null) _idxhdrFile.Dispose(); if(_stringsFile != null) _stringsFile.Dispose(); if(_urlstrFile != null) _urlstrFile.Dispose(); if(_urltblFile != null) _urltblFile.Dispose(); if(_topicsFile != null) _topicsFile.Dispose(); if(_tocidxFile != null) _tocidxFile.Dispose(); if(_kLinks != null) _kLinks.Dispose(); if(_aLinks != null) _aLinks.Dispose(); if(_ftSearcher != null) _ftSearcher.Dispose(); if(_chmFileInfo != null) _chmFileInfo = null; } } disposed = true; } } }