mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 11:56:26 +00:00
246 lines
6.4 KiB
C#
246 lines
6.4 KiB
C#
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Collections;
|
||
|
|
||
|
namespace HtmlHelp.ChmDecoding
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// The class <c>CHMUrltable</c> implements methods to decode the #URLTBL internal file.
|
||
|
/// </summary>
|
||
|
internal sealed class CHMUrltable : IDisposable
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Constant specifying the size of the data blocks
|
||
|
/// </summary>
|
||
|
private const int BLOCK_SIZE = 0x1000;
|
||
|
/// <summary>
|
||
|
/// Constant specifying the number of records per block
|
||
|
/// </summary>
|
||
|
private const int RECORDS_PER_BLOCK = 341;
|
||
|
/// <summary>
|
||
|
/// Internal flag specifying if the object is going to be disposed
|
||
|
/// </summary>
|
||
|
private bool disposed = false;
|
||
|
/// <summary>
|
||
|
/// Internal member storing the binary file data
|
||
|
/// </summary>
|
||
|
private byte[] _binaryFileData = null;
|
||
|
/// <summary>
|
||
|
/// Internal member storing the url table
|
||
|
/// </summary>
|
||
|
private ArrayList _urlTable = new ArrayList();
|
||
|
/// <summary>
|
||
|
/// Internal member storing the associated chmfile object
|
||
|
/// </summary>
|
||
|
private CHMFile _associatedFile = null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor of the class
|
||
|
/// </summary>
|
||
|
/// <param name="binaryFileData">binary file data of the #URLTBL file</param>
|
||
|
/// <param name="associatedFile">associated chm file</param>
|
||
|
public CHMUrltable(byte[] binaryFileData, CHMFile associatedFile)
|
||
|
{
|
||
|
_binaryFileData = binaryFileData;
|
||
|
_associatedFile = associatedFile;
|
||
|
DecodeData();
|
||
|
|
||
|
// clear internal binary data after extraction
|
||
|
_binaryFileData = null;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Standard constructor
|
||
|
/// </summary>
|
||
|
internal CHMUrltable()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#region Data dumping
|
||
|
/// <summary>
|
||
|
/// Dump the class data to a binary writer
|
||
|
/// </summary>
|
||
|
/// <param name="writer">writer to write the data</param>
|
||
|
internal void Dump(ref BinaryWriter writer)
|
||
|
{
|
||
|
writer.Write( _urlTable.Count );
|
||
|
foreach(UrlTableEntry curItem in _urlTable)
|
||
|
{
|
||
|
curItem.Dump(ref writer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads the object data from a dump store
|
||
|
/// </summary>
|
||
|
/// <param name="reader">reader to read the data</param>
|
||
|
internal void ReadDump(ref BinaryReader reader)
|
||
|
{
|
||
|
int i=0;
|
||
|
int nCnt = reader.ReadInt32();
|
||
|
|
||
|
for(i=0; i<nCnt;i++)
|
||
|
{
|
||
|
UrlTableEntry newItem = new UrlTableEntry();
|
||
|
newItem.SetCHMFile(_associatedFile);
|
||
|
newItem.ReadDump(ref reader);
|
||
|
_urlTable.Add(newItem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets the associated CHMFile instance
|
||
|
/// </summary>
|
||
|
/// <param name="associatedFile">instance to set</param>
|
||
|
internal void SetCHMFile(CHMFile associatedFile)
|
||
|
{
|
||
|
_associatedFile = associatedFile;
|
||
|
|
||
|
foreach(UrlTableEntry curEntry in _urlTable)
|
||
|
{
|
||
|
curEntry.SetCHMFile(associatedFile);
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
/// <summary>
|
||
|
/// Decodes the binary file data and fills the internal properties
|
||
|
/// </summary>
|
||
|
/// <returns>true if succeeded</returns>
|
||
|
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) )
|
||
|
{
|
||
|
nCurOffset = (int)memStream.Position;
|
||
|
byte [] dataBlock = binReader.ReadBytes(BLOCK_SIZE);
|
||
|
bRet &= DecodeBlock(dataBlock, ref nCurOffset);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Decodes a block of url-string data
|
||
|
/// </summary>
|
||
|
/// <param name="dataBlock">block of data</param>
|
||
|
/// <param name="nOffset">current file offset</param>
|
||
|
/// <returns>true if succeeded</returns>
|
||
|
private bool DecodeBlock( byte[] dataBlock, ref int nOffset )
|
||
|
{
|
||
|
bool bRet = true;
|
||
|
int blockOffset = nOffset;
|
||
|
|
||
|
MemoryStream memStream = new MemoryStream(dataBlock);
|
||
|
BinaryReader binReader = new BinaryReader(memStream);
|
||
|
|
||
|
for(int i=0; i < RECORDS_PER_BLOCK; i++)
|
||
|
{
|
||
|
int recordOffset = blockOffset + (int)memStream.Position;
|
||
|
|
||
|
uint nuniqueID = (uint) binReader.ReadInt32(); // unknown dword
|
||
|
int ntopicsIdx = binReader.ReadInt32();
|
||
|
int urlstrOffset = binReader.ReadInt32();
|
||
|
|
||
|
UrlTableEntry newEntry = new UrlTableEntry(nuniqueID, recordOffset, ntopicsIdx, urlstrOffset, _associatedFile);
|
||
|
_urlTable.Add(newEntry);
|
||
|
|
||
|
if( memStream.Position >= memStream.Length)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(dataBlock.Length == BLOCK_SIZE)
|
||
|
binReader.ReadInt32();
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the arraylist containing all urltable entries.
|
||
|
/// </summary>
|
||
|
public ArrayList UrlTable
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _urlTable;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the urltable entry of a given offset
|
||
|
/// </summary>
|
||
|
public UrlTableEntry this[int offset]
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
foreach(UrlTableEntry curEntry in _urlTable)
|
||
|
if(curEntry.EntryOffset == offset)
|
||
|
return curEntry;
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the urltable entry of a given uniqueID
|
||
|
/// </summary>
|
||
|
public UrlTableEntry GetByUniqueID(uint uniqueID)
|
||
|
{
|
||
|
foreach(UrlTableEntry curEntry in UrlTable)
|
||
|
{
|
||
|
if(curEntry.UniqueID == uniqueID)
|
||
|
return curEntry;
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Implement IDisposable.
|
||
|
/// </summary>
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
/// <param name="disposing">disposing flag</param>
|
||
|
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;
|
||
|
_urlTable = null;
|
||
|
}
|
||
|
}
|
||
|
disposed = true;
|
||
|
}
|
||
|
}
|
||
|
}
|