using System; using System.IO; using System.Text; using System.Diagnostics; using System.Collections.Specialized; using ICSharpCode.SharpZipLib; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using HtmlHelp; // using HtmlHelp.Storage; namespace HtmlHelp.ChmDecoding { /// /// Enumeration for specifying the dumping compression /// public enum DumpCompression { /// /// None - no data compression will be used. /// Fastest but most memory intensive /// None = 0, /// /// Minimum - a minimum data compression will be used. /// Fast but not much data reduction /// Minimum = 1, /// /// Medium - a medium data compression will be used. /// Slower but medium data reduction /// Medium = 2, /// /// Maximum - a maximum data compression will be used. /// Slowest but maximum data reduction /// Maximum = 3 } /// /// Flags which specify which data should be dumped /// [FlagsAttribute()] public enum DumpingFlags { /// /// DumpTextTOC - if this flag is set, text-based TOCs (sitemap format) will be dumped /// DumpTextTOC = 1, /// /// DumpBinaryTOC - if this flag is set, binary TOCs will be dumped /// DumpBinaryTOC = 2, /// /// DumpTextIndex - if this flag is set, the text-based index (sitemap format) will be dumped /// DumpTextIndex = 4, /// /// DumpBinaryIndex - if this flag is set, the binary index will be dumped /// DumpBinaryIndex = 8, /// /// DumpStrings - if this flag is set, the internal #STRINGS file will be dumped /// DumpStrings = 16, /// /// DumpUrlStr - if this flag is set, the internal #URLSTR file will be dumped /// DumpUrlStr = 32, /// /// DumpUrlTbl - if this flag is set, the internal #URLTBL file will be dumped /// DumpUrlTbl = 64, /// /// DumpTopics - if this flag is set, the internal #TOPICS file will be dumped /// DumpTopics = 128, /// /// DumpFullText - if this flag is set, the internal $FIftiMain file will be dumped /// DumpFullText = 256 } /// /// The class DumpingInfo implements information properties for the CHMFile class /// if and how data dumping should be used. /// public sealed class DumpingInfo { public bool m_bAllowSaveDump=true; private readonly static BitVector32.Section DumpFlags = BitVector32.CreateSection(512); private const string _dumpHeader = "HtmlHelpSystem dump file 1.0"; private string _outputDir = ""; // emtpy string means, same directory as chm file private DumpCompression _compressionLevel = DumpCompression.Maximum; private CHMFile _chmFile = null; private DeflaterOutputStream _outputStream = null; private InflaterInputStream _inputStream = null; private BinaryWriter _writer = null; private BinaryReader _reader = null; private BitVector32 _flags; /// /// Constructor of the class /// /// Combine flag values to specify which data should be dumped. /// output directory. emtpy string means, /// same directory as chm file (only if destination = ExternalFile) /// compression which should be used public DumpingInfo(DumpingFlags flags, string outputDir, DumpCompression compressionLevel) { _flags = new BitVector32(0); int i = _flags[DumpFlags]; _flags[DumpFlags] = i | (int)flags; _outputDir = outputDir; _compressionLevel = compressionLevel; } /// /// Gets the flag if text-based TOCs will be written to the dumping file /// public bool DumpTextTOC { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpTextTOC) != 0); } } /// /// Gets the flag if binary TOCs will be written to the dumping file /// public bool DumpBinaryTOC { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpBinaryTOC) != 0); } } /// /// Gets the flag if the text-based index will be written to the dumping file /// public bool DumpTextIndex { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpTextIndex) != 0); } } /// /// Gets the flag if the binary index will be written to the dumping file /// public bool DumpBinaryIndex { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpBinaryIndex) != 0); } } /// /// Gets the flag if the #STRINGS file will be written to the dumping file /// public bool DumpStrings { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpStrings) != 0); } } /// /// Gets the flag if the #URLSTR file will be written to the dumping file /// public bool DumpUrlStr { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpUrlStr) != 0); } } /// /// Gets the flag if the #URLTBL file will be written to the dumping file /// public bool DumpUrlTbl { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpUrlTbl) != 0); } } /// /// Gets the flag if the #TOPICS file will be written to the dumping file /// public bool DumpTopics { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpTopics) != 0); } } /// /// Gets the flag if the $FIftiMain file will be written to the dumping file /// public bool DumpFullText { get { return ((_flags[DumpFlags] & (int)DumpingFlags.DumpFullText) != 0); } } /// /// Gets the dump output directory. /// /// emtpy string means, same directory as chm file /// If Destination is set to DumpingOutput.InternalFile this property will be ignored public string OutputDir { get { return _outputDir; } } /// /// The compression level used. /// public DumpCompression CompressionLevel { get { return _compressionLevel; } } /// /// Gets/Sets the CHMFile instance associated with this object /// internal CHMFile ChmFile { get { return _chmFile; } set { _chmFile = value; } } /// /// Translates the compression level to the deflater constants /// private int CompLvl { get { switch(CompressionLevel) { case DumpCompression.None: return Deflater.NO_COMPRESSION; case DumpCompression.Minimum: return Deflater.BEST_SPEED; case DumpCompression.Medium: return Deflater.DEFAULT_COMPRESSION; case DumpCompression.Maximum: return Deflater.BEST_COMPRESSION; } return Deflater.BEST_COMPRESSION; } } /// /// Checks if a dump exists /// internal bool DumpExists { get { if(_flags[DumpFlags] == 0) return false; // we have a reader or writer to the dump so it must exist if( (_reader != null) || (_writer != null) ) return true; string sDmpFile = _chmFile.ChmFilePath; sDmpFile=sDmpFile.ToLower().Replace(".chm",".CHB"); return File.Exists(sDmpFile); } } /// /// Gets a binary writer instance which allows you to write to the dump /// internal BinaryWriter Writer { get { if (m_bAllowSaveDump==false) return null; if(_flags[DumpFlags] == 0) throw new InvalidOperationException("Nothing to dump. No flags have been set !"); if(_reader != null) throw new InvalidOperationException("Can't write and read at the same time !"); if(_chmFile == null) throw new InvalidOperationException("Only usable with an associated CHMFile instance !"); if(_writer==null) { string sDmpFile = _chmFile.ChmFilePath; sDmpFile=sDmpFile.ToLower().Replace(".chm",".CHB"); StreamWriter stream = new StreamWriter(sDmpFile, false, _chmFile.TextEncoding); // write header info uncompressed BinaryWriter _hwriter = new BinaryWriter(stream.BaseStream); _hwriter.Write(_dumpHeader); _hwriter.Write((int)CompressionLevel); if(_compressionLevel == DumpCompression.None) { _writer = new BinaryWriter(stream.BaseStream); } else { _outputStream = new DeflaterOutputStream(stream.BaseStream, new Deflater(CompLvl)); _writer = new BinaryWriter(_outputStream); } } return _writer; } } /// /// Gets a binary reader which allows you to read from the dump /// internal BinaryReader Reader { get { if(_writer != null) throw new InvalidOperationException("Can't write and read at the same time !"); if(_chmFile == null) throw new InvalidOperationException("Only usable with an associated CHMFile instance !"); if(_reader==null) { string sDmpFile = _chmFile.ChmFilePath; sDmpFile=sDmpFile.ToLower().Replace(".chm",".CHB"); StreamReader stream = new StreamReader(sDmpFile, _chmFile.TextEncoding); BinaryReader _hReader = new BinaryReader(stream.BaseStream); string sH = _hReader.ReadString(); if(sH != _dumpHeader) { _hReader.Close(); Debug.WriteLine("Unexpected dump-file header !"); throw new FormatException("DumpingInfo.Reader - Unexpected dump-file header !"); } _compressionLevel = (DumpCompression)_hReader.ReadInt32(); // if(_compressionLevel != (DumpCompression)_hReader.ReadInt32()) // { // _hReader.Close(); // return null; // } if(_compressionLevel == DumpCompression.None) { _reader = new BinaryReader(stream.BaseStream); } else { _inputStream = new InflaterInputStream(stream.BaseStream, new Inflater()); _reader = new BinaryReader(_inputStream); } } return _reader; } } /// /// Saves data and closes the dump /// /// true if succeed internal bool SaveData() { if (m_bAllowSaveDump==false) return true; if(_writer != null) { if(_writer!=null) _writer.Close(); _outputStream = null; _writer = null; } if(_reader != null) { if(_reader!=null) _reader.Close(); _inputStream = null; _reader = null; } return true; } } }