3 using System.Collections;
5 namespace HtmlHelp.ChmDecoding
8 /// The class <c>CHMUrltable</c> implements methods to decode the #URLTBL internal file.
10 internal sealed class CHMUrltable : IDisposable
13 /// Constant specifying the size of the data blocks
15 private const int BLOCK_SIZE = 0x1000;
17 /// Constant specifying the number of records per block
19 private const int RECORDS_PER_BLOCK = 341;
21 /// Internal flag specifying if the object is going to be disposed
23 private bool disposed = false;
25 /// Internal member storing the binary file data
27 private byte[] _binaryFileData = null;
29 /// Internal member storing the url table
31 private ArrayList _urlTable = new ArrayList();
33 /// Internal member storing the associated chmfile object
35 private CHMFile _associatedFile = null;
38 /// Constructor of the class
40 /// <param name="binaryFileData">binary file data of the #URLTBL file</param>
41 /// <param name="associatedFile">associated chm file</param>
42 public CHMUrltable(byte[] binaryFileData, CHMFile associatedFile)
44 _binaryFileData = binaryFileData;
45 _associatedFile = associatedFile;
48 // clear internal binary data after extraction
49 _binaryFileData = null;
53 /// Standard constructor
55 internal CHMUrltable()
61 /// Dump the class data to a binary writer
63 /// <param name="writer">writer to write the data</param>
64 internal void Dump(ref BinaryWriter writer)
66 writer.Write( _urlTable.Count );
67 foreach(UrlTableEntry curItem in _urlTable)
69 curItem.Dump(ref writer);
74 /// Reads the object data from a dump store
76 /// <param name="reader">reader to read the data</param>
77 internal void ReadDump(ref BinaryReader reader)
80 int nCnt = reader.ReadInt32();
84 UrlTableEntry newItem = new UrlTableEntry();
85 newItem.SetCHMFile(_associatedFile);
86 newItem.ReadDump(ref reader);
87 _urlTable.Add(newItem);
92 /// Sets the associated CHMFile instance
94 /// <param name="associatedFile">instance to set</param>
95 internal void SetCHMFile(CHMFile associatedFile)
97 _associatedFile = associatedFile;
99 foreach(UrlTableEntry curEntry in _urlTable)
101 curEntry.SetCHMFile(associatedFile);
107 /// Decodes the binary file data and fills the internal properties
109 /// <returns>true if succeeded</returns>
110 private bool DecodeData()
114 MemoryStream memStream = new MemoryStream(_binaryFileData);
115 BinaryReader binReader = new BinaryReader(memStream);
119 while( (memStream.Position < memStream.Length) && (bRet) )
121 nCurOffset = (int)memStream.Position;
122 byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);
123 bRet &= DecodeBlock(dataBlock, ref nCurOffset);
130 /// Decodes a block of url-string data
132 /// <param name="dataBlock">block of data</param>
133 /// <param name="nOffset">current file offset</param>
134 /// <returns>true if succeeded</returns>
135 private bool DecodeBlock( byte[] dataBlock, ref int nOffset )
138 int blockOffset = nOffset;
140 MemoryStream memStream = new MemoryStream(dataBlock);
141 BinaryReader binReader = new BinaryReader(memStream);
143 for(int i=0; i < RECORDS_PER_BLOCK; i++)
145 int recordOffset = blockOffset + (int)memStream.Position;
147 uint nuniqueID = (uint) binReader.ReadInt32(); // unknown dword
148 int ntopicsIdx = binReader.ReadInt32();
149 int urlstrOffset = binReader.ReadInt32();
151 UrlTableEntry newEntry = new UrlTableEntry(nuniqueID, recordOffset, ntopicsIdx, urlstrOffset, _associatedFile);
152 _urlTable.Add(newEntry);
154 if( memStream.Position >= memStream.Length)
158 if(dataBlock.Length == BLOCK_SIZE)
159 binReader.ReadInt32();
165 /// Gets the arraylist containing all urltable entries.
167 public ArrayList UrlTable
176 /// Gets the urltable entry of a given offset
178 public UrlTableEntry this[int offset]
182 foreach(UrlTableEntry curEntry in _urlTable)
183 if(curEntry.EntryOffset == offset)
191 /// Gets the urltable entry of a given uniqueID
193 public UrlTableEntry GetByUniqueID(uint uniqueID)
195 foreach(UrlTableEntry curEntry in UrlTable)
197 if(curEntry.UniqueID == uniqueID)
205 /// Implement IDisposable.
207 public void Dispose()
210 // This object will be cleaned up by the Dispose method.
211 // Therefore, you should call GC.SupressFinalize to
212 // take this object off the finalization queue
213 // and prevent finalization code for this object
214 // from executing a second time.
215 GC.SuppressFinalize(this);
219 /// Dispose(bool disposing) executes in two distinct scenarios.
220 /// If disposing equals true, the method has been called directly
221 /// or indirectly by a user's code. Managed and unmanaged resources
223 /// If disposing equals false, the method has been called by the
224 /// runtime from inside the finalizer and you should not reference
225 /// other objects. Only unmanaged resources can be disposed.
227 /// <param name="disposing">disposing flag</param>
228 private void Dispose(bool disposing)
230 // Check to see if Dispose has already been called.
233 // If disposing equals true, dispose all managed
234 // and unmanaged resources.
237 // Dispose managed resources.
238 _binaryFileData = null;