Import TechBot
authorCasper Hornstrup <chorns@users.sourceforge.net>
Sat, 15 Jan 2005 19:27:25 +0000 (19:27 +0000)
committerCasper Hornstrup <chorns@users.sourceforge.net>
Sat, 15 Jan 2005 19:27:25 +0000 (19:27 +0000)
svn path=/trunk/; revision=13064

94 files changed:
irc/TechBot/CHMLibrary/AssemblyInfo.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/BinaryReaderHelp.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMBtree.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMFile.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMIdxhdr.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMStrings.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMSystem.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMTocidx.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMTopics.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMUrlstr.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/CHMUrltable.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/DumpingInfo.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/FullTextEngine.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/HHCParser.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/HHCParser2.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/HHKParser.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/TopicEntry.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/UrlTableEntry.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMDecoding/enumerations.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMLibrary.cmbx [new file with mode: 0644]
irc/TechBot/CHMLibrary/CHMLibrary.prjx [new file with mode: 0644]
irc/TechBot/CHMLibrary/Category.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/ChmFileInfo.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/Default.build [new file with mode: 0644]
irc/TechBot/CHMLibrary/HtmlHelpSystem.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/HttpUtility.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/Index.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/IndexItem.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/IndexTopic.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/InformationType.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/Storage/CHMStream.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/TOCItem.cs [new file with mode: 0644]
irc/TechBot/CHMLibrary/TableOfContents.cs [new file with mode: 0644]
irc/TechBot/Compression/AssemblyInfo.cs [new file with mode: 0644]
irc/TechBot/Compression/Checksums/Adler32.cs [new file with mode: 0644]
irc/TechBot/Compression/Checksums/CRC32.cs [new file with mode: 0644]
irc/TechBot/Compression/Checksums/IChecksum.cs [new file with mode: 0644]
irc/TechBot/Compression/Checksums/StrangeCRC.cs [new file with mode: 0644]
irc/TechBot/Compression/Compression.cmbx [new file with mode: 0644]
irc/TechBot/Compression/Compression.prjx [new file with mode: 0644]
irc/TechBot/Compression/Default.build [new file with mode: 0644]
irc/TechBot/Compression/Deflater.cs [new file with mode: 0644]
irc/TechBot/Compression/DeflaterConstants.cs [new file with mode: 0644]
irc/TechBot/Compression/DeflaterEngine.cs [new file with mode: 0644]
irc/TechBot/Compression/DeflaterHuffman.cs [new file with mode: 0644]
irc/TechBot/Compression/DeflaterPending.cs [new file with mode: 0644]
irc/TechBot/Compression/Inflater.cs [new file with mode: 0644]
irc/TechBot/Compression/InflaterDynHeader.cs [new file with mode: 0644]
irc/TechBot/Compression/InflaterHuffmanTree.cs [new file with mode: 0644]
irc/TechBot/Compression/PendingBuffer.cs [new file with mode: 0644]
irc/TechBot/Compression/Streams/DeflaterOutputStream.cs [new file with mode: 0644]
irc/TechBot/Compression/Streams/InflaterInputStream.cs [new file with mode: 0644]
irc/TechBot/Compression/Streams/OutputWindow.cs [new file with mode: 0644]
irc/TechBot/Compression/Streams/StreamManipulator.cs [new file with mode: 0644]
irc/TechBot/Compression/ZipException.cs [new file with mode: 0644]
irc/TechBot/Default.build [new file with mode: 0644]
irc/TechBot/TechBot.Console/App.config [new file with mode: 0644]
irc/TechBot/TechBot.Console/AssemblyInfo.cs [new file with mode: 0644]
irc/TechBot/TechBot.Console/Default.build [new file with mode: 0644]
irc/TechBot/TechBot.Console/Main.cs [new file with mode: 0644]
irc/TechBot/TechBot.Console/TechBot.Console.cmbx [new file with mode: 0644]
irc/TechBot/TechBot.Console/TechBot.Console.prjx [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/AssemblyInfo.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/Default.build [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/IRC.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/IrcChannel.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/IrcClient.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/IrcException.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/IrcMessage.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/IrcUser.cs [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/TechBot.IRCLibrary.cmbx [new file with mode: 0644]
irc/TechBot/TechBot.IRCLibrary/TechBot.IRCLibrary.prjx [new file with mode: 0644]
irc/TechBot/TechBot.Library/ApiCommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/AssemblyInfo.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/Default.build [new file with mode: 0644]
irc/TechBot/TechBot.Library/HelpCommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/HresultCommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/ICommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/IrcService.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/NtStatusCommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/NumberParser.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/ServiceOutput.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/SvnCommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/TechBot.Library.cmbx [new file with mode: 0644]
irc/TechBot/TechBot.Library/TechBot.Library.prjx [new file with mode: 0644]
irc/TechBot/TechBot.Library/TechBotService.cs [new file with mode: 0644]
irc/TechBot/TechBot.Library/WinerrorCommand.cs [new file with mode: 0644]
irc/TechBot/TechBot.cmbx [new file with mode: 0644]
irc/TechBot/TechBot/App.config [new file with mode: 0644]
irc/TechBot/TechBot/AssemblyInfo.cs [new file with mode: 0644]
irc/TechBot/TechBot/Default.build [new file with mode: 0644]
irc/TechBot/TechBot/ServiceThread.cs [new file with mode: 0644]
irc/TechBot/TechBot/TechBot.prjx [new file with mode: 0644]
irc/TechBot/TechBot/TechBotService.cs [new file with mode: 0644]

diff --git a/irc/TechBot/CHMLibrary/AssemblyInfo.cs b/irc/TechBot/CHMLibrary/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..dbacda1
--- /dev/null
@@ -0,0 +1,32 @@
+using System.Reflection;\r
+using System.Runtime.CompilerServices;\r
+\r
+// Information about this assembly is defined by the following\r
+// attributes.\r
+//\r
+// change them to the information which is associated with the assembly\r
+// you compile.\r
+\r
+[assembly: AssemblyTitle("")]\r
+[assembly: AssemblyDescription("")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("")]\r
+[assembly: AssemblyProduct("")]\r
+[assembly: AssemblyCopyright("")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]\r
+\r
+// The assembly version has following format :\r
+//\r
+// Major.Minor.Build.Revision\r
+//\r
+// You can specify all values by your own or you can build default build and revision\r
+// numbers with the '*' character (the default):\r
+\r
+[assembly: AssemblyVersion("1.0.*")]\r
+\r
+// The following attributes specify the key for the sign of your assembly. See the\r
+// .NET Framework documentation for more information about signing.\r
+// This is not required, if you don't want signing let these attributes like they're.\r
+[assembly: AssemblyDelaySign(false)]\r
+[assembly: AssemblyKeyFile("")]\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/BinaryReaderHelp.cs b/irc/TechBot/CHMLibrary/CHMDecoding/BinaryReaderHelp.cs
new file mode 100644 (file)
index 0000000..64c9668
--- /dev/null
@@ -0,0 +1,274 @@
+using System;\r
+using System.Collections;\r
+using System.IO;\r
+using System.Text;\r
+using System.Globalization;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// The class <c>BinaryReaderHelp</c> implements static helper methods for extracting binary data \r
+       /// from a binary reader object.\r
+       /// </summary>\r
+       internal class BinaryReaderHelp\r
+       {\r
+               /// <summary>\r
+               /// Internal helper method to extract null-terminated strings from a binary reader\r
+               /// </summary>\r
+               /// <param name="binReader">reference to the binary reader</param>\r
+               /// <param name="offset">offset in the stream</param>\r
+               /// <param name="noOffset">true if the offset value should be used</param>\r
+               /// <param name="encoder">encoder used for text encoding</param>\r
+               /// <returns>An extracted string value</returns>\r
+               internal static string ExtractString(ref BinaryReader binReader, int offset, bool noOffset, Encoding encoder)\r
+               {\r
+                       string strReturn = "";\r
+\r
+                       if(encoder == null)\r
+                               encoder = Encoding.ASCII;\r
+\r
+                       ArrayList nameBytes = new ArrayList();\r
+                       byte curByte;\r
+                       \r
+                       if(!noOffset)\r
+                               binReader.BaseStream.Seek(offset, SeekOrigin.Begin);\r
+\r
+                       if(binReader.BaseStream.Position >= binReader.BaseStream.Length)\r
+                               return "";\r
+\r
+                       curByte = binReader.ReadByte();\r
+                       while( (curByte != (byte)0) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )\r
+                       {       \r
+                               nameBytes.Add( curByte );\r
+                               curByte = binReader.ReadByte();\r
+                       }\r
+\r
+                       byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));\r
+                       strReturn = encoder.GetString(name,0,name.Length);\r
+\r
+                       return strReturn;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Internal helper method to extract a string with a specific length from the binary reader\r
+               /// </summary>\r
+               /// <param name="binReader">reference to the binary reader</param>\r
+               /// <param name="length">length of the string (number of bytes)</param>\r
+               /// <param name="offset">offset in the stream</param>\r
+               /// <param name="noOffset">true if the offset value should be used</param>\r
+               /// <param name="encoder">encoder used for text encoding</param>\r
+               /// <returns>An extracted string value</returns>\r
+               internal static string ExtractString(ref BinaryReader binReader, int length, int offset, bool noOffset, Encoding encoder)\r
+               {\r
+                       string strReturn = "";\r
+\r
+                       if(length == 0)\r
+                               return "";\r
+\r
+                       if(encoder == null)\r
+                               encoder = Encoding.ASCII;\r
+\r
+                       ArrayList nameBytes = new ArrayList();\r
+                       byte curByte;\r
+                       \r
+                       if(!noOffset)\r
+                               binReader.BaseStream.Seek(offset, SeekOrigin.Begin);\r
+\r
+                       if(binReader.BaseStream.Position >= binReader.BaseStream.Length)\r
+                               return "";\r
+\r
+                       curByte = binReader.ReadByte();\r
+                       while( (curByte != (byte)0) && (nameBytes.Count < length) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )\r
+                       {       \r
+                               nameBytes.Add( curByte );\r
+\r
+                               if(nameBytes.Count < length)\r
+                                       curByte = binReader.ReadByte();\r
+                       }\r
+\r
+                       byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));\r
+                       strReturn = encoder.GetString(name,0,name.Length);\r
+\r
+                       return strReturn;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Internal helper method to extract a string with a specific length from the binary reader\r
+               /// </summary>\r
+               /// <param name="binReader">reference to the binary reader</param>\r
+               /// <param name="bFoundTerminator">reference to a bool vairable which will receive true if the\r
+               /// string terminator \0 was found. false indicates that the end of the stream was reached.</param>\r
+               /// <param name="offset">offset in the stream</param>\r
+               /// <param name="noOffset">true if the offset value should be used</param>\r
+               /// <param name="encoder">encoder used for text encoding</param>\r
+               /// <returns>An extracted string value</returns>\r
+               internal static string ExtractString(ref BinaryReader binReader, ref bool bFoundTerminator, int offset, bool noOffset, Encoding encoder)\r
+               {\r
+                       string strReturn = "";\r
+\r
+                       ArrayList nameBytes = new ArrayList();\r
+                       byte curByte;\r
+                       \r
+                       if(encoder == null)\r
+                               encoder = Encoding.ASCII;\r
+\r
+                       if(!noOffset)\r
+                               binReader.BaseStream.Seek(offset, SeekOrigin.Begin);\r
+\r
+                       if(binReader.BaseStream.Position >= binReader.BaseStream.Length)\r
+                               return "";\r
+\r
+                       curByte = binReader.ReadByte();\r
+                       while( (curByte != (byte)0) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )\r
+                       {       \r
+                               nameBytes.Add( curByte );\r
+                               curByte = binReader.ReadByte();\r
+\r
+                               if( curByte == (byte)0 )\r
+                               {\r
+                                       bFoundTerminator = true;\r
+                               }\r
+                       }\r
+\r
+                       byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));\r
+                       strReturn = encoder.GetString(name,0,name.Length);\r
+\r
+                       return strReturn;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Internal helper method to extract a null-terminated UTF-16/UCS-2 strings from a binary reader\r
+               /// </summary>\r
+               /// <param name="binReader">reference to the binary reader</param>\r
+               /// <param name="offset">offset in the stream</param>\r
+               /// <param name="noOffset">true if the offset value should be used</param>\r
+               /// <param name="encoder">encoder used for text encoding</param>\r
+               /// <returns>An extracted string value</returns>\r
+               internal static string ExtractUTF16String(ref BinaryReader binReader, int offset, bool noOffset, Encoding encoder)\r
+               {\r
+                       string strReturn = "";\r
+\r
+                       ArrayList nameBytes = new ArrayList();\r
+                       byte curByte;\r
+                       int lastByte=-1;\r
+                       \r
+                       if(!noOffset)\r
+                               binReader.BaseStream.Seek(offset, SeekOrigin.Begin);\r
+\r
+                       if(binReader.BaseStream.Position >= binReader.BaseStream.Length)\r
+                               return "";\r
+\r
+                       if(encoder == null)\r
+                               encoder = Encoding.Unicode;\r
+\r
+                       curByte = binReader.ReadByte();\r
+                       int nCnt = 0;\r
+                       while( ((curByte != (byte)0) || (lastByte != 0) ) && (binReader.BaseStream.Position < binReader.BaseStream.Length) )\r
+                       {       \r
+                               nameBytes.Add( curByte );\r
+\r
+                               if(nCnt%2 == 0)\r
+                                       lastByte = (int)curByte;\r
+\r
+                               curByte = binReader.ReadByte();\r
+\r
+                               nCnt++;\r
+                       }\r
+\r
+                       byte[] name = (byte[]) (nameBytes.ToArray(System.Type.GetType("System.Byte")));\r
+                       strReturn = Encoding.Unicode.GetString(name,0,name.Length);\r
+\r
+                       // apply text encoding\r
+                       name = Encoding.Default.GetBytes(strReturn);\r
+                       strReturn = encoder.GetString(name,0,name.Length);\r
+\r
+                       return strReturn;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Internal helper for reading ENCINT encoded integer values\r
+               /// </summary>\r
+               /// <param name="binReader">reference to the reader</param>\r
+               /// <returns>a long value</returns>\r
+               internal static long ReadENCINT(ref BinaryReader binReader)\r
+               {\r
+                       long nRet = 0;\r
+                       byte buffer = 0;\r
+                       int shift = 0;\r
+\r
+                       if(binReader.BaseStream.Position >= binReader.BaseStream.Length)\r
+                               return nRet;\r
+                       \r
+                       do\r
+                       {\r
+                               buffer = binReader.ReadByte();\r
+                               nRet |= ((long)((buffer & (byte)0x7F))) << shift;\r
+                               shift += 7;\r
+\r
+                       }while ( (buffer & (byte)0x80) != 0);\r
+\r
+                       return nRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Reads an s/r encoded value from the byte array and decodes it into an integer\r
+               /// </summary>\r
+               /// <param name="wclBits">a byte array containing all bits (contains only 0 or 1 elements)</param>\r
+               /// <param name="s">scale param for encoding</param>\r
+               /// <param name="r">root param for encoding</param>\r
+               /// <param name="nBitIndex">current index in the wclBits array</param>\r
+               /// <returns>Returns an decoded integer value.</returns>\r
+               internal static int ReadSRItem(byte[] wclBits, int s, int r, ref int nBitIndex)\r
+               {\r
+                       int nRet = 0;\r
+                       int q = r;\r
+\r
+                       int nPref1Cnt = 0;\r
+\r
+                       while( wclBits[nBitIndex++] == 1)\r
+                       {\r
+                               nPref1Cnt++;\r
+                       }\r
+\r
+                       if(nPref1Cnt == 0)\r
+                       {\r
+                               int nMask = 0;\r
+\r
+                               for(int nbits=0; nbits<q;nbits++)\r
+                               {\r
+                                       nMask |= ( 0x01 & (int)wclBits[nBitIndex]) << (q-nbits-1);\r
+                                       nBitIndex++;\r
+                               }\r
+\r
+                               nRet = nMask;\r
+                       } \r
+                       else \r
+                       {\r
+                               q += (nPref1Cnt-1);\r
+\r
+                               int nMask = 0;\r
+                               int nRMaxValue = 0;\r
+\r
+                               for(int nbits=0; nbits<q;nbits++)\r
+                               {\r
+                                       nMask |= ( 0x01 & (int)wclBits[nBitIndex]) << (q-nbits-1);\r
+                                       nBitIndex++;\r
+                               }\r
+\r
+                               for(int nsv=0; nsv<r; nsv++)\r
+                               {\r
+                                       nRMaxValue = nRMaxValue << 1;\r
+                                       nRMaxValue |= 0x1;\r
+                               }\r
+       \r
+                               nRMaxValue++; // startvalue of s/r encoding with 1 prefixing '1'\r
+\r
+                               nRMaxValue *= (int) Math.Pow((double)2, (double)(nPref1Cnt-1));\r
+\r
+                               nRet = nRMaxValue + nMask;\r
+                       }\r
+\r
+                       return nRet;\r
+               }\r
+       }\r
+}\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/CHMBtree.cs b/irc/TechBot/CHMLibrary/CHMDecoding/CHMBtree.cs
new file mode 100644 (file)
index 0000000..f1d1a66
--- /dev/null
@@ -0,0 +1,325 @@
+using System;\r
+using System.IO;\r
+using System.Collections;\r
+using System.Collections.Specialized;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// The class <c>CHMBtree</c> implements methods/properties to decode the binary help index. \r
+       /// This class automatically creates an index arraylist for the current CHMFile instance. \r
+       /// It does not store the index internally !\r
+       /// </summary>\r
+       /// <remarks>The binary index can be found in the storage file $WWKeywordLinks/BTree</remarks>\r
+       internal sealed class CHMBtree : IDisposable\r
+       {\r
+               /// <summary>\r
+               /// Constant specifying the size of the string blocks\r
+               /// </summary>\r
+               private const int BLOCK_SIZE = 2048;\r
+               /// <summary>\r
+               /// Internal flag specifying if the object is going to be disposed\r
+               /// </summary>\r
+               private bool disposed = false;\r
+               /// <summary>\r
+               /// Internal member storing the binary file data\r
+               /// </summary>\r
+               private byte[] _binaryFileData = null;\r
+               /// <summary>\r
+               /// Internal member storing flags\r
+               /// </summary>\r
+               private int _flags = 0;\r
+               /// <summary>\r
+               /// Internal member storing the data format\r
+               /// </summary>\r
+               private byte[] _dataFormat = new byte[16];\r
+               /// <summary>\r
+               /// Internal member storing the index of the last listing block\r
+               /// </summary>\r
+               private int _indexOfLastListingBlock = 0;\r
+               /// <summary>\r
+               /// Internal member storing the index of the root block\r
+               /// </summary>\r
+               private int _indexOfRootBlock = 0;\r
+               /// <summary>\r
+               /// Internal member storing the number of blocks\r
+               /// </summary>\r
+               private int _numberOfBlocks = 0;\r
+               /// <summary>\r
+               /// Internal member storing the tree depth. \r
+               /// (1 if no index blocks, 2 one level of index blocks, ...)\r
+               /// </summary>\r
+               private int _treeDepth = 0;\r
+               /// <summary>\r
+               /// Internal member storing the number of keywords in the file\r
+               /// </summary>\r
+               private int _numberOfKeywords = 0;\r
+               /// <summary>\r
+               /// Internal member storing the codepage\r
+               /// </summary>\r
+               private int _codePage = 0;\r
+               /// <summary>\r
+               /// true if the index is from a CHI or CHM file, else CHW\r
+               /// </summary>\r
+               private bool _isCHI_CHM = true;\r
+               /// <summary>\r
+               /// Internal member storing the associated chmfile object\r
+               /// </summary>\r
+               private CHMFile _associatedFile = null;\r
+               /// <summary>\r
+               /// Internal flag specifying if we have to read listing or index blocks\r
+               /// </summary>\r
+               private bool _readListingBlocks = true;\r
+               /// <summary>\r
+               /// Internal member storing an indexlist of the current file.\r
+               /// </summary>\r
+               private ArrayList _indexList = new ArrayList();\r
+\r
+               /// <summary>\r
+               /// Constructor of the class\r
+               /// </summary>\r
+               /// <param name="binaryFileData">binary file data of the $WWKeywordLinks/BTree file</param>\r
+               /// <param name="associatedFile">associated chm file</param>\r
+               public CHMBtree(byte[] binaryFileData, CHMFile associatedFile)\r
+               {\r
+                       if( associatedFile == null)\r
+                       {\r
+                               throw new ArgumentException("CHMBtree.ctor() - Associated CHMFile must not be null !", "associatedFile");\r
+                       }\r
+\r
+                       _binaryFileData = binaryFileData;\r
+                       _associatedFile = associatedFile;\r
+                       DecodeData();\r
+\r
+                       // clear internal binary data after extraction\r
+                       _binaryFileData = null;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Decodes the binary file data and fills the internal properties\r
+               /// </summary>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeData()\r
+               {\r
+                       bool bRet = true;\r
+\r
+                       MemoryStream memStream = new MemoryStream(_binaryFileData);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+                       \r
+                       int nCurOffset = 0;\r
+                       int nTemp = 0;\r
+\r
+                       // decode header\r
+                       binReader.ReadChars(2); // 2chars signature (not important)\r
+                       \r
+                       _flags = (int)binReader.ReadInt16(); // WORD flags\r
+\r
+                       binReader.ReadInt16(); // size of blocks (always 2048)\r
+\r
+                       _dataFormat = binReader.ReadBytes(16);\r
+                       \r
+                       binReader.ReadInt32();  // unknown DWORD\r
+\r
+                       _indexOfLastListingBlock = binReader.ReadInt32();\r
+                       _indexOfRootBlock = binReader.ReadInt32();\r
+\r
+                       binReader.ReadInt32(); // unknown DWORD\r
+\r
+                       _numberOfBlocks = binReader.ReadInt32();\r
+                       _treeDepth = binReader.ReadInt16();\r
+                       _numberOfKeywords = binReader.ReadInt32();\r
+                       _codePage = binReader.ReadInt32();\r
+\r
+                       binReader.ReadInt32(); // lcid DWORD\r
+                       \r
+                       nTemp = binReader.ReadInt32();\r
+                       _isCHI_CHM = (nTemp==1);\r
+\r
+                       binReader.ReadInt32(); // unknown DWORD\r
+                       binReader.ReadInt32(); // unknown DWORD\r
+                       binReader.ReadInt32(); // unknown DWORD\r
+                       binReader.ReadInt32(); // unknown DWORD\r
+\r
+                       // end of header decode\r
+\r
+                       while( (memStream.Position < memStream.Length) && (bRet) )\r
+                       {\r
+                               nCurOffset = (int)memStream.Position;\r
+                               byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);\r
+                               bRet &= DecodeBlock(dataBlock, ref nCurOffset, _treeDepth-1);\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Decodes a block of url-string data\r
+               /// </summary>\r
+               /// <param name="dataBlock">block of data</param>\r
+               /// <param name="nOffset">current file offset</param>\r
+               /// <param name="indexBlocks">number of index blocks</param>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeBlock( byte[] dataBlock, ref int nOffset, int indexBlocks )\r
+               {\r
+                       bool bRet = true;\r
+                       int nblockOffset = nOffset;\r
+\r
+                       MemoryStream memStream = new MemoryStream(dataBlock);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+\r
+                       int freeSpace = binReader.ReadInt16(); // length of freespace\r
+                       int nrOfEntries = binReader.ReadInt16(); // number of entries\r
+\r
+                       bool bListingEndReached = false;\r
+\r
+                       //while( (memStream.Position < (memStream.Length-freeSpace)) && (bRet) )\r
+                       //{\r
+                               int nIndexOfPrevBlock = -1;\r
+                               int nIndexOfNextBlock = -1;\r
+                               int nIndexOfChildBlock = 0;\r
+                               \r
+                               if(_readListingBlocks)\r
+                               {\r
+                                       nIndexOfPrevBlock = binReader.ReadInt32(); // -1 if this is the header\r
+                                       nIndexOfNextBlock = binReader.ReadInt32(); // -1 if this is the last block\r
+                               } \r
+                               else \r
+                               {\r
+                                       nIndexOfChildBlock = binReader.ReadInt32(); \r
+                               }\r
+\r
+                               for(int nE = 0; nE < nrOfEntries; nE++)\r
+                               {\r
+                                       if(_readListingBlocks)\r
+                                       {\r
+                                               bListingEndReached = (nIndexOfNextBlock==-1);\r
+\r
+                                               string keyWord = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);\r
+\r
+                                               bool isSeeAlsoKeyword = (binReader.ReadInt16()!=0);\r
+                               \r
+                                               int indent = binReader.ReadInt16(); // indent of entry\r
+                                               int nCharIndex = binReader.ReadInt32();\r
+\r
+                                               binReader.ReadInt32();\r
+\r
+                                               int numberOfPairs =     binReader.ReadInt32();\r
+\r
+                                               int[] nTopics = new int[numberOfPairs];\r
+                                               string[] seeAlso = new string[numberOfPairs];\r
+\r
+                                               for(int i=0; i < numberOfPairs; i++)\r
+                                               {\r
+                                                       if(isSeeAlsoKeyword)\r
+                                                       {\r
+                                                               seeAlso[i] = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);\r
+                                                       } \r
+                                                       else \r
+                                                       {\r
+                                                               nTopics[i] = binReader.ReadInt32();\r
+                                                       }\r
+                                               }\r
+\r
+                                               binReader.ReadInt32(); // unknown\r
+\r
+                                               int nIndexOfThisEntry = binReader.ReadInt32();\r
+\r
+                                               IndexItem newItem = new IndexItem(_associatedFile, keyWord, isSeeAlsoKeyword, indent, nCharIndex, nIndexOfThisEntry, seeAlso, nTopics);\r
+                                               _indexList.Add(newItem);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               string keyWord = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);\r
+\r
+                                               bool isSeeAlsoKeyword = (binReader.ReadInt16()!=0);\r
+                               \r
+                                               int indent = binReader.ReadInt16(); // indent of entry\r
+                                               int nCharIndex = binReader.ReadInt32();\r
+\r
+                                               binReader.ReadInt32();\r
+\r
+                                               int numberOfPairs =     binReader.ReadInt32();\r
+\r
+                                               int[] nTopics = new int[numberOfPairs];\r
+                                               string[] seeAlso = new string[numberOfPairs];\r
+\r
+                                               for(int i=0; i < numberOfPairs; i++)\r
+                                               {\r
+                                                       if(isSeeAlsoKeyword)\r
+                                                       {\r
+                                                               seeAlso[i] = BinaryReaderHelp.ExtractUTF16String(ref binReader, 0, true, _associatedFile.TextEncoding);\r
+                                                       } \r
+                                                       else \r
+                                                       {\r
+                                                               nTopics[i] = binReader.ReadInt32();\r
+                                                       }\r
+                                               }\r
+\r
+                                               int nIndexChild = binReader.ReadInt32();\r
+                                               int nIndexOfThisEntry=-1;\r
+\r
+                                               IndexItem newItem = new IndexItem(_associatedFile, keyWord, isSeeAlsoKeyword, indent, nCharIndex, nIndexOfThisEntry, seeAlso, nTopics);\r
+                                               _indexList.Add(newItem);\r
+\r
+                                       }\r
+                               }\r
+                       //}\r
+\r
+                       binReader.ReadBytes(freeSpace);\r
+                       \r
+\r
+                       if( bListingEndReached )\r
+                               _readListingBlocks = false;\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal generated index list\r
+               /// </summary>\r
+               internal ArrayList IndexList\r
+               {\r
+                       get { return _indexList; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Implement IDisposable.\r
+               /// </summary>\r
+               public void Dispose()\r
+               {\r
+                       Dispose(true);\r
+                       // This object will be cleaned up by the Dispose method.\r
+                       // Therefore, you should call GC.SupressFinalize to\r
+                       // take this object off the finalization queue \r
+                       // and prevent finalization code for this object\r
+                       // from executing a second time.\r
+                       GC.SuppressFinalize(this);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Dispose(bool disposing) executes in two distinct scenarios. \r
+               /// If disposing equals true, the method has been called directly \r
+               /// or indirectly by a user's code. Managed and unmanaged resources \r
+               /// can be disposed. \r
+               /// If disposing equals false, the method has been called by the \r
+               /// runtime from inside the finalizer and you should not reference  \r
+               /// other objects. Only unmanaged resources can be disposed.\r
+               /// </summary>\r
+               /// <param name="disposing">disposing flag</param>\r
+               private void Dispose(bool disposing)\r
+               {\r
+                       // Check to see if Dispose has already been called.\r
+                       if(!this.disposed)\r
+                       {\r
+                               // If disposing equals true, dispose all managed \r
+                               // and unmanaged resources.\r
+                               if(disposing)\r
+                               {\r
+                                       // Dispose managed resources.\r
+                                       _binaryFileData = null;\r
+                               }\r
+                       }\r
+                       disposed = true;         \r
+               }\r
+       }\r
+}\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/CHMFile.cs b/irc/TechBot/CHMLibrary/CHMDecoding/CHMFile.cs
new file mode 100644 (file)
index 0000000..a39ffc4
--- /dev/null
@@ -0,0 +1,2061 @@
+using System;\r
+using System.Diagnostics;\r
+using System.Collections;\r
+using System.Collections.Specialized;\r
+using System.IO;\r
+using System.Text;\r
+using System.Runtime.InteropServices;\r
+using System.Globalization;\r
+// using HtmlHelp.Storage;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// Internal enumeration for specifying the type of the html-help file\r
+       /// </summary>\r
+       internal enum HtmlHelpFileType\r
+       {\r
+               /// <summary>\r
+               /// CHM - compiled contents file\r
+               /// </summary>\r
+               /// <remarks>A file with this extension must always exist. If the file would be too long, some parts \r
+               /// can be splitted into the filestypes below.</remarks>\r
+               CHM = 0,\r
+               /// <summary>\r
+               /// CHI - compiled system file\r
+               /// </summary>\r
+               CHI = 1,\r
+               /// <summary>\r
+               /// CHQ - compiled fulltext search file\r
+               /// </summary>\r
+               CHQ = 2,\r
+               /// <summary>\r
+               /// CHW - compiled index file\r
+               /// </summary>\r
+               CHW = 3\r
+\r
+       }\r
+\r
+       /// <summary>\r
+       /// The class <c>CHMFile</c> implemts methods and properties for handling a single chmfile.\r
+       /// </summary>\r
+       public sealed class CHMFile : IDisposable\r
+       {\r
+               /// <summary>\r
+               /// Internal member storing a reference to the hosting HtmlHelpSystem instance\r
+               /// </summary>\r
+               private HtmlHelpSystem _systemInstance = null;\r
+               /// <summary>\r
+               /// Internal flag specifying if only system data has been loaded\r
+               /// </summary>\r
+               private bool _onlySystem = false;\r
+               /// <summary>\r
+               /// Internal flag specifying if the object is going to be disposed\r
+               /// </summary>\r
+               private bool disposed = false;\r
+               /// <summary>\r
+               /// Internal arraylist containing the table of contents\r
+               /// </summary>\r
+               private ArrayList _toc = new ArrayList();\r
+               /// <summary>\r
+               /// Internal arraylist containing items of the toc which are merge-Links\r
+               /// </summary>\r
+               private ArrayList _mergeLinks = new ArrayList();\r
+               /// <summary>\r
+               /// Internal member storing the read information types\r
+               /// </summary>\r
+               private ArrayList _informationTypes = new ArrayList();\r
+               /// <summary>\r
+               /// Internal member storing the read categories\r
+               /// </summary>\r
+               private ArrayList _categories = new ArrayList();\r
+               /// <summary>\r
+               /// Internal arraylist containing the index (klinks)\r
+               /// </summary>\r
+               private ArrayList _indexKLinks = new ArrayList();\r
+               /// <summary>\r
+               /// Internal arraylist containing the index (alinks)\r
+               /// </summary>\r
+               private ArrayList _indexALinks = new ArrayList();\r
+               /// <summary>\r
+               /// Internal member storing the full filename\r
+               /// </summary>\r
+               private string _chmFileName = "";\r
+               /// <summary>\r
+               /// Internal member storing the full filename of the chi-file (includes all system files)\r
+               /// The file name is zero-length if there is no chi-file\r
+               /// </summary>\r
+               private string _chiFileName = "";\r
+               /// <summary>\r
+               /// Internal member storing the full filename of the chw-file (includes the help index)\r
+               /// The file name is zero-length if there is no chw-file\r
+               /// </summary>\r
+               private string _chwFileName = "";\r
+               /// <summary>\r
+               /// Internal member storing the full filename of the chq-file (includes the fulltext contents)\r
+               /// The file name is zero-length if there is no chq-file\r
+               /// </summary>\r
+               private string _chqFileName = "";\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #SYSTEM file\r
+               /// </summary>\r
+               private CHMSystem _systemFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #IDXHDR file\r
+               /// </summary>\r
+               private CHMIdxhdr _idxhdrFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #STRINGS file\r
+               /// </summary>\r
+               private CHMStrings _stringsFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #URLSTR file\r
+               /// </summary>\r
+               private CHMUrlstr _urlstrFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #URLTBL file\r
+               /// </summary>\r
+               private CHMUrltable _urltblFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #TOPICS file\r
+               /// </summary>\r
+               private CHMTopics _topicsFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal #TOCIDX file\r
+               /// </summary>\r
+               private CHMTocidx _tocidxFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal binary index file (KLinks).\r
+               /// </summary>\r
+               private CHMBtree _kLinks = null;\r
+               /// <summary>\r
+               /// Internal member storing the decoded information from the internal binary index file (ALinks).\r
+               /// </summary>\r
+               private CHMBtree _aLinks = null;\r
+               /// <summary>\r
+               /// Internal member storing the fulltext searcher for this file\r
+               /// </summary>\r
+               private FullTextEngine _ftSearcher = null;\r
+               /// <summary>\r
+               /// Internal member storing the default encoder\r
+               /// </summary>\r
+               private Encoding _textEncoding = Encoding.GetEncoding(1252); // standard windows-1252 encoder\r
+               /// <summary>\r
+               /// Internal memebr storing the chm file info\r
+               /// </summary>\r
+               private ChmFileInfo _chmFileInfo = null;\r
+               /// <summary>\r
+               /// Internal flag specifying if the dump must be written (if enabled)\r
+               /// </summary>\r
+               private bool _mustWriteDump = false;\r
+               /// <summary>\r
+               /// Internal flag specifying if data was read using the dump\r
+               /// </summary>\r
+               private bool _dumpRead = false;\r
+               /// <summary>\r
+               /// Internal member for specifying the number of dump-reading trys.\r
+               /// If dump-reading fails, this is used that it will not be opened a second time\r
+               /// (in CHM-Systems with CHM, CHI, etc. files)\r
+               /// </summary>\r
+               private int _dumpReadTrys = 0;\r
+               /// <summary>\r
+               /// Internal member storing the dumping info instance\r
+               /// </summary>\r
+               private DumpingInfo _dmpInfo = null;\r
+\r
+               private CHMStream.CHMStream _currentWrapper;\r
+               private CHMStream.CHMStream _baseStream=null;\r
+               public CHMStream.CHMStream BaseStream\r
+               {\r
+                       get \r
+                       { \r
+                               if (_baseStream==null)\r
+                                       _baseStream=new CHMStream.CHMStream(this.ChmFilePath);\r
+                               return _baseStream; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Creates a new instance of the class\r
+               /// </summary>\r
+               /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>\r
+               /// <param name="chmFile">chm file to read</param>\r
+               public CHMFile(HtmlHelpSystem systemInstance, string chmFile) : this(systemInstance, chmFile, false, null)\r
+               {\r
+               }\r
+\r
+               /// <summary>\r
+               /// Creates a new instance of the class\r
+               /// </summary>\r
+               /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>\r
+               /// <param name="chmFile">chm file to read</param>\r
+               /// <param name="dmpInfo">A dumping info class</param>\r
+               public CHMFile(HtmlHelpSystem systemInstance, string chmFile, DumpingInfo dmpInfo) : this(systemInstance, chmFile, false, dmpInfo)\r
+               {\r
+               }\r
+\r
+               /// <summary>\r
+               /// Creates a new instance of the class\r
+               /// </summary>\r
+               /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>\r
+               /// <param name="chmFile">chm file to read</param>\r
+               /// <param name="onlySystemData">true if only system data should be extracted (no index or toc)</param>\r
+               internal CHMFile(HtmlHelpSystem systemInstance, string chmFile, bool onlySystemData) : this(systemInstance, chmFile, onlySystemData, null)\r
+               {\r
+               }\r
+\r
+               /// <summary>\r
+               /// Creates a new instance of the class\r
+               /// </summary>\r
+               /// <param name="systemInstance">a reference to the hosting HtmlHelpSystem instance</param>\r
+               /// <param name="chmFile">chm file to read</param>\r
+               /// <param name="onlySystemData">true if only system data should be extracted (no index or toc)</param>\r
+               /// <param name="dmpInfo">A dumping info class</param>\r
+               internal CHMFile(HtmlHelpSystem systemInstance, string chmFile, bool onlySystemData, DumpingInfo dmpInfo)\r
+               {\r
+                       _systemInstance = systemInstance;\r
+                       _dumpReadTrys=0;\r
+\r
+                       _dmpInfo = dmpInfo;\r
+                       if(dmpInfo != null)\r
+                       {\r
+                               dmpInfo.ChmFile = this;\r
+                       }\r
+\r
+                       if( ! chmFile.ToLower().EndsWith(".chm") )\r
+                       {\r
+                               throw new ArgumentException("HtmlHelp file must have the extension .chm !", "chmFile");\r
+                       }\r
+\r
+                       _chmFileName = chmFile;\r
+                       _chiFileName = "";\r
+\r
+                       // Read the IStorage file system\r
+                       if( File.Exists(chmFile) )\r
+                       {\r
+                               _onlySystem = onlySystemData;\r
+                               \r
+                               DateTime dtStartHH = DateTime.Now;\r
+\r
+                               string sCHIName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chi";\r
+                               string sCHQName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chq";\r
+                               string sCHWName = _chmFileName.Substring(0, _chmFileName.Length-3) + "chw";\r
+\r
+                               // If there is a CHI file present (this file includes the internal system files for the current chm file)\r
+                               if( File.Exists(sCHIName) )\r
+                               {\r
+                                       _chiFileName = sCHIName;\r
+                               \r
+                                       ReadFile(_chiFileName, HtmlHelpFileType.CHI);\r
+                               }\r
+\r
+                               // If there is a CHW file present (this file includes the internal binary index of the help)\r
+                               if(( File.Exists(sCHWName) ) && (!_onlySystem) )\r
+                               {\r
+                                       _chwFileName = sCHWName;\r
+                               \r
+                                       ReadFile(_chwFileName, HtmlHelpFileType.CHW);\r
+                               }\r
+\r
+                               // If there is a CHQ file present (this file includes the fulltext-search data)\r
+                               if(( File.Exists(sCHQName) ) && (!_onlySystem) )\r
+                               {\r
+                                       _chqFileName = sCHQName;\r
+                               \r
+                                       ReadFile(_chqFileName, HtmlHelpFileType.CHQ);\r
+                               }\r
+\r
+                               ReadFile(chmFile, HtmlHelpFileType.CHM);\r
+\r
+                               if(_mustWriteDump)\r
+                               {                                       \r
+                                       _mustWriteDump = !SaveDump(dmpInfo);\r
+\r
+                               }\r
+\r
+                               // check the default-topic setting\r
+                               if(_systemFile.DefaultTopic.Length > 0)\r
+                               {\r
+                                       CHMStream.CHMStream iw=null;\r
+                                       iw = new CHMStream.CHMStream(chmFile);\r
+                                       _currentWrapper=iw;\r
+\r
+                                       // tryo to open the topic file\r
+                                       MemoryStream fileObject = iw.OpenStream( _systemFile.DefaultTopic);\r
+                                       if( fileObject != null)\r
+                                       {\r
+                                               // if succeed, the topic default topic is OK\r
+                                               fileObject.Close();\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               // set the first topic of the toc-tree as default topic\r
+                                               if(_toc.Count > 0)\r
+                                               {\r
+                                                       _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local );\r
+                                               }\r
+                                       }\r
+                                       _currentWrapper=null;\r
+                               } \r
+                               else \r
+                               {\r
+                                       // set the first topic of the toc-tree as default topic\r
+                                       if(_toc.Count > 0)\r
+                                       {\r
+                                               _systemFile.SetDefaultTopic( ((TOCItem) _toc[0]).Local );\r
+                                       }\r
+                               }\r
+\r
+                               _chmFileInfo = new ChmFileInfo(this);\r
+                       } \r
+                       else \r
+                       {\r
+                               throw new ArgumentException("File '" + chmFile + "' not found !", "chmFile");\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Read a IStorage file\r
+               /// </summary>\r
+               /// <param name="fname">filename</param>\r
+               /// <param name="type">type of file</param>\r
+               private void ReadFile(string fname, HtmlHelpFileType type)\r
+               {\r
+                       CHMStream.CHMStream iw=null;\r
+                       iw=new CHMStream.CHMStream();                   \r
+                       iw.OpenCHM(fname);\r
+                       _currentWrapper=iw;\r
+                       MemoryStream fileObject=null;                   \r
+\r
+                       // ITStorageWrapper iw = null;\r
+\r
+                       // Open the internal chm system files and parse their content\r
+                       // FileObject fileObject = null;\r
+                       // iw = new ITStorageWrapper(fname, false);                     \r
+\r
+                       if( (type != HtmlHelpFileType.CHQ) && (type != HtmlHelpFileType.CHW) )\r
+                       {                               \r
+                               fileObject = iw.OpenStream("#SYSTEM");\r
+                               if ((fileObject != null) && (fileObject.Length>0))\r
+                                       _systemFile = new CHMSystem(fileObject.ToArray(), this);                                                                        \r
+\r
+                               fileObject = iw.OpenStream("#IDXHDR");\r
+                               if ((fileObject != null) && (fileObject.Length>0))\r
+                                       _idxhdrFile = new CHMIdxhdr(fileObject.ToArray(), this);                                        \r
+                               \r
+                               // try to read Dump\r
+                               if((!_dumpRead)&&(CheckDump(_dmpInfo))&&(_dumpReadTrys==0))\r
+                               {\r
+                                       _dumpReadTrys++;\r
+                                       _dumpRead = LoadDump(_dmpInfo);                                 \r
+                               }\r
+\r
+                               if( (!_dumpRead)||(!_dmpInfo.DumpStrings) )\r
+                               {\r
+                                       fileObject = iw.OpenStream( "#STRINGS");\r
+                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                               _stringsFile = new CHMStrings(fileObject.ToArray(), this);\r
+                               }\r
+\r
+                               if( (!_dumpRead)||(!_dmpInfo.DumpUrlStr) )\r
+                               {\r
+                                       fileObject = iw.OpenStream( "#URLSTR");\r
+                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                               _urlstrFile = new CHMUrlstr(fileObject.ToArray(), this);\r
+                               }\r
+\r
+                               if( (!_dumpRead)||(!_dmpInfo.DumpUrlTbl) )\r
+                               {\r
+                                       fileObject = iw.OpenStream( "#URLTBL");\r
+                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                               _urltblFile = new CHMUrltable(fileObject.ToArray(), this);\r
+                               }\r
+\r
+                               if( (!_dumpRead)||(!_dmpInfo.DumpTopics) )\r
+                               {\r
+                                       fileObject = iw.OpenStream( "#TOPICS");\r
+                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                               _topicsFile = new CHMTopics(fileObject.ToArray(), this);\r
+                               }\r
+\r
+                               if(!_onlySystem)\r
+                               {\r
+                                       if( (!_dumpRead)||(!_dmpInfo.DumpBinaryTOC) )\r
+                                       {\r
+                                               fileObject = iw.OpenStream( "#TOCIDX");\r
+                                               if( (fileObject != null) && (fileObject.Length>0) && (_systemFile.BinaryTOC) )\r
+                                               {\r
+                                                       _tocidxFile = new CHMTocidx(fileObject.ToArray(), this);\r
+                                                       _toc = _tocidxFile.TOC;                                                 \r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               if( (_systemFile != null) && (!_onlySystem) )\r
+                               {\r
+                                       if(!_systemFile.BinaryTOC)\r
+                                       {\r
+                                               if( (!_dumpRead)||(!_dmpInfo.DumpTextTOC) )\r
+                                               {\r
+                                                       CHMStream.chmUnitInfo HHCInfo=iw.GetFileInfoByExtension(".hhc");\r
+                                                       if (HHCInfo!=null)\r
+                                                       {\r
+                                                               fileObject = iw.OpenStream(HHCInfo);                                                    \r
+                                                               if ((fileObject != null) && (fileObject.Length>0))\r
+                                                               {\r
+                                                                       ASCIIEncoding ascii=new ASCIIEncoding();                        \r
+                                                                       string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length);\r
+\r
+                                                                       _toc = HHCParser.ParseHHC(fileString, this);\r
+                                                               }\r
+\r
+                                                               if(HHCParser.HasMergeLinks)\r
+                                                                       _mergeLinks = HHCParser.MergeItems;\r
+                                                       }                                                       \r
+                                               }\r
+                                       } \r
+                               }\r
+                       }\r
+\r
+                       if( type != HtmlHelpFileType.CHQ ) // no index information in CHQ files (only fulltext search)\r
+                       {\r
+                               if( (_systemFile != null) && (!_onlySystem) )\r
+                               {\r
+                                       if( ! _systemFile.BinaryIndex )\r
+                                       {\r
+                                               if( (!_dumpRead)||(!_dmpInfo.DumpTextIndex) )\r
+                                               {\r
+                                                       fileObject = iw.OpenStream( _systemFile.IndexFile);\r
+                                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                                       {\r
+\r
+                                                               string fileString = this.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);\r
+                                                               // string fileString = fileObject.ReadFromFile(this.TextEncoding);\r
+                                                               fileObject.Close();\r
+\r
+                                                               _indexKLinks = HHKParser.ParseHHK(fileString, this);\r
+                                                               _indexKLinks.Sort();\r
+                                                       }\r
+                                               }\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               if( (!_dumpRead)||(!_dmpInfo.DumpBinaryIndex) )\r
+                                               {\r
+                                                       fileObject=iw.OpenStream(@"$WWKeywordLinks\BTree");\r
+                                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                                       {\r
+                                                               _kLinks = new CHMBtree(fileObject.ToArray(), this);\r
+                                                               _indexKLinks = _kLinks.IndexList;\r
+                                                       }\r
+\r
+                                                       fileObject =iw.OpenStream(@"$WWAssociativeLinks\BTree");\r
+                                                       if ((fileObject != null) && (fileObject.Length>0))\r
+                                                       {                                                                       \r
+                                                               _aLinks = new CHMBtree(fileObject.ToArray(), this);\r
+                                                               _indexALinks = _aLinks.IndexList;\r
+                                                               _indexALinks.Sort();                                                                    \r
+                                                       }                                                       \r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if( (type != HtmlHelpFileType.CHI) && (type != HtmlHelpFileType.CHW) )\r
+                       {\r
+                               if( (_systemFile != null) && (!_onlySystem) )\r
+                               {\r
+                                       if( _systemFile.FullTextSearch)\r
+                                       {\r
+                                               if( (!_dumpRead)||(!_dmpInfo.DumpFullText) )\r
+                                               {\r
+                                                       fileObject = iw.OpenStream("$FIftiMain");\r
+                                                       if(( fileObject != null) && (fileObject .Length>0))\r
+                                                               _ftSearcher = new FullTextEngine(fileObject .ToArray(), this);                                                  \r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       _currentWrapper=null;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Enumerates the files in the chm storage and gets all files matching a given extension.\r
+               /// </summary>\r
+               /// <param name="extension">extension to return</param>\r
+               /// <returns>Returns an arraylist of filenames or null if nothing found</returns>\r
+               /// <remarks>On large CHMs, enumerations are very slow. Only use it if necessary !</remarks>\r
+               internal ArrayList EnumFilesByExtension(string extension)\r
+               {\r
+                       ArrayList arrRet = new ArrayList();\r
+\r
+                       CHMStream.CHMStream iw = null;\r
+                       if(_currentWrapper == null)\r
+                               iw = new CHMStream.CHMStream(_chmFileName);\r
+                       else\r
+                               iw = _currentWrapper;\r
+\r
+                       arrRet=iw.GetFileListByExtenstion(extension);\r
+                       \r
+                       if(arrRet.Count > 0)\r
+                               return arrRet;\r
+\r
+                       return null;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Searches an TOC entry using the local\r
+               /// </summary>\r
+               /// <param name="local">local to search</param>\r
+               /// <returns>Returns the TOC item</returns>\r
+               internal TOCItem GetTOCItemByLocal(string local)\r
+               {\r
+                       return GetTOCItemByLocal(this.TOC, local);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Recursively searches an TOC entry using its local\r
+               /// </summary>\r
+               /// <param name="arrTOC">toc level list</param>\r
+               /// <param name="local">local to search</param>\r
+               /// <returns>Returns the TOC item</returns>\r
+               private TOCItem GetTOCItemByLocal(ArrayList arrTOC, string local)\r
+               {\r
+                       TOCItem ret = null;\r
+                       foreach(TOCItem curItem in arrTOC)\r
+                       {\r
+                               string scL = curItem.Local.ToLower();\r
+                               string sL = local.ToLower();\r
+\r
+                               while(scL[0]=='/') // delete prefixing '/'\r
+                                       scL = scL.Substring(1);\r
+\r
+                               while(sL[0]=='/') // delete prefixing '/'\r
+                                       sL = sL.Substring(1);\r
+\r
+                               if(scL == sL)\r
+                                       return curItem;\r
+\r
+                               if(curItem.Children.Count > 0)\r
+                               {\r
+                                       ret =  GetTOCItemByLocal(curItem.Children, local);\r
+                                       if(ret != null)\r
+                                               return ret;\r
+                               }\r
+                       }\r
+\r
+                       return ret;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Removes a TOCItem from the toc\r
+               /// </summary>\r
+               /// <param name="rem">item to remove</param>\r
+               /// <returns>Returns true if removed</returns>\r
+               internal bool RemoveTOCItem(TOCItem rem)\r
+               {\r
+                       if(rem == null)\r
+                               return false;\r
+\r
+                       return RemoveTOCItem(this.TOC, rem);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Recursively searches a TOCItem and removes it if found\r
+               /// </summary>\r
+               /// <param name="arrTOC">toc level list</param>\r
+               /// <param name="rem">item to remove</param>\r
+               /// <returns>Returns true if removed</returns>\r
+               private bool RemoveTOCItem(ArrayList arrTOC, TOCItem rem)\r
+               {\r
+                       for(int i=0; i<arrTOC.Count;i++)\r
+                       {\r
+                               TOCItem curItem = arrTOC[i] as TOCItem;\r
+\r
+                               if(curItem == rem)\r
+                               {\r
+                                       arrTOC.RemoveAt(i);\r
+                                       return true;\r
+                               }\r
+\r
+                               if(curItem.Children.Count > 0)\r
+                               {\r
+                                       bool bRem = RemoveTOCItem(curItem.Children, rem);\r
+                                       if(bRem)\r
+                                               return true;\r
+                               }\r
+                       }\r
+\r
+                       return false;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Returns true if the HtmlHelpSystem instance contains 1 or more information types\r
+               /// </summary>\r
+               public bool HasInformationTypes\r
+               {\r
+                       get { return (_informationTypes.Count>0); }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Returns true if the HtmlHelpSystem instance contains 1 or more categories\r
+               /// </summary>\r
+               public bool HasCategories\r
+               {\r
+                       get { return (_categories.Count>0); }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets an ArrayList of <see cref="InformationType">InformationType</see> items\r
+               /// </summary>\r
+               public ArrayList InformationTypes\r
+               {\r
+                       get { return _informationTypes; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets an ArrayList of <see cref="Category">Category</see> items\r
+               /// </summary>\r
+               public ArrayList Categories\r
+               {\r
+                       get { return _categories; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the information type specified by its name\r
+               /// </summary>\r
+               /// <param name="name">name of the information type to receive</param>\r
+               /// <returns>Returns the Instance for the name or null if not found</returns>\r
+               public InformationType GetInformationType(string name)\r
+               {\r
+                       if(HasInformationTypes)\r
+                       {\r
+                               for(int i=0; i<_informationTypes.Count;i++)\r
+                               {\r
+                                       InformationType iT = _informationTypes[i] as InformationType;\r
+\r
+                                       if(iT.Name == name)\r
+                                               return iT;\r
+                               }\r
+                       }\r
+\r
+                       return null;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the category specifiyd by its name\r
+               /// </summary>\r
+               /// <param name="name">name of the category</param>\r
+               /// <returns>Returns the Instance for the name or null if not found</returns>\r
+               public Category GetCategory(string name)\r
+               {\r
+                       if(HasCategories)\r
+                       {\r
+                               for(int i=0; i<_categories.Count;i++)\r
+                               {\r
+                                       Category cat = _categories[i] as Category;\r
+\r
+                                       if(cat.Name == name)\r
+                                               return cat;\r
+                               }\r
+                       }\r
+\r
+                       return null;\r
+               }\r
+\r
+               #region Dumping methods\r
+               \r
+               /// <summary>\r
+               /// Checks if a dump for this file exists and if it can be read\r
+               /// </summary>\r
+               /// <param name="dmpInfo">dumping info class</param>\r
+               /// <returns>true if it can be read</returns>\r
+               private bool CheckDump(DumpingInfo dmpInfo)\r
+               {\r
+                       if(_dumpReadTrys<=0)\r
+                               _mustWriteDump = false;\r
+\r
+                       if(_onlySystem)\r
+                               return false;\r
+\r
+                       if( dmpInfo != null )\r
+                       {\r
+                               if(_dumpReadTrys > 0)\r
+                                       return _mustWriteDump;\r
+\r
+                               _mustWriteDump = !dmpInfo.DumpExists;\r
+                               return !_mustWriteDump;\r
+                       }\r
+\r
+                       return false;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Saves the the toc and index into a data dump\r
+               /// </summary>\r
+               /// <param name="dmpInfo">dumping info</param>\r
+               /// <returns>true if succeed</returns>\r
+               private bool SaveDump(DumpingInfo dmpInfo)\r
+               {\r
+                       if(dmpInfo == null)\r
+                               return false;\r
+\r
+                       bool bRet = false;\r
+\r
+\r
+                       BinaryWriter writer = dmpInfo.Writer;\r
+\r
+                       int nCnt = 0;\r
+                       try\r
+                       {\r
+                               Debug.WriteLine("writing dump-file header");\r
+                               FileInfo fi = new FileInfo(_chmFileName);\r
+                               string ftime = fi.LastWriteTime.ToString("dd.MM.yyyy HH:mm:ss.ffffff");\r
+\r
+                               writer.Write("HtmlHelpSystem dump file 1.0");\r
+                               writer.Write(ftime);\r
+                               writer.Write(_textEncoding.CodePage);\r
+\r
+                               // strings dumping\r
+                               if(dmpInfo.DumpStrings)\r
+                               {\r
+                                       writer.Write(true); // data should be in dump\r
+\r
+                                       if(_stringsFile==null)\r
+                                       {\r
+                                               writer.Write(false); // data not supported by the chm\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               Debug.WriteLine("writing #STRINGS");\r
+                                               writer.Write(true); // data supported and following\r
+                                               _stringsFile.Dump(ref writer);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       writer.Write(false); // data is not in dump\r
+                               }\r
+\r
+                               // urlstr dumping\r
+                               if(dmpInfo.DumpUrlStr)\r
+                               {\r
+                                       writer.Write(true);\r
+\r
+                                       if(_urlstrFile==null)\r
+                                       {\r
+                                               writer.Write(false);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               Debug.WriteLine("writing #URLSTR");\r
+                                               writer.Write(true);\r
+                                               _urlstrFile.Dump(ref writer);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       writer.Write(false);\r
+                               }\r
+\r
+                               // urltbl dumping\r
+                               if(dmpInfo.DumpUrlTbl)\r
+                               {\r
+                                       writer.Write(true);\r
+\r
+                                       if(_urltblFile==null)\r
+                                       {\r
+                                               writer.Write(false);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               Debug.WriteLine("writing #URLTBL");\r
+                                               writer.Write(true);\r
+                                               _urltblFile.Dump(ref writer);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       writer.Write(false);\r
+                               }\r
+\r
+                               // topics dumping\r
+                               if(dmpInfo.DumpTopics)\r
+                               {\r
+                                       writer.Write(true);\r
+\r
+                                       if(_topicsFile==null)\r
+                                       {\r
+                                               writer.Write(false);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               Debug.WriteLine("writing #TOPICS");\r
+                                               writer.Write(true);\r
+                                               _topicsFile.Dump(ref writer);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       writer.Write(false);\r
+                               }\r
+\r
+                               // ftsearch dumping\r
+                               if(dmpInfo.DumpFullText)\r
+                               {\r
+                                       writer.Write(true);\r
+\r
+                                       if(_ftSearcher==null)\r
+                                       {\r
+                                               writer.Write(false);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               Debug.WriteLine("writing $FIftiMain");\r
+                                               writer.Write(true);\r
+                                               _ftSearcher.Dump(ref writer);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       writer.Write(false);\r
+                               }\r
+\r
+                               // TOC dumping\r
+                               bool bWriteTOC = false;\r
+\r
+                               if( (_systemFile.BinaryTOC) && (dmpInfo.DumpBinaryTOC) )\r
+                               {\r
+                                       Debug.WriteLine("writing binary TOC");\r
+                                       bWriteTOC = true;\r
+                               }\r
+\r
+                               if( (!_systemFile.BinaryTOC) && (dmpInfo.DumpTextTOC) )\r
+                               {\r
+                                       Debug.WriteLine("writing text-based TOC");\r
+                                       bWriteTOC = true;\r
+                               }\r
+\r
+                               writer.Write(bWriteTOC);\r
+\r
+                               if(bWriteTOC)\r
+                               {\r
+                                       // write table of contents\r
+                                       writer.Write( _toc.Count );\r
+\r
+                                       for(nCnt=0; nCnt < _toc.Count; nCnt++)\r
+                                       {\r
+                                               TOCItem curItem = ((TOCItem)(_toc[nCnt]));\r
+                                               curItem.Dump( ref writer );\r
+                                       }\r
+                               }\r
+\r
+                               // Index dumping\r
+                               bool bWriteIdx = false;\r
+\r
+                               if( (_systemFile.BinaryIndex) && (dmpInfo.DumpBinaryIndex) )\r
+                               {\r
+                                       Debug.WriteLine("writing binary index");\r
+                                       bWriteIdx = true;\r
+                               }\r
+\r
+                               if( (!_systemFile.BinaryIndex) && (dmpInfo.DumpTextIndex) )\r
+                               {\r
+                                       Debug.WriteLine("writing text-based index");\r
+                                       bWriteIdx = true;\r
+                               }\r
+\r
+                               writer.Write(bWriteIdx);\r
+\r
+                               if(bWriteIdx)\r
+                               {\r
+                                       // write index\r
+                                       writer.Write( _indexALinks.Count );\r
+                                       for(nCnt=0; nCnt < _indexALinks.Count; nCnt++)\r
+                                       {\r
+                                               IndexItem curItem = ((IndexItem)(_indexALinks[nCnt]));\r
+                                               curItem.Dump( ref writer );\r
+                                       }\r
+\r
+                                       writer.Write( _indexKLinks.Count );\r
+                                       for(nCnt=0; nCnt < _indexKLinks.Count; nCnt++)\r
+                                       {\r
+                                               IndexItem curItem = ((IndexItem)(_indexKLinks[nCnt]));\r
+                                               curItem.Dump( ref writer );\r
+                                       }\r
+                               }\r
+\r
+                               // Information types dumping\r
+                               writer.Write( _informationTypes.Count );\r
+\r
+                               Debug.WriteLine("writing " + _informationTypes.Count.ToString() + " information types");\r
+\r
+                               for(nCnt=0; nCnt<_informationTypes.Count;nCnt++)\r
+                               {\r
+                                       InformationType curType = _informationTypes[nCnt] as InformationType;\r
+                                       \r
+                                       curType.Dump(ref writer);\r
+                               }\r
+\r
+                               // Categories dumping\r
+                               writer.Write( _categories.Count );\r
+\r
+                               Debug.WriteLine("writing " + _categories.Count.ToString() + " categories");\r
+\r
+                               for(nCnt=0; nCnt<_categories.Count; nCnt++)\r
+                               {\r
+                                       Category curCat = _categories[nCnt] as Category;\r
+\r
+                                       curCat.Dump( ref writer);\r
+                               }\r
+\r
+                               bRet=true;\r
+                       }\r
+                       finally\r
+                       {\r
+                               dmpInfo.SaveData();\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Parses a HHC file which is located in the current CHM.\r
+               /// </summary>\r
+               /// <param name="hhcFile">hhc file to parse</param>\r
+               /// <returns>an arraylist with toc items</returns>\r
+               public ArrayList ParseHHC(string hhcFile)\r
+               {\r
+                       ArrayList arrRet = new ArrayList();\r
+                       \r
+                       CHMStream.CHMStream iw=null;\r
+                       iw=new CHMStream.CHMStream();                   \r
+                       iw.OpenCHM(_chmFileName);                       \r
+                       MemoryStream fileObject=null;                   \r
+\r
+                       fileObject = iw.OpenStream(hhcFile);\r
+                       if( fileObject != null)\r
+                       {       \r
+                               ASCIIEncoding ascii=new ASCIIEncoding();                        \r
+                               string fileString =ascii.GetString(fileObject.ToArray(),0,(int)fileObject.Length);                              \r
+                               fileObject.Close();\r
+\r
+                               arrRet = HHCParser.ParseHHC(fileString, this);\r
+\r
+                               if(HHCParser.HasMergeLinks)\r
+                               {\r
+                                       foreach(TOCItem curItem in HHCParser.MergeItems)\r
+                                       {\r
+                                               _mergeLinks.Add(curItem);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       return arrRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Loads the toc and index from a data dump\r
+               /// </summary>\r
+               /// <param name="dmpInfo">dumping info</param>\r
+               /// <returns>true if succeed</returns>\r
+               private bool LoadDump(DumpingInfo dmpInfo)\r
+               {\r
+                       if(dmpInfo == null)\r
+                               return false;\r
+\r
+                       bool bRet = false;\r
+\r
+                       try\r
+                       {\r
+                               BinaryReader reader = dmpInfo.Reader;\r
+\r
+                               if(reader == null)\r
+                               {\r
+                                       Debug.WriteLine("No reader returned !");\r
+                                       dmpInfo.SaveData(); // closes the dump\r
+                                       _mustWriteDump = true;\r
+                                       return false;\r
+                               }\r
+\r
+                               int nCnt = 0;\r
+\r
+                               Debug.WriteLine("reading dump-file header");\r
+                               FileInfo fi = new FileInfo(_chmFileName);\r
+                               string ftime = fi.LastWriteTime.ToString("dd.MM.yyyy HH:mm:ss.ffffff");\r
+\r
+                               string header = reader.ReadString();\r
+\r
+                               if( header != "HtmlHelpSystem dump file 1.0")\r
+                               {\r
+                                       Debug.WriteLine("Unsupported dump-file format !");\r
+                                       dmpInfo.SaveData(); // closes the dump\r
+                                       _mustWriteDump = true;\r
+                                       return false;\r
+                               }\r
+\r
+                               string ftimecheck = reader.ReadString();\r
+\r
+                               reader.ReadInt32(); // codepage, we'll use the same as for the chm file which is already set.\r
+\r
+//                             if(ftimecheck != ftime)\r
+//                             {\r
+//                                     Debug.WriteLine("Dump is out of date (CHM file changed during last dump creation) !");\r
+//                                     dmpInfo.SaveData(); // closes the dump\r
+//                                     _mustWriteDump = true;\r
+//                                     return false; // force reload\r
+//                             }\r
+                               \r
+\r
+                               bool bFlag=false;  // true if data should be in dump\r
+                               bool bFlagSupp=false; // false if data is not supported by the chm\r
+\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       bFlagSupp = reader.ReadBoolean();\r
+\r
+                                       if(!dmpInfo.DumpStrings)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #STRINGS found but not expected !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(bFlagSupp)\r
+                                       {\r
+                                               Debug.WriteLine("reading #STRINGS");\r
+                                               _stringsFile = new CHMStrings();\r
+                                               _stringsFile.SetCHMFile(this);\r
+                                               _stringsFile.ReadDump(ref reader);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       if(dmpInfo.DumpStrings)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #STRINGS expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       bFlagSupp = reader.ReadBoolean();\r
+\r
+                                       if(!dmpInfo.DumpUrlStr)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #URLSTR found but not expected !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(bFlagSupp)\r
+                                       {\r
+                                               Debug.WriteLine("reading #URLSTR");\r
+                                               _urlstrFile = new CHMUrlstr();\r
+                                               _urlstrFile.SetCHMFile(this);\r
+                                               _urlstrFile.ReadDump(ref reader);\r
+                                       }\r
+                               }\r
+                               else \r
+                               {\r
+                                       if(dmpInfo.DumpUrlStr)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #URLSTR expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       bFlagSupp = reader.ReadBoolean();\r
+\r
+                                       if(!dmpInfo.DumpUrlTbl)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #URLTBL found but not expected !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(bFlagSupp)\r
+                                       {\r
+                                               Debug.WriteLine("reading #URLTBL");\r
+                                               _urltblFile = new CHMUrltable();\r
+                                               _urltblFile.SetCHMFile(this);\r
+                                               _urltblFile.ReadDump(ref reader);\r
+                                       }\r
+                               }\r
+                               else \r
+                               {\r
+                                       if(dmpInfo.DumpUrlTbl)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #URLTBL expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       bFlagSupp = reader.ReadBoolean();\r
+\r
+                                       if(!dmpInfo.DumpTopics)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #TOPICS found but not expected !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(bFlagSupp)\r
+                                       {\r
+                                               Debug.WriteLine("reading #TOPICS");\r
+                                               _topicsFile = new CHMTopics();\r
+                                               _topicsFile.SetCHMFile(this);\r
+                                               _topicsFile.ReadDump(ref reader);\r
+                                       }\r
+                               }\r
+                               else \r
+                               {\r
+                                       if(dmpInfo.DumpTopics)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped #TOPICS expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       bFlagSupp = reader.ReadBoolean();\r
+\r
+                                       if(!dmpInfo.DumpFullText)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped $FIftiMain found but not expected !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(bFlagSupp)\r
+                                       {\r
+                                               Debug.WriteLine("reading $FIftiMain");\r
+                                               _ftSearcher = new FullTextEngine();\r
+                                               _ftSearcher.SetCHMFile(this);\r
+                                               _ftSearcher.ReadDump(ref reader);\r
+                                       }\r
+                               }\r
+                               else \r
+                               {\r
+                                       if(dmpInfo.DumpFullText)\r
+                                       {\r
+                                               Debug.WriteLine("Dumped $FIftiMain expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               // read table of contents\r
+                               _toc.Clear();\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       if((_systemFile.BinaryTOC)&&(!dmpInfo.DumpBinaryTOC))\r
+                                       {\r
+                                               Debug.WriteLine("Binary TOC expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       } \r
+\r
+                                       if((!_systemFile.BinaryTOC)&&(!dmpInfo.DumpTextTOC))\r
+                                       {\r
+                                               Debug.WriteLine("Text-based TOC expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(_systemFile.BinaryTOC)\r
+                                               Debug.WriteLine("reading binary TOC");\r
+                                       else\r
+                                               Debug.WriteLine("reading text-based TOC");\r
+\r
+                                       int nTocCnt = reader.ReadInt32();\r
+\r
+                                       for(nCnt=0; nCnt < nTocCnt; nCnt++)\r
+                                       {\r
+                                               TOCItem item = new TOCItem();\r
+                                               item.AssociatedFile = this;\r
+                                               item.ChmFile = _chmFileName;\r
+                                               item.ReadDump(ref reader);\r
+                                               if(item.MergeLink.Length > 0)\r
+                                                       _mergeLinks.Add(item);\r
+\r
+                                               _toc.Add(item);\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       if((_systemFile.BinaryTOC)&&(dmpInfo.DumpBinaryTOC))\r
+                                       {\r
+                                               Debug.WriteLine("Binary TOC expected but no TOC dump !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       } \r
+\r
+                                       if((!_systemFile.BinaryTOC)&&(dmpInfo.DumpTextTOC))\r
+                                       {\r
+                                               Debug.WriteLine("Text-based TOC expected but no TOC dump !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               // read index\r
+                               _indexALinks.Clear();\r
+                               _indexKLinks.Clear();\r
+\r
+                               bFlag = reader.ReadBoolean();\r
+\r
+                               if(bFlag)\r
+                               {\r
+                                       if((_systemFile.BinaryIndex)&&(!dmpInfo.DumpBinaryIndex))\r
+                                       {\r
+                                               Debug.WriteLine("Binary index expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if((!_systemFile.BinaryIndex)&&(!dmpInfo.DumpTextIndex))\r
+                                       {\r
+                                               Debug.WriteLine("Binary index expected but not found !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+\r
+                                       if(_systemFile.BinaryIndex)\r
+                                               Debug.WriteLine("reading binary index");\r
+                                       else\r
+                                               Debug.WriteLine("reading text-based index");\r
+\r
+                                       int nIndxaCnt = reader.ReadInt32();\r
+\r
+                                       for(nCnt=0; nCnt < nIndxaCnt; nCnt++)\r
+                                       {\r
+                                               IndexItem item = new IndexItem();\r
+                                               item.ChmFile = this;\r
+                                               item.ReadDump(ref reader);\r
+                                               _indexALinks.Add(item);\r
+                                       }\r
+\r
+                               \r
+                                       int nIndxkCnt = reader.ReadInt32();\r
+\r
+                                       for(nCnt=0; nCnt < nIndxkCnt; nCnt++)\r
+                                       {\r
+                                               IndexItem item = new IndexItem();\r
+                                               item.ChmFile = this;\r
+                                               item.ReadDump(ref reader);\r
+                                               _indexKLinks.Add(item);\r
+                                       }\r
+                               }\r
+                               else \r
+                               {\r
+                                       if((_systemFile.BinaryIndex)&&(dmpInfo.DumpBinaryIndex))\r
+                                       {\r
+                                               Debug.WriteLine("Binary index expected but no index in dump !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       } \r
+\r
+                                       if((!_systemFile.BinaryIndex)&&(dmpInfo.DumpTextIndex))\r
+                                       {\r
+                                               Debug.WriteLine("Text-based index expected but no index dump !");\r
+                                               dmpInfo.SaveData(); // closes the dump\r
+                                               _mustWriteDump = true;\r
+                                               return false; // force reload\r
+                                       }\r
+                               }\r
+\r
+                               // read information types from dump\r
+                               int nITCnt = reader.ReadInt32();\r
+\r
+                               Debug.WriteLine("Reading " + nITCnt.ToString() + " information types from dump !");\r
+\r
+                               for(nCnt=0; nCnt<nITCnt; nCnt++)\r
+                               {\r
+                                       InformationType newType = new InformationType();\r
+                                       newType.ReadDump(ref reader);\r
+\r
+                                       if( SystemInstance.GetInformationType( newType.Name ) != null)\r
+                                       {\r
+                                               // information type of this name already exists in the helpsystem\r
+                                               InformationType sysType = SystemInstance.GetInformationType( newType.Name );\r
+                                               _informationTypes.Add(sysType);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               _informationTypes.Add( newType );\r
+                                       }\r
+                               }\r
+\r
+                               // read categories from dump\r
+                               int nCCnt = reader.ReadInt32();\r
+\r
+                               Debug.WriteLine("Reading " + nITCnt.ToString() + " categories from dump !");\r
+\r
+                               for(nCnt=0; nCnt<nCCnt; nCnt++)\r
+                               {\r
+                                       Category newCat = new Category();\r
+                                       newCat.ReadDump(ref reader, this);\r
+\r
+                                       if( SystemInstance.GetCategory( newCat.Name ) != null)\r
+                                       {\r
+                                               // category of this name already exists in the helpsystem\r
+                                               Category sysCat = SystemInstance.GetCategory( newCat.Name );\r
+\r
+                                               sysCat.MergeInfoTypes( newCat );\r
+                                               _categories.Add( sysCat );\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               _categories.Add( newCat );\r
+                                       }\r
+                               }\r
+\r
+                               _dumpRead = true;\r
+                               bRet = true;\r
+                       }\r
+                       catch(Exception ex)\r
+                       {\r
+                               Debug.WriteLine("###ERROR :" + ex.Message);\r
+                               _mustWriteDump = true;\r
+                       }\r
+                       finally\r
+                       {\r
+                               dmpInfo.SaveData(); // closes the dump\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               #endregion\r
+\r
+               #region Internal properties\r
+               /// <summary>\r
+               /// Gets the current storage wrapper.\r
+               /// </summary>\r
+               /// <remarks>This property will return not null, if there are currently file read actions running !</remarks>\r
+               internal CHMStream.CHMStream CurrentStorageWrapper\r
+               {\r
+                       get { return _currentWrapper;}\r
+               }\r
+               /// <summary>\r
+               /// Gets/sets the hosting HtmlHelpSystem instance\r
+               /// </summary>\r
+               internal HtmlHelpSystem SystemInstance\r
+               {\r
+                       get { return _systemInstance; }\r
+                       set { _systemInstance = value; }\r
+               }\r
+               /// <summary>\r
+               /// Gets an arraylist of TOC items which contains merg-links to other CHMs\r
+               /// </summary>\r
+               internal ArrayList MergLinks\r
+               {\r
+                       get { return _mergeLinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal system file instance\r
+               /// </summary>\r
+               internal CHMSystem SystemFile\r
+               {\r
+                       get { return _systemFile; }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets the internal idxhdr file instance\r
+               /// </summary>\r
+               internal CHMIdxhdr IdxHdrFile\r
+               {\r
+                       get { return _idxhdrFile; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal strings file instance\r
+               /// </summary>\r
+               internal CHMStrings StringsFile\r
+               {\r
+                       get { return _stringsFile; }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Gets the internal urlstr file instance\r
+               /// </summary>\r
+               internal CHMUrlstr UrlstrFile\r
+               {\r
+                       get { return _urlstrFile; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal urltbl file instance\r
+               /// </summary>\r
+               internal CHMUrltable UrltblFile\r
+               {\r
+                       get { return _urltblFile; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal topics file instance\r
+               /// </summary>\r
+               internal CHMTopics TopicsFile\r
+               {\r
+                       get { return _topicsFile; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal tocidx file instance\r
+               /// </summary>\r
+               internal CHMTocidx TocidxFile\r
+               {\r
+                       get { return _tocidxFile; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal btree file instance for alinks\r
+               /// </summary>\r
+               internal CHMBtree ALinksFile\r
+               {\r
+                       get { return _aLinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal btree file instance for klinks\r
+               /// </summary>\r
+               internal CHMBtree KLinksFile\r
+               {\r
+                       get { return _kLinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets/Sets the text encoding\r
+               /// </summary>\r
+               internal Encoding TextEncoding\r
+               {\r
+                       get { return _textEncoding; }\r
+                       set { _textEncoding = value; }\r
+               }\r
+\r
+               #endregion\r
+\r
+               #region Properties from the #SYSTEM file\r
+               /// <summary>\r
+               /// Gets the file version of the chm file. \r
+               /// 2 for Compatibility=1.0,  3 for Compatibility=1.1\r
+               /// </summary>\r
+               internal int FileVersion\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return 0;\r
+\r
+                               return _systemFile.FileVersion; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the contents file name\r
+               /// </summary>\r
+               internal string ContentsFile\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.ContentsFile; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the index file name\r
+               /// </summary>\r
+               internal string IndexFile\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.IndexFile; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the default help topic\r
+               /// </summary>\r
+               internal string DefaultTopic\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.DefaultTopic; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the title of the help window\r
+               /// </summary>\r
+               internal string HelpWindowTitle\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.Title; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if DBCS is in use\r
+               /// </summary>\r
+               internal bool DBCS\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return false;\r
+\r
+                               return _systemFile.DBCS; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if full-text-search is available\r
+               /// </summary>\r
+               internal bool FullTextSearch\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return false;\r
+\r
+                               return _systemFile.FullTextSearch; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the file has ALinks\r
+               /// </summary>\r
+               internal bool HasALinks\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return false;\r
+\r
+                               return _systemFile.HasALinks; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the file has KLinks\r
+               /// </summary>\r
+               internal bool HasKLinks\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return false;\r
+\r
+                               return _systemFile.HasKLinks; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the default window name\r
+               /// </summary>\r
+               internal string DefaultWindow\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.DefaultWindow; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the file name of the compile file\r
+               /// </summary>\r
+               internal string CompileFile\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.CompileFile; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the chm has a binary index file\r
+               /// </summary>\r
+               internal bool BinaryIndex\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return false;\r
+\r
+                               return _systemFile.BinaryIndex; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the chm has a binary index file\r
+               /// </summary>\r
+               internal string CompilerVersion\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return String.Empty;\r
+\r
+                               return _systemFile.CompilerVersion; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the chm has a binary toc file\r
+               /// </summary>\r
+               internal bool BinaryTOC\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return false;\r
+\r
+                               return _systemFile.BinaryTOC; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the font face of the read font property.\r
+               /// Empty string for default font.\r
+               /// </summary>\r
+               internal string FontFace\r
+               {\r
+                       get\r
+                       {\r
+                               if(_systemFile==null)\r
+                                       return "";\r
+                                       \r
+                               return _systemFile.FontFace; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the font size of the read font property.\r
+               /// 0 for default font size\r
+               /// </summary>\r
+               internal double FontSize\r
+               {\r
+                       get\r
+                       {\r
+                               if(_systemFile==null)\r
+                                       return 0;\r
+                                       \r
+                               return _systemFile.FontSize; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the character set of the read font property\r
+               /// 1 for default\r
+               /// </summary>\r
+               internal int CharacterSet\r
+               {\r
+                       get\r
+                       {\r
+                               if(_systemFile==null)\r
+                                       return 1;\r
+                                       \r
+                               return _systemFile.CharacterSet; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the codepage depending on the read font property\r
+               /// </summary>\r
+               internal int CodePage\r
+               {\r
+                       get\r
+                       {\r
+                               if(_systemFile==null)\r
+                                       return CultureInfo.CurrentCulture.TextInfo.ANSICodePage;\r
+                                       \r
+                               return _systemFile.CodePage; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the assiciated culture info\r
+               /// </summary>\r
+               internal CultureInfo Culture\r
+               {\r
+                       get \r
+                       { \r
+                               if(_systemFile==null)\r
+                                       return CultureInfo.CurrentCulture;\r
+                                       \r
+                               return _systemFile.Culture; \r
+                       }\r
+               }\r
+\r
+               #endregion \r
+\r
+               #region Properties from the #IDXHDR file\r
+               /// <summary>\r
+               /// Gets the number of topic nodes including the contents and index files\r
+               /// </summary>\r
+               internal int NumberOfTopicNodes\r
+               {\r
+                       get \r
+                       {\r
+                               if(_idxhdrFile==null)\r
+                                       return 0;\r
+\r
+                               return _idxhdrFile.NumberOfTopicNodes; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the ImageList string specyfied in the #IDXHDR file.\r
+               /// </summary>\r
+               /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>\r
+               internal string ImageList\r
+               {\r
+                       get \r
+                       {\r
+                               if( (_stringsFile == null) || (_idxhdrFile == null) )\r
+                                       return "";\r
+\r
+                               return _stringsFile[ _idxhdrFile.ImageListOffset ];\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// True if the value of the ImageType param of the \r
+               /// "text/site properties" object of the sitemap contents is "Folder". \r
+               /// </summary>\r
+               /// <remarks>If this is set to true, the help will display folders instead of books</remarks>\r
+               internal bool ImageTypeFolder\r
+               {\r
+                       get \r
+                       { \r
+                               if(_idxhdrFile==null)\r
+                                       return false;\r
+\r
+                               return _idxhdrFile.ImageTypeFolder; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the background setting \r
+               /// </summary>\r
+               internal int Background\r
+               {\r
+                       get \r
+                       { \r
+                               if(_idxhdrFile==null)\r
+                                       return 0;\r
+\r
+                               return _idxhdrFile.Background; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the foreground setting \r
+               /// </summary>\r
+               internal int Foreground\r
+               {\r
+                       get \r
+                       { \r
+                               if(_idxhdrFile==null)\r
+                                       return 0;\r
+\r
+                               return _idxhdrFile.Foreground; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the Font string specyfied in the #IDXHDR file.\r
+               /// </summary>\r
+               /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>\r
+               internal string FontName\r
+               {\r
+                       get \r
+                       {\r
+                               if( (_stringsFile == null) || (_idxhdrFile == null) )\r
+                                       return "";\r
+\r
+                               return _stringsFile[ _idxhdrFile.FontOffset ];\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the FrameName string specyfied in the #IDXHDR file.\r
+               /// </summary>\r
+               /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>\r
+               internal string FrameName\r
+               {\r
+                       get \r
+                       {\r
+                               if( (_stringsFile == null) || (_idxhdrFile == null) )\r
+                                       return "";\r
+\r
+                               return _stringsFile[ _idxhdrFile.FrameNameOffset ];\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the WindowName string specyfied in the #IDXHDR file.\r
+               /// </summary>\r
+               /// <remarks>This property uses the #STRINGS file to extract the string at a given offset.</remarks>\r
+               internal string WindowName\r
+               {\r
+                       get \r
+                       {\r
+                               if( (_stringsFile == null) || (_idxhdrFile == null) )\r
+                                       return "";\r
+\r
+                               return _stringsFile[ _idxhdrFile.WindowNameOffset ];\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets a string array containing the merged file names\r
+               /// </summary>\r
+               internal string[] MergedFiles\r
+               {\r
+                       get\r
+                       {\r
+                               if( (_stringsFile == null) || (_idxhdrFile == null) )\r
+                                       return new string[0];\r
+\r
+                               string[] saRet = new string[ _idxhdrFile.MergedFileOffsets.Count ];\r
+\r
+                               for(int i=0; i < _idxhdrFile.MergedFileOffsets.Count; i++)\r
+                               {\r
+                                       saRet[i] = _stringsFile[ (int)_idxhdrFile.MergedFileOffsets[i] ];\r
+                               }\r
+\r
+                               return saRet;\r
+                       }\r
+               }\r
+               #endregion\r
+\r
+               /// <summary>\r
+               /// Gets the file info associated with this instance\r
+               /// </summary>\r
+               public ChmFileInfo FileInfo\r
+               {\r
+                       get { return _chmFileInfo; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal toc read from the text-based hhc file\r
+               /// </summary>\r
+               public ArrayList TOC\r
+               {\r
+                       get { return _toc; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal index read from the chm file.\r
+               /// </summary>\r
+               public ArrayList IndexKLinks\r
+               {\r
+                       get { return _indexKLinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal index read from the chm file.\r
+               /// </summary>\r
+               public ArrayList IndexALinks\r
+               {\r
+                       get { return _indexALinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the full-text search engine for this file\r
+               /// </summary>\r
+               internal FullTextEngine FullTextSearchEngine\r
+               {\r
+                       get { return _ftSearcher; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the full pathname of the file\r
+               /// </summary>\r
+               public string ChmFilePath\r
+               {\r
+                       get { return _chmFileName; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the full pathname of the chi-file\r
+               /// The file name is zero-length if there is no chi-file\r
+               /// </summary>\r
+               public string ChiFilePath\r
+               {\r
+                       get { return _chiFileName; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the full pathname of the chw-file\r
+               /// The file name is zero-length if there is no chw-file\r
+               /// </summary>\r
+               public string ChwFilePath\r
+               {\r
+                       get { return _chwFileName; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the full pathname of the chq-file\r
+               /// The file name is zero-length if there is no chq-file\r
+               /// </summary>\r
+               public string ChqFilePath\r
+               {\r
+                       get { return _chqFileName; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Forms an URL for the web browser\r
+               /// </summary>\r
+               /// <param name="local">local resource</param>\r
+               /// <returns>a url for the web-browser</returns>\r
+               internal string FormURL(string local)\r
+               {\r
+                       if( (local.ToLower().IndexOf("http://") >= 0) ||\r
+                               (local.ToLower().IndexOf("https://") >= 0) ||\r
+                               (local.ToLower().IndexOf("mailto:") >= 0) ||\r
+                               (local.ToLower().IndexOf("ftp://") >= 0)  ||\r
+                               (local.ToLower().IndexOf("ms-its:") >= 0))                              \r
+                               return local;\r
+\r
+                       return HtmlHelpSystem.UrlPrefix + _chmFileName + "::/" + local;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Implement IDisposable.\r
+               /// </summary>\r
+               public void Dispose()\r
+               {\r
+                       Dispose(true);\r
+                       // This object will be cleaned up by the Dispose method.\r
+                       // Therefore, you should call GC.SupressFinalize to\r
+                       // take this object off the finalization queue \r
+                       // and prevent finalization code for this object\r
+                       // from executing a second time.\r
+                       GC.SuppressFinalize(this);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Dispose(bool disposing) executes in two distinct scenarios. \r
+               /// If disposing equals true, the method has been called directly \r
+               /// or indirectly by a user's code. Managed and unmanaged resources \r
+               /// can be disposed. \r
+               /// If disposing equals false, the method has been called by the \r
+               /// runtime from inside the finalizer and you should not reference  \r
+               /// other objects. Only unmanaged resources can be disposed.\r
+               /// </summary>\r
+               /// <param name="disposing">disposing flag</param>\r
+               private void Dispose(bool disposing)\r
+               {\r
+                       // Check to see if Dispose has already been called.\r
+                       if(!this.disposed)\r
+                       {\r
+                               // If disposing equals true, dispose all managed \r
+                               // and unmanaged resources.\r
+                               if(disposing)\r
+                               {\r
+                                       // Dispose managed resources.\r
+                                       _toc.Clear();\r
+                                       _indexKLinks.Clear();\r
+                                       _indexALinks.Clear();\r
+\r
+                                       if(_systemFile!=null)\r
+                                               _systemFile.Dispose();\r
+\r
+                                       if(_idxhdrFile != null)\r
+                                               _idxhdrFile.Dispose();\r
+\r
+                                       if(_stringsFile != null)\r
+                                               _stringsFile.Dispose();\r
+\r
+                                       if(_urlstrFile != null)\r
+                                               _urlstrFile.Dispose();\r
+\r
+                                       if(_urltblFile != null)\r
+                                               _urltblFile.Dispose();\r
+\r
+                                       if(_topicsFile != null)\r
+                                               _topicsFile.Dispose();\r
+\r
+                                       if(_tocidxFile != null)\r
+                                               _tocidxFile.Dispose();\r
+\r
+                                       if(_kLinks != null)\r
+                                               _kLinks.Dispose();\r
+\r
+                                       if(_aLinks != null)\r
+                                               _aLinks.Dispose();\r
+\r
+                                       if(_ftSearcher != null)\r
+                                               _ftSearcher.Dispose();\r
+\r
+                                       if(_chmFileInfo != null)\r
+                                               _chmFileInfo = null;\r
+                               }\r
+                       }\r
+                       disposed = true;         \r
+               }\r
+\r
+       }\r
+}\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/CHMIdxhdr.cs b/irc/TechBot/CHMLibrary/CHMDecoding/CHMIdxhdr.cs
new file mode 100644 (file)
index 0000000..7ac64ac
--- /dev/null
@@ -0,0 +1,286 @@
+using System;\r
+using System.Collections;\r
+using System.IO;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// The class <c>CHMIdxhdr</c> implements t properties which have been read from the #IDXHDR file.\r
+       /// </summary>\r
+       internal sealed class CHMIdxhdr : IDisposable\r
+       {\r
+               /// <summary>\r
+               /// Internal flag specifying if the object is going to be disposed\r
+               /// </summary>\r
+               private bool disposed = false;\r
+               /// <summary>\r
+               /// Internal member storing the binary file data\r
+               /// </summary>\r
+               private byte[] _binaryFileData = null;\r
+               /// <summary>\r
+               /// Internal member storing the number of topic nodes including the contents and index files\r
+               /// </summary>\r
+               private int _numberOfTopicNodes = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset in the #STRINGS file of the ImageList param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               private int _imageListOffset = 0;\r
+               /// <summary>\r
+               /// True if the value of the ImageType param of the "text/site properties" object of the sitemap contents is "Folder". \r
+               /// </summary>\r
+               private bool _imageTypeFolder = false;\r
+               /// <summary>\r
+               /// Internal member storing the background value\r
+               /// </summary>\r
+               private int _background = 0;\r
+               /// <summary>\r
+               /// Internal member storing the foreground value\r
+               /// </summary>\r
+               private int _foreground = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset in the #STRINGS file of the Font param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               private int _fontOffset = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset in the #STRINGS file of the FrameName param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               private int _frameNameOffset = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset in the #STRINGS file of the WindowName param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               private int _windowNameOffset = 0;\r
+               /// <summary>\r
+               /// Internal member storing the number of merged files\r
+               /// </summary>\r
+               private int _numberOfMergedFiles = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset in the #STRINGS file of the merged file names\r
+               /// </summary>\r
+               private ArrayList _mergedFileOffsets = new ArrayList();\r
+               /// <summary>\r
+               /// Internal member storing the associated chmfile object\r
+               /// </summary>\r
+               private CHMFile _associatedFile = null;\r
+\r
+               /// <summary>\r
+               /// Constructor of the class\r
+               /// </summary>\r
+               /// <param name="binaryFileData">binary file data of the #IDXHDR file</param>\r
+               /// <param name="associatedFile">associated CHMFile instance</param>\r
+               public CHMIdxhdr(byte[] binaryFileData, CHMFile associatedFile)\r
+               {\r
+                       _binaryFileData = binaryFileData;\r
+                       _associatedFile = associatedFile;\r
+                       DecodeData();\r
+               }\r
+\r
+               /// <summary>\r
+               /// Decodes the binary file data and fills the internal properties\r
+               /// </summary>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeData()\r
+               {\r
+                       bool bRet = true;\r
+\r
+                       MemoryStream memStream = new MemoryStream(_binaryFileData);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+\r
+                       int nTemp = 0;\r
+\r
+                       // 4 character T#SM\r
+                       binReader.ReadBytes(4);\r
+                       // unknown timestamp DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // unknown 1\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // number of topic nodes including the contents & index files\r
+                       _numberOfTopicNodes = binReader.ReadInt32();\r
+                       \r
+                       // unknown DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // offset in the strings file\r
+                       _imageListOffset = binReader.ReadInt32();\r
+                       if( _imageListOffset == 0)\r
+                               _imageListOffset = -1; // 0/-1 = none\r
+\r
+                       // unknown DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // 1 if the value of the ImageType param of the "text/site properties" object of the sitemap contents is "Folder". \r
+                       nTemp = binReader.ReadInt32();\r
+                       _imageTypeFolder = (nTemp == 1);\r
+\r
+                       // offset in the strings file\r
+                       _background = binReader.ReadInt32();\r
+                       // offset in the strings file\r
+                       _foreground = binReader.ReadInt32();\r
+\r
+                       // offset in the strings file\r
+                       _fontOffset = binReader.ReadInt32();\r
+\r
+                       // window styles DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+                       // window styles DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // unknown DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // offset in the strings file\r
+                       _frameNameOffset = binReader.ReadInt32();\r
+                       if( _frameNameOffset == 0)\r
+                               _frameNameOffset = -1; // 0/-1 = none\r
+                       // offset in the strings file\r
+                       _windowNameOffset = binReader.ReadInt32();\r
+                       if( _windowNameOffset == 0)\r
+                               _windowNameOffset = -1; // 0/-1 = none\r
+\r
+                       // informations types DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // unknown DWORD\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       // number of merged files in the merged file list DWORD\r
+                       _numberOfMergedFiles = binReader.ReadInt32();\r
+\r
+                       nTemp = binReader.ReadInt32();\r
+\r
+                       for(int i = 0; i < _numberOfMergedFiles; i++)\r
+                       {\r
+                               // DWORD offset value of merged file\r
+                               nTemp = binReader.ReadInt32();\r
+                               \r
+                               if(nTemp > 0)\r
+                                       _mergedFileOffsets.Add(nTemp);\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the number of topic nodes including the contents and index files\r
+               /// </summary>\r
+               public int NumberOfTopicNodes\r
+               {\r
+                       get { return _numberOfTopicNodes; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the offset in the #STRINGS file of the ImageList \r
+               /// param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               public int ImageListOffset\r
+               {\r
+                       get { return _imageListOffset; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// True if the value of the ImageType param of the \r
+               /// "text/site properties" object of the sitemap contents is "Folder". \r
+               /// </summary>\r
+               /// <remarks>If this is set to true, the help will display folders instead of books</remarks>\r
+               public bool ImageTypeFolder\r
+               {\r
+                       get { return _imageTypeFolder; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the background setting \r
+               /// </summary>\r
+               public int Background\r
+               {\r
+                       get { return _background; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the foreground setting \r
+               /// </summary>\r
+               public int Foreground\r
+               {\r
+                       get { return _foreground; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the offset in the #STRINGS file of the Font \r
+               /// param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               public int WindowNameOffset\r
+               {\r
+                       get { return _fontOffset; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the offset in the #STRINGS file of the FrameName \r
+               /// param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               public int FrameNameOffset\r
+               {\r
+                       get { return _frameNameOffset; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the offset in the #STRINGS file of the WindowName \r
+               /// param of the "text/site properties" object of the sitemap contents\r
+               /// </summary>\r
+               public int FontOffset\r
+               {\r
+                       get { return _windowNameOffset; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets an array list of offset numbers in the #STRINGS file of the \r
+               /// merged file names.\r
+               /// </summary>\r
+               public ArrayList MergedFileOffsets\r
+               {\r
+                       get { return _mergedFileOffsets; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Implement IDisposable.\r
+               /// </summary>\r
+               public void Dispose()\r
+               {\r
+                       Dispose(true);\r
+                       // This object will be cleaned up by the Dispose method.\r
+                       // Therefore, you should call GC.SupressFinalize to\r
+                       // take this object off the finalization queue \r
+                       // and prevent finalization code for this object\r
+                       // from executing a second time.\r
+                       GC.SuppressFinalize(this);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Dispose(bool disposing) executes in two distinct scenarios. \r
+               /// If disposing equals true, the method has been called directly \r
+               /// or indirectly by a user's code. Managed and unmanaged resources \r
+               /// can be disposed. \r
+               /// If disposing equals false, the method has been called by the \r
+               /// runtime from inside the finalizer and you should not reference  \r
+               /// other objects. Only unmanaged resources can be disposed.\r
+               /// </summary>\r
+               /// <param name="disposing">disposing flag</param>\r
+               private void Dispose(bool disposing)\r
+               {\r
+                       // Check to see if Dispose has already been called.\r
+                       if(!this.disposed)\r
+                       {\r
+                               // If disposing equals true, dispose all managed \r
+                               // and unmanaged resources.\r
+                               if(disposing)\r
+                               {\r
+                                       // Dispose managed resources.\r
+                                       _binaryFileData = null;\r
+                                       _mergedFileOffsets = null;\r
+                               }\r
+             \r
+                                         \r
+                       }\r
+                       disposed = true;         \r
+               }\r
+       }\r
+}\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/CHMStrings.cs b/irc/TechBot/CHMLibrary/CHMDecoding/CHMStrings.cs
new file mode 100644 (file)
index 0000000..5942d4e
--- /dev/null
@@ -0,0 +1,256 @@
+using System;\r
+using System.IO;\r
+using System.Collections;\r
+using System.Collections.Specialized;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// The class <c>CHMStrings</c> implements a string collection read from the #STRINGS file\r
+       /// </summary>\r
+       internal sealed class CHMStrings : IDisposable\r
+       {\r
+               /// <summary>\r
+               /// Constant specifying the size of the string blocks\r
+               /// </summary>\r
+               private const int STRING_BLOCK_SIZE = 4096;\r
+               /// <summary>\r
+               /// Internal flag specifying if the object is going to be disposed\r
+               /// </summary>\r
+               private bool disposed = false;\r
+               /// <summary>\r
+               /// Internal member storing the binary file data\r
+               /// </summary>\r
+               private byte[] _binaryFileData = null;\r
+               /// <summary>\r
+               /// Internal member storing the string dictionary\r
+               /// </summary>\r
+               private Hashtable _stringDictionary = new Hashtable();\r
+               /// <summary>\r
+               /// Internal member storing the associated chmfile object\r
+               /// </summary>\r
+               private CHMFile _associatedFile = null;\r
+\r
+               /// <summary>\r
+               /// Constructor of the class\r
+               /// </summary>\r
+               /// <param name="binaryFileData">binary file data of the #STRINGS file</param>\r
+               /// <param name="associatedFile">associated chm file</param>\r
+               public CHMStrings(byte[] binaryFileData, CHMFile associatedFile)\r
+               {\r
+                       _binaryFileData = binaryFileData;\r
+                       _associatedFile = associatedFile;\r
+                       DecodeData();\r
+               }\r
+\r
+               \r
+               /// <summary>\r
+               /// Standard constructor\r
+               /// </summary>\r
+               internal CHMStrings()\r
+               {\r
+               }\r
+\r
+               #region Data dumping\r
+               /// <summary>\r
+               /// Dump the class data to a binary writer\r
+               /// </summary>\r
+               /// <param name="writer">writer to write the data</param>\r
+               internal void Dump(ref BinaryWriter writer)\r
+               {\r
+                       writer.Write( _stringDictionary.Count );\r
+\r
+                       if (_stringDictionary.Count != 0)\r
+                       {\r
+                               IDictionaryEnumerator iDictionaryEnumerator = _stringDictionary.GetEnumerator();\r
+                               while (iDictionaryEnumerator.MoveNext())\r
+                               {\r
+                                       DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;\r
+                                       writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );\r
+                                       writer.Write( dictionaryEntry.Value.ToString() );\r
+                               }\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Reads the object data from a dump store\r
+               /// </summary>\r
+               /// <param name="reader">reader to read the data</param>\r
+               internal void ReadDump(ref BinaryReader reader)\r
+               {\r
+                       int nCnt = reader.ReadInt32();\r
+\r
+                       for(int i=0; i<nCnt;i++)\r
+                       {\r
+                               int nKey = reader.ReadInt32();\r
+                               string sValue = reader.ReadString();\r
+                               \r
+                               _stringDictionary[nKey.ToString()] = sValue;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Sets the associated CHMFile instance\r
+               /// </summary>\r
+               /// <param name="associatedFile">instance to set</param>\r
+               internal void SetCHMFile(CHMFile associatedFile)\r
+               {\r
+                       _associatedFile = associatedFile;\r
+               }\r
+               #endregion\r
+\r
+               /// <summary>\r
+               /// Decodes the binary file data and fills the internal properties\r
+               /// </summary>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeData()\r
+               {\r
+                       bool bRet = true;\r
+\r
+                       MemoryStream memStream = new MemoryStream(_binaryFileData);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+       \r
+                       //binReader.ReadByte(); // file starts with a NULL character for 0-based offset indexing\r
+                       \r
+                       int nStringOffset = 0;\r
+                       int nSubsetOffset = 0;\r
+\r
+                       while( (memStream.Position < memStream.Length) && (bRet) )\r
+                       {\r
+                               nStringOffset = (int)memStream.Position;\r
+                               byte [] stringBlock = binReader.ReadBytes(STRING_BLOCK_SIZE);\r
+                               bRet &= DecodeBlock(stringBlock, ref nStringOffset, ref nSubsetOffset);\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Decodes a string block\r
+               /// </summary>\r
+               /// <param name="stringBlock">byte array which represents the string block</param>\r
+               /// <param name="nStringOffset">current string offset number</param>\r
+               /// <param name="nSubsetOffset">reference to a subset variable</param>\r
+               /// <returns>true if succeeded</returns>\r
+               /// <remarks>If a string crosses the end of a block then it will be cut off \r
+               /// without a NT and repeated in full, with a NT, at the start of the next block. \r
+               /// For eg "To customize the appearance of a contents file" might become \r
+               /// "To customize the (block ending)To customize the appearance of a contents file" \r
+               /// when there are 17 bytes left at the end of the block. </remarks>\r
+               private bool DecodeBlock( byte[] stringBlock, ref int nStringOffset, ref int nSubsetOffset)\r
+               {\r
+                       bool bRet = true;\r
+\r
+                       MemoryStream memStream = new MemoryStream(stringBlock);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+\r
+                       while( (memStream.Position < memStream.Length) && (bRet) )\r
+                       {\r
+                               bool bFoundTerminator = false;\r
+\r
+                               int nCurOffset = nStringOffset + (int)memStream.Position;\r
+\r
+                               string sTemp = BinaryReaderHelp.ExtractString(ref binReader, ref bFoundTerminator, 0, true, _associatedFile.TextEncoding);\r
+\r
+                               if(nSubsetOffset != 0)\r
+                               {\r
+                                       _stringDictionary[nSubsetOffset.ToString()] = sTemp.ToString();\r
+                               } \r
+                               else \r
+                               {\r
+                                       _stringDictionary[nCurOffset.ToString()] = sTemp.ToString();\r
+                               }\r
+\r
+                               if( bFoundTerminator )\r
+                               {\r
+                                       nSubsetOffset = 0;\r
+                               } \r
+                               else \r
+                               {\r
+                                       nSubsetOffset = nCurOffset;\r
+                               }\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Indexer which returns the string at a given offset\r
+               /// </summary>\r
+               public string this[int offset]\r
+               {\r
+                       get\r
+                       {\r
+                               if(offset == -1)\r
+                                       return String.Empty;\r
+\r
+                               string sTemp = (string)_stringDictionary[ offset.ToString() ];\r
+\r
+                               if(sTemp == null)\r
+                                       return String.Empty;\r
+\r
+                               return sTemp;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Indexer which returns the string at a given offset\r
+               /// </summary>\r
+               public string this[string offset]\r
+               {\r
+                       get\r
+                       {\r
+                               if(offset == "-1")\r
+                                       return String.Empty;\r
+\r
+                               string sTemp = (string)_stringDictionary[ offset ];\r
+\r
+                               if(sTemp == null)\r
+                                       return String.Empty;\r
+\r
+                               return sTemp;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Implement IDisposable.\r
+               /// </summary>\r
+               public void Dispose()\r
+               {\r
+                       Dispose(true);\r
+                       // This object will be cleaned up by the Dispose method.\r
+                       // Therefore, you should call GC.SupressFinalize to\r
+                       // take this object off the finalization queue \r
+                       // and prevent finalization code for this object\r
+                       // from executing a second time.\r
+                       GC.SuppressFinalize(this);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Dispose(bool disposing) executes in two distinct scenarios. \r
+               /// If disposing equals true, the method has been called directly \r
+               /// or indirectly by a user's code. Managed and unmanaged resources \r
+               /// can be disposed. \r
+               /// If disposing equals false, the method has been called by the \r
+               /// runtime from inside the finalizer and you should not reference  \r
+               /// other objects. Only unmanaged resources can be disposed.\r
+               /// </summary>\r
+               /// <param name="disposing">disposing flag</param>\r
+               private void Dispose(bool disposing)\r
+               {\r
+                       // Check to see if Dispose has already been called.\r
+                       if(!this.disposed)\r
+                       {\r
+                               // If disposing equals true, dispose all managed \r
+                               // and unmanaged resources.\r
+                               if(disposing)\r
+                               {\r
+                                       // Dispose managed resources.\r
+                                       _binaryFileData = null;\r
+                                       _stringDictionary = null;\r
+                               }\r
+                       }\r
+                       disposed = true;         \r
+               }\r
+       }\r
+}\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/CHMSystem.cs b/irc/TechBot/CHMLibrary/CHMDecoding/CHMSystem.cs
new file mode 100644 (file)
index 0000000..042e243
--- /dev/null
@@ -0,0 +1,821 @@
+using System;\r
+using System.Collections;\r
+using System.Diagnostics;\r
+using System.IO;\r
+using System.Text;\r
+using System.Globalization;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// The class <c>CHMSystem</c> reads the #SYSTEM file of the chm and stores its settings\r
+       /// </summary>\r
+       internal sealed class CHMSystem : IDisposable\r
+       {\r
+               /// <summary>\r
+               /// Internal flag specifying if the object is going to be disposed\r
+               /// </summary>\r
+               private bool disposed = false;\r
+               /// <summary>\r
+               /// Internal member storing the binary file data\r
+               /// </summary>\r
+               private byte[] _binaryFileData = null;\r
+               /// <summary>\r
+               /// Internal member storing the file version \r
+               /// </summary>\r
+               private int _fileVersion = 0;\r
+               /// <summary>\r
+               /// Internal member storing the contents file path\r
+               /// </summary>\r
+               private string _contentsFile = "";\r
+               /// <summary>\r
+               /// Internal member storing the index file path\r
+               /// </summary>\r
+               private string _indexFile = "";\r
+               /// <summary>\r
+               /// Internal member storing the default help topic\r
+               /// </summary>\r
+               private string _defaultTopic = "";\r
+               /// <summary>\r
+               /// Internal member storing the help-window title\r
+               /// </summary>\r
+               private string _title = "";\r
+               /// <summary>\r
+               /// Internal flag if dbcs is on\r
+               /// </summary>\r
+               private bool _dbcs = false;\r
+               /// <summary>\r
+               /// Internal flag if fulltext search is enabled\r
+               /// </summary>\r
+               private bool _fullTextSearch = false;\r
+               /// <summary>\r
+               /// Internal flag if KLinks are in the file\r
+               /// </summary>\r
+               private bool _hasKLinks = false;\r
+               /// <summary>\r
+               /// Internal flag if ALinks are in the file\r
+               /// </summary>\r
+               private bool _hasALinks = false;\r
+               /// <summary>\r
+               /// Internal member storing the name of the default window\r
+               /// </summary>\r
+               private string _defaultWindow = "";\r
+               /// <summary>\r
+               /// Internal member storing the filename of the compiled file\r
+               /// </summary>\r
+               private string _compileFile = "";\r
+               /// <summary>\r
+               /// Internal flag storing the offset value of the binary index\r
+               /// </summary>\r
+               private uint _binaryIndexURLTableID = 0;\r
+               /// <summary>\r
+               /// Inernal member storing the compiler version this file was compiled\r
+               /// </summary>\r
+               private string _compilerVersion = "";\r
+               /// <summary>\r
+               /// Internal flag storing the offset value of the binary TOC\r
+               /// </summary>\r
+               private uint _binaryTOCURLTableID = 0;\r
+               /// <summary>\r
+               /// Internal member storing the associated chmfile object\r
+               /// </summary>\r
+               private CHMFile _associatedFile = null;\r
+               /// <summary>\r
+               /// Internal member storing the default fontface, size, charset\r
+               /// </summary>\r
+               private string _defaultFont = "";\r
+               /// <summary>\r
+               /// Internal member storing the culture info of the file\r
+               /// </summary>\r
+               private CultureInfo _culture;\r
+\r
+               /// <summary>\r
+               /// Constructor of the class\r
+               /// </summary>\r
+               /// <param name="binaryFileData">binary file data of the #SYSTEM file</param>\r
+               /// <param name="associatedFile">associated chm file</param>\r
+               public CHMSystem(byte[] binaryFileData, CHMFile associatedFile)\r
+               {\r
+                       _binaryFileData = binaryFileData;\r
+                       _associatedFile = associatedFile;\r
+                       DecodeData();\r
+\r
+                       if(_culture == null)\r
+                       {\r
+                               // Set the text encoder of the chm file to the read charset/codepage\r
+                               _associatedFile.TextEncoding = Encoding.GetEncoding( this.CodePage );\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Decodes the binary file data and fills the internal properties\r
+               /// </summary>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeData()\r
+               {\r
+                       bool bRet = true;\r
+\r
+                       MemoryStream memStream = new MemoryStream(_binaryFileData);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+\r
+                       // First entry = DWORD for version number\r
+                       _fileVersion = (int) binReader.ReadInt32();\r
+\r
+                       while( (memStream.Position < memStream.Length) && (bRet) )\r
+                       {\r
+                               bRet &= DecodeEntry(ref binReader);\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Decodes an #system file entry\r
+               /// </summary>\r
+               /// <param name="binReader">binary reader reference</param>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeEntry(ref BinaryReader binReader)\r
+               {\r
+                       bool bRet = true;\r
+\r
+                       int code = (int) binReader.ReadInt16(); // entry code, WORD\r
+                       int length = (int) binReader.ReadInt16(); // length of entry\r
+\r
+                       switch(code)\r
+                       {\r
+                               case 0:\r
+                               {\r
+                                       _contentsFile = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 1:\r
+                               {\r
+                                       _indexFile = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 2:\r
+                               {\r
+                                       _defaultTopic = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 3:\r
+                               {\r
+                                       _title = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 4:\r
+                               {\r
+                                       int nTemp = 0;\r
+                                       nTemp = binReader.ReadInt32(); // read DWORD LCID\r
+                                       _culture = new CultureInfo(nTemp);\r
+\r
+                                       if(_culture != null)\r
+                                               _associatedFile.TextEncoding = Encoding.GetEncoding(_culture.TextInfo.ANSICodePage);\r
+\r
+                                       nTemp = binReader.ReadInt32(); // read DWORD DBCS\r
+                                       _dbcs = (nTemp == 1);\r
+\r
+                                       nTemp = binReader.ReadInt32(); // read DWORD Fulltext search\r
+                                       _fullTextSearch = (nTemp == 1);\r
+\r
+                                       nTemp = binReader.ReadInt32(); // read DWORD has klinks\r
+                                       _hasKLinks = (nTemp != 0);\r
+\r
+                                       nTemp = binReader.ReadInt32(); // read DWORD has alinks\r
+                                       _hasALinks = (nTemp != 0);\r
+                                       \r
+                                       // read the rest of code 4 (not important for us)\r
+                                       byte[] temp = new byte[length-(5*4)];\r
+                                       temp = binReader.ReadBytes(length-(5*4));\r
+                               };break;\r
+                               case 5:\r
+                               {\r
+                                       _defaultWindow = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 6:\r
+                               {\r
+                                       _compileFile = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 7:\r
+                               {\r
+                                       if(_fileVersion > 2)\r
+                                       {\r
+                                               _binaryIndexURLTableID = (uint) binReader.ReadInt32();\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               byte[] read = binReader.ReadBytes(length);\r
+                                               int i=read.Length;\r
+                                       }\r
+                               };break;\r
+                               case 8:\r
+                               {\r
+                                       // abbreviation (not interresting for us)\r
+                                       byte[] read = binReader.ReadBytes(length);\r
+                                       int i=read.Length;\r
+                               };break;\r
+                               case 9:\r
+                               {\r
+                                       _compilerVersion = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+                               };break;\r
+                               case 10:\r
+                               {\r
+                                       // timestamp of the file (not interresting for us)\r
+                                       byte[] read = binReader.ReadBytes(length);\r
+                                       int i=read.Length;\r
+                               };break;\r
+                               case 11:\r
+                               {\r
+                                       if(_fileVersion > 2)\r
+                                       {\r
+                                               _binaryTOCURLTableID = (uint) binReader.ReadInt32();\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               byte[] read = binReader.ReadBytes(length);\r
+                                               int i=read.Length;\r
+                                       }\r
+                               };break;\r
+                               case 12:\r
+                               {\r
+                                       // number of information bytes\r
+                                       byte[] read = binReader.ReadBytes(length);\r
+                                       int i=read.Length;\r
+                               };break;\r
+                               case 13:\r
+                               {\r
+                                       // copy of file #idxhdr\r
+                                       byte[] read = binReader.ReadBytes(length);\r
+                                       int i=read.Length;\r
+                               };break;\r
+                               case 14:\r
+                               {\r
+                                       // custom tabs for HH viewer\r
+                                       byte[] read = binReader.ReadBytes(length);\r
+                                       int i=read.Length;\r
+                               };break;\r
+                               case 15:\r
+                               {\r
+                                       // a checksum\r
+                                       byte[] read = binReader.ReadBytes(length);\r
+                                       int i=read.Length;\r
+                               };break;\r
+                               case 16:\r
+                               {\r
+                                       // Default Font=string,number,number  \r
+                                       // The string is the name of the font, the first number is the \r
+                                       // point size & the last number is the character set used by the font. \r
+                                       // For acceptable values see *_CHARSET defines in wingdi.h from the \r
+                                       // Windows SDK or the same file in MinGW or Wine. \r
+                                       // Most of the time you will only want to use 0, which is the value for ANSI, \r
+                                       // which is the subset of ASCII used by Windows. \r
+                                       _defaultFont = BinaryReaderHelp.ExtractString(ref binReader,length, 0, true, _associatedFile.TextEncoding);\r
+\r
+                               };break;\r
+                               default:\r
+                               {\r
+                                       byte[] temp = new byte[length];\r
+                                       temp = binReader.ReadBytes(length);\r
+                                       //bRet = false;\r
+                                       int i=temp.Length;\r
+                               };break;\r
+                       }\r
+\r
+                       return bRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Reads all HHC files and checks which one has the global object tag.\r
+               /// This hhc file will be returned as master hhc\r
+               /// </summary>\r
+               /// <param name="hhcTopics">list of topics containing the extension hhc</param>\r
+               /// <param name="TopicItemArrayList">true if the arraylist contains topic items</param>\r
+               /// <returns>the filename of the found master toc</returns>\r
+               private string GetMasterHHC(ArrayList hhcTopics, bool TopicItemArrayList)\r
+               {\r
+                       string sRet = "";\r
+\r
+                       if( (hhcTopics!=null) && (hhcTopics.Count > 0) )\r
+                       {\r
+                               if( TopicItemArrayList )\r
+                               {\r
+                                       if(hhcTopics.Count == 1)\r
+                                       {\r
+                                               sRet = ((TopicEntry)hhcTopics[0]).Locale;\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               foreach(TopicEntry curEntry in hhcTopics)\r
+                                               {\r
+                                                       CHMStream.CHMStream iw=null;\r
+                                                       MemoryStream fileObject=null;                   \r
+\r
+                                                       if( _associatedFile.CurrentStorageWrapper == null)\r
+                                                       {\r
+                                                               iw=new CHMStream.CHMStream();                   \r
+                                                               iw.OpenCHM(_associatedFile.ChmFilePath);                        \r
+                                                       } \r
+                                                       else \r
+                                                       {\r
+                                                               iw = _associatedFile.CurrentStorageWrapper;\r
+                                                       }\r
+\r
+                                                       fileObject = iw.OpenStream(curEntry.Locale);\r
+                                                       if( fileObject != null)\r
+                                                       {\r
+                                                               string fileString =_associatedFile.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);\r
+                                                               fileObject.Close();\r
+\r
+                                                               if( HHCParser.HasGlobalObjectTag(fileString, _associatedFile) )\r
+                                                               {\r
+                                                                       sRet = curEntry.Locale;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       if(hhcTopics.Count == 1)\r
+                                       {\r
+                                               sRet = ((string)hhcTopics[0]);\r
+                                       } \r
+                                       else \r
+                                       {\r
+                                               foreach(string curEntry in hhcTopics)\r
+                                               {\r
+                                                       CHMStream.CHMStream iw=null;\r
+                                                       MemoryStream fileObject=null;                   \r
+\r
+                                                       if( _associatedFile.CurrentStorageWrapper == null)\r
+                                                       {                                                               \r
+                                                               iw=new CHMStream.CHMStream();                   \r
+                                                               iw.OpenCHM(_associatedFile.ChmFilePath);                        \r
+                                                       } \r
+                                                       else \r
+                                                       {\r
+                                                               iw = _associatedFile.CurrentStorageWrapper;\r
+                                                       }\r
+\r
+                                                       fileObject = iw.OpenStream(curEntry);\r
+                                                       if( fileObject != null)\r
+                                                       {\r
+                                                               string fileString =_associatedFile.TextEncoding.GetString(fileObject.ToArray(),0,(int)fileObject.Length);                                                               \r
+                                                               fileObject.Close();\r
+\r
+                                                               if( HHCParser.HasGlobalObjectTag(fileString, _associatedFile) )\r
+                                                               {\r
+                                                                       sRet = curEntry;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       return sRet;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the file version of the chm file. \r
+               /// 2 for Compatibility=1.0,  3 for Compatibility=1.1\r
+               /// </summary>\r
+               public int FileVersion\r
+               {\r
+                       get { return _fileVersion; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the contents file name\r
+               /// </summary>\r
+               public string ContentsFile\r
+               {\r
+                       get \r
+                       { \r
+                               if( BinaryTOC ) // if the file contains a binary TOC\r
+                               {\r
+                                       // make sure the CHMFile instance exists and has loaded the file #URLTBL\r
+                                       if( (_associatedFile != null) && (_associatedFile.UrltblFile != null ) )\r
+                                       {\r
+                                               // Get an url-table entry by its unique id\r
+                                               UrlTableEntry entry = _associatedFile.UrltblFile.GetByUniqueID( this.BinaryTOCURLTableID );\r
+                                               if(entry != null)\r
+                                               {\r
+                                                       // entry found, return the url ( = filename )\r
+                                                       return entry.URL;\r
+                                               }\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       if(_contentsFile.Length <= 0)\r
+                                       {\r
+                                               string sCheck = "Table of Contents.hhc"; // default HHP contents filename\r
+\r
+                                               if( (_associatedFile != null) && (_associatedFile.TopicsFile != null ) )\r
+                                               {\r
+                                                       TopicEntry te = _associatedFile.TopicsFile.GetByLocale( sCheck );\r
+\r
+                                                       if( te == null)\r
+                                                       {\r
+                                                               sCheck = "toc.hhc"; // default HHP contents filename\r
+\r
+                                                               te = _associatedFile.TopicsFile.GetByLocale( sCheck );\r
+\r
+                                                               if( te == null)\r
+                                                               {\r
+                                                                       sCheck = CompileFile + ".hhc";\r
+\r
+                                                                       te = _associatedFile.TopicsFile.GetByLocale( sCheck );\r
+\r
+                                                                       if( te == null)\r
+                                                                       {\r
+                                                                               ArrayList arrExt = _associatedFile.TopicsFile.GetByExtension("hhc");\r
+\r
+                                                                               if( arrExt == null )\r
+                                                                               {\r
+                                                                                       arrExt = _associatedFile.EnumFilesByExtension("hhc");\r
+\r
+                                                                                       if( arrExt == null )\r
+                                                                                       {\r
+                                                                                               Debug.WriteLine("CHMSystem.ContentsFile - Failed, contents file not found !");\r
+                                                                                       } \r
+                                                                                       else \r
+                                                                                       {\r
+                                                                                               if(arrExt.Count > 1)\r
+                                                                                               {\r
+                                                                                                       sCheck = GetMasterHHC(arrExt, false);\r
+                                                                                                       _contentsFile = sCheck;\r
+                                                                                               } \r
+                                                                                               else \r
+                                                                                               {\r
+                                                                                                       _contentsFile = ((string)arrExt[0]);\r
+                                                                                                       sCheck = _contentsFile;\r
+                                                                                               }\r
+                                                                                       }\r
+                                                                               } \r
+                                                                               else \r
+                                                                               {\r
+                                                                                       if(arrExt.Count > 1)\r
+                                                                                       {\r
+                                                                                               sCheck = GetMasterHHC(arrExt, true);\r
+                                                                                               _contentsFile = sCheck;\r
+                                                                                       } \r
+                                                                                       else \r
+                                                                                       {\r
+                                                                                               _contentsFile = ((TopicEntry)arrExt[0]).Locale;\r
+                                                                                               sCheck = _contentsFile;\r
+                                                                                       }\r
+                                                                               }\r
+                                                                       } \r
+                                                                       else \r
+                                                                       {\r
+                                                                               _contentsFile = sCheck;\r
+                                                                       }\r
+                                                               } \r
+                                                               else \r
+                                                               {\r
+                                                                       _contentsFile = sCheck;\r
+                                                               }\r
+                                                       } \r
+                                                       else \r
+                                                       {\r
+                                                               _contentsFile = sCheck;\r
+                                                       }\r
+                                               }\r
+\r
+                                               return sCheck;\r
+                                       }\r
+                               }\r
+\r
+                               return _contentsFile; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the index file name\r
+               /// </summary>\r
+               public string IndexFile\r
+               {\r
+                       get \r
+                       { \r
+                               if( BinaryIndex ) // if the file contains a binary index\r
+                               {\r
+                                       // make sure the CHMFile instance exists and has loaded the file #URLTBL\r
+                                       if( (_associatedFile != null) && (_associatedFile.UrltblFile != null ) )\r
+                                       {\r
+                                               // Get an url-table entry by its unique id\r
+                                               UrlTableEntry entry = _associatedFile.UrltblFile.GetByUniqueID( this.BinaryIndexURLTableID );\r
+                                               if(entry != null)\r
+                                               {\r
+                                                       // entry found, return the url ( = filename )\r
+                                                       return entry.URL;\r
+                                               }\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       if(_indexFile.Length <= 0)\r
+                                       {\r
+                                               string sCheck = "Index.hhk"; // default HHP index filename\r
+\r
+                                               if( (_associatedFile != null) && (_associatedFile.TopicsFile != null ) )\r
+                                               {\r
+                                                       TopicEntry te = _associatedFile.TopicsFile.GetByLocale( sCheck );\r
+\r
+                                                       if( te == null)\r
+                                                       {\r
+                                                               sCheck = CompileFile + ".hhk";\r
+\r
+                                                               te = _associatedFile.TopicsFile.GetByLocale( sCheck );\r
+\r
+                                                               if( te == null)\r
+                                                               {\r
+                                                                       ArrayList arrExt = _associatedFile.TopicsFile.GetByExtension("hhk");\r
+\r
+                                                                       if( arrExt == null )\r
+                                                                       {\r
+                                                                               Debug.WriteLine("CHMSystem.IndexFile - Failed, index file not found !");\r
+                                                                       } \r
+                                                                       else \r
+                                                                       {\r
+                                                                               _indexFile = ((TopicEntry)arrExt[0]).Locale;\r
+                                                                               sCheck = _indexFile;\r
+                                                                       }\r
+                                                               } \r
+                                                               else \r
+                                                               {\r
+                                                                       _indexFile = sCheck;\r
+                                                               }\r
+                                                       } \r
+                                                       else \r
+                                                       {\r
+                                                               _indexFile = sCheck;\r
+                                                       }\r
+                                               }\r
+\r
+                                               return sCheck;\r
+                                       }\r
+                               }\r
+                               return _indexFile; \r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Sets the default topic of this file\r
+               /// </summary>\r
+               /// <param name="local">new local value of the topic</param>\r
+               internal void SetDefaultTopic(string local)\r
+               {\r
+                       _defaultTopic = local;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the default help topic\r
+               /// </summary>\r
+               public string DefaultTopic\r
+               {\r
+                       get { return _defaultTopic; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the title of the help window\r
+               /// </summary>\r
+               public string Title\r
+               {\r
+                       get { return _title; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if DBCS is in use\r
+               /// </summary>\r
+               public bool DBCS\r
+               {\r
+                       get { return _dbcs; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if full-text-search is available\r
+               /// </summary>\r
+               public bool FullTextSearch\r
+               {\r
+                       get { return _fullTextSearch; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the file has ALinks\r
+               /// </summary>\r
+               public bool HasALinks\r
+               {\r
+                       get { return _hasALinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the file has KLinks\r
+               /// </summary>\r
+               public bool HasKLinks\r
+               {\r
+                       get { return _hasKLinks; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the default window name\r
+               /// </summary>\r
+               public string DefaultWindow\r
+               {\r
+                       get { return _defaultWindow; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the file name of the compile file\r
+               /// </summary>\r
+               public string CompileFile\r
+               {\r
+                       get { return _compileFile; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the id of the binary index in the url table\r
+               /// </summary>\r
+               public uint BinaryIndexURLTableID\r
+               {\r
+                       get { return _binaryIndexURLTableID; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the chm has a binary index file\r
+               /// </summary>\r
+               public bool BinaryIndex\r
+               {\r
+                       get { return (_binaryIndexURLTableID>0); }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the chm has a binary index file\r
+               /// </summary>\r
+               public string CompilerVersion\r
+               {\r
+                       get { return _compilerVersion; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the id of the binary toc in the url table\r
+               /// </summary>\r
+               public uint BinaryTOCURLTableID\r
+               {\r
+                       get { return _binaryTOCURLTableID; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the flag if the chm has a binary toc file\r
+               /// </summary>\r
+               public bool BinaryTOC\r
+               {\r
+                       get { return (_binaryTOCURLTableID>0); }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the font face of the read font property.\r
+               /// Empty string for default font.\r
+               /// </summary>\r
+               public string FontFace\r
+               {\r
+                       get\r
+                       {\r
+                               if( _defaultFont.Length > 0)\r
+                               {\r
+                                       string [] fontSplit = _defaultFont.Split( new char[]{','});\r
+                                       if(fontSplit.Length > 0)\r
+                                               return fontSplit[0].Trim();\r
+                               }\r
+\r
+                               return "";\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the font size of the read font property.\r
+               /// 0 for default font size\r
+               /// </summary>\r
+               public double FontSize\r
+               {\r
+                       get\r
+                       {\r
+                               if( _defaultFont.Length > 0)\r
+                               {\r
+                                       string [] fontSplit = _defaultFont.Split( new char[]{','});\r
+                                       if(fontSplit.Length > 1)\r
+                                               return double.Parse(fontSplit[1].Trim());\r
+                               }\r
+\r
+                               return 0.0;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the character set of the read font property\r
+               /// 1 for default\r
+               /// </summary>\r
+               public int CharacterSet\r
+               {\r
+                       get\r
+                       {\r
+                               if( _defaultFont.Length > 0)\r
+                               {\r
+                                       string [] fontSplit = _defaultFont.Split( new char[]{','});\r
+                                       if(fontSplit.Length > 2)\r
+                                               return Int32.Parse(fontSplit[2].Trim());\r
+                               }\r
+\r
+                               return 0;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the codepage depending on the read font property\r
+               /// </summary>\r
+               public int CodePage\r
+               {\r
+                       get\r
+                       {\r
+                               // if we've read a LCID from the system file\r
+                               // ignore the font-property settings and return\r
+                               // the codepage generated from the culture info\r
+                               if(_culture != null)\r
+                               {\r
+                                       return _culture.TextInfo.ANSICodePage;\r
+                               }\r
+\r
+                               int nRet = 1252; // default codepage windows-1252\r
+\r
+                               int nCSet = CharacterSet;\r
+\r
+                               switch(nCSet)\r
+                               {\r
+                                       case 0x00: nRet = 1252;break;   // ANSI_CHARSET\r
+                                       case 0xCC: nRet = 1251;break;   // RUSSIAN_CHARSET\r
+                                       case 0xEE: nRet = 1250;break;   // EE_CHARSET\r
+                                       case 0xA1: nRet = 1253;break;   // GREEK_CHARSET\r
+                                       case 0xA2: nRet = 1254;break;   // TURKISH_CHARSET\r
+                                       case 0xBA: nRet = 1257;break;   // BALTIC_CHARSET\r
+                                       case 0xB1: nRet = 1255;break;   // HEBREW_CHARSET\r
+                                       case 0xB2: nRet = 1256;break;   // ARABIC_CHARSET\r
+                                       case 0x80: nRet =  932;break;   // SHIFTJIS_CHARSET\r
+                                       case 0x81: nRet =  949;break;   // HANGEUL_CHARSET\r
+                                       case 0x86: nRet =  936;break;   // GB2313_CHARSET\r
+                                       case 0x88: nRet =  950;break;   // CHINESEBIG5_CHARSET\r
+                               }\r
+\r
+                               return nRet;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the assiciated culture info\r
+               /// </summary>\r
+               public CultureInfo Culture\r
+               {\r
+                       get { return _culture; }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Implement IDisposable.\r
+               /// </summary>\r
+               public void Dispose()\r
+               {\r
+                       Dispose(true);\r
+                       // This object will be cleaned up by the Dispose method.\r
+                       // Therefore, you should call GC.SupressFinalize to\r
+                       // take this object off the finalization queue \r
+                       // and prevent finalization code for this object\r
+                       // from executing a second time.\r
+                       GC.SuppressFinalize(this);\r
+               }\r
+\r
+               /// <summary>\r
+               /// Dispose(bool disposing) executes in two distinct scenarios. \r
+               /// If disposing equals true, the method has been called directly \r
+               /// or indirectly by a user's code. Managed and unmanaged resources \r
+               /// can be disposed. \r
+               /// If disposing equals false, the method has been called by the \r
+               /// runtime from inside the finalizer and you should not reference  \r
+               /// other objects. Only unmanaged resources can be disposed.\r
+               /// </summary>\r
+               /// <param name="disposing">disposing flag</param>\r
+               private void Dispose(bool disposing)\r
+               {\r
+                       // Check to see if Dispose has already been called.\r
+                       if(!this.disposed)\r
+                       {\r
+                               // If disposing equals true, dispose all managed \r
+                               // and unmanaged resources.\r
+                               if(disposing)\r
+                               {\r
+                                       // Dispose managed resources.\r
+                                       _binaryFileData = null;\r
+                               }\r
+             \r
+                                         \r
+                       }\r
+                       disposed = true;         \r
+               }\r
+       }\r
+}\r
diff --git a/irc/TechBot/CHMLibrary/CHMDecoding/CHMTocidx.cs b/irc/TechBot/CHMLibrary/CHMDecoding/CHMTocidx.cs
new file mode 100644 (file)
index 0000000..d6ca1aa
--- /dev/null
@@ -0,0 +1,288 @@
+using System;\r
+using System.IO;\r
+using System.Collections;\r
+\r
+namespace HtmlHelp.ChmDecoding\r
+{\r
+       /// <summary>\r
+       /// The class <c>CHMTocidx</c> implements functions to decode the #TOCIDX internal file.\r
+       /// </summary>\r
+       internal sealed class CHMTocidx : IDisposable\r
+       {\r
+               /// <summary>\r
+               /// Constant specifying the size of the data blocks\r
+               /// </summary>\r
+               private const int BLOCK_SIZE = 0x1000;\r
+               /// <summary>\r
+               /// Internal flag specifying if the object is going to be disposed\r
+               /// </summary>\r
+               private bool disposed = false;\r
+               /// <summary>\r
+               /// Internal member storing the binary file data\r
+               /// </summary>\r
+               private byte[] _binaryFileData = null;\r
+               /// <summary>\r
+               /// Internal memebr storing the offset to the 20/28 byte structs\r
+               /// </summary>\r
+               private int _offset2028 = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset to the 16 byte structs\r
+               /// </summary>\r
+               private int _offset16structs = 0;\r
+               /// <summary>\r
+               /// Internal member storing the number of 16 byte structs\r
+               /// </summary>\r
+               private int _numberOf16structs = 0;\r
+               /// <summary>\r
+               /// Internal member storing the offset to the topic list\r
+               /// </summary>\r
+               private int _offsetOftopics = 0;\r
+               /// <summary>\r
+               /// Internal member storing the toc\r
+               /// </summary>\r
+               private ArrayList _toc = new ArrayList();\r
+               /// <summary>\r
+               /// Internal member for offset seeking\r
+               /// </summary>\r
+               private Hashtable _offsetTable = new Hashtable();\r
+               /// <summary>\r
+               /// Internal member storing the associated chmfile object\r
+               /// </summary>\r
+               private CHMFile _associatedFile = null;\r
+\r
+               /// <summary>\r
+               /// Constructor of the class\r
+               /// </summary>\r
+               /// <param name="binaryFileData">binary file data of the #TOCIDX file</param>\r
+               /// <param name="associatedFile">associated chm file</param>\r
+               public CHMTocidx(byte[] binaryFileData, CHMFile associatedFile)\r
+               {\r
+                       _binaryFileData = binaryFileData;\r
+                       _associatedFile = associatedFile;\r
+                       DecodeData();\r
+\r
+                       // clear internal binary data after extraction\r
+                       _binaryFileData = null;\r
+               }\r
+               \r
+               /// <summary>\r
+               /// Decodes the binary file data and fills the internal properties\r
+               /// </summary>\r
+               /// <returns>true if succeeded</returns>\r
+               private bool DecodeData()\r
+               {\r
+                       _toc = new ArrayList();\r
+                       _offsetTable = new Hashtable();\r
+\r
+                       bool bRet = true;\r
+\r
+                       MemoryStream memStream = new MemoryStream(_binaryFileData);\r
+                       BinaryReader binReader = new BinaryReader(memStream);\r
+                       \r
+                       int nCurOffset = 0;\r
+\r
+                       _offset2028 = binReader.ReadInt32();\r
+                       _offset16structs = binReader.ReadInt32();\r
+                       _numberOf16structs = binReader.ReadInt32();\r
+                       _offsetOftopics = binReader.ReadInt32();\r
+\r
+                       binReader.BaseStream.Seek( _offset2028, SeekOrigin.Begin );\r
+\r
+                       if( RecursivelyBuildTree(ref binReader, _offset2028, _toc, null) )\r
+                       {\r
+                               binReader.BaseStream.Seek( _offset16structs, SeekOrigin.Begin );\r
+                               nCurOffset = (int)binReader.BaseStream.Position;\r
+\r
+                               for(int i=0; i < _numberOf16structs; i++)\r
+                               {\r
+                                       int tocOffset = binReader.ReadInt32();\r
+                                       int sqNr = binReader.ReadInt32();\r
+                                       int topOffset = binReader.ReadInt32();\r
+