3 using System.Collections;
4 using System.Collections.Specialized;
6 namespace HtmlHelp.ChmDecoding
9 /// The class <c>CHMUrlstr</c> implements a string collection storing the URL strings of the help file
11 internal sealed class CHMUrlstr : IDisposable
14 /// Constant specifying the size of the string blocks
16 private const int BLOCK_SIZE = 0x1000;
18 /// Internal flag specifying if the object is going to be disposed
20 private bool disposed = false;
22 /// Internal member storing the binary file data
24 private byte[] _binaryFileData = null;
26 /// Internal member storing the url dictionary
28 private Hashtable _urlDictionary = new Hashtable();
30 /// Internal member storing the framename dictionary
32 private Hashtable _framenameDictionary = new Hashtable();
34 /// Internal member storing the associated chmfile object
36 private CHMFile _associatedFile = null;
39 /// Constructor of the class
41 /// <param name="binaryFileData">binary file data of the #URLSTR file</param>
42 /// <param name="associatedFile">associated chm file</param>
43 public CHMUrlstr(byte[] binaryFileData, CHMFile associatedFile)
45 _binaryFileData = binaryFileData;
46 _associatedFile = associatedFile;
49 // clear internal binary data after extraction
50 _binaryFileData = null;
54 /// Standard constructor
62 /// Dump the class data to a binary writer
64 /// <param name="writer">writer to write the data</param>
65 internal void Dump(ref BinaryWriter writer)
67 writer.Write( _urlDictionary.Count );
69 if (_urlDictionary.Count != 0)
71 IDictionaryEnumerator iDictionaryEnumerator = _urlDictionary.GetEnumerator();
72 while (iDictionaryEnumerator.MoveNext())
74 DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;
75 writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );
76 writer.Write( dictionaryEntry.Value.ToString() );
80 writer.Write( _framenameDictionary.Count );
82 if (_framenameDictionary.Count != 0)
84 IDictionaryEnumerator iDictionaryEnumerator = _framenameDictionary.GetEnumerator();
85 while (iDictionaryEnumerator.MoveNext())
87 DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;
88 writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );
89 writer.Write( dictionaryEntry.Value.ToString() );
95 /// Reads the object data from a dump store
97 /// <param name="reader">reader to read the data</param>
98 internal void ReadDump(ref BinaryReader reader)
101 int nCnt = reader.ReadInt32();
105 int nKey = reader.ReadInt32();
106 string sValue = reader.ReadString();
108 _urlDictionary[nKey.ToString()] = sValue;
111 nCnt = reader.ReadInt32();
115 int nKey = reader.ReadInt32();
116 string sValue = reader.ReadString();
118 _framenameDictionary[nKey.ToString()] = sValue;
123 /// Sets the associated CHMFile instance
125 /// <param name="associatedFile">instance to set</param>
126 internal void SetCHMFile(CHMFile associatedFile)
128 _associatedFile = associatedFile;
133 /// Decodes the binary file data and fills the internal properties
135 /// <returns>true if succeeded</returns>
136 private bool DecodeData()
140 MemoryStream memStream = new MemoryStream(_binaryFileData);
141 BinaryReader binReader = new BinaryReader(memStream);
145 while( (memStream.Position < memStream.Length) && (bRet) )
147 nCurOffset = (int)memStream.Position;
148 byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);
149 bRet &= DecodeBlock(dataBlock, ref nCurOffset);
156 /// Decodes a block of url-string data
158 /// <param name="dataBlock">block of data</param>
159 /// <param name="nOffset">current file offset</param>
160 /// <returns>true if succeeded</returns>
161 private bool DecodeBlock( byte[] dataBlock, ref int nOffset )
164 int blockOffset = nOffset;
166 MemoryStream memStream = new MemoryStream(dataBlock);
167 BinaryReader binReader = new BinaryReader(memStream);
170 binReader.ReadByte(); // first block starts with an unknown byte
172 while( (memStream.Position < (memStream.Length-8)) && (bRet) )
174 int entryOffset = blockOffset + (int)memStream.Position;
176 int urlOffset = binReader.ReadInt32();
177 int frameOffset = binReader.ReadInt32();
180 // There is one way to tell where the end of the URL/FrameName
181 // pairs occurs: Repeat the following: read 2 DWORDs and if both
182 // are less than the current offset then this is the start of the Local
183 // strings else skip two NT strings.
184 // if(( (urlOffset < (entryOffset+8)) && (frameOffset < (entryOffset+8)) ))
186 // //TODO: add correct string reading if an offset has been found
188 // int curOffset = (int)memStream.Position;
190 // memStream.Seek( (long)(blockOffset-urlOffset), SeekOrigin.Begin);
191 // string sTemp = CHMReader.ExtractString(ref binReader, 0, true);
193 // memStream.Seek( (long)(blockOffset-frameOffset), SeekOrigin.Begin);
194 // sTemp = CHMReader.ExtractString(ref binReader, 0, true);
196 // memStream.Seek((long)curOffset, SeekOrigin.Begin);
200 // int curOffs = (int)memStream.Position;
201 // BinaryReaderHelp.ExtractString(ref binReader, 0, true, _associatedFile.TextEncoding);
202 // nOffset += (int)memStream.Position - curOffs;
204 // curOffs = (int)memStream.Position;
205 // BinaryReaderHelp.ExtractString(ref binReader, 0, true, _associatedFile.TextEncoding);
206 // nOffset += (int)memStream.Position - curOffs;
210 bool bFoundTerminator = false;
212 string sTemp = BinaryReaderHelp.ExtractString(ref binReader, ref bFoundTerminator, 0, true, _associatedFile.TextEncoding);
216 //nOffset = nOffset + 1 + (int)memStream.Length - (int)memStream.Position;
217 memStream.Seek(memStream.Length-1, SeekOrigin.Begin);
221 _urlDictionary[entryOffset.ToString()] = sTemp.ToString();
222 _framenameDictionary[ entryOffset.ToString() ] = sTemp.ToString() ;
231 /// Gets the url at a given offset
233 /// <param name="offset">offset of url</param>
234 /// <returns>the url at the given offset</returns>
235 public string GetURLatOffset(int offset)
240 string sTemp = (string)_urlDictionary[ offset.ToString() ];
249 /// Gets the framename at a given offset
251 /// <param name="offset">offset of the framename</param>
252 /// <returns>the frame name at the given offset</returns>
253 public string GetFrameNameatOffset(int offset)
258 string sTemp = (string)_framenameDictionary[ offset.ToString() ];
267 /// Implement IDisposable.
269 public void Dispose()
272 // This object will be cleaned up by the Dispose method.
273 // Therefore, you should call GC.SupressFinalize to
274 // take this object off the finalization queue
275 // and prevent finalization code for this object
276 // from executing a second time.
277 GC.SuppressFinalize(this);
281 /// Dispose(bool disposing) executes in two distinct scenarios.
282 /// If disposing equals true, the method has been called directly
283 /// or indirectly by a user's code. Managed and unmanaged resources
285 /// If disposing equals false, the method has been called by the
286 /// runtime from inside the finalizer and you should not reference
287 /// other objects. Only unmanaged resources can be disposed.
289 /// <param name="disposing">disposing flag</param>
290 private void Dispose(bool disposing)
292 // Check to see if Dispose has already been called.
295 // If disposing equals true, dispose all managed
296 // and unmanaged resources.
299 // Dispose managed resources.
300 _binaryFileData = null;
301 _urlDictionary = null;
302 _framenameDictionary = null;