3 using System.Collections;
4 using System.Collections.Specialized;
6 namespace HtmlHelp.ChmDecoding
9 /// The class <c>CHMStrings</c> implements a string collection read from the #STRINGS file
11 internal sealed class CHMStrings : IDisposable
14 /// Constant specifying the size of the string blocks
16 private const int STRING_BLOCK_SIZE = 4096;
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 string dictionary
28 private Hashtable _stringDictionary = new Hashtable();
30 /// Internal member storing the associated chmfile object
32 private CHMFile _associatedFile = null;
35 /// Constructor of the class
37 /// <param name="binaryFileData">binary file data of the #STRINGS file</param>
38 /// <param name="associatedFile">associated chm file</param>
39 public CHMStrings(byte[] binaryFileData, CHMFile associatedFile)
41 _binaryFileData = binaryFileData;
42 _associatedFile = associatedFile;
48 /// Standard constructor
56 /// Dump the class data to a binary writer
58 /// <param name="writer">writer to write the data</param>
59 internal void Dump(ref BinaryWriter writer)
61 writer.Write( _stringDictionary.Count );
63 if (_stringDictionary.Count != 0)
65 IDictionaryEnumerator iDictionaryEnumerator = _stringDictionary.GetEnumerator();
66 while (iDictionaryEnumerator.MoveNext())
68 DictionaryEntry dictionaryEntry = (DictionaryEntry)iDictionaryEnumerator.Current;
69 writer.Write( Int32.Parse(dictionaryEntry.Key.ToString()) );
70 writer.Write( dictionaryEntry.Value.ToString() );
76 /// Reads the object data from a dump store
78 /// <param name="reader">reader to read the data</param>
79 internal void ReadDump(ref BinaryReader reader)
81 int nCnt = reader.ReadInt32();
83 for(int i=0; i<nCnt;i++)
85 int nKey = reader.ReadInt32();
86 string sValue = reader.ReadString();
88 _stringDictionary[nKey.ToString()] = sValue;
93 /// Sets the associated CHMFile instance
95 /// <param name="associatedFile">instance to set</param>
96 internal void SetCHMFile(CHMFile associatedFile)
98 _associatedFile = associatedFile;
103 /// Decodes the binary file data and fills the internal properties
105 /// <returns>true if succeeded</returns>
106 private bool DecodeData()
110 MemoryStream memStream = new MemoryStream(_binaryFileData);
111 BinaryReader binReader = new BinaryReader(memStream);
113 //binReader.ReadByte(); // file starts with a NULL character for 0-based offset indexing
115 int nStringOffset = 0;
116 int nSubsetOffset = 0;
118 while( (memStream.Position < memStream.Length) && (bRet) )
120 nStringOffset = (int)memStream.Position;
121 byte [] stringBlock = binReader.ReadBytes(STRING_BLOCK_SIZE);
122 bRet &= DecodeBlock(stringBlock, ref nStringOffset, ref nSubsetOffset);
129 /// Decodes a string block
131 /// <param name="stringBlock">byte array which represents the string block</param>
132 /// <param name="nStringOffset">current string offset number</param>
133 /// <param name="nSubsetOffset">reference to a subset variable</param>
134 /// <returns>true if succeeded</returns>
135 /// <remarks>If a string crosses the end of a block then it will be cut off
136 /// without a NT and repeated in full, with a NT, at the start of the next block.
137 /// For eg "To customize the appearance of a contents file" might become
138 /// "To customize the (block ending)To customize the appearance of a contents file"
139 /// when there are 17 bytes left at the end of the block. </remarks>
140 private bool DecodeBlock( byte[] stringBlock, ref int nStringOffset, ref int nSubsetOffset)
144 MemoryStream memStream = new MemoryStream(stringBlock);
145 BinaryReader binReader = new BinaryReader(memStream);
147 while( (memStream.Position < memStream.Length) && (bRet) )
149 bool bFoundTerminator = false;
151 int nCurOffset = nStringOffset + (int)memStream.Position;
153 string sTemp = BinaryReaderHelp.ExtractString(ref binReader, ref bFoundTerminator, 0, true, _associatedFile.TextEncoding);
155 if(nSubsetOffset != 0)
157 _stringDictionary[nSubsetOffset.ToString()] = sTemp.ToString();
161 _stringDictionary[nCurOffset.ToString()] = sTemp.ToString();
164 if( bFoundTerminator )
170 nSubsetOffset = nCurOffset;
178 /// Indexer which returns the string at a given offset
180 public string this[int offset]
187 string sTemp = (string)_stringDictionary[ offset.ToString() ];
197 /// Indexer which returns the string at a given offset
199 public string this[string offset]
206 string sTemp = (string)_stringDictionary[ offset ];
216 /// Implement IDisposable.
218 public void Dispose()
221 // This object will be cleaned up by the Dispose method.
222 // Therefore, you should call GC.SupressFinalize to
223 // take this object off the finalization queue
224 // and prevent finalization code for this object
225 // from executing a second time.
226 GC.SuppressFinalize(this);
230 /// Dispose(bool disposing) executes in two distinct scenarios.
231 /// If disposing equals true, the method has been called directly
232 /// or indirectly by a user's code. Managed and unmanaged resources
234 /// If disposing equals false, the method has been called by the
235 /// runtime from inside the finalizer and you should not reference
236 /// other objects. Only unmanaged resources can be disposed.
238 /// <param name="disposing">disposing flag</param>
239 private void Dispose(bool disposing)
241 // Check to see if Dispose has already been called.
244 // If disposing equals true, dispose all managed
245 // and unmanaged resources.
248 // Dispose managed resources.
249 _binaryFileData = null;
250 _stringDictionary = null;