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;
}
}
}