using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
namespace HtmlHelp.ChmDecoding
{
///
/// The class CHMTopics implements functionality to decode the #TOPICS internal file
///
internal sealed class CHMTopics : IDisposable
{
///
/// Internal flag specifying if the object is going to be disposed
///
private bool disposed = false;
///
/// Internal member storing the binary file data
///
private byte[] _binaryFileData = null;
///
/// Internal member storing the associated chmfile object
///
private CHMFile _associatedFile = null;
///
/// Internal member storing the topic list
///
private ArrayList _topicTable = new ArrayList();
///
/// Constructor of the class
///
/// binary file data of the #TOPICS file
/// associated chm file
public CHMTopics(byte[] binaryFileData, CHMFile associatedFile)
{
_binaryFileData = binaryFileData;
_associatedFile = associatedFile;
DecodeData();
// clear internal binary data after extraction
_binaryFileData = null;
}
///
/// Standard constructor
///
internal CHMTopics()
{
}
#region Data dumping
///
/// Dump the class data to a binary writer
///
/// writer to write the data
internal void Dump(ref BinaryWriter writer)
{
writer.Write( _topicTable.Count );
foreach(TopicEntry curItem in _topicTable)
{
curItem.Dump(ref writer);
}
}
///
/// Reads the object data from a dump store
///
/// reader to read the data
internal void ReadDump(ref BinaryReader reader)
{
int i=0;
int nCnt = reader.ReadInt32();
for(i=0; i
/// Sets the associated CHMFile instance
///
/// instance to set
internal void SetCHMFile(CHMFile associatedFile)
{
_associatedFile = associatedFile;
foreach(TopicEntry curEntry in _topicTable)
{
curEntry.SetCHMFile(associatedFile);
}
}
#endregion
///
/// Decodes the binary file data and fills the internal properties
///
/// true if succeeded
private bool DecodeData()
{
bool bRet = true;
MemoryStream memStream = new MemoryStream(_binaryFileData);
BinaryReader binReader = new BinaryReader(memStream);
int nCurOffset = 0;
while( (memStream.Position < memStream.Length) && (bRet) )
{
int entryOffset = nCurOffset;
int tocIdx = binReader.ReadInt32();
int titleOffset = binReader.ReadInt32();
int urltablOffset = binReader.ReadInt32();
int visibilityMode = binReader.ReadInt16();
int unknownMode = binReader.ReadInt16();
TopicEntry newEntry = new TopicEntry(entryOffset, tocIdx, titleOffset, urltablOffset, visibilityMode, unknownMode, _associatedFile);
_topicTable.Add( newEntry );
nCurOffset = (int)memStream.Position;
}
return bRet;
}
///
/// Gets the arraylist containing all topic entries.
///
public ArrayList TopicTable
{
get
{
return _topicTable;
}
}
///
/// Gets the topic entry of a given offset
///
public TopicEntry this[int offset]
{
get
{
foreach(TopicEntry curEntry in _topicTable)
if(curEntry.EntryOffset == offset)
return curEntry;
return null;
}
}
///
/// Searches a topic by the locale name
///
/// locale name to search
/// The topicentry instance if found, otherwise null
public TopicEntry GetByLocale(string locale)
{
foreach(TopicEntry curEntry in TopicTable)
{
if(curEntry.Locale.ToLower() == locale.ToLower())
return curEntry;
}
return null;
}
///
/// Searches the topics for all files with a given file extension
///
/// extension to search
/// An arraylist of TopicEntry instances or null if no topic was found
public ArrayList GetByExtension(string fileExtension)
{
ArrayList arrRet = new ArrayList();
foreach(TopicEntry curEntry in TopicTable)
{
if(curEntry.Locale.ToLower().EndsWith(fileExtension.ToLower()))
arrRet.Add(curEntry);
}
if(arrRet.Count > 0)
return arrRet;
return null;
}
///
/// Implement IDisposable.
///
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
///
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
///
/// disposing flag
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
_binaryFileData = null;
_topicTable=null;
}
}
disposed = true;
}
}
}