mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-09 02:16:46 +00:00
Migrate to external libmspack
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -7,3 +7,6 @@
|
||||
[submodule "HLLibSharp"]
|
||||
path = HLLibSharp
|
||||
url = https://github.com/mnadareski/HLLibSharp
|
||||
[submodule "LibMSPackSharp"]
|
||||
path = LibMSPackSharp
|
||||
url = https://github.com/mnadareski/LibMSPackSharp.git
|
||||
|
||||
@@ -22,6 +22,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Dtf.Compression.
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HLLibSharp", "HLLibSharp\HLLibSharp\HLLibSharp.csproj", "{14E9764A-A8BF-44C0-A1A8-2C95EA307040}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibMSPackSharp", "LibMSPackSharp\LibMSPackSharp\LibMSPackSharp.csproj", "{BD8144B8-4857-47E6-9717-E9F2DB374A89}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -52,6 +54,10 @@ Global
|
||||
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -37,9 +37,6 @@
|
||||
<DefaultItemExcludes>
|
||||
$(DefaultItemExcludes);
|
||||
**\AssemblyInfo.cs;
|
||||
External\hllib\HLExtract\**\*;
|
||||
External\hllib\HLExtract.Net\Program.cs;
|
||||
External\hllib\HLLib\**\*;
|
||||
External\stormlibsharp\lib\**;
|
||||
External\stormlibsharp\TestConsole\**
|
||||
</DefaultItemExcludes>
|
||||
@@ -59,15 +56,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HLLibSharp\HLLibSharp\HLLibSharp.csproj" />
|
||||
<ProjectReference Include="..\WixToolset\src\WixToolset.Dtf.Compression.Cab\WixToolset.Dtf.Compression.Cab.csproj" />
|
||||
<ProjectReference Include="..\WixToolset\src\WixToolset.Dtf.Compression\WixToolset.Dtf.Compression.csproj" />
|
||||
<ProjectReference Include="..\LibMSPackSharp\LibMSPackSharp\LibMSPackSharp.csproj" />
|
||||
<ProjectReference Include="..\WixToolset\src\WixToolset.Dtf.WindowsInstaller\WixToolset.Dtf.WindowsInstaller.csproj">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="External\cabextract\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
public abstract class BaseDecompressState
|
||||
{
|
||||
/// <summary>
|
||||
/// System wrapper for I/O operations
|
||||
/// </summary>
|
||||
public SystemImpl System { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Persistent error state of the state
|
||||
/// </summary>
|
||||
public Error Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input file handle
|
||||
/// </summary>
|
||||
public FileStream InputFileHandle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output file handle
|
||||
/// </summary>
|
||||
public FileStream OutputFileHandle { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of common fields shared by all decompressors
|
||||
/// </summary>
|
||||
public abstract class BaseDecompressor
|
||||
{
|
||||
/// <summary>
|
||||
/// System wrapper for I/O operations
|
||||
/// </summary>
|
||||
public SystemImpl System { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Persistent error state of the decompressor
|
||||
/// </summary>
|
||||
public Error Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the internal buffer
|
||||
/// </summary>
|
||||
public int BufferSize { get; set; }
|
||||
}
|
||||
}
|
||||
16
BurnOutSharp/External/libmspack/BaseHeader.cs
vendored
16
BurnOutSharp/External/libmspack/BaseHeader.cs
vendored
@@ -1,16 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for decompressor-used objects
|
||||
/// </summary>
|
||||
public abstract class BaseHeader { }
|
||||
}
|
||||
145
BurnOutSharp/External/libmspack/CAB/Cabinet.cs
vendored
145
BurnOutSharp/External/libmspack/CAB/Cabinet.cs
vendored
@@ -1,145 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains
|
||||
* "folders", which are compressed spans of data. Each cabinet has
|
||||
* "files", whose metadata is in the cabinet header, but whose actual data
|
||||
* is stored compressed in one of the "folders". Cabinets can span more
|
||||
* than one physical file on disk, in which case they are a "cabinet set",
|
||||
* and usually the last folder of each cabinet extends into the next
|
||||
* cabinet.
|
||||
*
|
||||
* For a complete description of the format, see the MSDN site:
|
||||
* http://msdn.microsoft.com/en-us/library/bb267310.aspx
|
||||
*/
|
||||
|
||||
/* Notes on compliance with cabinet specification:
|
||||
*
|
||||
* One of the main changes between cabextract 0.6 and libmspack's cab
|
||||
* decompressor is the move from block-oriented decompression to
|
||||
* stream-oriented decompression.
|
||||
*
|
||||
* cabextract would read one data block from disk, decompress it with the
|
||||
* appropriate method, then write the decompressed data. The CAB
|
||||
* specification is specifically designed to work like this, as it ensures
|
||||
* compression matches do not span the maximum decompressed block size
|
||||
* limit of 32kb.
|
||||
*
|
||||
* However, the compression algorithms used are stream oriented, with
|
||||
* specific hacks added to them to enforce the "individual 32kb blocks"
|
||||
* rule in CABs. In other file formats, they do not have this limitation.
|
||||
*
|
||||
* In order to make more generalised decompressors, libmspack's CAB
|
||||
* decompressor has moved from being block-oriented to more stream
|
||||
* oriented. This also makes decompression slightly faster.
|
||||
*
|
||||
* However, this leads to incompliance with the CAB specification. The
|
||||
* CAB controller can no longer ensure each block of input given to the
|
||||
* decompressors is matched with their output. The "decompressed size" of
|
||||
* each individual block is thrown away.
|
||||
*
|
||||
* Each CAB block is supposed to be seen as individually compressed. This
|
||||
* means each consecutive data block can have completely different
|
||||
* "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in
|
||||
* reality, all data blocks in a folder decompress to exactly 32768 bytes,
|
||||
* excepting the final block.
|
||||
*
|
||||
* Given this situation, the decompression algorithms are designed to
|
||||
* realign their input bitstreams on 32768 output-byte boundaries, and
|
||||
* various other special cases have been made. libmspack will not
|
||||
* correctly decompress LZX or Quantum compressed folders where the blocks
|
||||
* do not follow this "32768 bytes until last block" pattern. It could be
|
||||
* implemented if needed, but hopefully this is not necessary -- it has
|
||||
* not been seen in over 3Gb of CAB archives.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a single cabinet file.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
///
|
||||
/// If this cabinet is part of a merged cabinet set, the #files and #folders
|
||||
/// fields are common to all cabinets in the set, and will be identical.
|
||||
/// </summary>
|
||||
/// <see cref="Decompressor.Open(string)"/>
|
||||
/// <see cref="Decompressor.Close(Cabinet)"/>
|
||||
/// <see cref="Decompressor.Search(string)"/>
|
||||
public class Cabinet : BaseHeader
|
||||
{
|
||||
#region Internal
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet header information
|
||||
/// </summary>
|
||||
internal _CabinetHeader Header { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The next cabinet in a chained list, if this cabinet was opened with
|
||||
/// mscab_decompressor::search(). May be NULL to mark the end of the
|
||||
/// list.
|
||||
/// </summary>
|
||||
public Cabinet Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the cabinet. More correctly, the filename of the
|
||||
/// physical file that the cabinet resides in. This is given by the
|
||||
/// library user and may be in any format.
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file offset of cabinet within the physical file it resides in.
|
||||
/// </summary>
|
||||
public long BaseOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The previous cabinet in a cabinet set, or NULL.
|
||||
/// </summary>
|
||||
public Cabinet PreviousCabinet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The next cabinet in a cabinet set, or NULL.
|
||||
/// </summary>
|
||||
public Cabinet NextCabinet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the previous cabinet in a cabinet set, or NULL.
|
||||
/// </summary>
|
||||
public string PreviousName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the next cabinet in a cabinet set, or NULL.
|
||||
/// </summary>
|
||||
public string NextName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the disk containing the previous cabinet in a cabinet, or NULL.
|
||||
/// </summary>
|
||||
public string PreviousInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the disk containing the next cabinet in a cabinet set, or NULL.
|
||||
/// </summary>
|
||||
public string NextInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of all files in the cabinet or cabinet set.
|
||||
/// </summary>
|
||||
public InternalFile Files { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of all folders in the cabinet or cabinet set.
|
||||
/// </summary>
|
||||
public Folder Folders { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
// TODO
|
||||
public class Compressor
|
||||
{
|
||||
public SystemImpl System { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using LibMSPackSharp.Compression;
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
public class DecompressState : BaseDecompressState
|
||||
{
|
||||
/// <summary>
|
||||
/// Current folder we're extracting from
|
||||
/// </summary>
|
||||
public Folder Folder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current folder split we're in
|
||||
/// </summary>
|
||||
public FolderData Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed offset within folder
|
||||
/// </summary>
|
||||
public uint Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Which block are we decompressing?
|
||||
/// </summary>
|
||||
public uint Block { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cumulative sum of block output sizes
|
||||
/// </summary>
|
||||
public long Outlen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of compression used by folder
|
||||
/// </summary>
|
||||
public CompressionType CompressionType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompressor state
|
||||
/// </summary>
|
||||
public BaseDecompressState DecompressorState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet where input data comes from
|
||||
/// </summary>
|
||||
public Cabinet InputCabinet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input data consumed
|
||||
/// </summary>
|
||||
public int InputPointer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input data end
|
||||
/// </summary>
|
||||
public int InputEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// One input block of data
|
||||
/// </summary>
|
||||
public byte[] Input { get; set; } = new byte[Constants.CAB_INPUTBUF];
|
||||
|
||||
/// <summary>
|
||||
/// Decompressor code
|
||||
/// </summary>
|
||||
public Error Decompress(object o, long bytes)
|
||||
{
|
||||
switch (CompressionType & CompressionType.COMPTYPE_MASK)
|
||||
{
|
||||
case CompressionType.COMPTYPE_NONE:
|
||||
return (o as None)?.Decompress(bytes) ?? Error.MSPACK_ERR_ARGS;
|
||||
|
||||
case CompressionType.COMPTYPE_MSZIP:
|
||||
return (o as MSZIP)?.Decompress(bytes) ?? Error.MSPACK_ERR_ARGS;
|
||||
|
||||
case CompressionType.COMPTYPE_QUANTUM:
|
||||
return (o as QTM)?.Decompress(bytes) ?? Error.MSPACK_ERR_ARGS;
|
||||
|
||||
case CompressionType.COMPTYPE_LZX:
|
||||
return (o as LZX)?.Decompress(bytes) ?? Error.MSPACK_ERR_ARGS;
|
||||
|
||||
default:
|
||||
return Error = Error.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1500
BurnOutSharp/External/libmspack/CAB/Decompressor.cs
vendored
1500
BurnOutSharp/External/libmspack/CAB/Decompressor.cs
vendored
File diff suppressed because it is too large
Load Diff
112
BurnOutSharp/External/libmspack/CAB/Enums.cs
vendored
112
BurnOutSharp/External/libmspack/CAB/Enums.cs
vendored
@@ -1,112 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
[Flags]
|
||||
public enum CompressionType : ushort
|
||||
{
|
||||
COMPTYPE_MASK = 0x000f,
|
||||
|
||||
COMPTYPE_NONE = 0x0000,
|
||||
COMPTYPE_MSZIP = 0x0001,
|
||||
COMPTYPE_QUANTUM = 0x0002,
|
||||
COMPTYPE_LZX = 0x0003,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FileAttributes : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the file is write protected.
|
||||
/// </summary>
|
||||
MSCAB_ATTRIB_RDONLY = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the file is hidden.
|
||||
/// </summary>
|
||||
MSCAB_ATTRIB_HIDDEN = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the file is a operating system file.
|
||||
/// </summary>
|
||||
MSCAB_ATTRIB_SYSTEM = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the file is "archived".
|
||||
/// </summary>
|
||||
MSCAB_ATTRIB_ARCH = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the file is an executable program.
|
||||
/// </summary>
|
||||
MSCAB_ATTRIB_EXEC = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the filename is in UTF8 format rather than ISO-8859-1.
|
||||
/// </summary>
|
||||
MSCAB_ATTRIB_UTF_NAME = 0x80,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FileFlags : ushort
|
||||
{
|
||||
CONTINUED_FROM_PREV = 0xFFFD,
|
||||
CONTINUED_TO_NEXT = 0xFFFE,
|
||||
CONTINUED_PREV_AND_NEXT = 0xFFFF,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum HeaderFlags : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the cabinet is part of a cabinet set, and has a predecessor cabinet.
|
||||
/// </summary>
|
||||
MSCAB_HDR_PREVCAB = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the cabinet is part of a cabinet set, and has a successor cabinet.
|
||||
/// </summary>
|
||||
MSCAB_HDR_NEXTCAB = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the cabinet has reserved header space.
|
||||
/// </summary>
|
||||
MSCAB_HDR_RESV = 0x0004,
|
||||
}
|
||||
|
||||
public enum Parameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Search buffer size.
|
||||
/// </summary>
|
||||
MSCABD_PARAM_SEARCHBUF = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Repair MS-ZIP streams?
|
||||
/// </summary>
|
||||
MSCABD_PARAM_FIXMSZIP = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Size of decompression buffer
|
||||
/// </summary>
|
||||
MSCABD_PARAM_DECOMPBUF = 2,
|
||||
|
||||
/// <summary>
|
||||
/// salvage data from bad cabinets?
|
||||
/// If enabled, open() will skip file with bad folder indices or filenames
|
||||
/// rather than reject the whole cabinet, and extract() will limit rather than
|
||||
/// reject files with invalid offsets and lengths, and bad data block checksums
|
||||
/// will be ignored. Available only in CAB decoder version 2 and above.
|
||||
/// </summary>
|
||||
MSCABD_PARAM_SALVAGE = 3,
|
||||
}
|
||||
}
|
||||
60
BurnOutSharp/External/libmspack/CAB/Folder.cs
vendored
60
BurnOutSharp/External/libmspack/CAB/Folder.cs
vendored
@@ -1,60 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a single folder in a cabinet or cabinet set.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
///
|
||||
/// A folder is a single compressed stream of data. When uncompressed, it
|
||||
/// holds the data of one or more files. A folder may be split across more
|
||||
/// than one cabinet.
|
||||
/// </summary>
|
||||
public class Folder
|
||||
{
|
||||
#region Internal
|
||||
|
||||
/// <summary>
|
||||
/// Folder header information
|
||||
/// </summary>
|
||||
internal _FolderHeader Header { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// A pointer to the next folder in this cabinet or cabinet set, or NULL
|
||||
/// if this is the final folder.
|
||||
/// </summary>
|
||||
public Folder Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where are the data blocks?
|
||||
/// </summary>
|
||||
public FolderData Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// First file needing backwards merge
|
||||
/// </summary>
|
||||
public InternalFile MergePrev { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// First file needing forwards merge
|
||||
/// </summary>
|
||||
public InternalFile MergeNext { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
/// <summary>
|
||||
/// There is one of these for every cabinet a folder spans
|
||||
/// </summary>
|
||||
public class FolderData
|
||||
{
|
||||
public FolderData Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet file of this folder span
|
||||
/// </summary>
|
||||
public Cabinet Cab { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet offset of first datablock
|
||||
/// </summary>
|
||||
public long Offset { get; set; }
|
||||
};
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a single file in a cabinet or cabinet set.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class InternalFile
|
||||
{
|
||||
#region Internal
|
||||
|
||||
/// <summary>
|
||||
/// File header information
|
||||
/// </summary>
|
||||
internal _FileHeader Header { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The next file in the cabinet or cabinet set, or NULL if this is the final file.
|
||||
/// </summary>
|
||||
public InternalFile Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the file.
|
||||
///
|
||||
/// A null terminated string of up to 255 bytes in length, it may be in
|
||||
/// either ISO-8859-1 or UTF8 format, depending on the file attributes.
|
||||
/// </summary>
|
||||
/// <see cref="_FileHeader.Attributes"/>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A pointer to the folder that contains this file.
|
||||
/// </summary>
|
||||
public Folder Folder { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
internal class _CabinetHeader
|
||||
{
|
||||
#region Normal Header
|
||||
|
||||
/// <summary>
|
||||
/// "MSCF"
|
||||
/// </summary>
|
||||
/// <remarks>0x00</remarks>
|
||||
public uint Signature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x04</remarks>
|
||||
public uint Reserved0 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of the cabinet file in bytes.
|
||||
/// </summary>
|
||||
/// <remarks>0x08</remarks>
|
||||
public uint CabinetSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0C</remarks>
|
||||
public uint Reserved1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x10</remarks>
|
||||
public uint FileOffset { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x14</remarks>
|
||||
public uint Reserved2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minor cabinet version
|
||||
/// </summary>
|
||||
/// <remarks>0x18</remarks>
|
||||
public byte MinorVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Major cabinet version
|
||||
/// </summary>
|
||||
/// <remarks>0x19</remarks>
|
||||
public byte MajorVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of internal folders
|
||||
/// </summary>
|
||||
/// <remarks>0x1A</remarks>
|
||||
public ushort NumFolders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of internal files
|
||||
/// </summary>
|
||||
/// <remarks>0x1C</remarks>
|
||||
public ushort NumFiles { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header flags.
|
||||
/// </summary>
|
||||
/// <remarks>0x1E</remarks>
|
||||
/// <see cref="Cabinet.PreviousName"/>
|
||||
/// <see cref="Cabinet.PreviousInfo"/>
|
||||
/// <see cref="Cabinet.NextName"/>
|
||||
/// <see cref="Cabinet.NextInfo"/>
|
||||
/// <see cref="Cabinet.HeaderResv"/>
|
||||
public HeaderFlags Flags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set ID of the cabinet. All cabinets in the same set should have
|
||||
/// the same set ID.
|
||||
/// </summary>
|
||||
/// <remarks>0x20</remarks>
|
||||
public ushort SetID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The index number of the cabinet within the set. Numbering should
|
||||
/// start from 0 for the first cabinet in the set, and increment by 1 for
|
||||
/// each following cabinet.
|
||||
/// </summary>
|
||||
/// <remarks>0x22</remarks>
|
||||
public ushort CabinetIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the normal Cabinet header in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x24;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extended Header
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes reserved in the header area of the cabinet.
|
||||
///
|
||||
/// If this is non-zero and flags has MSCAB_HDR_RESV set, this data can
|
||||
/// be read by the calling application. It is of the given length,
|
||||
/// located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the
|
||||
/// cabinet file.
|
||||
/// </summary>
|
||||
/// <remarks>0x24</remarks>
|
||||
/// <see cref="Flags"/>
|
||||
public ushort HeaderReserved { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes reserved in the folder area of the cabinet
|
||||
/// </summary>
|
||||
/// <remarks>0x26</remarks>
|
||||
public byte FolderReserved { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes reserved in the data area of the cabinet
|
||||
/// </summary>
|
||||
/// <remarks>0x27</remarks>
|
||||
public byte DataReserved { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the extended Cabinet header in bytes
|
||||
/// </summary>
|
||||
public const int ExtendedSize = 0x04;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _CabinetHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _CabinetHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _CabinetHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _CabinetHeader();
|
||||
|
||||
header.Signature = BitConverter.ToUInt32(buffer, 0x00);
|
||||
if (header.Signature != 0x4643534D)
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
header.Reserved0 = BitConverter.ToUInt32(buffer, 0x04);
|
||||
header.CabinetSize = BitConverter.ToUInt32(buffer, 0x08);
|
||||
header.Reserved1 = BitConverter.ToUInt32(buffer, 0x0C);
|
||||
header.FileOffset = BitConverter.ToUInt32(buffer, 0x10);
|
||||
header.Reserved2 = BitConverter.ToUInt32(buffer, 0x14);
|
||||
|
||||
// Expect version 1.3, but don't validate
|
||||
header.MinorVersion = buffer[0x18];
|
||||
header.MajorVersion = buffer[0x19];
|
||||
|
||||
header.NumFolders = BitConverter.ToUInt16(buffer, 0x1A);
|
||||
if (header.NumFolders == 0)
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
header.NumFiles = BitConverter.ToUInt16(buffer, 0x1C);
|
||||
if (header.NumFiles == 0)
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
header.Flags = (HeaderFlags)BitConverter.ToUInt16(buffer, 0x1E);
|
||||
header.SetID = BitConverter.ToUInt16(buffer, 0x20);
|
||||
header.CabinetIndex = BitConverter.ToUInt16(buffer, 0x20);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the extended header fields from buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
public void PopulateExtendedHeader(byte[] buffer)
|
||||
{
|
||||
if (buffer.Length < ExtendedSize)
|
||||
return;
|
||||
|
||||
// Expect less than 60,000, but don't validate
|
||||
HeaderReserved = BitConverter.ToUInt16(buffer, 0x00);
|
||||
FolderReserved = buffer[0x02];
|
||||
DataReserved = buffer[0x03];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
internal class _DataBlockHeader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Block CRC32 checksum
|
||||
/// </summary>
|
||||
/// <remarks>0x00</remarks>
|
||||
public uint CheckSum { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size of the data block
|
||||
/// </summary>
|
||||
/// <remarks>0x04</remarks>
|
||||
public ushort CompressedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed size of the data block
|
||||
/// </summary>
|
||||
/// <remarks>0x06</remarks>
|
||||
public ushort UncompressedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the Data Block header in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x08;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _DataBlockHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _DataBlockHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _DataBlockHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _DataBlockHeader();
|
||||
|
||||
header.CheckSum = BitConverter.ToUInt32(buffer, 0x00);
|
||||
header.CompressedSize = BitConverter.ToUInt16(buffer, 0x04);
|
||||
header.UncompressedSize = BitConverter.ToUInt16(buffer, 0x06);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
BurnOutSharp/External/libmspack/CAB/_FileHeader.cs
vendored
122
BurnOutSharp/External/libmspack/CAB/_FileHeader.cs
vendored
@@ -1,122 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
internal class _FileHeader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// The uncompressed length of the file, in bytes.
|
||||
/// </summary>
|
||||
/// <remarks>0x00</remarks>
|
||||
public uint UncompressedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The uncompressed offset of this file in its folder.
|
||||
/// </summary>
|
||||
/// <remarks>0x04</remarks>
|
||||
public uint FolderOffset { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Internal index of the folder
|
||||
/// </summary>
|
||||
/// <remarks>0x08</remarks>
|
||||
public FileFlags FolderIndex { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// File's last modified date, day field.
|
||||
/// </summary>
|
||||
/// <remarks>0x0A</remarks>
|
||||
public byte LastModifiedDateDay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File's last modified date, month field.
|
||||
/// </summary>
|
||||
/// <remarks>0x0A</remarks>
|
||||
public byte LastModifiedDateMonth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File's last modified date, year field.
|
||||
/// </summary>
|
||||
/// <remarks>0x0A</remarks>
|
||||
public int LastModifiedDateYear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File's last modified time, hour field.
|
||||
/// </summary>
|
||||
/// <remarks>0x0C</remarks>
|
||||
public byte LastModifiedTimeHour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File's last modified time, minute field.
|
||||
/// </summary>
|
||||
/// <remarks>0x0C</remarks>
|
||||
public byte LastModifiedTimeMinute { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File's last modified time, second field.
|
||||
/// </summary>
|
||||
/// <remarks>0x0C</remarks>
|
||||
public byte LastModifiedTimeSecond { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File attributes.
|
||||
/// </summary>
|
||||
/// <remarks>0x0E</remarks>
|
||||
public FileAttributes Attributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the File header in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x10;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _FileHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _FileHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _FileHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _FileHeader();
|
||||
|
||||
header.UncompressedSize = BitConverter.ToUInt32(buffer, 0x00);
|
||||
header.FolderOffset = BitConverter.ToUInt32(buffer, 0x04);
|
||||
header.FolderIndex = (FileFlags)BitConverter.ToUInt16(buffer, 0x08);
|
||||
|
||||
// Get date
|
||||
ushort x = BitConverter.ToUInt16(buffer, 0x0A);
|
||||
header.LastModifiedDateDay = (byte)(x & 0x1F);
|
||||
header.LastModifiedDateMonth = (byte)((x >> 5) & 0xF);
|
||||
header.LastModifiedDateYear = (x >> 9) + 1980;
|
||||
|
||||
// Get time
|
||||
x = BitConverter.ToUInt16(buffer, 0x0C);
|
||||
header.LastModifiedTimeHour = (byte)(x >> 11);
|
||||
header.LastModifiedTimeMinute = (byte)((x >> 5) & 0x3F);
|
||||
header.LastModifiedTimeSecond = (byte)((x << 1) & 0x3E);
|
||||
|
||||
header.Attributes = (FileAttributes)BitConverter.ToUInt16(buffer, 0x0E);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CAB
|
||||
{
|
||||
internal class _FolderHeader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Cabinet offset of first datablock
|
||||
/// </summary>
|
||||
/// <remarks>0x00</remarks>
|
||||
public uint DataOffset { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total number of data blocks used by this folder. This includes
|
||||
/// data blocks present in other files, if this folder spans more than
|
||||
/// one cabinet.
|
||||
/// </summary>
|
||||
/// <remarks>0x04</remarks>
|
||||
public ushort NumBlocks { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The compression format used by this folder.
|
||||
///
|
||||
/// The macro MSCABD_COMP_METHOD() should be used on this field to get
|
||||
/// the algorithm used. The macro MSCABD_COMP_LEVEL() should be used to get
|
||||
/// the "compression level".
|
||||
/// </summary>
|
||||
/// <remarks>0x06</remarks>
|
||||
public CompressionType CompType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the Folder header in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x08;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _FolderHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _FolderHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _FolderHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _FolderHeader();
|
||||
|
||||
header.DataOffset = BitConverter.ToUInt32(buffer, 0x00);
|
||||
header.NumBlocks = BitConverter.ToUInt16(buffer, 0x04);
|
||||
header.CompType = (CompressionType)BitConverter.ToUInt16(buffer, 0x06);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
85
BurnOutSharp/External/libmspack/CHM/CHM.cs
vendored
85
BurnOutSharp/External/libmspack/CHM/CHM.cs
vendored
@@ -1,85 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a CHM helpfile.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class CHM : BaseHeader
|
||||
{
|
||||
#region Internal
|
||||
|
||||
/// <summary>
|
||||
/// CHM header information
|
||||
/// </summary>
|
||||
internal _CHMHeader Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header section table information
|
||||
/// </summary>
|
||||
internal _HeaderSectionTable HeaderSectionTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header section 0 information
|
||||
/// </summary>
|
||||
internal _HeaderSection0 HeaderSection0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header section 1 information
|
||||
/// </summary>
|
||||
internal _HeaderSection1 HeaderSection1 { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the CHM helpfile. This is given by the library user
|
||||
/// and may be in any format.
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of all non-system files in the CHM helpfile.
|
||||
/// </summary>
|
||||
public DecompressFile Files { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of all system files in the CHM helpfile.
|
||||
///
|
||||
/// System files are files which begin with "::". They are meta-files
|
||||
/// generated by the CHM creation process.
|
||||
/// </summary>
|
||||
public DecompressFile SysFiles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The section 0 (uncompressed) data in this CHM helpfile.
|
||||
/// </summary>
|
||||
public UncompressedSection Sec0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The section 1 (MSCompressed) data in this CHM helpfile.
|
||||
/// </summary>
|
||||
public MSCompressedSection Sec1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A cache of loaded chunks, filled in by mschm_decoder::fast_find().
|
||||
/// Available only in CHM decoder version 2 and above.
|
||||
/// </summary>
|
||||
public byte[][] ChunkCache { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a file to be placed in a CHM helpfile.
|
||||
///
|
||||
/// A contiguous array of these structures should be passed to
|
||||
/// Compressor.Generate(). The array list is terminated with an
|
||||
/// entry whose InternalFile.Section field is set to #MSCHMC_ENDLIST, the
|
||||
/// other fields in this entry are ignored.
|
||||
/// </summary>
|
||||
public class CompressFile
|
||||
{
|
||||
/// <summary>
|
||||
/// One of #MSCHMC_ENDLIST, #MSCHMC_UNCOMP or #MSCHMC_MSCOMP.
|
||||
/// </summary>
|
||||
public SectionType Section { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of the source file that will be added to the CHM. This
|
||||
/// is passed directly to mspack_system::open()
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full path and filename of the file within the CHM helpfile, a
|
||||
/// UTF-1 encoded null-terminated string.
|
||||
/// </summary>
|
||||
public string CHMFilename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of the file, in bytes. This will be adhered to strictly
|
||||
/// and a read error will be issued if this many bytes cannot be read
|
||||
/// from the real file at CHM generation time.
|
||||
/// </summary>
|
||||
public long Length { get; set; }
|
||||
}
|
||||
}
|
||||
149
BurnOutSharp/External/libmspack/CHM/Compressor.cs
vendored
149
BurnOutSharp/External/libmspack/CHM/Compressor.cs
vendored
@@ -1,149 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A compressor for .CHM (Microsoft HTMLHelp) files.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateCHMCompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroyCHMCompressor(Compressor)"/>
|
||||
public class Compressor
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public SystemImpl System { get; set; }
|
||||
|
||||
public string TempFile { get; set; }
|
||||
|
||||
public bool UseTempFile { get; set; }
|
||||
|
||||
public Error Error { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Generates a CHM help file.
|
||||
///
|
||||
/// The help file will contain up to two sections, an Uncompressed
|
||||
/// section and potentially an MSCompressed (LZX compressed)
|
||||
/// section.
|
||||
///
|
||||
/// While the contents listing of a CHM file is always in lexical order,
|
||||
/// the file list passed in will be taken as the correct order for files
|
||||
/// within the sections. It is in your interest to place similar files
|
||||
/// together for better compression.
|
||||
///
|
||||
/// There are two modes of generation, to use a temporary file or not to
|
||||
/// use one. See use_temporary_file() for the behaviour of generate() in
|
||||
/// these two different modes.
|
||||
/// </summary>
|
||||
/// <param name="fileList">
|
||||
/// an array of mschmc_file structures, terminated
|
||||
/// with an entry whose mschmc_file::section field is
|
||||
/// #MSCHMC_ENDLIST. The order of the list is
|
||||
/// preserved within each section. The length of any
|
||||
/// mschmc_file::chm_filename string cannot exceed
|
||||
/// roughly 4096 bytes. Each source file must be able
|
||||
/// to supply as many bytes as given in the
|
||||
/// mschmc_file::length field.
|
||||
/// </param>
|
||||
/// <param name="outputFile">
|
||||
/// the file to write the generated CHM helpfile to.
|
||||
/// This is passed directly to mspack_system::open()
|
||||
/// </param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <see cref="UseTemporaryFile"/>
|
||||
/// <see cref="SetParam"/>
|
||||
public Error Generate(CompressFile[] fileList, string outputFile) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Specifies whether a temporary file is used during CHM generation.
|
||||
///
|
||||
/// The CHM file format includes data about the compressed section (such
|
||||
/// as its overall size) that is stored in the output CHM file prior to
|
||||
/// the compressed section itself. This unavoidably requires that the
|
||||
/// compressed section has to be generated, before these details can be
|
||||
/// set. There are several ways this can be handled. Firstly, the
|
||||
/// compressed section could be generated entirely in memory before
|
||||
/// writing any of the output CHM file.This approach is not used in
|
||||
/// libmspack, as the compressed section can exceed the addressable
|
||||
/// memory space on most architectures.
|
||||
///
|
||||
/// libmspack has two options, either to write these unknowable sections
|
||||
/// with blank data, generate the compressed section, then re-open the
|
||||
/// output file for update once the compressed section has been
|
||||
/// completed, or to write the compressed section to a temporary file,
|
||||
/// then write the entire output file at once, performing a simple
|
||||
/// file-to-file copy for the compressed section.
|
||||
///
|
||||
/// The simple solution of buffering the entire compressed section in
|
||||
/// memory can still be used, if desired.As the temporary file's
|
||||
/// filename is passed directly to mspack_system::open(), it is possible
|
||||
/// for a custom mspack_system implementation to hold this file in memory,
|
||||
/// without writing to a disk.
|
||||
///
|
||||
/// If a temporary file is set, generate() performs the following
|
||||
/// sequence of events: the temporary file is opened for writing, the
|
||||
/// compression algorithm writes to the temporary file, the temporary
|
||||
/// file is closed.Then the output file is opened for writing and the
|
||||
/// temporary file is re-opened for reading.The output file is written
|
||||
/// and the temporary file is read from. Both files are then closed.The
|
||||
/// temporary file itself is not deleted. If that is desired, the
|
||||
/// temporary file should be deleted after the completion of generate(),
|
||||
/// if it exists.
|
||||
///
|
||||
/// If a temporary file is set not to be used, generate() performs the
|
||||
/// following sequence of events: the output file is opened for writing,
|
||||
/// then it is written and closed.The output file is then re-opened for
|
||||
/// update, the appropriate sections are seek() ed to and re-written, then
|
||||
/// the output file is closed.
|
||||
/// </summary>
|
||||
/// <param name="useTempFile">
|
||||
/// non-zero if the temporary file should be used,
|
||||
/// zero if the temporary file should not be used.
|
||||
/// </param>
|
||||
/// <param name="tempFile">
|
||||
/// a file to temporarily write compressed data to,
|
||||
/// before opening it for reading and copying the
|
||||
/// contents to the output file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <see cref="Generate"/>
|
||||
public Error UseTemporaryFile(bool useTempFile, string tempFile) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Sets a CHM compression engine parameter.
|
||||
/// </summary>
|
||||
/// <param name="param">the parameter to set</param>
|
||||
/// <param name="value">the value to set the parameter to</param>
|
||||
/// <returns>
|
||||
/// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
|
||||
/// is a problem with either parameter or value.
|
||||
/// </returns>
|
||||
/// <see cref="Generate"/>
|
||||
public Error SetParam(Parameters param, int value) => throw new NotImplementedException();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a file stored in a CHM helpfile.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class DecompressFile
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to the next file in the list, or NULL if this is the final file.
|
||||
/// </summary>
|
||||
public DecompressFile Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A pointer to the section that this file is located in. Indirectly,
|
||||
/// it also points to the CHM helpfile the file is located in.
|
||||
/// </summary>
|
||||
public Section Section { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The offset within the section data that this file is located at.
|
||||
/// </summary>
|
||||
public long Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of this file, in bytes
|
||||
/// </summary>
|
||||
public long Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The filename of this file -- a null terminated string in UTF-8.
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using LibMSPackSharp.Compression;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
public class DecompressState : BaseDecompressState
|
||||
{
|
||||
/// <summary>
|
||||
/// CHM file being decompressed
|
||||
/// </summary>
|
||||
public CHM Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed offset within folder
|
||||
/// </summary>
|
||||
public long Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset in input file
|
||||
/// </summary>
|
||||
public long InOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// LZX decompressor state
|
||||
/// </summary>
|
||||
public LZX State { get; set; }
|
||||
}
|
||||
}
|
||||
1470
BurnOutSharp/External/libmspack/CHM/Decompressor.cs
vendored
1470
BurnOutSharp/External/libmspack/CHM/Decompressor.cs
vendored
File diff suppressed because it is too large
Load Diff
83
BurnOutSharp/External/libmspack/CHM/Enums.cs
vendored
83
BurnOutSharp/External/libmspack/CHM/Enums.cs
vendored
@@ -1,83 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
public enum Parameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the "timestamp" of the CHM file
|
||||
/// generated. This is not a timestamp, see mschmd_header::timestamp
|
||||
/// for a description. If this timestamp is 0, generate() will use its
|
||||
/// own algorithm for making a unique ID, based on the lengths and
|
||||
/// names of files in the CHM itself. Defaults to 0, any value between
|
||||
/// 0 and (2^32)-1 is valid.
|
||||
/// </summary>
|
||||
MSCHMC_PARAM_TIMESTAMP = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the "language" of the CHM file
|
||||
/// generated. This is not the language used in the CHM file, but the
|
||||
/// language setting of the user who ran the HTMLHelp compiler. It
|
||||
/// defaults to 0x0409. The valid range is between 0x0000 and 0x7F7F.
|
||||
/// </summary>
|
||||
MSCHMC_PARAM_LANGUAGE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the size of the LZX history window,
|
||||
/// which is also the interval at which the compressed data stream can be
|
||||
/// randomly accessed. The value is not a size in bytes, but a power of
|
||||
/// two. The default value is 16 (which makes the window 2^16 bytes, or
|
||||
/// 64 kilobytes), the valid range is from 15 (32 kilobytes) to 21 (2
|
||||
/// megabytes).
|
||||
/// </summary>
|
||||
MSCHMC_PARAM_LZXWINDOW = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the "density" of quick reference
|
||||
/// entries stored at the end of directory listing chunk. Each chunk is
|
||||
/// 4096 bytes in size, and contains as many file entries as there is
|
||||
/// room for. At the other end of the chunk, a list of "quick reference"
|
||||
/// pointers is included. The offset of every 'N'th file entry is given a
|
||||
/// quick reference, where N = (2 ^ density) + 1.The default density is
|
||||
/// 2. The smallest density is 0 (N = 2), the maximum is 10 (N = 1025). As
|
||||
/// each file entry requires at least 5 bytes, the maximum number of
|
||||
/// entries in a single chunk is roughly 800, so the maximum value 10
|
||||
/// can be used to indicate there are no quickrefs at all.
|
||||
/// </summary>
|
||||
MSCHMC_PARAM_DENSITY = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether or not to include quick lookup
|
||||
/// index chunk(s), in addition to normal directory listing chunks. A
|
||||
/// value of zero means no index chunks will be created, a non-zero value
|
||||
/// means index chunks will be created. The default is zero, "don't
|
||||
/// create an index".
|
||||
/// </summary>
|
||||
MSCHMC_PARAM_INDEX = 4,
|
||||
}
|
||||
|
||||
public enum SectionType
|
||||
{
|
||||
/// <summary>
|
||||
/// end of CHM file list
|
||||
/// </summary>
|
||||
MSCHMC_ENDLIST = 0,
|
||||
|
||||
/// <summary>
|
||||
/// this file is in the Uncompressed section
|
||||
/// </summary>
|
||||
MSCHMC_UNCOMP = 1,
|
||||
|
||||
/// <summary>
|
||||
/// this file is in the MSCompressed section
|
||||
/// </summary>
|
||||
MSCHMC_MSCOMP = 2,
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents the LZX compressed section of a CHM helpfile.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class MSCompressedSection : Section
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to the meta-file which represents all LZX compressed data.
|
||||
/// </summary>
|
||||
public DecompressFile Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A pointer to the file which contains the LZX control data.
|
||||
/// </summary>
|
||||
public DecompressFile Control { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A pointer to the file which contains the LZX reset table.
|
||||
/// </summary>
|
||||
public DecompressFile ResetTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A pointer to the file which contains the LZX span information.
|
||||
/// Available only in CHM decoder version 2 and above.
|
||||
/// </summary>
|
||||
public DecompressFile SpanInfo { get; set; }
|
||||
}
|
||||
}
|
||||
41
BurnOutSharp/External/libmspack/CHM/Section.cs
vendored
41
BurnOutSharp/External/libmspack/CHM/Section.cs
vendored
@@ -1,41 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents a section of a CHM helpfile.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
///
|
||||
/// Not used directly, but used as a generic base type for
|
||||
/// mschmd_sec_uncompressed and mschmd_sec_mscompressed.
|
||||
/// </summary>
|
||||
public class Section
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to the CHM helpfile that contains this section.
|
||||
/// </summary>
|
||||
public CHM Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The section ID. Either 0 for the uncompressed section
|
||||
/// mschmd_sec_uncompressed, or 1 for the LZX compressed section
|
||||
/// mschmd_sec_mscompressed. No other section IDs are known.
|
||||
/// </summary>
|
||||
public uint ID { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents the uncompressed section of a CHM helpfile.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class UncompressedSection : Section
|
||||
{
|
||||
/// <summary>
|
||||
/// The file offset of where this section begins in the CHM helpfile.
|
||||
/// </summary>
|
||||
public long Offset { get; set; }
|
||||
}
|
||||
}
|
||||
118
BurnOutSharp/External/libmspack/CHM/_CHMHeader.cs
vendored
118
BurnOutSharp/External/libmspack/CHM/_CHMHeader.cs
vendored
@@ -1,118 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _CHMHeader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// "ITSF"
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public uint Signature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The version of the CHM file format used in this file.
|
||||
/// </summary>
|
||||
/// <remarks>0x0004</remarks>
|
||||
public uint Version { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0008</remarks>
|
||||
public uint HeaderLen { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x000C</remarks>
|
||||
public uint Unknown1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The "timestamp" of the CHM helpfile.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x0010
|
||||
///
|
||||
/// It is the lower 32 bits of a 64-bit value representing the number of
|
||||
/// centiseconds since 1601-01-01 00:00:00 UTC, plus 42. It is not useful
|
||||
/// as a timestamp, but it is useful as a semi-unique ID.
|
||||
/// </remarks>
|
||||
public uint Timestamp { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default Language and Country ID (LCID) of the user who ran the
|
||||
/// HTMLHelp Compiler. This is not the language of the CHM file itself.
|
||||
/// </summary>
|
||||
/// <remarks>0x0014</remarks>
|
||||
public uint LanguageID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header GUID 1
|
||||
/// </summary>
|
||||
/// <remarks>0x0018</remarks>
|
||||
public Guid GUID1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header GUID 2
|
||||
/// </summary>
|
||||
/// <remarks>0x0028</remarks>
|
||||
public Guid GUID2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the CHM header in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x0038;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _CHMHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _CHMHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _CHMHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _CHMHeader();
|
||||
|
||||
header.Signature = BitConverter.ToUInt32(buffer, 0x0000);
|
||||
if (header.Signature != 0x46535449)
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
// Expect version less than or equal to 3, but don't validate
|
||||
header.Version = BitConverter.ToUInt32(buffer, 0x0004);
|
||||
header.HeaderLen = BitConverter.ToUInt32(buffer, 0x0008);
|
||||
header.Unknown1 = BitConverter.ToUInt32(buffer, 0x000C);
|
||||
header.Timestamp = BitConverter.ToUInt32(buffer, 0x0010);
|
||||
header.LanguageID = BitConverter.ToUInt32(buffer, 0x0014);
|
||||
|
||||
header.GUID1 = new Guid(new ReadOnlySpan<byte>(buffer, 0x0018, 0x10).ToArray());
|
||||
if (header.GUID1 != Guid.Parse("7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC"))
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
header.GUID2 = new Guid(new ReadOnlySpan<byte>(buffer, 0x0028, 0x10).ToArray());
|
||||
if (header.GUID2 != Guid.Parse("7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC"))
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _HeaderSection0
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public uint Unknown1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0004</remarks>
|
||||
public uint Unknown2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of the CHM helpfile, in bytes.
|
||||
/// </summary>
|
||||
/// <remarks>0x0008</remarks>
|
||||
public long FileLength { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0010</remarks>
|
||||
public uint Unknown3 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0014</remarks>
|
||||
public uint Unknown4 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the header section 0 in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x0018;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _HeaderSection0() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _HeaderSection0 from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _HeaderSection0 headerSection)
|
||||
{
|
||||
headerSection = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
headerSection = new _HeaderSection0();
|
||||
|
||||
headerSection.Unknown1 = BitConverter.ToUInt32(buffer, 0x0000);
|
||||
headerSection.Unknown2 = BitConverter.ToUInt32(buffer, 0x0004);
|
||||
headerSection.FileLength = BitConverter.ToInt64(buffer, 0x0008);
|
||||
|
||||
// TODO: Is this supposed to be <= 0?
|
||||
if (headerSection.FileLength != 0)
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
headerSection.Unknown3 = BitConverter.ToUInt32(buffer, 0x0010);
|
||||
headerSection.Unknown4 = BitConverter.ToUInt32(buffer, 0x0014);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _HeaderSection1
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public uint Signature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0004</remarks>
|
||||
public uint Version { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0008</remarks>
|
||||
public uint HeaderLen { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x000C</remarks>
|
||||
public uint Unknown1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of each PMGL/PMGI chunk, in bytes.
|
||||
/// </summary>
|
||||
/// <remarks>0x0010</remarks>
|
||||
public uint ChunkSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The "density" of the quick-reference section in PMGL/PMGI chunks.
|
||||
/// </summary>
|
||||
/// <remarks>0x0014</remarks>
|
||||
public uint Density { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The depth of the index tree.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x0018
|
||||
///
|
||||
/// - if 1, there are no PMGI chunks, only PMGL chunks.
|
||||
/// - if 2, there is 1 PMGI chunk. All chunk indices point to PMGL chunks.
|
||||
/// - if 3, the root PMGI chunk points to secondary PMGI chunks, which in turn point to PMGL chunks.
|
||||
/// - and so on...
|
||||
/// </remarks>
|
||||
public uint Depth { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of the root PMGI chunk.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x001C
|
||||
///
|
||||
/// If there is no index in the CHM helpfile, this will be 0xFFFFFFFF.
|
||||
/// </remarks>
|
||||
public uint IndexRoot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of the first PMGL chunk. Usually zero.
|
||||
/// Available only in CHM decoder version 2 and above.
|
||||
/// </summary>
|
||||
/// <remarks>0x0020</remarks>
|
||||
public uint FirstPMGL { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of the last PMGL chunk. Usually num_chunks-1.
|
||||
/// Available only in CHM decoder version 2 and above.
|
||||
/// </summary>
|
||||
/// <remarks>0x0024</remarks>
|
||||
public uint LastPMGL { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0028</remarks>
|
||||
public uint Unknown2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of PMGL/PMGI directory chunks in this CHM helpfile.
|
||||
/// </summary>
|
||||
/// <remarks>0x002C</remarks>
|
||||
public uint NumChunks { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0030</remarks>
|
||||
public uint LanguageID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0034</remarks>
|
||||
public Guid GUID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0044</remarks>
|
||||
public uint Unknown3 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0048</remarks>
|
||||
public uint Unknown4 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x004C</remarks>
|
||||
public uint Unknown5 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0050</remarks>
|
||||
public uint Unknown6 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the header section 1 in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x0054;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _HeaderSection1() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _HeaderSection1 from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _HeaderSection1 headerSection)
|
||||
{
|
||||
headerSection = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
headerSection = new _HeaderSection1();
|
||||
|
||||
headerSection.Signature = BitConverter.ToUInt32(buffer, 0x0000);
|
||||
headerSection.Version = BitConverter.ToUInt32(buffer, 0x0004);
|
||||
headerSection.HeaderLen = BitConverter.ToUInt32(buffer, 0x0008);
|
||||
headerSection.Unknown1 = BitConverter.ToUInt32(buffer, 0x000C);
|
||||
headerSection.ChunkSize = BitConverter.ToUInt32(buffer, 0x0010);
|
||||
headerSection.Density = BitConverter.ToUInt32(buffer, 0x0014);
|
||||
headerSection.Depth = BitConverter.ToUInt32(buffer, 0x0018);
|
||||
headerSection.IndexRoot = BitConverter.ToUInt32(buffer, 0x001C);
|
||||
headerSection.FirstPMGL = BitConverter.ToUInt32(buffer, 0x0020);
|
||||
headerSection.LastPMGL = BitConverter.ToUInt32(buffer, 0x0024);
|
||||
headerSection.Unknown2 = BitConverter.ToUInt32(buffer, 0x0028);
|
||||
headerSection.NumChunks = BitConverter.ToUInt32(buffer, 0x002C);
|
||||
headerSection.LanguageID = BitConverter.ToUInt32(buffer, 0x0030);
|
||||
headerSection.GUID = new Guid(new ReadOnlySpan<byte>(buffer, 0x0034, 0x10).ToArray());
|
||||
headerSection.Unknown3 = BitConverter.ToUInt32(buffer, 0x0044);
|
||||
headerSection.Unknown4 = BitConverter.ToUInt32(buffer, 0x0048);
|
||||
headerSection.Unknown5 = BitConverter.ToUInt32(buffer, 0x004C);
|
||||
headerSection.Unknown6 = BitConverter.ToUInt32(buffer, 0x0050);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _HeaderSectionTable
|
||||
{
|
||||
#region Regular Table
|
||||
|
||||
/// <summary>
|
||||
/// Header section 0 offset
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public long OffsetHS0 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header section 0 length
|
||||
/// </summary>
|
||||
/// <remarks>0x0008</remarks>
|
||||
public long LengthHS0 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header section 1 offset
|
||||
/// The file offset of the first PMGL/PMGI directory chunk.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x0010
|
||||
///
|
||||
/// This is internally settable because it has to be corrected in some cases
|
||||
/// </remarks>
|
||||
public long OffsetHS1 { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header section 1 length
|
||||
/// </summary>
|
||||
/// <remarks>0x0018</remarks>
|
||||
public long LengthHS1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the version 1 and 2 header section table in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x0020;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Version 3 Table
|
||||
|
||||
/// <summary>
|
||||
/// Header section 0 offset correct
|
||||
/// </summary>
|
||||
/// <remarks>0x0020</remarks>
|
||||
public long OffsetCS0 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the version 3 header section table in bytes
|
||||
/// </summary>
|
||||
public const int V3Size = 0x0028;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _HeaderSectionTable() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _HeaderSectionTable from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _HeaderSectionTable headerSectionTable)
|
||||
{
|
||||
headerSectionTable = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
headerSectionTable = new _HeaderSectionTable();
|
||||
|
||||
headerSectionTable.OffsetHS0 = BitConverter.ToInt64(buffer, 0x0000);
|
||||
headerSectionTable.LengthHS0 = BitConverter.ToInt64(buffer, 0x0008);
|
||||
headerSectionTable.OffsetHS1 = BitConverter.ToInt64(buffer, 0x0010);
|
||||
headerSectionTable.LengthHS1 = BitConverter.ToInt64(buffer, 0x0018);
|
||||
|
||||
if (buffer.Length >= V3Size)
|
||||
{
|
||||
headerSectionTable.OffsetCS0 = BitConverter.ToInt64(buffer, 0x0020);
|
||||
}
|
||||
|
||||
// OffsetCS0 does not exist in version 1 or 2 CHM files.
|
||||
// The offset will be corrected later, once HS1 is read.
|
||||
// TODO: Are these supposed to be == 0?
|
||||
if (headerSectionTable.OffsetHS0 != 0 || headerSectionTable.OffsetHS1 != 0 || headerSectionTable.OffsetCS0 != 0)
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _LZXControlData
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Length of the control data
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public uint Length { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// "LZXC"
|
||||
/// </summary>
|
||||
/// <remarks>0x0004</remarks>
|
||||
public uint Signature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Control data version
|
||||
/// </summary>
|
||||
/// <remarks>0x0008</remarks>
|
||||
public uint Version { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reset interval
|
||||
/// </summary>
|
||||
/// <remarks>0x000C</remarks>
|
||||
public uint ResetInterval { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window size
|
||||
/// </summary>
|
||||
/// <remarks>0x0010</remarks>
|
||||
public uint WindowSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache size
|
||||
/// </summary>
|
||||
/// <remarks>0x0014</remarks>
|
||||
public uint CacheSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache size
|
||||
/// </summary>
|
||||
/// <remarks>0x0018</remarks>
|
||||
public uint Unknown1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the LZX control data in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x001C;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _LZXControlData() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _LZXControlData from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _LZXControlData controlData)
|
||||
{
|
||||
controlData = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
controlData = new _LZXControlData();
|
||||
|
||||
controlData.Length = BitConverter.ToUInt32(buffer, 0x0000);
|
||||
controlData.Signature = BitConverter.ToUInt32(buffer, 0x0004);
|
||||
if (controlData.Signature != 0x43585A4C)
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
controlData.Version = BitConverter.ToUInt32(buffer, 0x0008);
|
||||
switch (controlData.Version)
|
||||
{
|
||||
case 1:
|
||||
controlData.ResetInterval = BitConverter.ToUInt32(buffer, 0x000C);
|
||||
controlData.WindowSize = BitConverter.ToUInt32(buffer, 0x0010);
|
||||
break;
|
||||
case 2:
|
||||
controlData.ResetInterval = BitConverter.ToUInt32(buffer, 0x000C) * LZX_FRAME_SIZE;
|
||||
controlData.WindowSize = BitConverter.ToUInt32(buffer, 0x0010) * LZX_FRAME_SIZE;
|
||||
break;
|
||||
default:
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
controlData.CacheSize = BitConverter.ToUInt32(buffer, 0x0014);
|
||||
controlData.Unknown1 = BitConverter.ToUInt32(buffer, 0x0018);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of bits in the window based on the window size
|
||||
/// </summary>
|
||||
/// <param name="windowBits">Window </param>
|
||||
/// <returns>An error code or MSPACK_ERR_OK if all is good</returns>
|
||||
public Error GetWindowBits(out int windowBits)
|
||||
{
|
||||
switch (WindowSize)
|
||||
{
|
||||
case 0x008000:
|
||||
windowBits = 15;
|
||||
break;
|
||||
|
||||
case 0x010000:
|
||||
windowBits = 16;
|
||||
break;
|
||||
|
||||
case 0x020000:
|
||||
windowBits = 17;
|
||||
break;
|
||||
|
||||
case 0x040000:
|
||||
windowBits = 18;
|
||||
break;
|
||||
|
||||
case 0x080000:
|
||||
windowBits = 19;
|
||||
break;
|
||||
|
||||
case 0x100000:
|
||||
windowBits = 20;
|
||||
break;
|
||||
|
||||
case 0x200000:
|
||||
windowBits = 21;
|
||||
break;
|
||||
|
||||
default:
|
||||
windowBits = -1;
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _LZXResetTable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// UNKNOWN
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public uint Unknown1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in the table
|
||||
/// </summary>
|
||||
/// <remarks>0x0004</remarks>
|
||||
public uint NumEntries { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of each entry
|
||||
/// </summary>
|
||||
/// <remarks>0x0008</remarks>
|
||||
public uint EntrySize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Table offset
|
||||
/// </summary>
|
||||
/// <remarks>0x000C</remarks>
|
||||
public uint TableOffset { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed length
|
||||
/// </summary>
|
||||
/// <remarks>0x0010</remarks>
|
||||
public long UncompressedLength { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compressed length
|
||||
/// </summary>
|
||||
/// <remarks>0x0018</remarks>
|
||||
public long CompressedLength { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Frame length
|
||||
/// </summary>
|
||||
/// <remarks>0x0020</remarks>
|
||||
public long FrameLength { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the LZX reset table in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x0028;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _LZXResetTable() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _LZXControlData from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _LZXResetTable resetTable)
|
||||
{
|
||||
resetTable = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
resetTable = new _LZXResetTable();
|
||||
|
||||
resetTable.Unknown1 = BitConverter.ToUInt32(buffer, 0x0000);
|
||||
resetTable.NumEntries = BitConverter.ToUInt32(buffer, 0x0004);
|
||||
resetTable.EntrySize = BitConverter.ToUInt32(buffer, 0x0008);
|
||||
resetTable.TableOffset = BitConverter.ToUInt32(buffer, 0x000C);
|
||||
resetTable.UncompressedLength = BitConverter.ToInt64(buffer, 0x0010);
|
||||
resetTable.CompressedLength = BitConverter.ToInt64(buffer, 0x0018);
|
||||
resetTable.FrameLength = BitConverter.ToInt64(buffer, 0x0020);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
BurnOutSharp/External/libmspack/CHM/_PMGHeader.cs
vendored
118
BurnOutSharp/External/libmspack/CHM/_PMGHeader.cs
vendored
@@ -1,118 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.CHM
|
||||
{
|
||||
internal class _PMGHeader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// "PMGL" or "PMGI"
|
||||
/// </summary>
|
||||
/// <remarks>0x0000</remarks>
|
||||
public uint Signature { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Quick reference size
|
||||
/// </summary>
|
||||
/// <remarks>0x0004</remarks>
|
||||
public uint QuickRefSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in a PMGI chunk
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x0008
|
||||
///
|
||||
/// Unused in PMGL
|
||||
/// </remarks>
|
||||
public uint PMGIEntries { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Previous chunk ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x000C
|
||||
///
|
||||
/// Does not exist in PMGI
|
||||
/// </remarks>
|
||||
public uint PrevChunk { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Next chunk ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x0010
|
||||
///
|
||||
/// Does not exist in PMGI
|
||||
/// </remarks>
|
||||
public uint NextChunk { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in a PMGL chunk
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 0x0014
|
||||
///
|
||||
/// Does not exist in PMGI
|
||||
/// </remarks>
|
||||
public uint PMGLEntries { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the PMGI header in bytes
|
||||
/// </summary>
|
||||
public const int PMGISize = 0x000C;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the PMGL header in bytes
|
||||
/// </summary>
|
||||
public const int PMGLSize = 0x0014;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _PMGHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _PMGHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _PMGHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < PMGISize)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _PMGHeader();
|
||||
|
||||
header.Signature = BitConverter.ToUInt32(buffer, 0x0000);
|
||||
header.QuickRefSize = BitConverter.ToUInt32(buffer, 0x0004);
|
||||
header.PMGIEntries = BitConverter.ToUInt32(buffer, 0x0008);
|
||||
|
||||
if (buffer.Length >= PMGLSize)
|
||||
{
|
||||
header.PrevChunk = BitConverter.ToUInt32(buffer, 0x000C);
|
||||
header.NextChunk = BitConverter.ToUInt32(buffer, 0x0010);
|
||||
header.PMGLEntries = BitConverter.ToUInt32(buffer, 0x0014);
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a PMG chunk is PMGL or PMGI
|
||||
/// </summary>
|
||||
/// <returns>True for PMGL and false of PMGI</returns>
|
||||
public bool IsPMGL() => Signature == 0x4C474D50;
|
||||
}
|
||||
}
|
||||
111
BurnOutSharp/External/libmspack/Checksum.cs
vendored
111
BurnOutSharp/External/libmspack/Checksum.cs
vendored
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
*
|
||||
* First, the polynomial itself and its table of feedback terms. The
|
||||
* polynomial is
|
||||
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
|
||||
*
|
||||
* Note that we take it "backwards" and put the highest-order term in
|
||||
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
|
||||
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
|
||||
* the MSB being 1
|
||||
*
|
||||
* Note that the usual hardware shift register implementation, which
|
||||
* is what we're using (we're merely optimizing it by doing eight-bit
|
||||
* chunks at a time) shifts bits into the lowest-order term. In our
|
||||
* implementation, that means shifting towards the right. Why do we
|
||||
* do it this way? Because the calculated CRC must be transmitted in
|
||||
* order from highest-order term to lowest-order term. UARTs transmit
|
||||
* characters in order from LSB to MSB. By storing the CRC this way
|
||||
* we hand it to the UART in the order low-byte to high-byte; the UART
|
||||
* sends each low-bit to hight-bit; and the result is transmission bit
|
||||
* by bit from highest- to lowest-order term without requiring any bit
|
||||
* shuffling on our part. Reception works similarly
|
||||
*
|
||||
* The feedback terms table consists of 256, 32-bit entries. Notes
|
||||
*
|
||||
* The table can be generated at runtime if desired; code to do so
|
||||
* is shown later. It might not be obvious, but the feedback
|
||||
* terms simply represent the results of eight shift/xor opera
|
||||
* tions for all combinations of data and CRC register values
|
||||
*
|
||||
* The values must be right-shifted by eight bits by the "updcrc
|
||||
* logic; the shift must be unsigned (bring in zeroes). On some
|
||||
* hardware you could probably optimize the shift in assembler by
|
||||
* using byte-swap instructions
|
||||
* polynomial $edb88320
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
public class Checksum
|
||||
{
|
||||
public static readonly uint[] CRC32Table = new uint[256]
|
||||
{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
|
||||
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
|
||||
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
|
||||
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
|
||||
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
|
||||
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
|
||||
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
|
||||
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
|
||||
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
|
||||
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
|
||||
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
|
||||
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
|
||||
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
|
||||
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
|
||||
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
|
||||
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
|
||||
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
|
||||
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
|
||||
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
|
||||
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
|
||||
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
|
||||
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
|
||||
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
|
||||
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
|
||||
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
|
||||
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
|
||||
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
|
||||
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
|
||||
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
|
||||
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
|
||||
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
|
||||
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
|
||||
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
|
||||
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
|
||||
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
|
||||
0x2d02ef8d
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Return a 32-bit CRC of the contents of the buffer.
|
||||
/// </summary>
|
||||
public static uint CRC32(byte[] ss, int pointer, int len, uint val)
|
||||
{
|
||||
while (--len >= 0)
|
||||
val = CRC32Table[(val ^ ss[pointer++]) & 0xff] ^ (val >> 8);
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
/* This header defines macros that read data streams by
|
||||
* the individual bits
|
||||
*
|
||||
* INIT_BITS initialises bitstream state in state structure
|
||||
* STORE_BITS stores bitstream state in state structure
|
||||
* RESTORE_BITS restores bitstream state from state structure
|
||||
* ENSURE_BITS(n) ensure there are at least N bits in the bit buffer
|
||||
* READ_BITS(var,n) takes N bits from the buffer and puts them in var
|
||||
* PEEK_BITS(n) extracts without removing N bits from the bit buffer
|
||||
* REMOVE_BITS(n) removes N bits from the bit buffer
|
||||
*
|
||||
* READ_BITS simply calls ENSURE_BITS, PEEK_BITS and REMOVE_BITS,
|
||||
* which means it's limited to reading the number of bits you can
|
||||
* ensure at any one time. It also fails if asked to read zero bits.
|
||||
* If you need to read zero bits, or more bits than can be ensured in
|
||||
* one go, use READ_MANY_BITS instead.
|
||||
*
|
||||
* These macros have variable names baked into them, so to use them
|
||||
* you have to define some macros:
|
||||
* - BITS_TYPE: the type name of your state structure
|
||||
* - BITS_VAR: the variable that points to your state structure
|
||||
* - define BITS_ORDER_MSB if bits are read from the MSB, or
|
||||
* define BITS_ORDER_LSB if bits are read from the LSB
|
||||
* - READ_BYTES: some code that reads more data into the bit buffer,
|
||||
* it should use READ_IF_NEEDED (calls read_input if the byte buffer
|
||||
* is empty), then INJECT_BITS(data,n) to put data from the byte
|
||||
* buffer into the bit buffer.
|
||||
*
|
||||
* You also need to define some variables and structure members:
|
||||
* - byte[] i_ptr; // current position in the byte buffer
|
||||
* - byte[] i_end; // end of the byte buffer
|
||||
* - uint bit_buffer; // the bit buffer itself
|
||||
* - uint bits_left; // number of bits remaining
|
||||
*
|
||||
* If you use read_input() and READ_IF_NEEDED, they also expect these
|
||||
* structure members:
|
||||
* - struct mspack_system *sys; // to access sys->read()
|
||||
* - uint error; // to record/return read errors
|
||||
* - byte input_end; // to mark reaching the EOF
|
||||
* - byte[] inbuf; // the input byte buffer
|
||||
* - uint inbuf_size; // the size of the input byte buffer
|
||||
*
|
||||
* Your READ_BYTES implementation should read data from *i_ptr and
|
||||
* put them in the bit buffer. READ_IF_NEEDED will call read_input()
|
||||
* if i_ptr reaches i_end, and will fill up inbuf and set i_ptr to
|
||||
* the start of inbuf and i_end to the end of inbuf.
|
||||
*
|
||||
* If you're reading in MSB order, the routines work by using the area
|
||||
* beyond the MSB and the LSB of the bit buffer as a free source of
|
||||
* zeroes when shifting. This avoids having to mask any bits. So we
|
||||
* have to know the bit width of the bit buffer variable. We use
|
||||
* <limits.h> and CHAR_BIT to find the size of the bit buffer in bits.
|
||||
*
|
||||
* If you are reading in LSB order, bits need to be masked. Normally
|
||||
* this is done by computing the mask: N bits are masked by the value
|
||||
* (1<<N)-1). However, you can define BITS_LSB_TABLE to use a lookup
|
||||
* table instead of computing this. This adds two new macros,
|
||||
* PEEK_BITS_T and READ_BITS_T which work the same way as PEEK_BITS
|
||||
* and READ_BITS, except they use this lookup table. This is useful if
|
||||
* you need to look up a number of bits that are only known at
|
||||
* runtime, so the bit mask can't be turned into a constant by the
|
||||
* compiler.
|
||||
* The bit buffer datatype should be at least 32 bits wide: it must be
|
||||
* possible to ENSURE_BITS(17), so it must be possible to add 16 new bits
|
||||
* to the bit buffer when the bit buffer already has 1 to 15 bits left.
|
||||
*/
|
||||
public abstract partial class CompressionStream : BaseDecompressState
|
||||
{
|
||||
#region Common
|
||||
|
||||
/// <summary>
|
||||
/// Initialises bitstream state in state structure
|
||||
/// </summary>
|
||||
public void INIT_BITS()
|
||||
{
|
||||
InputPointer = 0;
|
||||
InputEnd = 0;
|
||||
BitBuffer = 0;
|
||||
BitsLeft = 0;
|
||||
EndOfInput = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure there are at least N bits in the bit buffer
|
||||
/// </summary>
|
||||
public void ENSURE_BITS(int nbits)
|
||||
{
|
||||
while (BitsLeft < nbits)
|
||||
{
|
||||
READ_BYTES();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from the input if the buffer is empty
|
||||
/// </summary>
|
||||
public void READ_IF_NEEDED()
|
||||
{
|
||||
if (InputPointer >= InputEnd)
|
||||
ReadInput();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read bytes from the input into the bit buffer
|
||||
/// </summary>
|
||||
public abstract void READ_BYTES();
|
||||
|
||||
/// <summary>
|
||||
/// Read an input stream and fill the buffer
|
||||
/// </summary>
|
||||
protected virtual void ReadInput()
|
||||
{
|
||||
int read = System.Read(InputFileHandle, InputBuffer, 0, (int)InputBufferSize);
|
||||
if (read < 0)
|
||||
{
|
||||
Error = Error.MSPACK_ERR_READ;
|
||||
return;
|
||||
}
|
||||
|
||||
// We might overrun the input stream by asking for bits we don't use,
|
||||
// so fake 2 more bytes at the end of input
|
||||
if (read == 0)
|
||||
{
|
||||
if (EndOfInput > 0)
|
||||
{
|
||||
Console.WriteLine("Out of input bytes");
|
||||
Error = Error.MSPACK_ERR_READ;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
read = 2;
|
||||
InputBuffer[0] = InputBuffer[1] = 0;
|
||||
EndOfInput = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update i_ptr and i_end
|
||||
InputPointer = 0;
|
||||
InputEnd = read;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MSB
|
||||
|
||||
/// <summary>
|
||||
/// Inject data into the bit buffer
|
||||
/// </summary>
|
||||
public void INJECT_BITS_MSB(int bitdata, int nbits)
|
||||
{
|
||||
BitBuffer |= ((uint)bitdata << (BITBUF_WIDTH - nbits - BitsLeft));
|
||||
BitsLeft += nbits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts without removing N bits from the bit buffer
|
||||
/// </summary>
|
||||
public long PEEK_BITS_MSB(int nbits) => (BitBuffer >> (BITBUF_WIDTH - (nbits)));
|
||||
|
||||
/// <summary>
|
||||
/// Takes N bits from the buffer and puts them in var
|
||||
/// </summary>
|
||||
public long READ_BITS_MSB(int nbits)
|
||||
{
|
||||
ENSURE_BITS(nbits);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
|
||||
long temp = PEEK_BITS_MSB(nbits);
|
||||
|
||||
REMOVE_BITS_MSB(nbits);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read multiple bits and put them in var
|
||||
/// </summary>
|
||||
public long READ_MANY_BITS_MSB(int nbits)
|
||||
{
|
||||
byte needed = (byte)(nbits), bitrun;
|
||||
long temp = 0;
|
||||
while (needed > 0)
|
||||
{
|
||||
if (BitsLeft <= (BITBUF_WIDTH - 16))
|
||||
{
|
||||
READ_BYTES();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitrun = (byte)((BitsLeft < needed) ? BitsLeft : needed);
|
||||
temp = (temp << bitrun) | PEEK_BITS_MSB(bitrun);
|
||||
REMOVE_BITS_MSB(bitrun);
|
||||
needed -= bitrun;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes N bits from the bit buffer
|
||||
/// </summary>
|
||||
public void REMOVE_BITS_MSB(int nbits)
|
||||
{
|
||||
BitBuffer <<= nbits;
|
||||
BitsLeft -= nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LSB
|
||||
|
||||
/// <summary>
|
||||
/// Inject data into the bit buffer
|
||||
/// </summary>
|
||||
public void INJECT_BITS_LSB(int bitdata, int nbits)
|
||||
{
|
||||
BitBuffer |= (uint)(bitdata << BitsLeft);
|
||||
BitsLeft += nbits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts without removing N bits from the bit buffer
|
||||
/// </summary>
|
||||
public long PEEK_BITS_LSB(int nbits) => (BitBuffer & ((1 << (nbits)) - 1));
|
||||
|
||||
/// <summary>
|
||||
/// Extracts without removing N bits from the bit buffer using a bit mask
|
||||
/// </summary>
|
||||
public long PEEK_BITS_T_LSB(int nbits) => BitBuffer & LSBBitMask[(nbits)];
|
||||
|
||||
/// <summary>
|
||||
/// Takes N bits from the buffer and puts them in var
|
||||
/// </summary>
|
||||
public long READ_BITS_LSB(int nbits)
|
||||
{
|
||||
ENSURE_BITS(nbits);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
|
||||
long temp = PEEK_BITS_LSB(nbits);
|
||||
|
||||
REMOVE_BITS_LSB(nbits);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes N bits from the buffer and puts them in var using a bit mask
|
||||
/// </summary>
|
||||
public long READ_BITS_T_LSB(int nbits)
|
||||
{
|
||||
ENSURE_BITS(nbits);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return -1;
|
||||
|
||||
long temp = PEEK_BITS_T_LSB(nbits);
|
||||
|
||||
REMOVE_BITS_LSB(nbits);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes N bits from the bit buffer
|
||||
/// </summary>
|
||||
public void REMOVE_BITS_LSB(int nbits)
|
||||
{
|
||||
BitBuffer >>= nbits;
|
||||
BitsLeft -= nbits;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public abstract partial class CompressionStream : BaseDecompressState
|
||||
{
|
||||
#region Common
|
||||
|
||||
/// <summary>
|
||||
/// Per compression error code for decoding failure
|
||||
/// </summary>
|
||||
public abstract Error HUFF_ERROR();
|
||||
|
||||
#endregion
|
||||
|
||||
#region MSB
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the next huffman symbol from the input bitstream into var.
|
||||
/// Do not use this macro on a table unless build_decode_table() succeeded.
|
||||
/// </summary>
|
||||
public long READ_HUFFSYM_MSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
ENSURE_BITS(HUFF_MAXBITS);
|
||||
ushort sym = table[PEEK_BITS_MSB(tablebits)];
|
||||
if (sym >= maxsymbols)
|
||||
HUFF_TRAVERSE_MSB(ref sym, table, tablebits, maxsymbols);
|
||||
|
||||
REMOVE_BITS_MSB(lengths[sym]);
|
||||
return sym;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traverse for a single symbol
|
||||
/// </summary>
|
||||
private void HUFF_TRAVERSE_MSB(ref ushort sym, ushort[] table, int tablebits, int maxsymbols)
|
||||
{
|
||||
int i = 1 << (BITBUF_WIDTH - tablebits);
|
||||
do
|
||||
{
|
||||
if ((i >>= 1) == 0)
|
||||
{
|
||||
Error = HUFF_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
sym = table[(sym << 1) | ((BitBuffer & i) != 0 ? 1 : 0)];
|
||||
} while (sym >= maxsymbols);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function was originally coded by David Tritscher.
|
||||
///
|
||||
/// It builds a fast huffman decoding table from
|
||||
/// a canonical huffman code lengths table.
|
||||
/// </summary>
|
||||
/// <param name="nsyms">total number of symbols in this huffman tree.</param>
|
||||
/// <param name="nbits">any symbols with a code length of nbits or less can be decoded in one lookup of the table.</param>
|
||||
/// <param name="length">A table to get code lengths from [0 to nsyms-1]</param>
|
||||
/// <param name="table">
|
||||
/// The table to fill up with decoded symbols and pointers.
|
||||
/// Should be ((1<<nbits) + (nsyms*2)) in length.
|
||||
/// </param>
|
||||
/// <returns>True for OK or false for error</returns>
|
||||
public static bool MakeDecodeTableMSB(int nsyms, int nbits, byte[] length, ushort[] table)
|
||||
{
|
||||
ushort sym, next_symbol;
|
||||
long leaf, fill;
|
||||
byte bit_num;
|
||||
long pos = 0; // The current position in the decode table
|
||||
long table_mask = 1 << nbits;
|
||||
long bit_mask = table_mask >> 1; // Don't do 0 length codes
|
||||
|
||||
// Fill entries for codes short enough for a direct mapping
|
||||
for (bit_num = 1; bit_num <= nbits; bit_num++)
|
||||
{
|
||||
for (sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if (length[sym] != bit_num)
|
||||
continue;
|
||||
|
||||
leaf = pos;
|
||||
if ((pos += bit_mask) > table_mask)
|
||||
return false; // Table overrun
|
||||
|
||||
// Fill all possible lookups of this symbol with the symbol itself
|
||||
for (fill = bit_mask; fill-- > 0;)
|
||||
{
|
||||
table[leaf++] = sym;
|
||||
}
|
||||
}
|
||||
|
||||
bit_mask >>= 1;
|
||||
}
|
||||
|
||||
// Exit with success if table is now complete
|
||||
if (pos == table_mask)
|
||||
return true;
|
||||
|
||||
// Mark all remaining table entries as unused
|
||||
for (sym = (ushort)pos; sym < table_mask; sym++)
|
||||
{
|
||||
table[sym] = 0xFFFF;
|
||||
}
|
||||
|
||||
// next_symbol = base of allocation for long codes
|
||||
next_symbol = (ushort)(((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1));
|
||||
|
||||
// Give ourselves room for codes to grow by up to 16 more bits.
|
||||
// codes now start at bit nbits+16 and end at (nbits+16-codelength)
|
||||
pos <<= 16;
|
||||
table_mask <<= 16;
|
||||
bit_mask = 1 << 15;
|
||||
|
||||
for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++)
|
||||
{
|
||||
for (sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if (length[sym] != bit_num)
|
||||
continue;
|
||||
if (pos >= table_mask)
|
||||
return false; // Table overflow
|
||||
|
||||
leaf = pos >> 16;
|
||||
for (fill = 0; fill < (bit_num - nbits); fill++)
|
||||
{
|
||||
// If this path hasn't been taken yet, 'allocate' two entries
|
||||
if (table[leaf] == 0xFFFF)
|
||||
{
|
||||
table[(next_symbol << 1)] = 0xFFFF;
|
||||
table[(next_symbol << 1) + 1] = 0xFFFF;
|
||||
table[leaf] = next_symbol++;
|
||||
}
|
||||
|
||||
// Follow the path and select either left or right for next bit
|
||||
leaf = (uint)(table[leaf] << 1);
|
||||
if (((pos >> (15 - (int)fill)) & 1) != 0)
|
||||
leaf++;
|
||||
}
|
||||
|
||||
table[leaf] = sym;
|
||||
pos += bit_mask;
|
||||
}
|
||||
|
||||
bit_mask >>= 1;
|
||||
}
|
||||
|
||||
// Full table?
|
||||
return pos == table_mask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LSB
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the next huffman symbol from the input bitstream into var.
|
||||
/// Do not use this macro on a table unless build_decode_table() succeeded.
|
||||
/// </summary>
|
||||
public long READ_HUFFSYM_LSB(ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
ENSURE_BITS(HUFF_MAXBITS);
|
||||
ushort sym = table[PEEK_BITS_LSB(tablebits)];
|
||||
if (sym >= maxsymbols)
|
||||
HUFF_TRAVERSE_LSB(ref sym, table, tablebits, maxsymbols);
|
||||
|
||||
REMOVE_BITS_LSB(lengths[sym]);
|
||||
return sym;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traverse for a single symbol
|
||||
/// </summary>
|
||||
private void HUFF_TRAVERSE_LSB(ref ushort sym, ushort[] table, int tablebits, int maxsymbols)
|
||||
{
|
||||
int i = tablebits - 1;
|
||||
do
|
||||
{
|
||||
if (i++ > HUFF_MAXBITS)
|
||||
{
|
||||
Error = HUFF_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
sym = table[(sym << 1) | ((BitBuffer >> i) & 1)];
|
||||
} while (sym >= maxsymbols);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function was originally coded by David Tritscher.
|
||||
///
|
||||
/// It builds a fast huffman decoding table from
|
||||
/// a canonical huffman code lengths table.
|
||||
/// </summary>
|
||||
/// <param name="nsyms">total number of symbols in this huffman tree.</param>
|
||||
/// <param name="nbits">any symbols with a code length of nbits or less can be decoded in one lookup of the table.</param>
|
||||
/// <param name="length">A table to get code lengths from [0 to nsyms-1]</param>
|
||||
/// <param name="table">
|
||||
/// The table to fill up with decoded symbols and pointers.
|
||||
/// Should be ((1<<nbits) + (nsyms*2)) in length.
|
||||
/// </param>
|
||||
/// <returns>True for OK or false for error</returns>
|
||||
public static bool MakeDecodeTableLSB(int nsyms, int nbits, byte[] length, ushort[] table)
|
||||
{
|
||||
ushort sym, next_symbol;
|
||||
uint leaf, fill;
|
||||
uint reverse;
|
||||
byte bit_num;
|
||||
uint pos = 0; // The current position in the decode table
|
||||
uint table_mask = (uint)1 << nbits;
|
||||
uint bit_mask = table_mask >> 1; // Don't do 0 length codes
|
||||
|
||||
// Fill entries for codes short enough for a direct mapping
|
||||
for (bit_num = 1; bit_num <= nbits; bit_num++)
|
||||
{
|
||||
for (sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if (length[sym] != bit_num)
|
||||
continue;
|
||||
|
||||
// Reverse the significant bits
|
||||
fill = length[sym];
|
||||
reverse = pos >> (int)(nbits - fill);
|
||||
leaf = 0;
|
||||
|
||||
do
|
||||
{
|
||||
leaf <<= 1;
|
||||
leaf |= reverse & 1;
|
||||
reverse >>= 1;
|
||||
} while (--fill > 0);
|
||||
|
||||
if ((pos += bit_mask) > table_mask)
|
||||
return false; // Table overrun
|
||||
|
||||
// Fill all possible lookups of this symbol with the symbol itself
|
||||
fill = bit_mask;
|
||||
next_symbol = (ushort)(1 << bit_num);
|
||||
|
||||
do
|
||||
{
|
||||
table[leaf] = sym;
|
||||
leaf += next_symbol;
|
||||
} while (--fill > 0);
|
||||
}
|
||||
|
||||
bit_mask >>= 1;
|
||||
}
|
||||
|
||||
// Exit with success if table is now complete
|
||||
if (pos == table_mask)
|
||||
return true;
|
||||
|
||||
// Mark all remaining table entries as unused
|
||||
for (sym = (ushort)pos; sym < table_mask; sym++)
|
||||
{
|
||||
reverse = sym;
|
||||
leaf = 0;
|
||||
fill = (uint)nbits;
|
||||
|
||||
do
|
||||
{
|
||||
leaf <<= 1;
|
||||
leaf |= reverse & 1;
|
||||
reverse >>= 1;
|
||||
} while (--fill > 0);
|
||||
|
||||
table[leaf] = 0xFFFF;
|
||||
}
|
||||
|
||||
// next_symbol = base of allocation for long codes
|
||||
next_symbol = ((table_mask >> 1) < nsyms) ? (ushort)nsyms : (ushort)(table_mask >> 1);
|
||||
|
||||
// Give ourselves room for codes to grow by up to 16 more bits.
|
||||
// codes now start at bit nbits+16 and end at (nbits+16-codelength)
|
||||
pos <<= 16;
|
||||
table_mask <<= 16;
|
||||
bit_mask = 1 << 15;
|
||||
|
||||
for (bit_num = (byte)(nbits + 1); bit_num <= HUFF_MAXBITS; bit_num++)
|
||||
{
|
||||
for (sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if (length[sym] != bit_num)
|
||||
continue;
|
||||
if (pos >= table_mask)
|
||||
return false; // Table overflow
|
||||
|
||||
// leaf = the first nbits of the code, reversed
|
||||
reverse = pos >> 16;
|
||||
leaf = 0;
|
||||
fill = (uint)nbits;
|
||||
|
||||
do
|
||||
{
|
||||
leaf <<= 1;
|
||||
leaf |= reverse & 1;
|
||||
reverse >>= 1;
|
||||
} while (--fill > 0);
|
||||
|
||||
for (fill = 0; fill < (bit_num - nbits); fill++)
|
||||
{
|
||||
// If this path hasn't been taken yet, 'allocate' two entries
|
||||
if (table[leaf] == 0xFFFF)
|
||||
{
|
||||
table[(next_symbol << 1)] = 0xFFFF;
|
||||
table[(next_symbol << 1) + 1] = 0xFFFF;
|
||||
table[leaf] = (ushort)next_symbol++;
|
||||
}
|
||||
|
||||
// Follow the path and select either left or right for next bit
|
||||
leaf = (uint)(table[leaf] << 1);
|
||||
if (((pos >> (15 - (int)fill)) & 1) != 0)
|
||||
leaf++;
|
||||
}
|
||||
|
||||
table[leaf] = sym;
|
||||
pos += bit_mask;
|
||||
}
|
||||
|
||||
bit_mask >>= 1;
|
||||
}
|
||||
|
||||
// Full table?
|
||||
return pos == table_mask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public abstract partial class CompressionStream : BaseDecompressState
|
||||
{
|
||||
public byte[] InputBuffer { get; set; }
|
||||
|
||||
public uint InputBufferSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// i_ptr
|
||||
/// </summary>
|
||||
public int InputPointer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// i_end
|
||||
/// </summary>
|
||||
public int InputEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// o_ptr
|
||||
/// </summary>
|
||||
public int OutputPointer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// o_end
|
||||
/// </summary>
|
||||
public int OutputEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// bit_buffer
|
||||
/// </summary>
|
||||
public uint BitBuffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// bits_left
|
||||
/// </summary>
|
||||
public int BitsLeft { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Have we reached the end of input?
|
||||
/// </summary>
|
||||
public int EndOfInput { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2010 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
#region readbits.h
|
||||
|
||||
/// <summary>
|
||||
/// Bit width of a UInt32 bit buffer
|
||||
/// </summary>
|
||||
public const int BITBUF_WIDTH = 4 * CHAR_BIT;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits in a character
|
||||
/// </summary>
|
||||
internal const int CHAR_BIT = 8;
|
||||
|
||||
// lsb_bit_mask[n] = (1 << n) - 1
|
||||
internal static readonly ushort[] LSBBitMask = new ushort[17]
|
||||
{
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
|
||||
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region readhuff.h
|
||||
|
||||
/// <summary>
|
||||
/// Maximum bits in a Huffman code
|
||||
/// </summary>
|
||||
public const int HUFF_MAXBITS = 16;
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZSS
|
||||
|
||||
/// <summary>
|
||||
/// Size of an LZSS window
|
||||
/// </summary>
|
||||
public const int LZSS_WINDOW_SIZE = 4096;
|
||||
|
||||
/// <summary>
|
||||
/// LZSS window fill byte
|
||||
/// </summary>
|
||||
public const byte LZSS_WINDOW_FILL = 0x20;
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZX
|
||||
|
||||
// Some constants defined by the LZX specification
|
||||
public const int LZX_MIN_MATCH = 2;
|
||||
public const int LZX_MAX_MATCH = 257;
|
||||
public const int LZX_NUM_CHARS = 256;
|
||||
|
||||
public const int LZX_PRETREE_NUM_ELEMENTS = 20;
|
||||
public const int LZX_ALIGNED_NUM_ELEMENTS = 8; // Aligned offset tree #elements
|
||||
public const int LZX_NUM_PRIMARY_LENGTHS = 7; // This one missing from spec!
|
||||
public const int LZX_NUM_SECONDARY_LENGTHS = 249; // Length tree #elements
|
||||
|
||||
// LZX huffman defines: tweak tablebits as desired
|
||||
|
||||
public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
|
||||
public const byte LZX_PRETREE_TABLEBITS = 6;
|
||||
public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
|
||||
public const byte LZX_MAINTREE_TABLEBITS = 12;
|
||||
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
|
||||
public const byte LZX_LENGTH_TABLEBITS = 12;
|
||||
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
|
||||
public const byte LZX_ALIGNED_TABLEBITS = 7;
|
||||
public const int LZX_LENTABLE_SAFETY = 64; // Table decoding overruns are allowed
|
||||
|
||||
public const int LZX_FRAME_SIZE = 32768; // The size of a frame in LZX
|
||||
|
||||
#region LZX static data tables
|
||||
|
||||
/// <summary>
|
||||
/// LZX uses 'position slots' to represent match offsets. For every match,
|
||||
/// a small 'position slot' number and a small offset from that slot are
|
||||
/// encoded instead of one large offset.
|
||||
///
|
||||
/// The number of slots is decided by how many are needed to encode the
|
||||
/// largest offset for a given window size. This is easy when the gap between
|
||||
/// slots is less than 128Kb, it's a linear relationship. But when extra_bits
|
||||
/// reaches its limit of 17 (because LZX can only ensure reading 17 bits of
|
||||
/// data at a time), we can only jump 128Kb at a time and have to start
|
||||
/// using more and more position slots as each window size doubles.
|
||||
/// </summary>
|
||||
public static readonly uint[] LZXPositionSlots = new uint[11]
|
||||
{
|
||||
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// An index to the position slot bases
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Calculated as follows:
|
||||
/// LZXPositionBase[0] = 0
|
||||
/// LZXPositionBase[i] = LZXPositionBase[i - 1] + (1 << ExtraBits(i - 1))
|
||||
/// </remarks>
|
||||
public static readonly uint[] LZXPositionBase = new uint[290]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
|
||||
768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
|
||||
49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
|
||||
786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
|
||||
1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
|
||||
2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
|
||||
3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
|
||||
4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
|
||||
6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
|
||||
7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
|
||||
8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
|
||||
9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
|
||||
10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
|
||||
11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
|
||||
12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
|
||||
12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
|
||||
13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
|
||||
14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
|
||||
15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
|
||||
16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
|
||||
17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
|
||||
18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
|
||||
19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
|
||||
20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
|
||||
21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
|
||||
22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
|
||||
23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
|
||||
23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
|
||||
24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
|
||||
25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
|
||||
26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
|
||||
27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
|
||||
28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
|
||||
29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
|
||||
30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
|
||||
31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
|
||||
32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
|
||||
33161216, 33292288, 33423360
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region MSZIP
|
||||
|
||||
public const int MSZIP_FRAME_SIZE = 32768; // Size of LZ history window
|
||||
public const int MSZIP_LITERAL_MAXSYMBOLS = 288; // literal/length huffman tree
|
||||
public const int MSZIP_LITERAL_TABLEBITS = 9;
|
||||
public const int MSZIP_DISTANCE_MAXSYMBOLS = 32; // Distance huffman tree
|
||||
public const int MSZIP_DISTANCE_TABLEBITS = 6;
|
||||
|
||||
// If there are less direct lookup entries than symbols, the longer
|
||||
// code pointers will be <= maxsymbols. This must not happen, or we
|
||||
// will decode entries badly
|
||||
|
||||
//public const int MSZIP_LITERAL_TABLESIZE = (MSZIP_LITERAL_MAXSYMBOLS * 4);
|
||||
public const int MSZIP_LITERAL_TABLESIZE = ((1 << MSZIP_LITERAL_TABLEBITS) + (MSZIP_LITERAL_MAXSYMBOLS * 2));
|
||||
|
||||
//public const int MSZIP_DISTANCE_TABLESIZE = (MSZIP_DISTANCE_MAXSYMBOLS * 4);
|
||||
public const int MSZIP_DISTANCE_TABLESIZE = ((1 << MSZIP_DISTANCE_TABLEBITS) + (MSZIP_DISTANCE_MAXSYMBOLS * 2));
|
||||
|
||||
/// <summary>
|
||||
/// Match lengths for literal codes 257.. 285
|
||||
/// </summary>
|
||||
public static readonly ushort[] LiteralLengths = new ushort[29]
|
||||
{
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
|
||||
31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Match offsets for distance codes 0 .. 29
|
||||
/// </summary>
|
||||
public static readonly ushort[] DistanceOffsets = new ushort[30]
|
||||
{
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
|
||||
513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits required for literal codes 257.. 285
|
||||
/// </summary>
|
||||
public static readonly byte[] LiteralExtraBits = new byte[29]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits required for distance codes 0 .. 29
|
||||
/// </summary>
|
||||
public static readonly byte[] DistanceExtraBits = new byte[30]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
|
||||
6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The order of the bit length Huffman code lengths
|
||||
/// </summary>
|
||||
public static readonly byte[] BitLengthOrder = new byte[19]
|
||||
{
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region QTM
|
||||
|
||||
public const int QTM_FRAME_SIZE = 32768;
|
||||
|
||||
/* Quantum static data tables:
|
||||
*
|
||||
* Quantum uses 'position slots' to represent match offsets. For every
|
||||
* match, a small 'position slot' number and a small offset from that slot
|
||||
* are encoded instead of one large offset.
|
||||
*
|
||||
* position_base[] is an index to the position slot bases
|
||||
*
|
||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||
*
|
||||
* length_base[] and length_extra[] are equivalent in function, but are
|
||||
* used for encoding selector 6 (variable length match) match lengths,
|
||||
* instead of match offsets.
|
||||
*
|
||||
* They are generated with the following code:
|
||||
* uint i, offset;
|
||||
* for (i = 0, offset = 0; i < 42; i++) {
|
||||
* position_base[i] = offset;
|
||||
* extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
|
||||
* offset += 1 << extra_bits[i];
|
||||
* }
|
||||
* for (i = 0, offset = 0; i < 26; i++) {
|
||||
* length_base[i] = offset;
|
||||
* length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
|
||||
* offset += 1 << length_extra[i];
|
||||
* }
|
||||
* length_base[26] = 254; length_extra[26] = 0;
|
||||
*/
|
||||
|
||||
public static readonly uint[] QTMPositionBase = new uint[42]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
|
||||
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
|
||||
65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864
|
||||
};
|
||||
|
||||
public static readonly byte[] QTMExtraBits = new byte[42]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19
|
||||
};
|
||||
|
||||
public static readonly byte[] QTMLengthBase = new byte[27]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 18, 22, 26,
|
||||
30, 38, 46, 54, 62, 78, 94, 110, 126, 158, 190, 222, 254
|
||||
};
|
||||
|
||||
public static readonly byte[] QTMLengthExtra = new byte[27]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class DES
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public enum LZSSMode
|
||||
{
|
||||
LZSS_MODE_EXPAND = 0,
|
||||
|
||||
LZSS_MODE_MSHELP = 1,
|
||||
|
||||
LZSS_MODE_QBASIC = 2,
|
||||
}
|
||||
|
||||
public enum LZXBlockType : byte
|
||||
{
|
||||
LZX_BLOCKTYPE_INVALID0 = 0,
|
||||
|
||||
LZX_BLOCKTYPE_VERBATIM = 1,
|
||||
|
||||
LZX_BLOCKTYPE_ALIGNED = 2,
|
||||
|
||||
LZX_BLOCKTYPE_UNCOMPRESSED = 3,
|
||||
|
||||
LZX_BLOCKTYPE_INVALID4 = 4,
|
||||
|
||||
LZX_BLOCKTYPE_INVALID5 = 5,
|
||||
|
||||
LZX_BLOCKTYPE_INVALID6 = 6,
|
||||
|
||||
LZX_BLOCKTYPE_INVALID7 = 7,
|
||||
}
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2010 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Constants;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// In the KWAJ LZH format, there is no special 'eof' marker, it just
|
||||
/// ends. Depending on how many bits are left in the final byte when
|
||||
/// the stream ends, that might be enough to start another literal or
|
||||
/// match. The only easy way to detect that we've come to an end is to
|
||||
/// guard all bit-reading. We allow fake bits to be read once we reach
|
||||
/// the end of the stream, but we check if we then consumed any of
|
||||
/// those fake bits, after doing the READ_BITS / READ_HUFFSYM. This
|
||||
/// isn't how the default ReadInput works (it simply lets
|
||||
/// 2 fake bytes in then stops), so we implement our own.
|
||||
/// </summary>
|
||||
public partial class LZHKWAJ
|
||||
{
|
||||
public static LZHKWAJ Init(SystemImpl sys, FileStream input, FileStream output)
|
||||
{
|
||||
if (sys == null || input == null || output == null)
|
||||
return null;
|
||||
|
||||
return new LZHKWAJ()
|
||||
{
|
||||
System = sys,
|
||||
InputFileHandle = input,
|
||||
OutputFileHandle = output,
|
||||
};
|
||||
}
|
||||
|
||||
public Error Decompress()
|
||||
{
|
||||
int i;
|
||||
int lit_run = 0;
|
||||
int j, pos = 0, len, offset;
|
||||
uint[] types = new uint[6];
|
||||
|
||||
// Reset global state
|
||||
INIT_BITS();
|
||||
|
||||
for (i = 0; i < LZSS_WINDOW_SIZE; i++)
|
||||
{
|
||||
Window[i] = LZSS_WINDOW_FILL;
|
||||
}
|
||||
|
||||
// Read 6 encoding types (for byte alignment) but only 5 are needed
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
types[i] = (uint)READ_BITS_SAFE(4);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
// Read huffman table symbol lengths and build huffman trees
|
||||
BUILD_TREE(types[0], MATCHLEN1_table, MATCHLEN1_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN1_SYMS);
|
||||
BUILD_TREE(types[1], MATCHLEN2_table, MATCHLEN2_len, KWAJ_TABLEBITS, KWAJ_MATCHLEN2_SYMS);
|
||||
BUILD_TREE(types[2], LITLEN_table, LITLEN_len, KWAJ_TABLEBITS, KWAJ_LITLEN_SYMS);
|
||||
BUILD_TREE(types[3], OFFSET_table, OFFSET_len, KWAJ_TABLEBITS, KWAJ_OFFSET_SYMS);
|
||||
BUILD_TREE(types[4], LITERAL_table, LITERAL_len, KWAJ_TABLEBITS, KWAJ_LITERAL_SYMS);
|
||||
|
||||
while (EndOfInput == 0)
|
||||
{
|
||||
if (lit_run > 0)
|
||||
{
|
||||
len = (int)READ_HUFFSYM_SAFE(MATCHLEN2_table, MATCHLEN2_len, KWAJ_MATCHLEN2_TBLSIZE, KWAJ_MATCHLEN2_SYMS);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = (int)READ_HUFFSYM_SAFE(MATCHLEN1_table, MATCHLEN1_len, KWAJ_MATCHLEN1_TBLSIZE, KWAJ_MATCHLEN1_SYMS);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
len += 2;
|
||||
lit_run = 0; // Not the end of a literal run
|
||||
|
||||
j = (int)READ_HUFFSYM_SAFE(OFFSET_table, OFFSET_len, KWAJ_OFFSET_TBLSIZE, KWAJ_OFFSET_SYMS);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
offset = j << 6;
|
||||
|
||||
j = (int)READ_BITS_SAFE(6);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
offset |= j;
|
||||
|
||||
// Copy match as output and into the ring buffer
|
||||
while (len-- > 0)
|
||||
{
|
||||
Window[pos] = Window[(pos + 4096 - offset) & 4095];
|
||||
WRITE_BYTE(pos);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
pos++;
|
||||
pos &= 4095;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = (int)READ_HUFFSYM_SAFE(LITLEN_table, LITLEN_len, KWAJ_LITLEN_TBLSIZE, KWAJ_LITLEN_SYMS);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
len++;
|
||||
lit_run = (len == 32) ? 0 : 1; // End of a literal run?
|
||||
while (len-- > 0)
|
||||
{
|
||||
j = (int)READ_HUFFSYM_SAFE(LITERAL_table, LITERAL_len, KWAJ_LITERAL_TBLSIZE, KWAJ_LITERAL_SYMS);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
// Copy as output and into the ring buffer
|
||||
Window[pos] = (byte)j;
|
||||
|
||||
WRITE_BYTE(pos);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
pos++; pos &= 4095;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private Error BUILD_TREE(uint type, ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
Error err = ReadLens(type, (uint)maxsymbols, MATCHLEN1_len);
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
|
||||
if (!CompressionStream.MakeDecodeTableMSB(maxsymbols, tablebits, lengths, table))
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely read bits from the buffer
|
||||
/// </summary>
|
||||
private long READ_BITS_SAFE(int nbits)
|
||||
{
|
||||
long val = READ_BITS_MSB(nbits);
|
||||
if (EndOfInput != 0 && BitsLeft < EndOfInput)
|
||||
Error = Error.MSPACK_ERR_NOMEMORY;
|
||||
else
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely read a symbol from a Huffman tree
|
||||
/// </summary>
|
||||
private long READ_HUFFSYM_SAFE(ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
long val = READ_HUFFSYM_MSB(table, lengths, tablebits, maxsymbols);
|
||||
if (EndOfInput != 0 && BitsLeft < EndOfInput)
|
||||
Error = Error.MSPACK_ERR_NOMEMORY;
|
||||
else
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a single byte to the output stream
|
||||
/// </summary>
|
||||
private void WRITE_BYTE(int pos)
|
||||
{
|
||||
if (System.Write(OutputFileHandle, Window, pos, 1) != 1)
|
||||
Error = Error.MSPACK_ERR_WRITE;
|
||||
}
|
||||
|
||||
private Error ReadLens(uint type, uint numsyms, byte[] lens)
|
||||
{
|
||||
uint i, c, sel;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
i = numsyms;
|
||||
c = (uint)((i == 16) ? 4 : (i == 32) ? 5 : (i == 64) ? 6 : (i == 256) ? 8 : 0);
|
||||
for (i = 0; i < numsyms; i++)
|
||||
{
|
||||
lens[i] = (byte)c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
c = (uint)READ_BITS_SAFE(4);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
lens[0] = (byte)c;
|
||||
for (i = 1; i < numsyms; i++)
|
||||
{
|
||||
sel = (uint)READ_BITS_SAFE(1);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
lens[i] = (byte)c;
|
||||
}
|
||||
else
|
||||
{
|
||||
sel = (uint)READ_BITS_SAFE(1);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
lens[i] = (byte)++c;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = (uint)READ_BITS_SAFE(4);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
lens[i] = (byte)c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
c = (uint)READ_BITS_SAFE(4);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
lens[0] = (byte)c;
|
||||
for (i = 1; i < numsyms; i++)
|
||||
{
|
||||
sel = (uint)READ_BITS_SAFE(2);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
if (sel == 3)
|
||||
{
|
||||
c = (uint)READ_BITS_SAFE(4);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
c += (uint)((byte)sel - 1);
|
||||
}
|
||||
|
||||
lens[i] = (byte)c;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (i = 0; i < numsyms; i++)
|
||||
{
|
||||
c = (uint)READ_BITS_SAFE(4);
|
||||
if (Error == Error.MSPACK_ERR_NOMEMORY)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
lens[i] = (byte)c;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2010 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using static LibMSPackSharp.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZHKWAJ : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
if (InputPointer >= InputEnd)
|
||||
{
|
||||
ReadInput();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
InputPointer = InputPointer;
|
||||
InputEnd = InputEnd;
|
||||
}
|
||||
|
||||
INJECT_BITS_MSB(InputBuffer[InputPointer++], 8);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ReadInput()
|
||||
{
|
||||
int read;
|
||||
if (EndOfInput != 0)
|
||||
{
|
||||
EndOfInput += 8;
|
||||
InputBuffer[0] = 0;
|
||||
read = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
read = System.Read(InputFileHandle, InputBuffer, 0, KWAJ_INPUT_SIZE);
|
||||
if (read < 0)
|
||||
{
|
||||
Error = Error.MSPACK_ERR_READ;
|
||||
return;
|
||||
}
|
||||
|
||||
if (read == 0)
|
||||
{
|
||||
InputEnd = 8;
|
||||
InputBuffer[0] = 0;
|
||||
read = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update InputPointer and InputLength
|
||||
InputPointer = 0;
|
||||
InputEnd = read;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2010 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZHKWAJ : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Error HUFF_ERROR() => Error.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2010 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using static LibMSPackSharp.Constants;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZHKWAJ : CompressionStream
|
||||
{
|
||||
// Huffman code lengths
|
||||
|
||||
public byte[] MATCHLEN1_len { get; set; } = new byte[KWAJ_MATCHLEN1_SYMS];
|
||||
public byte[] MATCHLEN2_len { get; set; } = new byte[KWAJ_MATCHLEN2_SYMS];
|
||||
public byte[] LITLEN_len { get; set; } = new byte[KWAJ_LITLEN_SYMS];
|
||||
public byte[] OFFSET_len { get; set; } = new byte[KWAJ_OFFSET_SYMS];
|
||||
public byte[] LITERAL_len { get; set; } = new byte[KWAJ_LITERAL_SYMS];
|
||||
|
||||
// Huffman decoding tables
|
||||
|
||||
public ushort[] MATCHLEN1_table { get; set; } = new ushort[KWAJ_MATCHLEN1_TBLSIZE];
|
||||
public ushort[] MATCHLEN2_table { get; set; } = new ushort[KWAJ_MATCHLEN2_TBLSIZE];
|
||||
public ushort[] LITLEN_table { get; set; } = new ushort[KWAJ_LITLEN_TBLSIZE];
|
||||
public ushort[] OFFSET_table { get; set; } = new ushort[KWAJ_OFFSET_TBLSIZE];
|
||||
public ushort[] LITERAL_table { get; set; } = new ushort[KWAJ_LITERAL_TBLSIZE];
|
||||
|
||||
// History window
|
||||
|
||||
public byte[] Window { get; set; } = new byte[LZSS_WINDOW_SIZE];
|
||||
}
|
||||
}
|
||||
177
BurnOutSharp/External/libmspack/Compression/LZSS.cs
vendored
177
BurnOutSharp/External/libmspack/Compression/LZSS.cs
vendored
@@ -1,177 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2010 Stuart Caie.
|
||||
*
|
||||
* LZSS is a derivative of LZ77 and was created by James Storer and
|
||||
* Thomas Szymanski in 1982. Haruhiko Okumura wrote a very popular C
|
||||
* implementation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class LZSS
|
||||
{
|
||||
/// <summary>
|
||||
/// Decompresses an LZSS stream.
|
||||
///
|
||||
/// Input bytes will be read in as necessary using the system.read()
|
||||
/// function with the input file handle given.This will continue until
|
||||
/// system.read() returns 0 bytes, or an error.Errors will be passed
|
||||
/// out of the function as MSPACK_ERR_READ errors. Input streams should
|
||||
/// convey an "end of input stream" by refusing to supply all the bytes
|
||||
/// that LZSS asks for when they reach the end of the stream, rather
|
||||
/// than return an error code.
|
||||
///
|
||||
/// Output bytes will be passed to the system.write() function, using
|
||||
/// the output file handle given.More than one call may be made to
|
||||
/// system.write().
|
||||
///
|
||||
/// As EXPAND.EXE (SZDD/KWAJ), Microsoft Help and QBasic have slightly
|
||||
/// different encodings for the control byte and matches, a "mode"
|
||||
/// parameter is allowed, to choose the encoding.
|
||||
/// </summary>
|
||||
/// <param name="system">
|
||||
/// an mspack_system structure used to read from
|
||||
/// the input stream and write to the output
|
||||
/// stream, also to allocate and free memory.
|
||||
/// </param>
|
||||
/// <param name="input">an input stream with the LZSS data.</param>
|
||||
/// <param name="output">an output stream to write the decoded data to.</param>
|
||||
/// <param name="inputBufferSize">
|
||||
/// the number of bytes to use as an input
|
||||
/// bitstream buffer.
|
||||
/// </param>
|
||||
/// <param name="mode">one of LZSSMode values</param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public static Error Decompress(SystemImpl system, FileStream input, FileStream output, int input_buffer_size, LZSSMode mode)
|
||||
{
|
||||
// Check parameters
|
||||
if (system == null || input_buffer_size < 1 || (mode != LZSSMode.LZSS_MODE_EXPAND && mode != LZSSMode.LZSS_MODE_MSHELP && mode != LZSSMode.LZSS_MODE_QBASIC))
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
|
||||
// Allocate memory
|
||||
byte[] window = new byte[LZSS_WINDOW_SIZE + input_buffer_size];
|
||||
|
||||
// Initialise decompression
|
||||
int inbuf = LZSS_WINDOW_SIZE;
|
||||
for (int j = inbuf; j < window.Length; j++)
|
||||
{
|
||||
window[j] = LZSS_WINDOW_FILL;
|
||||
}
|
||||
|
||||
uint pos = LZSS_WINDOW_SIZE - (uint)((mode == LZSSMode.LZSS_MODE_QBASIC) ? 18 : 16);
|
||||
uint invert = (uint)((mode == LZSSMode.LZSS_MODE_MSHELP) ? ~0 : 0);
|
||||
int i_ptr = 0, i_end = 0, read;
|
||||
|
||||
// Loop forever; exit condition is in ENSURE_BYTES macro
|
||||
for (; ; )
|
||||
{
|
||||
//ENSURE_BYTES
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
{
|
||||
read = input.Read(window, inbuf, input_buffer_size);
|
||||
if (read <= 0)
|
||||
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
|
||||
|
||||
i_ptr = inbuf;
|
||||
i_end = read;
|
||||
}
|
||||
}
|
||||
|
||||
uint c = window[i_ptr++] ^ invert;
|
||||
for (uint i = 0x01; (i & 0xFF) != 0; i <<= 1)
|
||||
{
|
||||
// Literal
|
||||
if (c != 0 & i != 0)
|
||||
{
|
||||
//ENSURE_BYTES
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
{
|
||||
read = input.Read(window, inbuf, input_buffer_size);
|
||||
if (read <= 0)
|
||||
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
|
||||
|
||||
i_ptr = inbuf;
|
||||
i_end = read;
|
||||
}
|
||||
}
|
||||
|
||||
window[pos] = window[i_ptr++];
|
||||
|
||||
//WRITE_BYTE
|
||||
{
|
||||
try { output.Write(window, (int)pos, 1); }
|
||||
catch { return Error.MSPACK_ERR_WRITE; }
|
||||
}
|
||||
|
||||
pos++;
|
||||
pos &= LZSS_WINDOW_SIZE - 1;
|
||||
}
|
||||
|
||||
// Match
|
||||
else
|
||||
{
|
||||
//ENSURE_BYTES
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
{
|
||||
read = input.Read(window, inbuf, input_buffer_size);
|
||||
if (read <= 0)
|
||||
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
|
||||
|
||||
i_ptr = inbuf;
|
||||
i_end = read;
|
||||
}
|
||||
}
|
||||
|
||||
uint mpos = window[i_ptr++];
|
||||
|
||||
//ENSURE_BYTES
|
||||
{
|
||||
if (i_ptr >= i_end)
|
||||
{
|
||||
read = input.Read(window, inbuf, input_buffer_size);
|
||||
if (read <= 0)
|
||||
return (read < 0) ? Error.MSPACK_ERR_READ : Error.MSPACK_ERR_OK;
|
||||
|
||||
i_ptr = inbuf;
|
||||
i_end = read;
|
||||
}
|
||||
}
|
||||
|
||||
mpos |= (uint)(window[i_ptr] & 0xF0) << 4;
|
||||
uint len = (uint)(window[i_ptr++] & 0x0F) + 3;
|
||||
|
||||
while (len-- != 0)
|
||||
{
|
||||
window[pos] = window[mpos];
|
||||
|
||||
//WRITE_BYTE
|
||||
{
|
||||
try { output.Write(window, (int)pos, 1); }
|
||||
catch { return Error.MSPACK_ERR_WRITE; }
|
||||
}
|
||||
|
||||
pos++;
|
||||
pos &= LZSS_WINDOW_SIZE - 1;
|
||||
mpos++;
|
||||
mpos &= LZSS_WINDOW_SIZE - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* not reached */
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,847 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
/* Microsoft's LZX document (in cab-sdk.exe) and their implementation
|
||||
* of the com.ms.util.cab Java package do not concur.
|
||||
*
|
||||
* In the LZX document, there is a table showing the correlation between
|
||||
* window size and the number of position slots. It states that the 1MB
|
||||
* window = 40 slots and the 2MB window = 42 slots. In the implementation,
|
||||
* 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the
|
||||
* first slot whose position base is equal to or more than the required
|
||||
* window size'. This would explain why other tables in the document refer
|
||||
* to 50 slots rather than 42.
|
||||
*
|
||||
* The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
|
||||
* is not defined in the specification.
|
||||
*
|
||||
* The LZX document does not state the uncompressed block has an
|
||||
* uncompressed length field. Where does this length field come from, so
|
||||
* we can know how large the block is? The implementation has it as the 24
|
||||
* bits following after the 3 blocktype bits, before the alignment
|
||||
* padding.
|
||||
*
|
||||
* The LZX document states that aligned offset blocks have their aligned
|
||||
* offset huffman tree AFTER the main and length trees. The implementation
|
||||
* suggests that the aligned offset tree is BEFORE the main and length
|
||||
* trees.
|
||||
*
|
||||
* The LZX document decoding algorithm states that, in an aligned offset
|
||||
* block, if an extra_bits value is 1, 2 or 3, then that number of bits
|
||||
* should be read and the result added to the match offset. This is
|
||||
* correct for 1 and 2, but not 3, where just a huffman symbol (using the
|
||||
* aligned tree) should be read.
|
||||
*
|
||||
* Regarding the E8 preprocessing, the LZX document states 'No translation
|
||||
* may be performed on the last 6 bytes of the input block'. This is
|
||||
* correct. However, the pseudocode provided checks for the *E8 leader*
|
||||
* up to the last 6 bytes. If the leader appears between -10 and -7 bytes
|
||||
* from the end, this would cause the next four bytes to be modified, at
|
||||
* least one of which would be in the last 6 bytes, which is not allowed
|
||||
* according to the spec.
|
||||
*
|
||||
* The specification states that the huffman trees must always contain at
|
||||
* least one element. However, many CAB files contain blocks where the
|
||||
* length tree is completely empty (because there are no matches), and
|
||||
* this is expected to succeed.
|
||||
*
|
||||
* The errors in LZX documentation appear have been corrected in the
|
||||
* new documentation for the LZX DELTA format.
|
||||
*
|
||||
* http://msdn.microsoft.com/en-us/library/cc483133.aspx
|
||||
*
|
||||
* However, this is a different format, an extension of regular LZX.
|
||||
* I have noticed the following differences, there may be more:
|
||||
*
|
||||
* The maximum window size has increased from 2MB to 32MB. This also
|
||||
* increases the maximum number of position slots, etc.
|
||||
*
|
||||
* If the match length is 257 (the maximum possible), this signals
|
||||
* a further length decoding step, that allows for matches up to
|
||||
* 33024 bytes long.
|
||||
*
|
||||
* The format now allows for "reference data", supplied by the caller.
|
||||
* If match offsets go further back than the number of bytes
|
||||
* decompressed so far, that is them accessing the reference data.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZX
|
||||
{
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Allocates and initialises LZX decompression state for decoding an LZX
|
||||
/// stream.
|
||||
///
|
||||
/// This routine uses system.alloc() to allocate memory. If memory
|
||||
/// allocation fails, or the parameters to this function are invalid,
|
||||
/// null is returned.
|
||||
/// </summary>
|
||||
/// <param name="system">A SystemImpl structure used to read from the input stream and write to the output stream, also to allocate and free memory.</param>
|
||||
/// <param name="input">An input stream with the LZX data.</param>
|
||||
/// <param name="output">An output stream to write the decoded data to.</param>
|
||||
/// <param name="window_bits">The size of the decoding window, which must be between 15 and 21 inclusive for regular LZX data, or between 17 and 25 inclusive for LZX DELTA data.</param>
|
||||
/// <param name="reset_interval">
|
||||
/// The interval at which the LZX bitstream is reset, in multiples of LZX frames (32678 bytes),
|
||||
/// e.g. a value of 2 indicates the input stream resets after every 65536 output bytes.
|
||||
/// A value of 0 indicates that the bitstream never resets, such as in CAB LZX streams.
|
||||
/// </param>
|
||||
/// <param name="input_buffer_size">The number of bytes to use as an input bitstream buffer.</param>
|
||||
/// <param name="output_length">
|
||||
/// The length in bytes of the entirely decompressed output stream, if known in advance.
|
||||
/// It is used to correctly perform the Intel E8 transformation, which must stop 6 bytes before the very end of the decompressed stream.
|
||||
/// It is not otherwise used or adhered to. If the full decompressed length is known in advance, set it here.
|
||||
/// If it is NOT known, use the value 0, and call lzxd_set_outputLength() once it is known.
|
||||
/// If never set, 4 of the final 6 bytes of the output stream may be incorrect
|
||||
/// </param>
|
||||
/// <param name="is_delta">Should be zero for all regular LZX data, non-zero for LZX DELTA encoded data.</param>
|
||||
/// <returns>A pointer to an initialised LZX structure, or null if there was not enough memory or parameters to the function were wrong.</returns>
|
||||
public static LZX Init(SystemImpl system, FileStream input, FileStream output, int window_bits, int reset_interval, int input_buffer_size, long output_length, bool is_delta)
|
||||
{
|
||||
if (system == null)
|
||||
return null;
|
||||
|
||||
// LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB),
|
||||
// regular LZX windows are between 2^15 (32KiB) and 2^21 (2MiB)
|
||||
if (is_delta)
|
||||
{
|
||||
if (window_bits < 17 || window_bits > 25)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window_bits < 15 || window_bits > 21)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (reset_interval < 0 || output_length < 0)
|
||||
{
|
||||
Console.WriteLine("Reset interval or output length < 0");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Round up input buffer size to multiple of two
|
||||
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||
if (input_buffer_size < 2)
|
||||
return null;
|
||||
|
||||
// Allocate decompression state
|
||||
LZX lzx = new LZX()
|
||||
{
|
||||
// Allocate decompression window and input buffer
|
||||
Window = new byte[1 << window_bits],
|
||||
InputBuffer = new byte[input_buffer_size],
|
||||
|
||||
System = system,
|
||||
InputFileHandle = input,
|
||||
OutputFileHandle = output,
|
||||
Offset = 0,
|
||||
Length = output_length,
|
||||
|
||||
InputBufferSize = (uint)input_buffer_size,
|
||||
WindowSize = (uint)(1 << window_bits),
|
||||
ReferenceDataSize = 0,
|
||||
WindowPosition = 0,
|
||||
FramePosition = 0,
|
||||
Frame = 0,
|
||||
ResetInterval = (uint)reset_interval,
|
||||
IntelFileSize = 0,
|
||||
IntelStarted = false,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
NumOffsets = LZXPositionSlots[window_bits - 15] << 3,
|
||||
IsDelta = is_delta,
|
||||
|
||||
OutputPointer = 0,
|
||||
OutputEnd = 0,
|
||||
WriteFromE8 = false,
|
||||
};
|
||||
|
||||
lzx.ResetState();
|
||||
lzx.INIT_BITS();
|
||||
|
||||
return lzx;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads LZX DELTA reference data into the window and allows
|
||||
/// lzxd_decompress() to reference it.
|
||||
///
|
||||
/// Call this before the first call to lzxd_decompress().
|
||||
/// </summary>
|
||||
/// <param name="system">A SystemImpl structure to use with the input param. Only read() will be called.</param>
|
||||
/// <param name="input">An input file handle to read reference data using system.read().</param>
|
||||
/// <param name="length">The length of the reference data. Cannot be longer than the LZX window size.</param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error SetReferenceData(SystemImpl system, FileStream input, uint length)
|
||||
{
|
||||
if (!IsDelta)
|
||||
{
|
||||
Console.WriteLine("Only LZX DELTA streams support reference data");
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
if (Offset > 0)
|
||||
{
|
||||
Console.WriteLine("Too late to set reference data after decoding starts");
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
if (length > WindowSize)
|
||||
{
|
||||
Console.WriteLine($"Reference length ({length}) is longer than the window");
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
if (length > 0 && (system == null || input == null))
|
||||
{
|
||||
Console.WriteLine("Length > 0 but no system or input");
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
ReferenceDataSize = length;
|
||||
if (length > 0)
|
||||
{
|
||||
// Copy reference data
|
||||
int pos = (int)(WindowSize - length);
|
||||
int bytes = system.Read(input, Window, pos, (int)length);
|
||||
|
||||
// Length can't be more than 2^25, so no signedness problem
|
||||
if (bytes < (int)length)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
}
|
||||
|
||||
ReferenceDataSize = length;
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
// See description of outputLength in Init()
|
||||
public void SetOutputLength(long outputLength)
|
||||
{
|
||||
if (outputLength > 0)
|
||||
Length = outputLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses entire or partial LZX streams.
|
||||
///
|
||||
/// The number of bytes of data that should be decompressed is given as the
|
||||
/// out_bytes parameter. If more bytes are decoded than are needed, they
|
||||
/// will be kept over for a later invocation.
|
||||
///
|
||||
/// The output bytes will be passed to the system.write() function given in
|
||||
/// lzxd_init(), using the output file handle given in lzxd_init(). More than
|
||||
/// one call may be made to system.write().
|
||||
/// Input bytes will be read in as necessary using the system.read()
|
||||
/// function given in lzxd_init(), using the input file handle given in
|
||||
/// lzxd_init(). This will continue until system.read() returns 0 bytes,
|
||||
/// or an error. Errors will be passed out of the function as
|
||||
/// MSPACK_ERR_READ errors. Input streams should convey an "end of input
|
||||
/// stream" by refusing to supply all the bytes that LZX asks for when they
|
||||
/// reach the end of the stream, rather than return an error code.
|
||||
///
|
||||
/// If any error code other than MSPACK_ERR_OK is returned, the stream
|
||||
/// should be considered unusable and lzxd_decompress() should not be
|
||||
/// called again on this stream.
|
||||
/// </summary>
|
||||
/// <param name="out_bytes">The number of bytes of data to decompress.</param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Decompress(long out_bytes)
|
||||
{
|
||||
int match_length, length_footer, extra, verbatim_bits, bytes_todo;
|
||||
int this_run, main_element, aligned_bits, j, warned = 0;
|
||||
byte[] buf = new byte[12];
|
||||
int runsrc, rundest;
|
||||
uint frame_size = 0, end_frame, match_offset;
|
||||
|
||||
// Easy answers
|
||||
if (out_bytes < 0)
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
// Flush out any stored-up bytes before we begin
|
||||
int i = OutputEnd - OutputPointer;
|
||||
if (i > out_bytes)
|
||||
i = (int)out_bytes;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
if (System.Write(OutputFileHandle, WriteFromE8 ? E8Buffer : Window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
OutputPointer += i;
|
||||
Offset += i;
|
||||
out_bytes -= i;
|
||||
}
|
||||
|
||||
if (out_bytes == 0)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
end_frame = (uint)((Offset + out_bytes) / LZX_FRAME_SIZE) + 1;
|
||||
|
||||
while (Frame < end_frame)
|
||||
{
|
||||
// Have we reached the reset interval? (if there is one?)
|
||||
if (ResetInterval != 0 && ((Frame % ResetInterval) == 0))
|
||||
{
|
||||
if (BlockRemaining > 0)
|
||||
{
|
||||
// This is a file format error, we can make a best effort to extract what we can
|
||||
Console.WriteLine($"{BlockRemaining} bytes remaining at reset interval");
|
||||
if (warned == 0)
|
||||
{
|
||||
System.Message(null, "WARNING; invalid reset interval detected during LZX decompression");
|
||||
warned++;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-read the intel header and reset the huffman lengths
|
||||
ResetState();
|
||||
}
|
||||
|
||||
// LZX DELTA format has chunk_size, not present in LZX format
|
||||
if (IsDelta)
|
||||
{
|
||||
ENSURE_BITS(16);
|
||||
REMOVE_BITS_MSB(16);
|
||||
}
|
||||
|
||||
// Read header if necessary
|
||||
if (HeaderRead == 0)
|
||||
{
|
||||
// Read 1 bit. If bit=0, intel filesize = 0.
|
||||
// If bit=1, read intel filesize (32 bits)
|
||||
j = 0;
|
||||
i = (int)READ_BITS_MSB(1);
|
||||
if (i != 0)
|
||||
{
|
||||
i = (int)READ_BITS_MSB(16);
|
||||
j = (int)READ_BITS_MSB(16);
|
||||
}
|
||||
|
||||
IntelFileSize = (i << 16) | j;
|
||||
HeaderRead = 1;
|
||||
}
|
||||
|
||||
// Calculate size of frame: all frames are 32k except the final frame
|
||||
// which is 32kb or less. this can only be calculated when lzx->length
|
||||
// has been filled in.
|
||||
frame_size = LZX_FRAME_SIZE;
|
||||
if (Length != 0 && (Length - Offset) < frame_size)
|
||||
frame_size = (uint)(Length - Offset);
|
||||
|
||||
// Decode until one more frame is available
|
||||
bytes_todo = (int)(FramePosition + frame_size - WindowPosition);
|
||||
while (bytes_todo > 0)
|
||||
{
|
||||
// Initialise new block, if one is needed
|
||||
if (BlockRemaining == 0)
|
||||
{
|
||||
// Realign if previous block was an odd-sized UNCOMPRESSED block
|
||||
if (BlockType == LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED && (BlockLength & 1) != 0)
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
InputPointer++;
|
||||
}
|
||||
|
||||
// Read block type (3 bits) and block length (24 bits)
|
||||
BlockType = (LZXBlockType)READ_BITS_MSB(3);
|
||||
i = (int)READ_BITS_MSB(16);
|
||||
j = (int)READ_BITS_MSB(8);
|
||||
BlockRemaining = BlockLength = (i << 8) | j;
|
||||
Console.WriteLine($"New block - type: {BlockType}, length: {BlockLength}");
|
||||
|
||||
// Read individual block headers
|
||||
switch (BlockType)
|
||||
{
|
||||
case LZXBlockType.LZX_BLOCKTYPE_ALIGNED:
|
||||
// Read lengths of and build aligned huffman decoding tree
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
j = (int)READ_BITS_MSB(3);
|
||||
ALIGNED_len[i] = (byte)j;
|
||||
}
|
||||
|
||||
BUILD_TABLE(ALIGNED_table, ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS);
|
||||
|
||||
// Rest of aligned header is same as verbatim
|
||||
|
||||
// Read lengths of and build main huffman decoding tree
|
||||
ReadLengths(MAINTREE_len, 0, 256);
|
||||
ReadLengths(MAINTREE_len, 256, LZX_NUM_CHARS + NumOffsets);
|
||||
BUILD_TABLE(MAINTREE_table, MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
|
||||
// If the literal 0xE8 is anywhere in the block...
|
||||
if (MAINTREE_len[0xE8] != 0)
|
||||
IntelStarted = true;
|
||||
|
||||
// Read lengths of and build lengths huffman decoding tree
|
||||
ReadLengths(LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS);
|
||||
BUILD_TABLE_MAYBE_EMPTY();
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
|
||||
// Read lengths of and build main huffman decoding tree
|
||||
ReadLengths(MAINTREE_len, 0, 256);
|
||||
ReadLengths(MAINTREE_len, 256, LZX_NUM_CHARS + NumOffsets);
|
||||
BUILD_TABLE(MAINTREE_table, MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
|
||||
// If the literal 0xE8 is anywhere in the block...
|
||||
if (MAINTREE_len[0xE8] != 0)
|
||||
IntelStarted = true;
|
||||
|
||||
// Read lengths of and build lengths huffman decoding tree
|
||||
ReadLengths(LENGTH_len, 0, LZX_NUM_SECONDARY_LENGTHS);
|
||||
BUILD_TABLE_MAYBE_EMPTY();
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||
// Because we can't assume otherwise
|
||||
IntelStarted = true;
|
||||
|
||||
// Read 1-16 (not 0-15) bits to align to bytes
|
||||
if (BitsLeft == 0)
|
||||
ENSURE_BITS(16);
|
||||
|
||||
BitsLeft = 0;
|
||||
BitBuffer = 0;
|
||||
|
||||
// Read 12 bytes of stored R0 / R1 / R2 values
|
||||
for (rundest = 0, i = 0; i < 12; i++)
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
buf[rundest++] = InputBuffer[InputPointer++];
|
||||
}
|
||||
|
||||
R[0] = (uint)(buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24));
|
||||
R[1] = (uint)(buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24));
|
||||
R[2] = (uint)(buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24));
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine($"Bad block type {BlockType}");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode more of the block:
|
||||
// run = min(what's available, what's needed)
|
||||
this_run = BlockRemaining;
|
||||
if (this_run > bytes_todo)
|
||||
this_run = bytes_todo;
|
||||
|
||||
// Assume we decode exactly this_run bytes, for now
|
||||
bytes_todo -= this_run;
|
||||
BlockRemaining -= this_run;
|
||||
|
||||
// Decode at least this_run bytes
|
||||
switch (BlockType)
|
||||
{
|
||||
case LZXBlockType.LZX_BLOCKTYPE_ALIGNED:
|
||||
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
|
||||
while (this_run > 0)
|
||||
{
|
||||
main_element = (int)READ_HUFFSYM_MSB(MAINTREE_table, MAINTREE_len, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS);
|
||||
if (main_element < LZX_NUM_CHARS)
|
||||
{
|
||||
// Literal: 0 to LZX_NUM_CHARS-1
|
||||
Window[WindowPosition++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Match: LZX_NUM_CHARS ((slot<<3) | length_header (3 bits))
|
||||
main_element -= LZX_NUM_CHARS;
|
||||
|
||||
// Get match length
|
||||
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
||||
if (match_length == LZX_NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
if (LENGTH_empty)
|
||||
{
|
||||
Console.WriteLine("LENGTH symbol needed but tree is empty");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
length_footer = (int)READ_HUFFSYM_MSB(LENGTH_table, LENGTH_len, LZX_LENGTH_TABLEBITS, LZX_LENGTH_MAXSYMBOLS);
|
||||
match_length += length_footer;
|
||||
}
|
||||
|
||||
match_length += LZX_MIN_MATCH;
|
||||
|
||||
// Get match offset
|
||||
switch ((match_offset = (uint)(main_element >> 3)))
|
||||
{
|
||||
case 0:
|
||||
match_offset = R[0];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
match_offset = R[1];
|
||||
R[1] = R[0];
|
||||
R[0] = match_offset;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
match_offset = R[2];
|
||||
R[2] = R[0];
|
||||
R[0] = match_offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (BlockType == LZXBlockType.LZX_BLOCKTYPE_VERBATIM)
|
||||
{
|
||||
if (match_offset == 3)
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra = ExtraBits(match_offset);
|
||||
verbatim_bits = (int)READ_BITS_MSB(extra);
|
||||
match_offset = (uint)(PositionBase(match_offset) - 2 + verbatim_bits);
|
||||
}
|
||||
}
|
||||
else // LZX_BLOCKTYPE_ALIGNED
|
||||
{
|
||||
extra = ExtraBits(match_offset);
|
||||
match_offset = (uint)(PositionBase(match_offset) - 2);
|
||||
if (extra > 3) // >3: verbatim and aligned bits
|
||||
{
|
||||
extra -= 3;
|
||||
verbatim_bits = (int)READ_BITS_MSB(extra);
|
||||
match_offset += (uint)(verbatim_bits << 3);
|
||||
aligned_bits = (int)READ_HUFFSYM_MSB(ALIGNED_table, ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS);
|
||||
match_offset += (uint)aligned_bits;
|
||||
}
|
||||
else if (extra == 3) // 3: aligned bits only
|
||||
{
|
||||
aligned_bits = (int)READ_HUFFSYM_MSB(ALIGNED_table, ALIGNED_len, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS);
|
||||
match_offset += (uint)aligned_bits;
|
||||
}
|
||||
else if (extra > 0) // 1-2: verbatim bits only
|
||||
{
|
||||
verbatim_bits = (int)READ_BITS_MSB(extra);
|
||||
match_offset += (uint)verbatim_bits;
|
||||
}
|
||||
else // 0: not defined in LZX specification!
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update repeated offset LRU queue
|
||||
R[2] = R[1];
|
||||
R[1] = R[0];
|
||||
R[0] = match_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
// LZX DELTA uses max match length to signal even longer match
|
||||
if (match_length == LZX_MAX_MATCH && IsDelta)
|
||||
{
|
||||
int extra_len = 0;
|
||||
ENSURE_BITS(3); // 4 entry huffman tree
|
||||
if (PEEK_BITS_MSB(1) == 0)
|
||||
{
|
||||
REMOVE_BITS_MSB(1); // '0' -> 8 extra length bits
|
||||
extra_len = (int)READ_BITS_MSB(8);
|
||||
}
|
||||
else if (PEEK_BITS_MSB(2) == 2)
|
||||
{
|
||||
REMOVE_BITS_MSB(2); // '10' -> 10 extra length bits + 0x100
|
||||
extra_len = (int)READ_BITS_MSB(10);
|
||||
extra_len += 0x100;
|
||||
}
|
||||
else if (PEEK_BITS_MSB(3) == 6)
|
||||
{
|
||||
REMOVE_BITS_MSB(3); // '110' -> 12 extra length bits + 0x500
|
||||
extra_len = (int)READ_BITS_MSB(12);
|
||||
extra_len += 0x500;
|
||||
}
|
||||
else
|
||||
{
|
||||
REMOVE_BITS_MSB(3); // '111' -> 15 extra length bits
|
||||
extra_len = (int)READ_BITS_MSB(15);
|
||||
}
|
||||
|
||||
match_length += extra_len;
|
||||
}
|
||||
|
||||
if ((WindowPosition + match_length) > WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match ran over window wrap");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// TODO: This falls out of sync after (91,3)
|
||||
// - Official program goes to (94, 3)
|
||||
// - Ours goes to (95, 3)
|
||||
|
||||
// Copy match
|
||||
rundest = WindowPosition;
|
||||
i = match_length;
|
||||
|
||||
// Does match offset wrap the window?
|
||||
if (match_offset > WindowPosition)
|
||||
{
|
||||
if (match_offset > Offset && (match_offset - WindowPosition) > ReferenceDataSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond LZX stream");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// j = length from match offset to end of window
|
||||
j = (int)match_offset - WindowPosition;
|
||||
if (j > (int)WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond window boundaries");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
runsrc = (int)(WindowSize - j);
|
||||
if (j < i)
|
||||
{
|
||||
// If match goes over the window edge, do two copy runs
|
||||
i -= j;
|
||||
while (j-- > 0)
|
||||
{
|
||||
Window[rundest++] = Window[runsrc++];
|
||||
}
|
||||
|
||||
runsrc = 0;
|
||||
}
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
Window[rundest++] = Window[runsrc++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = rundest - (int)match_offset;
|
||||
while (i-- > 0)
|
||||
{
|
||||
Window[rundest++] = Window[runsrc++];
|
||||
}
|
||||
}
|
||||
|
||||
this_run -= match_length;
|
||||
WindowPosition += match_length;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LZXBlockType.LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||
// As this_run is limited not to wrap a frame, this also means it
|
||||
// won't wrap the window (as the window is a multiple of 32k)
|
||||
rundest = WindowPosition;
|
||||
WindowPosition += this_run;
|
||||
while (this_run > 0)
|
||||
{
|
||||
if ((i = InputEnd - InputPointer) == 0)
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i > this_run)
|
||||
i = this_run;
|
||||
|
||||
Array.Copy(InputBuffer, InputPointer, Window, rundest, i);
|
||||
rundest += 1;
|
||||
InputPointer += i;
|
||||
this_run -= i;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH; // Might as well
|
||||
}
|
||||
|
||||
// Did the final match overrun our desired this_run length?
|
||||
if (this_run < 0)
|
||||
{
|
||||
if ((uint)(-this_run) > BlockRemaining)
|
||||
{
|
||||
Console.Write($"Overrun went past end of block by {-this_run} ({BlockRemaining} remaining)");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
BlockRemaining -= -this_run;
|
||||
}
|
||||
}
|
||||
|
||||
// Streams don't extend over frame boundaries
|
||||
if ((WindowPosition - FramePosition) != frame_size)
|
||||
{
|
||||
Console.WriteLine($"Decode beyond output frame limits {WindowPosition - FramePosition} != {frame_size}");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// Re-align input bitstream
|
||||
if (BitsLeft > 0)
|
||||
ENSURE_BITS(16);
|
||||
if ((BitsLeft & 15) != 0)
|
||||
REMOVE_BITS_MSB(BitsLeft & 15);
|
||||
|
||||
// Check that we've used all of the previous frame first
|
||||
if (OutputPointer != OutputEnd)
|
||||
{
|
||||
Console.Write($"{OutputEnd - OutputPointer} avail bytes, new {frame_size} frame");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// Does this intel block _really_ need decoding?
|
||||
if (IntelStarted && IntelFileSize != 0 && Frame < 32768 && frame_size > 10)
|
||||
{
|
||||
int data = 0;
|
||||
int dataend = (int)frame_size - 10;
|
||||
int curpos = (int)Offset;
|
||||
int filesize = IntelFileSize;
|
||||
int abs_off, rel_off;
|
||||
|
||||
// Copy E8 block to the e8 buffer and tweak if needed
|
||||
WriteFromE8 = true;
|
||||
OutputPointer = data;
|
||||
Array.Copy(Window, FramePosition, E8Buffer, data, frame_size);
|
||||
|
||||
while (data < dataend)
|
||||
{
|
||||
if (E8Buffer[data++] != 0xE8)
|
||||
{
|
||||
curpos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
abs_off = E8Buffer[data + 0] | (E8Buffer[data + 1] << 8) | (E8Buffer[data + 2] << 16) | (E8Buffer[data + 3] << 24);
|
||||
if ((abs_off >= -curpos) && (abs_off < filesize))
|
||||
{
|
||||
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
|
||||
E8Buffer[data + 0] = (byte)rel_off;
|
||||
E8Buffer[data + 1] = (byte)(rel_off >> 8);
|
||||
E8Buffer[data + 2] = (byte)(rel_off >> 16);
|
||||
E8Buffer[data + 3] = (byte)(rel_off >> 24);
|
||||
}
|
||||
|
||||
data += 4;
|
||||
curpos += 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteFromE8 = false;
|
||||
OutputPointer = (int)FramePosition;
|
||||
}
|
||||
|
||||
OutputEnd = (int)frame_size;
|
||||
|
||||
// Write a frame
|
||||
i = (int)(out_bytes < frame_size ? out_bytes : frame_size);
|
||||
if (System.Write(OutputFileHandle, WriteFromE8 ? E8Buffer : Window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
OutputPointer += i;
|
||||
Offset += i;
|
||||
out_bytes -= i;
|
||||
|
||||
// Advance frame start position
|
||||
FramePosition += (uint)frame_size;
|
||||
Frame++;
|
||||
|
||||
// Wrap window / frame position pointers
|
||||
if (WindowPosition == WindowSize)
|
||||
WindowPosition = 0;
|
||||
if (FramePosition == WindowSize)
|
||||
FramePosition = 0;
|
||||
}
|
||||
|
||||
if (out_bytes > 0)
|
||||
{
|
||||
Console.WriteLine($"{out_bytes} bytes left to output");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// States how many bits of offset-from-base data is needed.
|
||||
/// </summary>
|
||||
private int ExtraBits(uint offset)
|
||||
{
|
||||
if (offset < 4)
|
||||
return 0;
|
||||
else if (offset >= 4 && offset < 36)
|
||||
return (int)Math.Floor((double)(offset / 2)) - 1;
|
||||
else // offset >= 36
|
||||
return 17;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An index to the position slot bases
|
||||
/// </summary>
|
||||
private long PositionBase(uint offset)
|
||||
{
|
||||
if (offset < 0 || offset >= 290)
|
||||
return 0;
|
||||
|
||||
return LZXPositionBase[offset];
|
||||
|
||||
// TODO: Replace naieve recursive implementation
|
||||
if (offset == 0)
|
||||
return 0;
|
||||
else
|
||||
return PositionBase(offset - 1) + (1 << ExtraBits(offset - 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal state
|
||||
/// </summary>
|
||||
private void ResetState()
|
||||
{
|
||||
R[0] = 1;
|
||||
R[1] = 1;
|
||||
R[2] = 1;
|
||||
HeaderRead = 0;
|
||||
BlockRemaining = 0;
|
||||
BlockType = LZXBlockType.LZX_BLOCKTYPE_INVALID0;
|
||||
WriteFromE8 = false;
|
||||
|
||||
// Initialise tables to 0 (because deltas will be applied to them)
|
||||
for (int i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++)
|
||||
{
|
||||
MAINTREE_len[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
|
||||
{
|
||||
LENGTH_len[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZX : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b0 = InputBuffer[InputPointer++];
|
||||
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b1 = InputBuffer[InputPointer++];
|
||||
INJECT_BITS_MSB((b1 << 8) | b0, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZX : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Error HUFF_ERROR() => Error.MSPACK_ERR_DECRUNCH;
|
||||
|
||||
/// <summary>
|
||||
/// BUILD_TABLE(tbl) builds a huffman lookup table from code lengths
|
||||
/// </summary>
|
||||
private Error BUILD_TABLE(ushort[] table, byte[] lengths, int tablebits, int maxsymbols)
|
||||
{
|
||||
if (!MakeDecodeTableMSB(maxsymbols, tablebits, lengths, table))
|
||||
{
|
||||
Console.WriteLine("Failed to build table");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private Error BUILD_TABLE_MAYBE_EMPTY()
|
||||
{
|
||||
LENGTH_empty = false;
|
||||
if (!MakeDecodeTableMSB(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, LENGTH_len, LENGTH_table))
|
||||
{
|
||||
for (int i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
|
||||
{
|
||||
if (LENGTH_len[i] > 0)
|
||||
{
|
||||
Console.WriteLine("Failed to build LENGTH table");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty tree - allow it, but don't decode symbols with it
|
||||
LENGTH_empty = true;
|
||||
}
|
||||
|
||||
return Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
|
||||
/// first to last in the given table. The code lengths are stored in their
|
||||
/// own special LZX way.
|
||||
/// </summary>
|
||||
private Error ReadLengths(byte[] lens, uint first, uint last)
|
||||
{
|
||||
uint x, y;
|
||||
int z;
|
||||
|
||||
// Read lengths for pretree (20 symbols, lengths stored in fixed 4 bits)
|
||||
for (x = 0; x < LZX_PRETREE_MAXSYMBOLS; x++)
|
||||
{
|
||||
y = (uint)READ_BITS_MSB(4);
|
||||
PRETREE_len[x] = (byte)y;
|
||||
}
|
||||
|
||||
BUILD_TABLE(PRETREE_table, PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
for (x = first; x < last;)
|
||||
{
|
||||
z = (int)READ_HUFFSYM_MSB(PRETREE_table, PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS);
|
||||
if (z == 17)
|
||||
{
|
||||
// Code = 17, run of ([read 4 bits]+4) zeros
|
||||
y = (uint)READ_BITS_MSB(4);
|
||||
y += 4;
|
||||
while (y-- > 0)
|
||||
{
|
||||
lens[x++] = 0;
|
||||
}
|
||||
}
|
||||
else if (z == 18)
|
||||
{
|
||||
// Code = 18, run of ([read 5 bits]+20) zeros
|
||||
y = (uint)READ_BITS_MSB(5);
|
||||
y += 20;
|
||||
while (y-- > 0)
|
||||
{
|
||||
lens[x++] = 0;
|
||||
}
|
||||
}
|
||||
else if (z == 19)
|
||||
{
|
||||
// Code = 19, run of ([read 1 bit]+4) [read huffman symbol]
|
||||
y = (uint)READ_BITS_MSB(1);
|
||||
y += 4;
|
||||
|
||||
z = (int)READ_HUFFSYM_MSB(PRETREE_table, PRETREE_len, LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS);
|
||||
z = lens[x] - z;
|
||||
if (z < 0)
|
||||
z += 17;
|
||||
|
||||
while (y-- > 0)
|
||||
{
|
||||
lens[x++] = (byte)z;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Code = 0 to 16, delta current length entry
|
||||
z = lens[x] - z;
|
||||
if (z < 0)
|
||||
z += 17;
|
||||
|
||||
lens[x++] = (byte)z;
|
||||
}
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
133
BurnOutSharp/External/libmspack/Compression/LZX.cs
vendored
133
BurnOutSharp/External/libmspack/Compression/LZX.cs
vendored
@@ -1,133 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2013 Stuart Caie.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* libmspack is free software { get; set; } you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class LZX : CompressionStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of bytes actually output
|
||||
/// </summary>
|
||||
public long Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Overall decompressed length of stream
|
||||
/// </summary>
|
||||
public long Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decoding window
|
||||
/// </summary>
|
||||
public byte[] Window { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window size
|
||||
/// </summary>
|
||||
public uint WindowSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// LZX DELTA reference data size
|
||||
/// </summary>
|
||||
public uint ReferenceDataSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of match_offset entries in table
|
||||
/// </summary>
|
||||
public uint NumOffsets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompression offset within window
|
||||
/// </summary>
|
||||
public int WindowPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current frame offset within in window
|
||||
/// </summary>
|
||||
public uint FramePosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of 32kb frames processed
|
||||
/// </summary>
|
||||
public uint Frame { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Which frame do we reset the compressor?
|
||||
/// </summary>
|
||||
public uint ResetInterval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For the LRU offset system
|
||||
/// </summary>
|
||||
public uint[] R { get; set; } = new uint[3];
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed length of this LZX block
|
||||
/// </summary>
|
||||
public int BlockLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed bytes still left to decode
|
||||
/// </summary>
|
||||
public int BlockRemaining { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Magic header value used for transform
|
||||
/// </summary>
|
||||
public int IntelFileSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Has intel E8 decoding started?
|
||||
/// </summary>
|
||||
public bool IntelStarted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of the current block
|
||||
/// </summary>
|
||||
public LZXBlockType BlockType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Have we started decoding at all yet?
|
||||
/// </summary>
|
||||
public byte HeaderRead { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Does stream follow LZX DELTA spec?
|
||||
/// </summary>
|
||||
public bool IsDelta { get; set; }
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] PRETREE_len { get; set; } = new byte[LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
|
||||
public byte[] MAINTREE_len { get; set; } = new byte[LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
|
||||
public byte[] LENGTH_len { get; set; } = new byte[LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
|
||||
public byte[] ALIGNED_len { get; set; } = new byte[LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Huffman decoding tables
|
||||
|
||||
public ushort[] PRETREE_table { get; set; } = new ushort[(1 << LZX_PRETREE_TABLEBITS) + (LZX_PRETREE_MAXSYMBOLS * 2)];
|
||||
public ushort[] MAINTREE_table { get; set; } = new ushort[(1 << LZX_MAINTREE_TABLEBITS) + (LZX_MAINTREE_MAXSYMBOLS * 2)];
|
||||
public ushort[] LENGTH_table { get; set; } = new ushort[(1 << LZX_LENGTH_TABLEBITS) + (LZX_LENGTH_MAXSYMBOLS * 2)];
|
||||
public ushort[] ALIGNED_table { get; set; } = new ushort[(1 << LZX_ALIGNED_TABLEBITS) + (LZX_ALIGNED_MAXSYMBOLS * 2)];
|
||||
|
||||
#endregion
|
||||
|
||||
public bool LENGTH_empty { get; set; }
|
||||
|
||||
public byte[] E8Buffer { get; set; } = new byte[LZX_FRAME_SIZE];
|
||||
|
||||
public bool WriteFromE8 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,613 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The deflate method was created by Phil Katz. MSZIP is equivalent to the
|
||||
* deflate method.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Allocates MS-ZIP decompression stream for decoding the given stream.
|
||||
///
|
||||
/// - uses system.alloc() to allocate memory
|
||||
///
|
||||
/// - returns null if not enough memory
|
||||
///
|
||||
/// - input_buffer_size is how many bytes to use as an input bitstream buffer
|
||||
///
|
||||
/// - if RepairMode is non-zero, errors in decompression will be skipped
|
||||
/// and 'holes' left will be filled with zero bytes. This allows at least
|
||||
/// a partial recovery of erroneous data.
|
||||
/// </summary>
|
||||
public static MSZIP Init(SystemImpl system, FileStream input, FileStream output, int input_buffer_size, bool repair_mode)
|
||||
{
|
||||
if (system == null)
|
||||
return null;
|
||||
|
||||
// Round up input buffer size to multiple of two
|
||||
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||
if (input_buffer_size < 2)
|
||||
return null;
|
||||
|
||||
// Allocate decompression state
|
||||
return new MSZIP
|
||||
{
|
||||
// Allocate input buffer
|
||||
InputBuffer = new byte[input_buffer_size],
|
||||
|
||||
// Initialise decompression state
|
||||
System = system,
|
||||
InputFileHandle = input,
|
||||
OutputFileHandle = output,
|
||||
InputBufferSize = (uint)input_buffer_size,
|
||||
EndOfInput = 0,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
RepairMode = repair_mode,
|
||||
|
||||
InputPointer = 0,
|
||||
InputEnd = 0,
|
||||
OutputPointer = 0,
|
||||
OutputEnd = 0,
|
||||
BitBuffer = 0,
|
||||
BitsLeft = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses, or decompresses more of, an MS-ZIP stream.
|
||||
///
|
||||
/// - out_bytes of data will be decompressed and the function will return
|
||||
/// with an MSPACK_ERR_OK return code.
|
||||
///
|
||||
/// - decompressing will stop as soon as out_bytes is reached. if the true
|
||||
/// amount of bytes decoded spills over that amount, they will be kept for
|
||||
/// a later invocation of mszipd_decompress().
|
||||
///
|
||||
/// - the output bytes will be passed to the system.write() function given in
|
||||
/// mszipd_init(), using the output file handle given in mszipd_init(). More
|
||||
/// than one call may be made to system.write()
|
||||
///
|
||||
/// - MS-ZIP will read input bytes as necessary using the system.read()
|
||||
/// function given in mszipd_init(), using the input file handle given in
|
||||
/// mszipd_init(). This will continue until system.read() returns 0 bytes,
|
||||
/// or an error.
|
||||
/// </summary>
|
||||
public Error Decompress(long out_bytes)
|
||||
{
|
||||
int i, readState;
|
||||
Error error;
|
||||
|
||||
// Easy answers
|
||||
if (out_bytes < 0)
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
// Flush out any stored-up bytes before we begin
|
||||
i = OutputEnd - OutputPointer;
|
||||
if (i > out_bytes)
|
||||
i = (int)out_bytes;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
if (System.Write(OutputFileHandle, Window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
OutputPointer += i;
|
||||
out_bytes -= i;
|
||||
}
|
||||
|
||||
if (out_bytes == 0)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
while (out_bytes > 0)
|
||||
{
|
||||
// Skip to next read 'CK' header
|
||||
i = BitsLeft & 7;
|
||||
|
||||
// Align to bytestream
|
||||
REMOVE_BITS_LSB(i);
|
||||
|
||||
readState = 0;
|
||||
do
|
||||
{
|
||||
i = (int)READ_BITS_LSB(8);
|
||||
|
||||
if (i == 'C')
|
||||
readState = 1;
|
||||
else if ((readState == 1) && (i == 'K'))
|
||||
readState = 2;
|
||||
else
|
||||
readState = 0;
|
||||
} while (readState != 2);
|
||||
|
||||
// Inflate a block, repair and realign if necessary
|
||||
WindowPosition = 0;
|
||||
BytesOutput = 0;
|
||||
|
||||
if ((error = Inflate()) != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
Console.WriteLine($"Inflate error {error}");
|
||||
if (RepairMode)
|
||||
{
|
||||
// Recover partially-inflated buffers
|
||||
if (BytesOutput == 0 && WindowPosition > 0)
|
||||
FlushWindow(WindowPosition);
|
||||
|
||||
System.Message(null, $"MSZIP error, {MSZIP_FRAME_SIZE - BytesOutput} bytes of data lost.");
|
||||
for (i = BytesOutput; i < MSZIP_FRAME_SIZE; i++)
|
||||
{
|
||||
Window[i] = 0x00;
|
||||
}
|
||||
|
||||
BytesOutput = MSZIP_FRAME_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Error = error;
|
||||
}
|
||||
}
|
||||
|
||||
OutputPointer = 0;
|
||||
OutputEnd = BytesOutput;
|
||||
|
||||
// Write a frame
|
||||
i = (out_bytes < BytesOutput) ? (int)out_bytes : BytesOutput;
|
||||
if (System.Write(OutputFileHandle, Window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
// mspack errors (i.e. read errors) are fatal and can't be recovered
|
||||
if ((error > 0) && RepairMode)
|
||||
return error;
|
||||
|
||||
OutputPointer += i;
|
||||
out_bytes -= i;
|
||||
}
|
||||
|
||||
if (out_bytes > 0)
|
||||
{
|
||||
Console.WriteLine($"Bytes left to output: {out_bytes}");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses an entire MS-ZIP stream in a KWAJ file. Acts very much
|
||||
/// like mszipd_decompress(), but doesn't take an out_bytes parameter
|
||||
/// </summary>
|
||||
public Error DecompressKWAJ()
|
||||
{
|
||||
int i, block_len;
|
||||
Error error;
|
||||
|
||||
// Unpack blocks until block_len == 0
|
||||
for (; ; )
|
||||
{
|
||||
// Align to bytestream, read block_len
|
||||
i = BitsLeft & 7;
|
||||
REMOVE_BITS_LSB(i);
|
||||
|
||||
block_len = (int)READ_BITS_LSB(8);
|
||||
i = (int)READ_BITS_LSB(8);
|
||||
|
||||
block_len |= i << 8;
|
||||
if (block_len == 0)
|
||||
break;
|
||||
|
||||
// Read "CK" header
|
||||
i = (int)READ_BITS_LSB(8);
|
||||
if (i != 'C')
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
i = (int)READ_BITS_LSB(8);
|
||||
if (i != 'K')
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
// Inflate block
|
||||
WindowPosition = 0;
|
||||
BytesOutput = 0;
|
||||
|
||||
if ((error = Inflate()) != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
Console.WriteLine($"Inflate error {error}");
|
||||
return Error = (error > 0) ? error : Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// Write inflated block
|
||||
try { System.Write(OutputFileHandle, Window, 0, BytesOutput); }
|
||||
catch { return Error = Error.MSPACK_ERR_WRITE; }
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private Error ReadLens()
|
||||
{
|
||||
// bitlen Huffman codes -- immediate lookup, 7 bit max code length
|
||||
ushort[] bl_table = new ushort[(1 << 7)];
|
||||
byte[] bl_len = new byte[19];
|
||||
|
||||
byte[] lens = new byte[MSZIP_LITERAL_MAXSYMBOLS + MSZIP_DISTANCE_MAXSYMBOLS];
|
||||
uint lit_codes, dist_codes, code, last_code = 0, bitlen_codes, i, run;
|
||||
|
||||
// Read the number of codes
|
||||
lit_codes = (uint)READ_BITS_LSB(5);
|
||||
lit_codes += 257;
|
||||
|
||||
dist_codes = (uint)READ_BITS_LSB(5);
|
||||
dist_codes += 1;
|
||||
|
||||
bitlen_codes = (uint)READ_BITS_LSB(5);
|
||||
bitlen_codes += 4;
|
||||
|
||||
if (lit_codes > MSZIP_LITERAL_MAXSYMBOLS)
|
||||
return Error.INF_ERR_SYMLENS;
|
||||
if (dist_codes > MSZIP_DISTANCE_MAXSYMBOLS)
|
||||
return Error.INF_ERR_SYMLENS;
|
||||
|
||||
// Read in the bit lengths in their unusual order
|
||||
for (i = 0; i < bitlen_codes; i++)
|
||||
{
|
||||
bl_len[BitLengthOrder[i]] = (byte)READ_BITS_LSB(3);
|
||||
}
|
||||
|
||||
while (i < 19)
|
||||
{
|
||||
bl_len[BitLengthOrder[i++]] = 0;
|
||||
}
|
||||
|
||||
// Create decoding table with an immediate lookup
|
||||
if (!CompressionStream.MakeDecodeTableLSB(19, 7, bl_len, bl_table))
|
||||
return Error.INF_ERR_BITLENTBL;
|
||||
|
||||
// Read literal / distance code lengths
|
||||
for (i = 0; i < (lit_codes + dist_codes); i++)
|
||||
{
|
||||
// Single-level huffman lookup
|
||||
|
||||
ENSURE_BITS(7);
|
||||
code = bl_table[PEEK_BITS_LSB(7)];
|
||||
REMOVE_BITS_LSB(bl_len[code]);
|
||||
|
||||
if (code < 16)
|
||||
{
|
||||
lens[i] = (byte)(last_code = code);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 16:
|
||||
run = (uint)READ_BITS_LSB(2);
|
||||
run += 3;
|
||||
code = last_code;
|
||||
break;
|
||||
|
||||
case 17:
|
||||
run = (uint)READ_BITS_LSB(3);
|
||||
run += 3;
|
||||
code = 0;
|
||||
break;
|
||||
|
||||
case 18:
|
||||
run = (uint)READ_BITS_LSB(7);
|
||||
run += 11;
|
||||
code = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine($"Bad code!: {code}");
|
||||
return Error.INF_ERR_BADBITLEN;
|
||||
}
|
||||
|
||||
if ((i + run) > (lit_codes + dist_codes))
|
||||
return Error.INF_ERR_BITOVERRUN;
|
||||
|
||||
while (run-- > 0)
|
||||
{
|
||||
lens[i++] = (byte)code;
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy LITERAL code lengths and clear any remaining
|
||||
i = lit_codes;
|
||||
Array.Copy(lens, 0, LITERAL_len, 0, i);
|
||||
while (i < MSZIP_LITERAL_MAXSYMBOLS)
|
||||
{
|
||||
LITERAL_len[i++] = 0;
|
||||
}
|
||||
|
||||
i = dist_codes;
|
||||
Array.Copy(lens, lit_codes, DISTANCE_len, 0, i);
|
||||
while (i < MSZIP_DISTANCE_MAXSYMBOLS)
|
||||
{
|
||||
DISTANCE_len[i++] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A clean implementation of RFC 1951 / inflate
|
||||
/// </summary>
|
||||
private Error Inflate()
|
||||
{
|
||||
uint last_block, block_type, distance, length, this_run, i;
|
||||
Error err;
|
||||
ushort sym;
|
||||
|
||||
do
|
||||
{
|
||||
// Read in last block bit
|
||||
last_block = (uint)READ_BITS_LSB(1);
|
||||
|
||||
// Read in block type
|
||||
block_type = (uint)READ_BITS_LSB(2);
|
||||
|
||||
if (block_type == 0)
|
||||
{
|
||||
// Uncompressed block
|
||||
byte[] lens_buf = new byte[4];
|
||||
|
||||
// Go to byte boundary
|
||||
i = (uint)(BitsLeft & 7);
|
||||
REMOVE_BITS_LSB((int)i);
|
||||
|
||||
// Read 4 bytes of data, emptying the bit-buffer if necessary
|
||||
for (i = 0; (BitsLeft >= 8); i++)
|
||||
{
|
||||
if (i == 4)
|
||||
return Error.INF_ERR_BITBUF;
|
||||
|
||||
lens_buf[i] = (byte)PEEK_BITS_LSB(8);
|
||||
REMOVE_BITS_LSB(8);
|
||||
}
|
||||
|
||||
if (BitsLeft != 0)
|
||||
return Error.INF_ERR_BITBUF;
|
||||
|
||||
while (i < 4)
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
lens_buf[i++] = InputBuffer[InputPointer++];
|
||||
}
|
||||
|
||||
// Get the length and its complement
|
||||
length = (ushort)(lens_buf[0] | (lens_buf[1] << 8));
|
||||
i = (ushort)(lens_buf[2] | (lens_buf[3] << 8));
|
||||
|
||||
ushort compl = (ushort)(~i & 0xFFFF);
|
||||
if (length != compl)
|
||||
return Error.INF_ERR_COMPLEMENT;
|
||||
|
||||
// Read and copy the uncompressed data into the window
|
||||
while (length > 0)
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
this_run = length;
|
||||
if (this_run > (uint)(InputEnd - InputPointer))
|
||||
this_run = (uint)(InputEnd - InputPointer);
|
||||
|
||||
if (this_run > (MSZIP_FRAME_SIZE - WindowPosition))
|
||||
this_run = MSZIP_FRAME_SIZE - WindowPosition;
|
||||
|
||||
Array.Copy(InputBuffer, InputPointer, Window, WindowPosition, this_run);
|
||||
|
||||
WindowPosition += this_run;
|
||||
InputPointer += (int)this_run;
|
||||
length -= this_run;
|
||||
|
||||
err = FLUSH_IF_NEEDED();
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else if ((block_type == 1) || (block_type == 2))
|
||||
{
|
||||
// Huffman-compressed LZ77 block
|
||||
uint match_posn, code;
|
||||
|
||||
if (block_type == 1)
|
||||
{
|
||||
// Block with fixed Huffman codes
|
||||
i = 0;
|
||||
while (i < 144)
|
||||
{
|
||||
LITERAL_len[i++] = 8;
|
||||
}
|
||||
|
||||
while (i < 256)
|
||||
{
|
||||
LITERAL_len[i++] = 9;
|
||||
}
|
||||
|
||||
while (i < 280)
|
||||
{
|
||||
LITERAL_len[i++] = 7;
|
||||
}
|
||||
|
||||
while (i < 288)
|
||||
{
|
||||
LITERAL_len[i++] = 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
DISTANCE_len[i] = 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Block with dynamic Huffman codes
|
||||
if ((err = ReadLens()) != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
}
|
||||
|
||||
// Now huffman lengths are read for either kind of block,
|
||||
// create huffman decoding tables
|
||||
if (!CompressionStream.MakeDecodeTableLSB(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, LITERAL_len, LITERAL_table))
|
||||
return Error.INF_ERR_LITERALTBL;
|
||||
|
||||
if (!CompressionStream.MakeDecodeTableLSB(MSZIP_DISTANCE_MAXSYMBOLS, MSZIP_DISTANCE_TABLEBITS, DISTANCE_len, DISTANCE_table))
|
||||
return Error.INF_ERR_DISTANCETBL;
|
||||
|
||||
// Decode forever until end of block code
|
||||
for (; ; )
|
||||
{
|
||||
code = (uint)READ_HUFFSYM_LSB(LITERAL_table, LITERAL_len, MSZIP_LITERAL_TABLEBITS, MSZIP_LITERAL_MAXSYMBOLS);
|
||||
|
||||
if (code < 256)
|
||||
{
|
||||
Window[WindowPosition++] = (byte)code;
|
||||
err = FLUSH_IF_NEEDED();
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
}
|
||||
else if (code == 256)
|
||||
{
|
||||
// END OF BLOCK CODE: loop break point
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
code -= 257; // Codes 257-285 are matches
|
||||
if (code >= 29)
|
||||
return Error.INF_ERR_LITCODE; // Codes 286-287 are illegal
|
||||
|
||||
length = (uint)READ_BITS_T_LSB(LiteralExtraBits[code]);
|
||||
length += LiteralLengths[code];
|
||||
|
||||
code = (uint)READ_HUFFSYM_LSB(DISTANCE_table, DISTANCE_len, MSZIP_DISTANCE_TABLEBITS, MSZIP_DISTANCE_MAXSYMBOLS);
|
||||
|
||||
if (code >= 30)
|
||||
return Error.INF_ERR_DISTCODE;
|
||||
|
||||
distance = (uint)READ_BITS_T_LSB(DistanceExtraBits[code]);
|
||||
distance += DistanceOffsets[code];
|
||||
|
||||
// Match position is window position minus distance. If distance
|
||||
// is more than window position numerically, it must 'wrap
|
||||
// around' the frame size.
|
||||
match_posn = (uint)((distance > WindowPosition) ? MSZIP_FRAME_SIZE : 0) + WindowPosition - distance;
|
||||
|
||||
// Copy match
|
||||
if (length < 12)
|
||||
{
|
||||
// Short match, use slower loop but no loop setup code
|
||||
while (length-- > 0)
|
||||
{
|
||||
Window[WindowPosition++] = Window[match_posn++];
|
||||
match_posn &= MSZIP_FRAME_SIZE - 1;
|
||||
err = FLUSH_IF_NEEDED();
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Longer match, use faster loop but with setup expense */
|
||||
int runsrc, rundest;
|
||||
do
|
||||
{
|
||||
this_run = length;
|
||||
if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
|
||||
this_run = MSZIP_FRAME_SIZE - match_posn;
|
||||
if ((WindowPosition + this_run) > MSZIP_FRAME_SIZE)
|
||||
this_run = MSZIP_FRAME_SIZE - WindowPosition;
|
||||
|
||||
rundest = (int)WindowPosition;
|
||||
WindowPosition += this_run;
|
||||
runsrc = (int)match_posn;
|
||||
match_posn += this_run;
|
||||
length -= this_run;
|
||||
while (this_run-- > 0)
|
||||
{
|
||||
Window[rundest++] = Window[runsrc++];
|
||||
}
|
||||
|
||||
if (match_posn == MSZIP_FRAME_SIZE)
|
||||
match_posn = 0;
|
||||
|
||||
err = FLUSH_IF_NEEDED();
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return err;
|
||||
} while (length > 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// block_type == 3 -- bad block type
|
||||
return Error.INF_ERR_BLOCKTYPE;
|
||||
}
|
||||
} while (last_block == 0);
|
||||
|
||||
// Flush the remaining data
|
||||
if (WindowPosition > 0)
|
||||
{
|
||||
if (FlushWindow(WindowPosition) != Error.MSPACK_ERR_OK)
|
||||
return Error.INF_ERR_FLUSH;
|
||||
}
|
||||
|
||||
// Return success
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private Error FLUSH_IF_NEEDED()
|
||||
{
|
||||
if (WindowPosition == MSZIP_FRAME_SIZE)
|
||||
{
|
||||
if (FlushWindow(MSZIP_FRAME_SIZE) != Error.MSPACK_ERR_OK)
|
||||
return Error.INF_ERR_FLUSH;
|
||||
|
||||
WindowPosition = 0;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// inflate() calls this whenever the window should be flushed. As
|
||||
/// MSZIP only expands to the size of the window, the implementation used
|
||||
/// simply keeps track of the amount of data flushed, and if more than 32k
|
||||
/// is flushed, an error is raised.
|
||||
/// </summary>
|
||||
private Error FlushWindow(uint data_flushed)
|
||||
{
|
||||
BytesOutput += (int)data_flushed;
|
||||
if (BytesOutput > MSZIP_FRAME_SIZE)
|
||||
{
|
||||
Console.WriteLine($"Overflow: {data_flushed} bytes flushed, total is now {BytesOutput}");
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The deflate method was created by Phil Katz. MSZIP is equivalent to the
|
||||
* deflate method.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class MSZIP : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
INJECT_BITS_LSB(InputBuffer[InputPointer++], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The deflate method was created by Phil Katz. MSZIP is equivalent to the
|
||||
* deflate method.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class MSZIP : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Error HUFF_ERROR() => Error.INF_ERR_HUFFSYM;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The deflate method was created by Phil Katz. MSZIP is equivalent to the
|
||||
* deflate method.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class MSZIP : CompressionStream
|
||||
{
|
||||
/// <summary>
|
||||
/// 32kb history window
|
||||
/// </summary>
|
||||
public byte[] Window { get; set; } = new byte[MSZIP_FRAME_SIZE];
|
||||
|
||||
/// <summary>
|
||||
/// Offset within window
|
||||
/// </summary>
|
||||
public uint WindowPosition { get; set; }
|
||||
|
||||
public bool RepairMode { get; set; }
|
||||
|
||||
public int BytesOutput { get; set; }
|
||||
|
||||
#region Huffman code lengths
|
||||
|
||||
public byte[] LITERAL_len { get; set; } = new byte[MSZIP_LITERAL_MAXSYMBOLS];
|
||||
public byte[] DISTANCE_len { get; set; } = new byte[MSZIP_DISTANCE_MAXSYMBOLS];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Huffman decoding tables
|
||||
|
||||
public ushort[] LITERAL_table { get; set; } = new ushort[MSZIP_LITERAL_TABLESIZE];
|
||||
public ushort[] DISTANCE_table { get; set; } = new ushort[MSZIP_DISTANCE_TABLESIZE];
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class None
|
||||
{
|
||||
public static None Init(SystemImpl sys, FileStream input, FileStream output, int bufsize)
|
||||
{
|
||||
return new None()
|
||||
{
|
||||
System = sys,
|
||||
InputFileHandle = input,
|
||||
OutputFileHandle = output,
|
||||
Buffer = new byte[bufsize],
|
||||
BufferSize = bufsize,
|
||||
};
|
||||
}
|
||||
|
||||
public Error Decompress(long bytes)
|
||||
{
|
||||
int run;
|
||||
while (bytes > 0)
|
||||
{
|
||||
run = (bytes > BufferSize) ? BufferSize : (int)bytes;
|
||||
|
||||
if (System.Read(InputFileHandle, Buffer, 0, run) != run)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
if (System.Write(OutputFileHandle, Buffer, 0, run) != run)
|
||||
return Error.MSPACK_ERR_WRITE;
|
||||
|
||||
bytes -= run;
|
||||
}
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// The "not compressed" method decompressor
|
||||
/// </summary>
|
||||
public partial class None : BaseDecompressState
|
||||
{
|
||||
public byte[] Buffer { get; set; }
|
||||
|
||||
public int BufferSize { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,542 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The Quantum method was created by David Stafford, adapted by Microsoft
|
||||
* Corporation.
|
||||
*
|
||||
* This decompressor is based on an implementation by Matthew Russotto, used
|
||||
* with permission.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
/* Quantum decompression implementation */
|
||||
|
||||
/* This decompressor was researched and implemented by Matthew Russotto. It
|
||||
* has since been tidied up by Stuart Caie. More information can be found at
|
||||
* http://www.speakeasy.org/~russotto/quantumcomp.html
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static LibMSPackSharp.Compression.Constants;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class QTM
|
||||
{
|
||||
/// <summary>
|
||||
/// allocates Quantum decompression state for decoding the given stream.
|
||||
///
|
||||
/// - returns null if window_bits is outwith the range 10 to 21 (inclusive).
|
||||
/// - uses system.alloc() to allocate memory
|
||||
/// - returns null if not enough memory
|
||||
/// - window_bits is the size of the Quantum window, from 1Kb(10) to 2Mb(21).
|
||||
/// - input_buffer_size is the number of bytes to use to store bitstream data.
|
||||
/// </summary>
|
||||
public static QTM Init(SystemImpl system, FileStream input, FileStream output, int window_bits, int input_buffer_size)
|
||||
{
|
||||
uint window_size = (uint)(1 << window_bits);
|
||||
|
||||
if (system == null)
|
||||
return null;
|
||||
|
||||
// Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb)
|
||||
if (window_bits < 10 || window_bits > 21)
|
||||
return null;
|
||||
|
||||
// Round up input buffer size to multiple of two
|
||||
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||
if (input_buffer_size < 2)
|
||||
return null;
|
||||
|
||||
// Allocate decompression state
|
||||
QTM qtm = new QTM()
|
||||
{
|
||||
// Allocate decompression window and input buffer
|
||||
Window = new byte[window_size],
|
||||
InputBuffer = new byte[input_buffer_size],
|
||||
|
||||
// Initialise decompression state
|
||||
System = system,
|
||||
InputFileHandle = input,
|
||||
OutputFileHandle = output,
|
||||
InputBufferSize = (uint)input_buffer_size,
|
||||
WindowSize = window_size,
|
||||
WindowPosition = 0,
|
||||
FrameTODO = QTM_FRAME_SIZE,
|
||||
HeaderRead = 0,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
|
||||
InputPointer = 0,
|
||||
InputEnd = 0,
|
||||
OutputPointer = 0,
|
||||
OutputEnd = 0,
|
||||
BitBuffer = 0,
|
||||
BitsLeft = 0,
|
||||
EndOfInput = 0,
|
||||
};
|
||||
|
||||
// Initialise arithmetic coding models
|
||||
// - model 4 depends on window size, ranges from 20 to 24
|
||||
// - model 5 depends on window size, ranges from 20 to 36
|
||||
// - model 6pos depends on window size, ranges from 20 to 42
|
||||
|
||||
int i = window_bits * 2;
|
||||
qtm.InitModel(qtm.Model0, qtm.Model0Symbols, 0, 64);
|
||||
qtm.InitModel(qtm.Model1, qtm.Model1Symbols, 64, 64);
|
||||
qtm.InitModel(qtm.Model2, qtm.Model2Symbols, 128, 64);
|
||||
qtm.InitModel(qtm.Model3, qtm.Model3Symbols, 192, 64);
|
||||
qtm.InitModel(qtm.Model4, qtm.Model4Symbols, 0, (i > 24) ? 24 : i);
|
||||
qtm.InitModel(qtm.Model5, qtm.Model5Symbols, 0, (i > 36) ? 36 : i);
|
||||
qtm.InitModel(qtm.Model6, qtm.Model6Symbols, 0, i);
|
||||
qtm.InitModel(qtm.Model6Len, qtm.Model6LenSymbols, 0, 27);
|
||||
qtm.InitModel(qtm.Model7, qtm.Model7Symbols, 0, 7);
|
||||
|
||||
// All ok
|
||||
return qtm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses, or decompresses more of, a Quantum stream.
|
||||
///
|
||||
/// - out_bytes of data will be decompressed and the function will return
|
||||
/// with an MSPACK_ERR_OK return code.
|
||||
///
|
||||
/// - decompressing will stop as soon as out_bytes is reached. if the true
|
||||
/// amount of bytes decoded spills over that amount, they will be kept for
|
||||
/// a later invocation of qtmd_decompress().
|
||||
///
|
||||
/// - the output bytes will be passed to the system.write() function given in
|
||||
/// qtmd_init(), using the output file handle given in qtmd_init(). More
|
||||
/// than one call may be made to system.write()
|
||||
///
|
||||
/// - Quantum will read input bytes as necessary using the system.read()
|
||||
/// function given in qtmd_init(), using the input file handle given in
|
||||
/// qtmd_init(). This will continue until system.read() returns 0 bytes,
|
||||
/// or an error.
|
||||
/// </summary>
|
||||
public Error Decompress(long out_bytes)
|
||||
{
|
||||
uint frame_todo, frame_end, window_posn, match_offset, range;
|
||||
byte[] window;
|
||||
int runsrc, rundest;
|
||||
int i, j, selector, extra, sym, match_length;
|
||||
ushort H, L, C, symf;
|
||||
|
||||
// Easy answers
|
||||
if (out_bytes < 0)
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return Error;
|
||||
|
||||
// Flush out any stored-up bytes before we begin
|
||||
i = OutputEnd - OutputPointer;
|
||||
if (i > out_bytes)
|
||||
i = (int)out_bytes;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
if (System.Write(OutputFileHandle, Window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
OutputPointer += i;
|
||||
out_bytes -= i;
|
||||
}
|
||||
|
||||
if (out_bytes == 0)
|
||||
return Error.MSPACK_ERR_OK;
|
||||
|
||||
// Restore local state
|
||||
window = Window;
|
||||
window_posn = WindowPosition;
|
||||
frame_todo = FrameTODO;
|
||||
H = High;
|
||||
L = Low;
|
||||
C = Current;
|
||||
|
||||
// While we do not have enough decoded bytes in reserve
|
||||
while ((OutputEnd - OutputPointer) < out_bytes)
|
||||
{
|
||||
// Read header if necessary. Initialises H, L and C
|
||||
if (HeaderRead != 0)
|
||||
{
|
||||
H = 0xFFFF;
|
||||
L = 0;
|
||||
C = (ushort)READ_BITS_MSB(16);
|
||||
HeaderRead = 1;
|
||||
}
|
||||
|
||||
// Decode more, up to the number of bytes needed, the frame boundary,
|
||||
// or the window boundary, whichever comes first
|
||||
frame_end = (uint)(window_posn + (out_bytes - (OutputEnd - OutputPointer)));
|
||||
if ((window_posn + frame_todo) < frame_end)
|
||||
frame_end = window_posn + frame_todo;
|
||||
if (frame_end > WindowSize)
|
||||
frame_end = WindowSize;
|
||||
|
||||
while (window_posn < frame_end)
|
||||
{
|
||||
selector = GET_SYMBOL(Model7, ref H, ref L, ref C);
|
||||
if (selector < 4)
|
||||
{
|
||||
// Literal byte
|
||||
QTMDModel mdl;
|
||||
switch (selector)
|
||||
{
|
||||
case 0:
|
||||
mdl = Model0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
mdl = Model1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
mdl = Model2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
default:
|
||||
mdl = Model3;
|
||||
break;
|
||||
}
|
||||
|
||||
sym = GET_SYMBOL(mdl, ref H, ref L, ref C);
|
||||
window[window_posn++] = (byte)sym;
|
||||
frame_todo--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Match repeated string
|
||||
switch (selector)
|
||||
{
|
||||
// Selector 4 = fixed length match (3 bytes)
|
||||
case 4:
|
||||
sym = GET_SYMBOL(Model4, ref H, ref L, ref C);
|
||||
extra = (int)READ_MANY_BITS_MSB(QTMExtraBits[sym]);
|
||||
match_offset = (uint)(QTMPositionBase[sym] + extra + 1);
|
||||
match_length = 3;
|
||||
break;
|
||||
|
||||
// Selector 5 = fixed length match (4 bytes)
|
||||
case 5:
|
||||
sym = GET_SYMBOL(Model5, ref H, ref L, ref C);
|
||||
extra = (int)READ_MANY_BITS_MSB(QTMExtraBits[sym]);
|
||||
match_offset = (uint)(QTMPositionBase[sym] + extra + 1);
|
||||
match_length = 4;
|
||||
break;
|
||||
|
||||
// Selector 6 = variable length match
|
||||
case 6:
|
||||
sym = GET_SYMBOL(Model6Len, ref H, ref L, ref C);
|
||||
extra = (int)READ_MANY_BITS_MSB(QTMLengthExtra[sym]);
|
||||
match_length = QTMLengthBase[sym] + extra + 5;
|
||||
|
||||
sym = GET_SYMBOL(Model6, ref H, ref L, ref C);
|
||||
extra = (int)READ_MANY_BITS_MSB(QTMExtraBits[sym]);
|
||||
match_offset = (uint)(QTMPositionBase[sym] + extra + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Should be impossible, model7 can only return 0-6
|
||||
Console.WriteLine($"Got {selector} from selector");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
rundest = (int)window_posn;
|
||||
frame_todo -= (uint)match_length;
|
||||
|
||||
// Does match destination wrap the window? This situation is possible
|
||||
// where the window size is less than the 32k frame size, but matches
|
||||
// must not go beyond a frame boundary
|
||||
if ((window_posn + match_length) > WindowSize)
|
||||
{
|
||||
// Copy first part of match, before window end
|
||||
i = (int)(WindowSize - window_posn);
|
||||
j = (int)(window_posn - match_offset);
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[j++ & (WindowSize - 1)];
|
||||
}
|
||||
|
||||
// Flush currently stored data
|
||||
i = (int)(WindowSize - OutputPointer);
|
||||
|
||||
// This should not happen, but if it does then this code
|
||||
// can't handle the situation (can't flush up to the end of
|
||||
// the window, but can't break out either because we haven't
|
||||
// finished writing the match). Bail out in this case
|
||||
if (i > out_bytes)
|
||||
{
|
||||
Console.WriteLine($"During window-wrap match; {i} bytes to flush but only need {out_bytes}");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
if (System.Write(OutputFileHandle, window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
out_bytes -= i;
|
||||
OutputPointer = 0;
|
||||
OutputEnd = 0;
|
||||
|
||||
// Copy second part of match, after window wrap
|
||||
rundest = 0;
|
||||
i = (int)(match_length - (WindowSize - window_posn));
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[j++ & (WindowSize - 1)];
|
||||
}
|
||||
|
||||
window_posn = (uint)(window_posn + match_length - WindowSize);
|
||||
|
||||
break; // Because "window_posn < frame_end" has now failed
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal match - output won't wrap window or frame end
|
||||
i = match_length;
|
||||
|
||||
// Does match _offset_ wrap the window?
|
||||
if (match_offset > window_posn)
|
||||
{
|
||||
// j = length from match offset to end of window
|
||||
j = (int)(match_offset - window_posn);
|
||||
if (j > (int)WindowSize)
|
||||
{
|
||||
Console.WriteLine("Match offset beyond window boundaries");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
runsrc = (int)(WindowSize - j);
|
||||
if (j < i)
|
||||
{
|
||||
// If match goes over the window edge, do two copy runs
|
||||
i -= j;
|
||||
while (j-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
|
||||
runsrc = 0;
|
||||
}
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = (int)(rundest - match_offset);
|
||||
while (i-- > 0)
|
||||
{
|
||||
window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
|
||||
window_posn += (uint)match_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutputEnd = (int)window_posn;
|
||||
|
||||
// If we subtracted too much from frame_todo, it will
|
||||
// wrap around past zero and go above its max value
|
||||
if (frame_todo > QTM_FRAME_SIZE)
|
||||
{
|
||||
Console.WriteLine("Overshot frame alignment");
|
||||
return Error = Error.MSPACK_ERR_DECRUNCH;
|
||||
}
|
||||
|
||||
// Another frame completed?
|
||||
if (frame_todo == 0)
|
||||
{
|
||||
// Re-align input
|
||||
if ((BitsLeft & 7) != 0)
|
||||
REMOVE_BITS_MSB(BitsLeft & 7);
|
||||
|
||||
// Special Quantum hack -- cabd.c injects a trailer byte to allow the
|
||||
// decompressor to realign itself. CAB Quantum blocks, unlike LZX
|
||||
// blocks, can have anything from 0 to 4 trailing null bytes.
|
||||
do
|
||||
{
|
||||
i = (int)READ_BITS_MSB(8);
|
||||
} while (i != 0xFF);
|
||||
|
||||
HeaderRead = 0;
|
||||
|
||||
frame_todo = QTM_FRAME_SIZE;
|
||||
}
|
||||
|
||||
// Window wrap?
|
||||
if (window_posn == WindowSize)
|
||||
{
|
||||
// Flush all currently stored data
|
||||
i = (OutputEnd - OutputPointer);
|
||||
|
||||
// Break out if we have more than enough to finish this request
|
||||
if (i >= out_bytes)
|
||||
break;
|
||||
|
||||
if (System.Write(OutputFileHandle, window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
out_bytes -= i;
|
||||
OutputPointer = 0;
|
||||
OutputEnd = 0;
|
||||
window_posn = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (out_bytes > 0)
|
||||
{
|
||||
i = (int)out_bytes;
|
||||
|
||||
if (System.Write(OutputFileHandle, window, OutputPointer, i) != i)
|
||||
return Error = Error.MSPACK_ERR_WRITE;
|
||||
|
||||
OutputPointer += i;
|
||||
}
|
||||
|
||||
// Store local state
|
||||
WindowPosition = window_posn;
|
||||
FrameTODO = frame_todo;
|
||||
High = H;
|
||||
Low = L;
|
||||
Current = C;
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
private ushort GET_SYMBOL(QTMDModel model, ref ushort H, ref ushort L, ref ushort C)
|
||||
{
|
||||
uint range = (uint)((H - L) & 0xFFFF) + 1;
|
||||
ushort symf = (ushort)(((((C - L + 1) * model.Syms[0].CumulativeFrequency) - 1) / range) & 0xFFFF);
|
||||
|
||||
int i = 1;
|
||||
for (; i < model.Entries; i++)
|
||||
{
|
||||
if (model.Syms[i].CumulativeFrequency <= symf)
|
||||
break;
|
||||
}
|
||||
|
||||
ushort temp = model.Syms[i - 1].Sym;
|
||||
|
||||
range = (uint)(H - L) + 1;
|
||||
symf = model.Syms[0].CumulativeFrequency;
|
||||
H = (ushort)(L + ((model.Syms[i - 1].CumulativeFrequency * range) / symf) - 1);
|
||||
L = (ushort)(L + ((model.Syms[i].CumulativeFrequency * range) / symf));
|
||||
|
||||
do
|
||||
{
|
||||
model.Syms[--i].CumulativeFrequency += 8;
|
||||
} while (i > 0);
|
||||
|
||||
if (model.Syms[0].CumulativeFrequency > 3800)
|
||||
UpdateModel(model);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if ((L & 0x8000) != (H & 0x8000))
|
||||
{
|
||||
if ((L & 0x4000) != 0 && (H & 0x4000) == 0)
|
||||
{
|
||||
// Underflow case
|
||||
C ^= 0x4000;
|
||||
L &= 0x3FFF;
|
||||
H |= 0x4000;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
L <<= 1;
|
||||
H = (ushort)((H << 1) | 1);
|
||||
|
||||
ENSURE_BITS(1);
|
||||
C = (ushort)((C << 1) | (PEEK_BITS_MSB(1)));
|
||||
REMOVE_BITS_MSB(1);
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
private void UpdateModel(QTMDModel model)
|
||||
{
|
||||
QTMDModelSym tmp;
|
||||
int i, j;
|
||||
|
||||
if (--model.ShiftsLeft > 0)
|
||||
{
|
||||
for (i = model.Entries - 1; i >= 0; i--)
|
||||
{
|
||||
// -1, not -2; the 0 entry saves this
|
||||
model.Syms[i].CumulativeFrequency >>= 1;
|
||||
if (model.Syms[i].CumulativeFrequency <= model.Syms[i + 1].CumulativeFrequency)
|
||||
model.Syms[i].CumulativeFrequency = (ushort)(model.Syms[i + 1].CumulativeFrequency + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
model.ShiftsLeft = 50;
|
||||
for (i = 0; i < model.Entries; i++)
|
||||
{
|
||||
// No -1, want to include the 0 entry
|
||||
|
||||
// This converts CumFreqs into frequencies, then shifts right
|
||||
model.Syms[i].CumulativeFrequency -= model.Syms[i + 1].CumulativeFrequency;
|
||||
model.Syms[i].CumulativeFrequency++; // Avoid losing things entirely
|
||||
model.Syms[i].CumulativeFrequency >>= 1;
|
||||
}
|
||||
|
||||
// Now sort by frequencies, decreasing order -- this must be an
|
||||
// inplace selection sort, or a sort with the same (in)stability
|
||||
// characteristics
|
||||
for (i = 0; i < model.Entries - 1; i++)
|
||||
{
|
||||
for (j = i + 1; j < model.Entries; j++)
|
||||
{
|
||||
if (model.Syms[i].CumulativeFrequency < model.Syms[j].CumulativeFrequency)
|
||||
{
|
||||
tmp = model.Syms[i];
|
||||
model.Syms[i] = model.Syms[j];
|
||||
model.Syms[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then convert frequencies back to CumFreq
|
||||
for (i = model.Entries - 1; i >= 0; i--)
|
||||
{
|
||||
model.Syms[i].CumulativeFrequency += model.Syms[i + 1].CumulativeFrequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitModel(QTMDModel model, QTMDModelSym[] syms, int start, int len)
|
||||
{
|
||||
model.ShiftsLeft = 4;
|
||||
model.Entries = len;
|
||||
model.Syms = syms;
|
||||
|
||||
for (int i = 0; i <= len; i++)
|
||||
{
|
||||
// Actual symbol
|
||||
syms[i].Sym = (ushort)(start + i);
|
||||
|
||||
// Current frequency of that symbol
|
||||
syms[i].CumulativeFrequency = (ushort)(len - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The Quantum method was created by David Stafford, adapted by Microsoft
|
||||
* Corporation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class QTM : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override void READ_BYTES()
|
||||
{
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b0 = InputBuffer[InputPointer++];
|
||||
|
||||
READ_IF_NEEDED();
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
return;
|
||||
|
||||
byte b1 = InputBuffer[InputPointer++];
|
||||
INJECT_BITS_MSB((b0 << 8) | b1, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The Quantum method was created by David Stafford, adapted by Microsoft
|
||||
* Corporation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class QTM : CompressionStream
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Error HUFF_ERROR() => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
123
BurnOutSharp/External/libmspack/Compression/QTM.cs
vendored
123
BurnOutSharp/External/libmspack/Compression/QTM.cs
vendored
@@ -1,123 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The Quantum method was created by David Stafford, adapted by Microsoft
|
||||
* Corporation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public partial class QTM : CompressionStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Decoding window
|
||||
/// </summary>
|
||||
public byte[] Window { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Window size
|
||||
/// </summary>
|
||||
public uint WindowSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompression offset within window
|
||||
/// </summary>
|
||||
public uint WindowPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Bytes remaining for current frame
|
||||
/// </summary>
|
||||
public uint FrameTODO { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// High: arith coding state
|
||||
/// </summary>
|
||||
public ushort High { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Low: arith coding state
|
||||
/// </summary>
|
||||
public ushort Low { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current: arith coding state
|
||||
/// </summary>
|
||||
public ushort Current { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Have we started decoding a new frame?
|
||||
/// </summary>
|
||||
public byte HeaderRead { get; set; }
|
||||
|
||||
// Four literal models, each representing 64 symbols
|
||||
|
||||
/// <summary>
|
||||
/// For literals from 0 to 63 (selector = 0)
|
||||
/// </summary>
|
||||
public QTMDModel Model0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For literals from 64 to 127 (selector = 1)
|
||||
/// </summary>
|
||||
public QTMDModel Model1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For literals from 128 to 191 (selector = 2)
|
||||
/// </summary>
|
||||
public QTMDModel Model2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For literals from 129 to 255 (selector = 3)
|
||||
/// </summary>
|
||||
public QTMDModel Model3 { get; set; }
|
||||
|
||||
// Three match models.
|
||||
|
||||
/// <summary>
|
||||
/// For match with fixed length of 3 bytes
|
||||
/// </summary>
|
||||
public QTMDModel Model4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For match with fixed length of 4 bytes
|
||||
/// </summary>
|
||||
public QTMDModel Model5 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For variable length match, encoded with model6len model
|
||||
/// </summary>
|
||||
public QTMDModel Model6 { get; set; }
|
||||
|
||||
public QTMDModel Model6Len { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6)
|
||||
/// </summary>
|
||||
public QTMDModel Model7 { get; set; }
|
||||
|
||||
// Symbol arrays for all models
|
||||
|
||||
public QTMDModelSym[] Model0Symbols { get; set; } = new QTMDModelSym[64 + 1];
|
||||
|
||||
public QTMDModelSym[] Model1Symbols { get; set; } = new QTMDModelSym[64 + 1];
|
||||
|
||||
public QTMDModelSym[] Model2Symbols { get; set; } = new QTMDModelSym[64 + 1];
|
||||
|
||||
public QTMDModelSym[] Model3Symbols { get; set; } = new QTMDModelSym[64 + 1];
|
||||
|
||||
public QTMDModelSym[] Model4Symbols { get; set; } = new QTMDModelSym[24 + 1];
|
||||
|
||||
public QTMDModelSym[] Model5Symbols { get; set; } = new QTMDModelSym[36 + 1];
|
||||
|
||||
public QTMDModelSym[] Model6Symbols { get; set; } = new QTMDModelSym[42 + 1];
|
||||
|
||||
public QTMDModelSym[] Model6LenSymbols { get; set; } = new QTMDModelSym[27 + 1];
|
||||
|
||||
public QTMDModelSym[] Model7Symbols { get; set; } = new QTMDModelSym[7 + 1];
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The Quantum method was created by David Stafford, adapted by Microsoft
|
||||
* Corporation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class QTMDModel
|
||||
{
|
||||
public int ShiftsLeft { get; set; }
|
||||
|
||||
public int Entries { get; set; }
|
||||
|
||||
public QTMDModelSym[] Syms { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* The Quantum method was created by David Stafford, adapted by Microsoft
|
||||
* Corporation.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.Compression
|
||||
{
|
||||
public class QTMDModelSym
|
||||
{
|
||||
public ushort Sym { get; set; }
|
||||
|
||||
public ushort CumulativeFrequency { get; set; }
|
||||
}
|
||||
}
|
||||
158
BurnOutSharp/External/libmspack/Constants.cs
vendored
158
BurnOutSharp/External/libmspack/Constants.cs
vendored
@@ -1,158 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
internal class Constants
|
||||
{
|
||||
#region CAB
|
||||
|
||||
// CAB data blocks are <= 32768 bytes in uncompressed form.Uncompressed
|
||||
// blocks have zero growth. MSZIP guarantees that it won't grow above
|
||||
// uncompressed size by more than 12 bytes.LZX guarantees it won't grow
|
||||
// more than 6144 bytes.Quantum has no documentation, but the largest
|
||||
// block seen in the wild is 337 bytes above uncompressed size.
|
||||
|
||||
public const int CAB_BLOCKMAX = 32768;
|
||||
public const int CAB_INPUTMAX = CAB_BLOCKMAX + 6144;
|
||||
|
||||
// input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block
|
||||
// plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment.
|
||||
//
|
||||
// When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be
|
||||
// up to 65535 bytes, so max input buffer size needed is 65535 + 1
|
||||
|
||||
public const int CAB_INPUTMAX_SALVAGE = 65535;
|
||||
public const int CAB_INPUTBUF = CAB_INPUTMAX_SALVAGE + 1;
|
||||
|
||||
// There are no more than 65535 data blocks per folder, so a folder cannot
|
||||
// be more than 32768*65535 bytes in length.As files cannot span more than
|
||||
// one folder, this is also their max offset, length and offset+length limit.
|
||||
|
||||
public const int CAB_FOLDERMAX = 65535;
|
||||
public const int CAB_LENGTHMAX = CAB_BLOCKMAX * CAB_FOLDERMAX;
|
||||
|
||||
#endregion
|
||||
|
||||
#region CHM
|
||||
|
||||
// Filenames of the system files used for decompression.
|
||||
// - Content and ControlData are essential.
|
||||
// - ResetTable is preferred, but SpanInfo can be used if not available
|
||||
public const string ContentName = "::DataSpace/Storage/MSCompressed/Content";
|
||||
public const string ControlName = "::DataSpace/Storage/MSCompressed/ControlData";
|
||||
public const string SpanInfoName = "::DataSpace/Storage/MSCompressed/SpanInfo";
|
||||
public const string ResetTableName = "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable";
|
||||
|
||||
#endregion
|
||||
|
||||
#region HLP
|
||||
|
||||
// None currently
|
||||
|
||||
#endregion
|
||||
|
||||
#region KWAJ
|
||||
|
||||
// Input buffer size during decompression - not worth parameterising IMHO
|
||||
public const int KWAJ_INPUT_SIZE = (2048);
|
||||
|
||||
// Huffman codes that are 9 bits or less are decoded immediately
|
||||
public const int KWAJ_TABLEBITS = (9);
|
||||
|
||||
// Number of codes in each huffman table
|
||||
|
||||
public const int KWAJ_MATCHLEN1_SYMS = (16);
|
||||
public const int KWAJ_MATCHLEN2_SYMS = (16);
|
||||
public const int KWAJ_LITLEN_SYMS = (32);
|
||||
public const int KWAJ_OFFSET_SYMS = (64);
|
||||
public const int KWAJ_LITERAL_SYMS = (256);
|
||||
|
||||
// Define decoding table sizes
|
||||
|
||||
public const int KWAJ_TABLESIZE = (1 << KWAJ_TABLEBITS);
|
||||
|
||||
//public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_MATCHLEN1_SYMS * 4);
|
||||
public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2));
|
||||
|
||||
//public const int KWAJ_MATCHLEN2_TBLSIZE = (KWAJ_MATCHLEN2_SYMS * 4);
|
||||
public const int KWAJ_MATCHLEN2_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN2_SYMS * 2));
|
||||
|
||||
//public const int KWAJ_LITLEN_TBLSIZE = (KWAJ_LITLEN_SYMS * 4);
|
||||
public const int KWAJ_LITLEN_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_LITLEN_SYMS * 2));
|
||||
|
||||
//public const int KWAJ_OFFSET_TBLSIZE = (KWAJ_OFFSET_SYMS * 4);
|
||||
public const int KWAJ_OFFSET_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_OFFSET_SYMS * 2));
|
||||
|
||||
//public const int KWAJ_LITERAL_TBLSIZE = (KWAJ_LITERAL_SYMS * 4);
|
||||
public const int KWAJ_LITERAL_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_LITERAL_SYMS * 2));
|
||||
|
||||
#endregion
|
||||
|
||||
#region LIT
|
||||
|
||||
// None currently
|
||||
|
||||
#endregion
|
||||
|
||||
#region OAB
|
||||
|
||||
// _Header
|
||||
public const int oabhead_VersionHi = 0x0000;
|
||||
public const int oabhead_VersionLo = 0x0004;
|
||||
public const int oabhead_BlockMax = 0x0008;
|
||||
public const int oabhead_TargetSize = 0x000c;
|
||||
public const int oabhead_SIZEOF = 0x0010;
|
||||
|
||||
// _Block
|
||||
public const int oabblk_Flags = 0x0000;
|
||||
public const int oabblk_CompSize = 0x0004;
|
||||
public const int oabblk_UncompSize = 0x0008;
|
||||
public const int oabblk_CRC = 0x000c;
|
||||
public const int oabblk_SIZEOF = 0x0010;
|
||||
|
||||
// _PatchHeader
|
||||
public const int patchhead_VersionHi = 0x0000;
|
||||
public const int patchhead_VersionLo = 0x0004;
|
||||
public const int patchhead_BlockMax = 0x0008;
|
||||
public const int patchhead_SourceSize = 0x000c;
|
||||
public const int patchhead_TargetSize = 0x0010;
|
||||
public const int patchhead_SourceCRC = 0x0014;
|
||||
public const int patchhead_TargetCRC = 0x0018;
|
||||
public const int patchhead_SIZEOF = 0x001c;
|
||||
|
||||
// _PatchBlock
|
||||
public const int patchblk_PatchSize = 0x0000;
|
||||
public const int patchblk_TargetSize = 0x0004;
|
||||
public const int patchblk_SourceSize = 0x0008;
|
||||
public const int patchblk_CRC = 0x000c;
|
||||
public const int patchblk_SIZEOF = 0x0010;
|
||||
|
||||
#endregion
|
||||
|
||||
#region SZDD
|
||||
|
||||
/// <summary>
|
||||
/// Input buffer size during decompression - not worth parameterising IMHO
|
||||
/// </summary>
|
||||
public const int SZDD_INPUT_SIZE = 2048;
|
||||
|
||||
public static readonly byte[] expandSignature = new byte[8]
|
||||
{
|
||||
0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33
|
||||
};
|
||||
|
||||
public static readonly byte[] qbasicSignature = new byte[8]
|
||||
{
|
||||
0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
293
BurnOutSharp/External/libmspack/Enums.cs
vendored
293
BurnOutSharp/External/libmspack/Enums.cs
vendored
@@ -1,293 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// All compressors and decompressors use the same set of error codes. Most
|
||||
/// methods return an error code directly.For methods which do not
|
||||
/// return error codes directly, the error code can be obtained with the
|
||||
/// last_error() method.
|
||||
/// </summary>
|
||||
public enum Error
|
||||
{
|
||||
#region MSPACK Errors
|
||||
|
||||
/// <summary>
|
||||
/// Used to indicate success.
|
||||
/// This error code is defined as zero, all other code are non-zero.
|
||||
/// </summary>
|
||||
MSPACK_ERR_OK = 0,
|
||||
|
||||
/// <summary>
|
||||
/// A method was called with inappropriate arguments.
|
||||
/// </summary>
|
||||
MSPACK_ERR_ARGS = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Error opening file
|
||||
/// </summary>
|
||||
MSPACK_ERR_OPEN = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Error reading file
|
||||
/// </summary>
|
||||
MSPACK_ERR_READ = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Error writing file
|
||||
/// </summary>
|
||||
MSPACK_ERR_WRITE = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Seek error
|
||||
/// </summary>
|
||||
MSPACK_ERR_SEEK = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Out of memory
|
||||
/// </summary>
|
||||
MSPACK_ERR_NOMEMORY = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Bad "magic id" in file
|
||||
/// </summary>
|
||||
MSPACK_ERR_SIGNATURE = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Bad or corrupt file format
|
||||
/// </summary>
|
||||
MSPACK_ERR_DATAFORMAT = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Bad checksum or CRC
|
||||
/// </summary>
|
||||
MSPACK_ERR_CHECKSUM = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Error during compression
|
||||
/// </summary>
|
||||
MSPACK_ERR_CRUNCH = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Error during decompression
|
||||
/// </summary>
|
||||
MSPACK_ERR_DECRUNCH = 11,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inflate Errors
|
||||
|
||||
/// <summary>
|
||||
/// Unknown block type
|
||||
/// </summary>
|
||||
INF_ERR_BLOCKTYPE = -1,
|
||||
|
||||
/// <summary>
|
||||
/// Block size complement mismatch
|
||||
/// </summary>
|
||||
INF_ERR_COMPLEMENT = -2,
|
||||
|
||||
/// <summary>
|
||||
/// Error from flush_window callback
|
||||
/// </summary>
|
||||
INF_ERR_FLUSH = -3,
|
||||
|
||||
/// <summary>
|
||||
/// Too many bits in bit buffer
|
||||
/// </summary>
|
||||
INF_ERR_BITBUF = -4,
|
||||
|
||||
/// <summary>
|
||||
/// Too many symbols in blocktype 2 header
|
||||
/// </summary>
|
||||
INF_ERR_SYMLENS = -5,
|
||||
|
||||
/// <summary>
|
||||
/// Failed to build bitlens huffman table
|
||||
/// </summary>
|
||||
INF_ERR_BITLENTBL = -6,
|
||||
|
||||
/// <summary>
|
||||
/// Failed to build literals huffman table
|
||||
/// </summary>
|
||||
INF_ERR_LITERALTBL = -7,
|
||||
|
||||
/// <summary>
|
||||
/// Failed to build distance huffman table
|
||||
/// </summary>
|
||||
INF_ERR_DISTANCETBL = -8,
|
||||
|
||||
/// <summary>
|
||||
/// Bitlen RLE code goes over table size
|
||||
/// </summary>
|
||||
INF_ERR_BITOVERRUN = -9,
|
||||
|
||||
/// <summary>
|
||||
/// Invalid bit-length code
|
||||
/// </summary>
|
||||
INF_ERR_BADBITLEN = -10,
|
||||
|
||||
/// <summary>
|
||||
/// Out-of-range literal code
|
||||
/// </summary>
|
||||
INF_ERR_LITCODE = -11,
|
||||
|
||||
/// <summary>
|
||||
/// Out-of-range distance code
|
||||
/// </summary>
|
||||
INF_ERR_DISTCODE = -12,
|
||||
|
||||
/// <summary>
|
||||
/// Somehow, distance is beyond 32k
|
||||
/// </summary>
|
||||
INF_ERR_DISTANCE = -13,
|
||||
|
||||
/// <summary>
|
||||
/// Out of bits decoding huffman symbol
|
||||
/// </summary>
|
||||
INF_ERR_HUFFSYM = -14,
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The interface to request current version of
|
||||
/// </summary>
|
||||
public enum Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the overall library version
|
||||
/// </summary>
|
||||
MSPACK_VER_LIBRARY = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mspack_system version
|
||||
/// </summary>
|
||||
MSPACK_VER_SYSTEM = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mscab_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSCABD = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mscab_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSCABC = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mschm_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSCHMD = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mschm_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSCHMC = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mslit_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSLITD = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mslit_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSLITC = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mshlp_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSHLPD = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mshlp_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSHLPC = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the msszdd_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSSZDDD = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the msszdd_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSSZDDC = 11,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mskwaj_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSKWAJD = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the mskwaj_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSKWAJC = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the msoab_decompressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSOABD = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Pass to mspack_version() to get the msoab_compressor version
|
||||
/// </summary>
|
||||
MSPACK_VER_MSOABC = 15,
|
||||
}
|
||||
|
||||
public enum OpenMode
|
||||
{
|
||||
/// <summary>
|
||||
/// mspack_system::open() mode: open existing file for reading.
|
||||
/// </summary>
|
||||
MSPACK_SYS_OPEN_READ = 0,
|
||||
|
||||
/// <summary>
|
||||
/// mspack_system::open() mode: open new file for writing
|
||||
/// </summary>
|
||||
MSPACK_SYS_OPEN_WRITE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// mspack_system::open() mode: open existing file for writing
|
||||
/// </summary>
|
||||
MSPACK_SYS_OPEN_UPDATE = 2,
|
||||
|
||||
/// <summary>
|
||||
/// mspack_system::open() mode: open existing file for writing
|
||||
/// </summary>
|
||||
MSPACK_SYS_OPEN_APPEND = 3,
|
||||
}
|
||||
|
||||
public enum SeekMode
|
||||
{
|
||||
/// <summary>
|
||||
/// mspack_system::seek() mode: seek relative to start of file
|
||||
/// </summary>
|
||||
MSPACK_SYS_SEEK_START = 0,
|
||||
|
||||
/// <summary>
|
||||
/// mspack_system::seek() mode: seek relative to current offset
|
||||
/// </summary>
|
||||
MSPACK_SYS_SEEK_CUR = 1,
|
||||
|
||||
/// <summary>
|
||||
/// mspack_system::seek() mode: seek relative to end of file
|
||||
/// </summary>
|
||||
MSPACK_SYS_SEEK_END = 2,
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.HLP
|
||||
{
|
||||
// TODO
|
||||
public class Compressor
|
||||
{
|
||||
public SystemImpl System { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.HLP
|
||||
{
|
||||
public class Decompressor : BaseDecompressor
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
119
BurnOutSharp/External/libmspack/KWAJ/Compressor.cs
vendored
119
BurnOutSharp/External/libmspack/KWAJ/Compressor.cs
vendored
@@ -1,119 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.KWAJ
|
||||
{
|
||||
/// <summary>
|
||||
/// A compressor for the KWAJ file format.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateKWAJCompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroyKWAJCompressor(Compressor)"/>
|
||||
public class Compressor
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public SystemImpl System { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!!
|
||||
/// </remarks>
|
||||
public int[] Param { get; set; } = new int[2];
|
||||
|
||||
public Error Error { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Reads an input file and creates a compressed output file in the
|
||||
/// KWAJ compressed file format.The KWAJ compression format is quick
|
||||
/// but gives poor compression.It is possible for the compressed output
|
||||
/// file to be larger than the input file.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// the name of the file to compressed. This is passed
|
||||
/// passed directly to mspack_system::open()
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// the name of the file to write compressed data to.
|
||||
/// This is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// the length of the uncompressed file, or -1 to indicate
|
||||
/// that this should be determined automatically by using
|
||||
/// mspack_system::seek() on the input file.
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <see cref="SetParam(Parameters, int)"/>
|
||||
public Error Compress(string input, string output, long length) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Sets an KWAJ compression engine parameter.
|
||||
///
|
||||
/// The following parameters are defined:
|
||||
///
|
||||
/// - #MSKWAJC_PARAM_COMP_TYPE: the compression method to use. Must
|
||||
/// be one of #MSKWAJC_COMP_NONE, #MSKWAJC_COMP_XOR, #MSKWAJ_COMP_SZDD
|
||||
/// or #MSKWAJ_COMP_LZH. The default is #MSKWAJ_COMP_LZH.
|
||||
///
|
||||
/// - #MSKWAJC_PARAM_INCLUDE_LENGTH: a boolean; should the compressed
|
||||
/// output file should include the uncompressed length of the input
|
||||
/// file in the header? This adds 4 bytes to the size of the output
|
||||
/// file. A value of zero says "no", non-zero says "yes". The default
|
||||
/// is "no".
|
||||
/// </summary>
|
||||
/// <param name="param">the parameter to set</param>
|
||||
/// <param name="value">the value to set the parameter to</param>
|
||||
/// <returns>MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
|
||||
/// is a problem with either parameter or value.
|
||||
/// </returns>
|
||||
/// <see cref="Generate"/>
|
||||
public Error SetParam(Parameters param, int value) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the original filename of the file before compression,
|
||||
/// which will be stored in the header of the output file.
|
||||
///
|
||||
/// The filename should be a null-terminated string, it must be an
|
||||
/// MS-DOS "8.3" type filename (up to 8 bytes for the filename, then
|
||||
/// optionally a "." and up to 3 bytes for a filename extension).
|
||||
///
|
||||
/// If null is passed as the filename, no filename is included in the
|
||||
/// header. This is the default.
|
||||
/// </summary>
|
||||
/// <param name="filename">The original filename to use</param>
|
||||
/// <returns>MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if the filename is too long</returns>
|
||||
public Error SetFilename(string filename) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Sets arbitrary data that will be stored in the header of the
|
||||
/// output file, uncompressed. It can be up to roughly 64 kilobytes,
|
||||
/// as the overall size of the header must not exceed 65535 bytes.
|
||||
/// The data can contain null bytes if desired.
|
||||
///
|
||||
/// If null is passed as the data pointer, or zero is passed as the
|
||||
/// length, no extra data is included in the header. This is the
|
||||
/// default.
|
||||
/// </summary>
|
||||
/// <param name="data">a pointer to the data to be stored in the header</param>
|
||||
/// <param name="bytes">the length of the data in bytes</param>
|
||||
/// <returns>MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS extra data is too long</returns>
|
||||
public Error SetExtraData(byte[] data, int pointer, int bytes) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
352
BurnOutSharp/External/libmspack/KWAJ/Decompressor.cs
vendored
352
BurnOutSharp/External/libmspack/KWAJ/Decompressor.cs
vendored
@@ -1,352 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using LibMSPackSharp.Compression;
|
||||
using static LibMSPackSharp.Constants;
|
||||
|
||||
namespace LibMSPackSharp.KWAJ
|
||||
{
|
||||
/// <summary>
|
||||
/// A decompressor for KWAJ compressed files.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateKWAJDecompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroyKWAJDecompressor(Decompressor)"/>
|
||||
public class Decompressor : BaseDecompressor
|
||||
{
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Opens a KWAJ file and reads the header.
|
||||
///
|
||||
/// If the file opened is a valid KWAJ file, all headers will be read and
|
||||
/// a mskwajd_header structure will be returned.
|
||||
///
|
||||
/// In the case of an error occuring, NULL is returned and the error code
|
||||
/// is available from last_error().
|
||||
///
|
||||
/// The filename pointer should be considered "in use" until close() is
|
||||
/// called on the KWAJ file.
|
||||
/// </summary>
|
||||
/// <param name="filename">
|
||||
/// the filename of the KWAJ compressed file. This is
|
||||
/// passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a mskwajd_header structure, or NULL on failure</returns>
|
||||
/// <see cref="Close(Header)"/>
|
||||
public Header Open(string filename)
|
||||
{
|
||||
FileStream fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ);
|
||||
if (fh == null)
|
||||
{
|
||||
Error = Error.MSPACK_ERR_OPEN;
|
||||
return null;
|
||||
}
|
||||
|
||||
Header hdr = new Header() { FileHandle = fh };
|
||||
|
||||
Error = ReadHeaders(fh, hdr);
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(fh);
|
||||
hdr = null;
|
||||
}
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes a previously opened KWAJ file.
|
||||
///
|
||||
/// This closes a KWAJ file and frees the mskwajd_header associated
|
||||
/// with it. The KWAJ header pointer is now invalid and cannot be
|
||||
/// used again.
|
||||
/// </summary>
|
||||
/// <param name="hdr">The KWAJ file to close</param>
|
||||
/// <see cref="Open(string)"/>
|
||||
public void Close(Header hdr)
|
||||
{
|
||||
if (System == null || hdr == null)
|
||||
return;
|
||||
|
||||
// Close the file handle associated
|
||||
System.Close(hdr.FileHandle);
|
||||
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the compressed data from a KWAJ file.
|
||||
///
|
||||
/// This decompresses the compressed KWAJ data stream and writes it to
|
||||
/// an output file.
|
||||
/// </summary>
|
||||
/// <param name="hdr">The KWAJ file to extract data from</param>
|
||||
/// <param name="filename">
|
||||
/// the filename to write the decompressed data to. This
|
||||
/// is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Extract(Header hdr, string filename)
|
||||
{
|
||||
FileStream fh = hdr?.FileHandle;
|
||||
if (fh == null)
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
|
||||
// Seek to the compressed data
|
||||
if (System.Seek(fh, hdr.KWAJHeader.DataOffset, SeekMode.MSPACK_SYS_SEEK_START))
|
||||
return Error = Error.MSPACK_ERR_SEEK;
|
||||
|
||||
// Open file for output
|
||||
FileStream outfh;
|
||||
if ((outfh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null)
|
||||
return Error = Error.MSPACK_ERR_OPEN;
|
||||
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
|
||||
// Decompress based on format
|
||||
if (hdr.KWAJHeader.CompressionType == CompressionType.MSKWAJ_COMP_NONE ||
|
||||
hdr.KWAJHeader.CompressionType == CompressionType.MSKWAJ_COMP_XOR)
|
||||
{
|
||||
// NONE is a straight copy. XOR is a copy xored with 0xFF
|
||||
byte[] buf = new byte[KWAJ_INPUT_SIZE];
|
||||
|
||||
int read, i;
|
||||
while ((read = System.Read(fh, buf, 0, KWAJ_INPUT_SIZE)) > 0)
|
||||
{
|
||||
if (hdr.KWAJHeader.CompressionType == CompressionType.MSKWAJ_COMP_XOR)
|
||||
{
|
||||
for (i = 0; i < read; i++)
|
||||
{
|
||||
buf[i] ^= 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (System.Write(outfh, buf, 0, read) != read)
|
||||
{
|
||||
Error = Error.MSPACK_ERR_WRITE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (read < 0)
|
||||
Error = Error.MSPACK_ERR_READ;
|
||||
}
|
||||
else if (hdr.KWAJHeader.CompressionType == CompressionType.MSKWAJ_COMP_SZDD)
|
||||
{
|
||||
Error = LZSS.Decompress(System, fh, outfh, KWAJ_INPUT_SIZE, LZSSMode.LZSS_MODE_EXPAND);
|
||||
}
|
||||
else if (hdr.KWAJHeader.CompressionType == CompressionType.MSKWAJ_COMP_LZH)
|
||||
{
|
||||
LZHKWAJ lzh = LZHKWAJ.Init(System, fh, outfh);
|
||||
Error = (lzh != null) ? lzh.Decompress() : Error.MSPACK_ERR_NOMEMORY;
|
||||
}
|
||||
else if (hdr.KWAJHeader.CompressionType == CompressionType.MSKWAJ_COMP_MSZIP)
|
||||
{
|
||||
MSZIP zip = MSZIP.Init(System, fh, outfh, KWAJ_INPUT_SIZE, false);
|
||||
Error = (zip != null) ? zip.DecompressKWAJ() : Error.MSPACK_ERR_NOMEMORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = Error.MSPACK_ERR_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Close output file
|
||||
System.Close(outfh);
|
||||
|
||||
return Error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses an KWAJ file to an output file in one step.
|
||||
///
|
||||
/// This opens an KWAJ file as input, reads the header, then decompresses
|
||||
/// the compressed data immediately to an output file, finally closing
|
||||
/// both the input and output file. It is more convenient to use than
|
||||
/// open() then extract() then close(), if you do not need to know the
|
||||
/// KWAJ output size or output filename.
|
||||
/// </summary>
|
||||
/// <param name="self">
|
||||
/// a self-referential pointer to the mskwaj_decompressor
|
||||
/// instance being called
|
||||
/// </param>
|
||||
/// <param name="input">
|
||||
/// the filename of the input KWAJ file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// the filename to write the decompressed data to. This
|
||||
/// is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Decompress(string input, string output)
|
||||
{
|
||||
Header hdr = Open(input);
|
||||
if (hdr == null)
|
||||
return Error;
|
||||
|
||||
Error error = Extract(hdr, output);
|
||||
Close(hdr);
|
||||
return Error = error;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Reads the headers of a KWAJ format file
|
||||
/// </summary>
|
||||
private Error ReadHeaders(FileStream fh, Header hdr)
|
||||
{
|
||||
// Read in the header
|
||||
byte[] buf = new byte[16];
|
||||
if (System.Read(fh, buf, 0, _KWAJHeader.Size) != _KWAJHeader.Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
// Create a new header based on that
|
||||
Error err = _KWAJHeader.Create(buf, out _KWAJHeader kwajHeader);
|
||||
if (err != Error.MSPACK_ERR_OK)
|
||||
return Error = err;
|
||||
|
||||
// Assign the header
|
||||
hdr.KWAJHeader = kwajHeader;
|
||||
|
||||
// Basic header fields
|
||||
hdr.Length = 0;
|
||||
hdr.Filename = null;
|
||||
hdr.Extra = null;
|
||||
hdr.ExtraLength = 0;
|
||||
|
||||
// Optional headers
|
||||
|
||||
// 4 bytes: length of unpacked file
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASLENGTH))
|
||||
{
|
||||
if (System.Read(fh, buf, 0, 4) != 4)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
hdr.Length = BitConverter.ToUInt32(buf, 0);
|
||||
}
|
||||
|
||||
// 2 bytes: unknown purpose
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASUNKNOWN1))
|
||||
{
|
||||
if (System.Read(fh, buf, 0, 2) != 2)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
}
|
||||
|
||||
// 2 bytes: length of section, then [length] bytes: unknown purpose
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASUNKNOWN2))
|
||||
{
|
||||
if (System.Read(fh, buf, 0, 2) != 2)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
int i = BitConverter.ToUInt16(buf, 0);
|
||||
if (System.Seek(fh, i, SeekMode.MSPACK_SYS_SEEK_CUR))
|
||||
return Error.MSPACK_ERR_SEEK;
|
||||
}
|
||||
|
||||
// Filename and extension
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILENAME) || hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILEEXT))
|
||||
{
|
||||
int len;
|
||||
|
||||
// Allocate memory for maximum length filename
|
||||
char[] fn = new char[13];
|
||||
int fnPtr = 0;
|
||||
|
||||
// Copy filename if present
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILENAME))
|
||||
{
|
||||
// Read and copy up to 9 bytes of a null terminated string
|
||||
if ((len = System.Read(fh, buf, 0, 9)) < 2)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
int i = 0;
|
||||
for (; i < len; i++)
|
||||
{
|
||||
if ((fn[fnPtr++] = (char)buf[i]) == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
// If string was 9 bytes with no null terminator, reject it
|
||||
if (i == 9 && buf[8] != '\0')
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
// Seek to byte after string ended in file
|
||||
if (System.Seek(fh, i + 1 - len, SeekMode.MSPACK_SYS_SEEK_CUR))
|
||||
return Error.MSPACK_ERR_SEEK;
|
||||
|
||||
fnPtr--; // Remove the null terminator
|
||||
}
|
||||
|
||||
// Copy extension if present
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASFILEEXT))
|
||||
{
|
||||
fn[fnPtr++] = '.';
|
||||
|
||||
// Read and copy up to 4 bytes of a null terminated string
|
||||
if ((len = System.Read(fh, buf, 0, 4)) < 2)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
int i = 0;
|
||||
for (; i < len; i++)
|
||||
{
|
||||
if ((fn[fnPtr++] = (char)buf[i]) == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
// If string was 4 bytes with no null terminator, reject it
|
||||
if (i == 4 && buf[3] != '\0')
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
// Seek to byte after string ended in file
|
||||
if (System.Seek(fh, i + 1 - len, SeekMode.MSPACK_SYS_SEEK_CUR))
|
||||
return Error.MSPACK_ERR_SEEK;
|
||||
|
||||
fnPtr--; // Remove the null terminator
|
||||
}
|
||||
|
||||
fn[fnPtr] = '\0';
|
||||
}
|
||||
|
||||
// 2 bytes: extra text length then [length] bytes of extra text data
|
||||
if (hdr.KWAJHeader.Flags.HasFlag(OptionalHeaderFlag.MSKWAJ_HDR_HASEXTRATEXT))
|
||||
{
|
||||
if (System.Read(fh, buf, 0, 2) != 2)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
int i = BitConverter.ToUInt16(buf, 0);
|
||||
byte[] extra = new byte[i + 1];
|
||||
if (System.Read(fh, extra, 0, i) != i)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
extra[i] = 0x00;
|
||||
hdr.Extra = Encoding.ASCII.GetString(extra, 0, extra.Length);
|
||||
hdr.ExtraLength = (ushort)i;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
88
BurnOutSharp/External/libmspack/KWAJ/Enums.cs
vendored
88
BurnOutSharp/External/libmspack/KWAJ/Enums.cs
vendored
@@ -1,88 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.KWAJ
|
||||
{
|
||||
public enum CompressionType
|
||||
{
|
||||
/// <summary>
|
||||
/// no compression.
|
||||
/// </summary>
|
||||
MSKWAJ_COMP_NONE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// no compression, 0xFF XOR "encryption".
|
||||
/// </summary>
|
||||
MSKWAJ_COMP_XOR = 1,
|
||||
|
||||
/// <summary>
|
||||
/// LZSS (same method as SZDD)
|
||||
/// </summary>
|
||||
MSKWAJ_COMP_SZDD = 2,
|
||||
|
||||
/// <summary>
|
||||
/// LZ+Huffman compression
|
||||
/// </summary>
|
||||
MSKWAJ_COMP_LZH = 3,
|
||||
|
||||
/// <summary>
|
||||
/// MSZIP
|
||||
/// </summary>
|
||||
MSKWAJ_COMP_MSZIP = 4,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum OptionalHeaderFlag : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// decompressed file length is included
|
||||
/// </summary>
|
||||
MSKWAJ_HDR_HASLENGTH = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// unknown 2-byte structure is included
|
||||
/// </summary>
|
||||
MSKWAJ_HDR_HASUNKNOWN1 = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// unknown multi-sized structure is included
|
||||
/// </summary>
|
||||
MSKWAJ_HDR_HASUNKNOWN2 = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// file name (no extension) is included
|
||||
/// </summary>
|
||||
MSKWAJ_HDR_HASFILENAME = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// file extension is included
|
||||
/// </summary>
|
||||
MSKWAJ_HDR_HASFILEEXT = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// extra text is included
|
||||
/// </summary>
|
||||
MSKWAJ_HDR_HASEXTRATEXT = 0x20,
|
||||
}
|
||||
|
||||
public enum Parameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Compression type
|
||||
/// </summary>
|
||||
MSKWAJC_PARAM_COMP_TYPE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Include the length of the uncompressed file in the header?
|
||||
/// </summary>
|
||||
MSKWAJC_PARAM_INCLUDE_LENGTH = 1,
|
||||
}
|
||||
}
|
||||
68
BurnOutSharp/External/libmspack/KWAJ/Header.cs
vendored
68
BurnOutSharp/External/libmspack/KWAJ/Header.cs
vendored
@@ -1,68 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace LibMSPackSharp.KWAJ
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents an KWAJ compressed file.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class Header : BaseHeader
|
||||
{
|
||||
#region Internal
|
||||
|
||||
/// <summary>
|
||||
/// KWAJ header information
|
||||
/// </summary>
|
||||
internal _KWAJHeader KWAJHeader { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Flags indicating which optional headers were included.
|
||||
/// </summary>
|
||||
public OptionalHeaderFlag Headers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of uncompressed data in the file, or 0 if not present.
|
||||
/// </summary>
|
||||
public long Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output filename, or NULL if not present
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extra uncompressed data (usually text) in the header.
|
||||
/// This data can contain nulls so use extra_length to get the size.
|
||||
/// </summary>
|
||||
public string Extra { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of extra uncompressed data in the header
|
||||
/// </summary>
|
||||
public ushort ExtraLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Internal file handle
|
||||
/// </summary>
|
||||
public FileStream FileHandle { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.KWAJ
|
||||
{
|
||||
internal class _KWAJHeader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// "KWAA"
|
||||
/// </summary>
|
||||
/// <remarks>0x00</remarks>
|
||||
public uint Signature1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Signature extension
|
||||
/// </summary>
|
||||
/// <remarks>0x04</remarks>
|
||||
public uint Signature2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The compression type
|
||||
/// </summary>
|
||||
/// <remarks>0x08</remarks>
|
||||
public CompressionType CompressionType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The offset in the file where the compressed data stream begins
|
||||
/// </summary>
|
||||
/// <remarks>0x0a</remarks>
|
||||
public ushort DataOffset { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public OptionalHeaderFlag Flags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the KWAJ header in bytes
|
||||
/// </summary>
|
||||
public const int Size = 0x0e;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private _KWAJHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a _KWAJHeader from a byte array, if possible
|
||||
/// </summary>
|
||||
public static Error Create(byte[] buffer, out _KWAJHeader header)
|
||||
{
|
||||
header = null;
|
||||
if (buffer == null || buffer.Length < Size)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
header = new _KWAJHeader();
|
||||
|
||||
header.Signature1 = BitConverter.ToUInt32(buffer, 0x00);
|
||||
if (header.Signature1 != 0x4A41574B)
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
header.Signature2 = BitConverter.ToUInt32(buffer, 0x04);
|
||||
if (header.Signature1 != 0xD127F088)
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
|
||||
header.CompressionType = (CompressionType)BitConverter.ToUInt16(buffer, 0x08);
|
||||
header.DataOffset = BitConverter.ToUInt16(buffer, 0x0a);
|
||||
header.Flags = (OptionalHeaderFlag)BitConverter.ToUInt16(buffer, 0x0c);
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.LIT
|
||||
{
|
||||
// TODO
|
||||
public class Compressor
|
||||
{
|
||||
public SystemImpl System { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.LIT
|
||||
{
|
||||
public class Decompressor : BaseDecompressor
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
499
BurnOutSharp/External/libmspack/Library.cs
vendored
499
BurnOutSharp/External/libmspack/Library.cs
vendored
@@ -1,499 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/** \mainpage
|
||||
*
|
||||
* \section intro Introduction
|
||||
*
|
||||
* libmspack is a library which provides compressors and decompressors,
|
||||
* archivers and dearchivers for Microsoft compression formats.
|
||||
*
|
||||
* \section formats Formats supported
|
||||
*
|
||||
* The following file formats are supported:
|
||||
* - SZDD files, which use LZSS compression
|
||||
* - KWAJ files, which use LZSS, LZSS+Huffman or deflate compression
|
||||
* - .HLP (MS Help) files, which use LZSS compression
|
||||
* - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression
|
||||
* - .CHM (HTML Help) files, which use LZX compression
|
||||
* - .LIT (MS EBook) files, which use LZX compression and DES encryption
|
||||
* - .LZX (Exchange Offline Addressbook) files, which use LZX compression
|
||||
*
|
||||
* To determine the capabilities of the library, and the binary
|
||||
* compatibility version of any particular compressor or decompressor, use
|
||||
* the mspack_version() function. The UNIX library interface version is
|
||||
* defined as the highest-versioned library component.
|
||||
*
|
||||
* \section starting Getting started
|
||||
*
|
||||
* The macro MSPACK_SYS_SELFTEST() should be used to ensure the library can
|
||||
* be used. In particular, it checks if the caller is using 32-bit file I/O
|
||||
* when the library is compiled for 64-bit file I/O and vice versa.
|
||||
*
|
||||
* If compiled normally, the library includes basic file I/O and memory
|
||||
* management functionality using the standard C library. This can be
|
||||
* customised and replaced entirely by creating a SystemImpl structure.
|
||||
*
|
||||
* A compressor or decompressor for the required format must be
|
||||
* instantiated before it can be used. Each construction function takes
|
||||
* one parameter, which is either a pointer to a custom SystemImpl
|
||||
* structure, or null to use the default. The instantiation returned, if
|
||||
* not null, contains function pointers (methods) to work with the given
|
||||
* file format.
|
||||
*
|
||||
* For compression:
|
||||
* - CreateCABCompressor() creates a mscab_compressor
|
||||
* - CreateCHMCompressor() creates a mschm_compressor
|
||||
* - CreateLITCompressor() creates a mslit_compressor
|
||||
* - CreateHLPCompressor() creates a mshlp_compressor
|
||||
* - CreateSZDDCompressor() creates a msszdd_compressor
|
||||
* - CreateKWAJCompressor() creates a mskwaj_compressor
|
||||
* - CreateOABCompressor() creates a msoab_compressor
|
||||
*
|
||||
* For decompression:
|
||||
* - mspack_create_cab_decompressor() creates a mscab_decompressor
|
||||
* - mspack_create_chm_decompressor() creates a mschm_decompressor
|
||||
* - mspack_create_lit_decompressor() creates a mslit_decompressor
|
||||
* - mspack_create_hlp_decompressor() creates a mshlp_decompressor
|
||||
* - mspack_create_szdd_decompressor() creates a msszdd_decompressor
|
||||
* - mspack_create_kwaj_decompressor() creates a mskwaj_decompressor
|
||||
* - mspack_create_oab_decompressor() creates a msoab_decompressor
|
||||
*
|
||||
* Once finished working with a format, each kind of
|
||||
* compressor/decompressor has its own specific destructor:
|
||||
* - mspack_destroy_cab_compressor()
|
||||
* - mspack_destroy_cab_decompressor()
|
||||
* - mspack_destroy_chm_compressor()
|
||||
* - mspack_destroy_chm_decompressor()
|
||||
* - mspack_destroy_lit_compressor()
|
||||
* - mspack_destroy_lit_decompressor()
|
||||
* - mspack_destroy_hlp_compressor()
|
||||
* - mspack_destroy_hlp_decompressor()
|
||||
* - mspack_destroy_szdd_compressor()
|
||||
* - mspack_destroy_szdd_decompressor()
|
||||
* - mspack_destroy_kwaj_compressor()
|
||||
* - mspack_destroy_kwaj_decompressor()
|
||||
* - mspack_destroy_oab_compressor()
|
||||
* - mspack_destroy_oab_decompressor()
|
||||
*
|
||||
* Destroying a compressor or decompressor does not destroy any objects,
|
||||
* structures or handles that have been created using that compressor or
|
||||
* decompressor. Ensure that everything created or opened is destroyed or
|
||||
* closed before compressor/decompressor is itself destroyed.
|
||||
*
|
||||
* \section threading Multi-threading
|
||||
*
|
||||
* libmspack methods are reentrant and multithreading-safe when each
|
||||
* thread has its own compressor or decompressor.
|
||||
* You should not call multiple methods simultaneously on a single
|
||||
* compressor or decompressor instance.
|
||||
*
|
||||
* If this may happen, you can either use one compressor or
|
||||
* decompressor per thread, or you can use your preferred lock,
|
||||
* semaphore or mutex library to ensure no more than one method on a
|
||||
* compressor/decompressor is called simultaneously. libmspack will
|
||||
* not do this locking for you.
|
||||
*
|
||||
* Example of incorrect behaviour:
|
||||
* - thread 1 calls mspack_create_cab_decompressor()
|
||||
* - thread 1 calls open()
|
||||
* - thread 1 calls extract() for one file
|
||||
* - thread 2 simultaneously calls extract() for another file
|
||||
*
|
||||
* Correct behaviour:
|
||||
* - thread 1 calls mspack_create_cab_decompressor()
|
||||
* - thread 2 calls mspack_create_cab_decompressor()
|
||||
* - thread 1 calls its own open() / extract()
|
||||
* - thread 2 simultaneously calls its own open() / extract()
|
||||
*
|
||||
* Also correct behaviour:
|
||||
* - thread 1 calls mspack_create_cab_decompressor()
|
||||
* - thread 1 locks a mutex for with the decompressor before
|
||||
* calling any methods on it, and unlocks the mutex after each
|
||||
* method returns.
|
||||
* - thread 1 can share the results of open() with thread 2, and both
|
||||
* can call extract(), provided they both guard against simultaneous
|
||||
* use of extract(), and any other methods, with the mutex
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
public static class Library
|
||||
{
|
||||
#region CAB
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="CAB.Compressor"/> or null</returns>
|
||||
public static CAB.Compressor CreateCABCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CAB decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="CAB.Decompressor"/> or null</returns>
|
||||
public static CAB.Decompressor CreateCABDecompressor(SystemImpl sys)
|
||||
{
|
||||
if (sys == null)
|
||||
sys = SystemImpl.DefaultSystem;
|
||||
if (!SystemImpl.ValidSystem(sys))
|
||||
return null;
|
||||
|
||||
return new CAB.Decompressor()
|
||||
{
|
||||
System = sys,
|
||||
State = null,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
|
||||
SearchBufferSize = 32768,
|
||||
FixMSZip = false,
|
||||
BufferSize = 4096,
|
||||
Salvage = false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing CAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="self">the <see cref="CAB.Compressor"/> to destroy</param>
|
||||
public static void DestroyCABCompressor(CAB.Compressor self)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing CAB decompressor.
|
||||
/// </summary>
|
||||
/// <param name="self">the <see cref="CAB.Decompressor"/> to destroy</param>
|
||||
public static void DestroyCABDecompressor(CAB.Decompressor self)
|
||||
{
|
||||
if (self != null)
|
||||
{
|
||||
SystemImpl sys = self.System;
|
||||
if (self.State != null)
|
||||
{
|
||||
sys.Close(self.State.InputFileHandle);
|
||||
sys.Close(self.State.OutputFileHandle);
|
||||
self.FreeDecompressionState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CHM
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CHM compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="CHM.Compressor"/> or null</returns>
|
||||
public static CHM.Compressor CreateCHMCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CHM decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="CHM.Decompressor"/> or null</returns>
|
||||
public static CHM.Decompressor CreateCHMDecompressor(SystemImpl sys)
|
||||
{
|
||||
if (sys == null)
|
||||
sys = SystemImpl.DefaultSystem;
|
||||
if (!SystemImpl.ValidSystem(sys))
|
||||
return null;
|
||||
|
||||
return new CHM.Decompressor()
|
||||
{
|
||||
System = sys,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
State = null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing CHM compressor.
|
||||
/// </summary>
|
||||
/// <param name="self">the <see cref="CHM.Compressor"/> to destroy</param>
|
||||
public static void DestroyCHMCompressor(CHM.Compressor self)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing CHM decompressor.
|
||||
/// </summary>
|
||||
/// <param name="self">the <see cref="CHM.Decompressor"/> to destroy</param>
|
||||
public static void DestroyCHMDecompressor(CHM.Decompressor self)
|
||||
{
|
||||
if (self != null)
|
||||
{
|
||||
SystemImpl sys = self.System;
|
||||
if (self.State != null)
|
||||
{
|
||||
sys.Close(self.State.InputFileHandle);
|
||||
sys.Close(self.State.OutputFileHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LIT
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new LIT compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="LIT.Compressor"/> or null</returns>
|
||||
public static LIT.Compressor CreateLITCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new LIT decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="LIT.Decompressor"/> or null</returns>
|
||||
public static LIT.Decompressor CreateLITDecompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing LIT compressor.
|
||||
/// </summary>
|
||||
/// <param name="c">the <see cref="LIT.Compressor"/> to destroy</param>
|
||||
public static void DestroyLITCompressor(LIT.Compressor c)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing LIT decompressor.
|
||||
/// </summary>
|
||||
/// <param name="d">the <see cref="LIT.Decompressor"/> to destroy</param>
|
||||
public static void DestroyLITDecompressor(LIT.Decompressor d)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HLP
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new HLP compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="HLP.Compressor"/> or null</returns>
|
||||
public static HLP.Compressor CreateHLPCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new HLP decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="HLP.Decompressor"/> or null</returns>
|
||||
public static HLP.Decompressor CreateHLPDecompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing HLP compressor.
|
||||
/// </summary>
|
||||
/// <param name="c">the <see cref="HLP.Compressor"/> to destroy</param>
|
||||
public static void DestroyHLPCompressor(HLP.Compressor c)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing HLP decompressor.
|
||||
/// </summary>
|
||||
/// <param name="d">the <see cref="HLP.Decompressor"/> to destroy</param>
|
||||
public static void DestroyHLPDecompressor(HLP.Decompressor d)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SZDD
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new SZDD compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="SZDD.Compressor"/> or null</returns>
|
||||
public static SZDD.Compressor CreateSZDDCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new SZDD decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="SZDD.Decompressor"/> or null</returns>
|
||||
public static SZDD.Decompressor CreateSZDDDecompressor(SystemImpl sys)
|
||||
{
|
||||
if (sys == null)
|
||||
sys = SystemImpl.DefaultSystem;
|
||||
if (!SystemImpl.ValidSystem(sys))
|
||||
return null;
|
||||
|
||||
return new SZDD.Decompressor()
|
||||
{
|
||||
System = sys,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing SZDD compressor.
|
||||
/// </summary>
|
||||
/// <param name="c">the <see cref="SZDD.Compressor"/> to destroy</param>
|
||||
public static void DestroySZDDCompressor(SZDD.Compressor c)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing SZDD decompressor.
|
||||
/// </summary>
|
||||
/// <param name="d">the <see cref="SZDD.Decompressor"/> to destroy</param>
|
||||
public static void DestroySZDDDecompressor(SZDD.Decompressor d) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region KWAJ
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new KWAJ compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="KWAJ.Compressor"/> or null</returns>
|
||||
public static KWAJ.Compressor CreateKWAJCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new KWAJ decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="KWAJ.Decompressor"/> or null</returns>
|
||||
public static KWAJ.Decompressor CreateKWAJDecompressor(SystemImpl sys)
|
||||
{
|
||||
if (sys == null)
|
||||
sys = SystemImpl.DefaultSystem;
|
||||
if (!SystemImpl.ValidSystem(sys))
|
||||
return null;
|
||||
|
||||
return new KWAJ.Decompressor()
|
||||
{
|
||||
System = sys,
|
||||
Error = Error.MSPACK_ERR_OK,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing KWAJ compressor.
|
||||
/// </summary>
|
||||
/// <param name="c">the <see cref="KWAJ.Compressor"/> to destroy</param>
|
||||
public static void DestroyKWAJCompressor(KWAJ.Compressor c)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing KWAJ decompressor.
|
||||
/// </summary>
|
||||
/// <param name="d">the <see cref="KWAJ.Decompressor"/> to destroy</param>
|
||||
public static void DestroyKWAJDecompressor(KWAJ.Decompressor d) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region OAB
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new OAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="OAB.Compressor"/> or null</returns>
|
||||
public static OAB.Compressor CreateOABCompressor(SystemImpl sys)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new OAB decompressor.
|
||||
/// </summary>
|
||||
/// <param name="sys">a custom SystemImpl structure, or null to use the default</param>
|
||||
/// <returns>a <see cref="OAB.Decompressor"/> or null</returns>
|
||||
public static OAB.Decompressor CreateOABDecompressor(SystemImpl sys)
|
||||
{
|
||||
if (sys == null)
|
||||
sys = SystemImpl.DefaultSystem;
|
||||
if (!SystemImpl.ValidSystem(sys))
|
||||
return null;
|
||||
|
||||
return new OAB.Decompressor()
|
||||
{
|
||||
System = sys,
|
||||
BufferSize = 4096,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing OAB compressor.
|
||||
/// </summary>
|
||||
/// <param name="c">the <see cref="OAB.Compressor"/> to destroy</param>
|
||||
public static void DestroyOABCompressor(OAB.Compressor c)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys an existing OAB decompressor.
|
||||
/// </summary>
|
||||
/// <param name="d">the <see cref="OAB.Decompressor"/> to destroy</param>
|
||||
public static void DestroyOABDecompressor(OAB.Decompressor d) { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.OAB
|
||||
{
|
||||
/// <summary>
|
||||
/// A compressor for the Offline Address Book (OAB) format.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateOABCompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroyOABCompressor(Compressor)"/>
|
||||
public class Compressor
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public SystemImpl System { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Compress a full OAB file.
|
||||
///
|
||||
/// The input file will be read and the compressed contents written to the
|
||||
/// output file.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// The filename of the input file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// The filename of the output file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Compress(string input, string output) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Generate a compressed incremental OAB patch file.
|
||||
///
|
||||
/// The two uncompressed files "input" and "base" will be read, and an
|
||||
/// incremental patch to generate "input" from "base" will be written to
|
||||
/// the output file.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// The filename of the input file containing the new
|
||||
/// version of its contents. This is passed directly
|
||||
/// to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="baseFile">
|
||||
/// The filename of the original base file containing
|
||||
/// the old version of its contents, against which the
|
||||
/// incremental patch shall generated. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// The filename of the output file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error CompressIncremental(string input, string baseFile, string output) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
502
BurnOutSharp/External/libmspack/OAB/Decompressor.cs
vendored
502
BurnOutSharp/External/libmspack/OAB/Decompressor.cs
vendored
@@ -1,502 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using LibMSPackSharp.Compression;
|
||||
using static LibMSPackSharp.Constants;
|
||||
|
||||
namespace LibMSPackSharp.OAB
|
||||
{
|
||||
/// <summary>
|
||||
/// A decompressor for .LZX (Offline Address Book) files
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateOABDecompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroyOABDecompressor(Decompressor)"/>
|
||||
public class Decompressor : BaseDecompressor
|
||||
{
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses a full Offline Address Book file.
|
||||
///
|
||||
/// If the input file is a valid compressed Offline Address Book file,
|
||||
/// it will be read and the decompressed contents will be written to
|
||||
/// the output file.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// The filename of the input file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// The filename of the output file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Decompress(string input, string output)
|
||||
{
|
||||
byte[] hdrbuf = new byte[oabhead_SIZEOF];
|
||||
LZX lzx = null;
|
||||
Error ret = Error.MSPACK_ERR_OK;
|
||||
|
||||
FileStream infh = System.Open(input, OpenMode.MSPACK_SYS_OPEN_READ);
|
||||
if (infh == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_OPEN;
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (System.Read(infh, hdrbuf, 0, oabhead_SIZEOF) != oabhead_SIZEOF)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_READ;
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (BitConverter.ToUInt32(hdrbuf, oabhead_VersionHi) != 3 ||
|
||||
BitConverter.ToUInt32(hdrbuf, oabhead_VersionLo) != 1)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_SIGNATURE;
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint block_max = BitConverter.ToUInt32(hdrbuf, oabhead_BlockMax);
|
||||
uint target_size = BitConverter.ToUInt32(hdrbuf, oabhead_TargetSize);
|
||||
|
||||
FileStream outfh = System.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE);
|
||||
if (outfh == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_OPEN;
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
byte[] buf = new byte[BufferSize];
|
||||
|
||||
SystemImpl oabd_sys = System;
|
||||
oabd_sys.Read = SysRead;
|
||||
oabd_sys.Write = SysWrite;
|
||||
|
||||
InternalFile in_ofh = new InternalFile();
|
||||
in_ofh.OrigSys = System;
|
||||
in_ofh.OrigFile = infh;
|
||||
|
||||
InternalFile out_ofh = new InternalFile();
|
||||
out_ofh.OrigSys = System;
|
||||
out_ofh.OrigFile = outfh;
|
||||
|
||||
while (target_size > 0)
|
||||
{
|
||||
if (System.Read(infh, buf, 0, oabblk_SIZEOF) != oabblk_SIZEOF)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_READ;
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint blk_flags = BitConverter.ToUInt32(buf, oabblk_Flags);
|
||||
uint blk_csize = BitConverter.ToUInt32(buf, oabblk_CompSize);
|
||||
uint blk_dsize = BitConverter.ToUInt32(buf, oabblk_UncompSize);
|
||||
uint blk_crc = BitConverter.ToUInt32(buf, oabblk_CRC);
|
||||
|
||||
if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_DATAFORMAT;
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (blk_flags == 0)
|
||||
{
|
||||
// Uncompressed block
|
||||
if (blk_dsize != blk_csize)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_DATAFORMAT;
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = CopyFileHandle(infh, outfh, (int)blk_dsize, buf, BufferSize);
|
||||
if (ret != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// LZX compressed block
|
||||
int window_bits = 17;
|
||||
|
||||
while (window_bits < 25 && (1U << window_bits) < blk_dsize)
|
||||
{
|
||||
window_bits++;
|
||||
}
|
||||
|
||||
in_ofh.Available = (int)blk_csize;
|
||||
out_ofh.CRC = 0xffffffff;
|
||||
|
||||
lzx = LZX.Init(oabd_sys, in_ofh.OrigFile, out_ofh.OrigFile, window_bits, 0, BufferSize, blk_dsize, true);
|
||||
if (lzx == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_NOMEMORY;
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = lzx.Decompress(blk_dsize);
|
||||
if (ret != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lzx = null;
|
||||
|
||||
// Consume any trailing padding bytes before the next block
|
||||
ret = CopyFileHandle(infh, null, in_ofh.Available, buf, BufferSize);
|
||||
if (ret != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (out_ofh.CRC != blk_crc)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_CHECKSUM;
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
target_size -= blk_dsize;
|
||||
}
|
||||
|
||||
System.Close(outfh);
|
||||
System.Close(infh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses an Offline Address Book with an incremental patch file.
|
||||
///
|
||||
/// This requires both a full UNCOMPRESSED Offline Address Book file to
|
||||
/// act as the "base", and a compressed incremental patch file as input.
|
||||
/// If the input file is valid, it will be decompressed with reference to
|
||||
/// the base file, and the decompressed contents will be written to the
|
||||
/// output file.
|
||||
///
|
||||
/// There is no way to tell what the right base file is for the given
|
||||
/// incremental patch, but if you get it wrong, this will usually result
|
||||
/// in incorrect data being decompressed, which will then fail a checksum
|
||||
/// test.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// The filename of the input file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="basePath">
|
||||
/// The filename of the base file to which the
|
||||
/// incremental patch shall be applied. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// The filename of the output file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error DecompressIncremental(string input, string basePath, string output)
|
||||
{
|
||||
byte[] hdrbuf = new byte[patchhead_SIZEOF];
|
||||
LZX lzx = null;
|
||||
int window_bits;
|
||||
uint window_size;
|
||||
Error ret = Error.MSPACK_ERR_OK;
|
||||
|
||||
FileStream infh = System.Open(input, OpenMode.MSPACK_SYS_OPEN_READ);
|
||||
if (infh == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_OPEN;
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (System.Read(infh, hdrbuf, 0, patchhead_SIZEOF) != patchhead_SIZEOF)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_READ;
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (BitConverter.ToUInt32(hdrbuf, patchhead_VersionHi) != 3 ||
|
||||
BitConverter.ToUInt32(hdrbuf, patchhead_VersionLo) != 2)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_SIGNATURE;
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint block_max = BitConverter.ToUInt32(hdrbuf, patchhead_BlockMax);
|
||||
uint target_size = BitConverter.ToUInt32(hdrbuf, patchhead_TargetSize);
|
||||
|
||||
// We use it for reading block headers too
|
||||
if (block_max < patchblk_SIZEOF)
|
||||
block_max = patchblk_SIZEOF;
|
||||
|
||||
FileStream basefh = System.Open(basePath, OpenMode.MSPACK_SYS_OPEN_READ);
|
||||
if (basefh == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_OPEN;
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
FileStream outfh = System.Open(output, OpenMode.MSPACK_SYS_OPEN_WRITE);
|
||||
if (outfh == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_OPEN;
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
byte[] buf = new byte[BufferSize];
|
||||
|
||||
SystemImpl oabd_sys = System;
|
||||
oabd_sys.Read = SysRead;
|
||||
oabd_sys.Write = SysWrite;
|
||||
|
||||
InternalFile in_ofh = new InternalFile();
|
||||
in_ofh.OrigSys = System;
|
||||
in_ofh.OrigFile = infh;
|
||||
|
||||
InternalFile out_ofh = new InternalFile();
|
||||
out_ofh.OrigSys = System;
|
||||
out_ofh.OrigFile = outfh;
|
||||
|
||||
while (target_size > 0)
|
||||
{
|
||||
if (System.Read(infh, buf, 0, patchblk_SIZEOF) != patchblk_SIZEOF)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_READ;
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint blk_csize = BitConverter.ToUInt32(buf, patchblk_PatchSize);
|
||||
uint blk_dsize = BitConverter.ToUInt32(buf, patchblk_TargetSize);
|
||||
uint blk_ssize = BitConverter.ToUInt32(buf, patchblk_SourceSize);
|
||||
uint blk_crc = BitConverter.ToUInt32(buf, patchblk_CRC);
|
||||
|
||||
if (blk_dsize > block_max || blk_dsize > target_size || blk_ssize > block_max)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_DATAFORMAT;
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
window_size = (uint)((blk_ssize + 32767) & ~32767);
|
||||
window_size += blk_dsize;
|
||||
window_bits = 17;
|
||||
|
||||
while (window_bits < 25 && (1U << window_bits) < window_size)
|
||||
window_bits++;
|
||||
|
||||
in_ofh.Available = (int)blk_csize;
|
||||
out_ofh.CRC = 0xffffffff;
|
||||
|
||||
lzx = LZX.Init(oabd_sys, in_ofh.OrigFile, out_ofh.OrigFile, window_bits, 0, 4096, blk_dsize, true);
|
||||
if (lzx == null)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_NOMEMORY;
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = lzx.SetReferenceData(System, basefh, blk_ssize);
|
||||
if (ret != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = lzx.Decompress(blk_dsize);
|
||||
if (ret != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lzx = null;
|
||||
|
||||
// Consume any trailing padding bytes before the next block
|
||||
ret = CopyFileHandle(infh, null, in_ofh.Available, buf, BufferSize);
|
||||
if (ret != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (out_ofh.CRC != blk_crc)
|
||||
{
|
||||
ret = Error.MSPACK_ERR_CHECKSUM;
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
target_size -= blk_dsize;
|
||||
}
|
||||
|
||||
System.Close(outfh);
|
||||
System.Close(basefh);
|
||||
System.Close(infh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an OAB decompression engine parameter. Available only in OAB
|
||||
/// decompressor version 2 and above.
|
||||
///
|
||||
/// - #MSOABD_PARAM_DECOMPBUF: How many bytes should be used as an input
|
||||
/// buffer by decompressors? The minimum value is 16. The default value
|
||||
/// is 4096.
|
||||
/// </summary>
|
||||
/// <param name="param">The parameter to set</param>
|
||||
/// <param name="value">The value to set the parameter to</param>
|
||||
/// <returns>
|
||||
/// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
|
||||
/// is a problem with either parameter or value.
|
||||
/// </returns>
|
||||
public Error SetParam(Parameters param, int value)
|
||||
{
|
||||
if (param == Parameters.MSOABD_PARAM_DECOMPBUF && value >= 16)
|
||||
{
|
||||
// Must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF)
|
||||
BufferSize = value;
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region I/O Methods
|
||||
|
||||
private static int SysRead(object baseFile, byte[] buf, int pointer, int size)
|
||||
{
|
||||
InternalFile file = baseFile as InternalFile;
|
||||
if (file == null)
|
||||
return 0;
|
||||
|
||||
int bytes_read;
|
||||
|
||||
if (size > file.Available)
|
||||
size = file.Available;
|
||||
|
||||
bytes_read = file.OrigSys.Read(file.OrigFile, buf, pointer, size);
|
||||
if (bytes_read < 0)
|
||||
return bytes_read;
|
||||
|
||||
file.Available -= bytes_read;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
private static int SysWrite(object baseFile, byte[] buf, int pointer, int size)
|
||||
{
|
||||
// Null output file means skip those bytes
|
||||
if (baseFile == null)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
else if (baseFile is InternalFile file)
|
||||
{
|
||||
int bytes_written = file.OrigSys.Write(file.OrigFile, buf, pointer, size);
|
||||
if (bytes_written > 0)
|
||||
file.CRC = Checksum.CRC32(buf, 0, bytes_written, file.CRC);
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
else if (baseFile is FileStream impl)
|
||||
{
|
||||
return SystemImpl.DefaultSystem.Write(impl, buf, pointer, size);
|
||||
}
|
||||
|
||||
// Unknown file to write to
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Copy between the input and output, if possible
|
||||
/// </summary>
|
||||
private Error CopyFileHandle(FileStream input, FileStream output, int bytesToCopy, byte[] buf, int bufferSize)
|
||||
{
|
||||
while (bytesToCopy > 0)
|
||||
{
|
||||
int run = bufferSize;
|
||||
if (run > bytesToCopy)
|
||||
run = bytesToCopy;
|
||||
|
||||
if (System.Read(input, buf, 0, run) != run)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
if (output != null && System.Write(output, buf, 0, run) != run)
|
||||
return Error.MSPACK_ERR_WRITE;
|
||||
|
||||
bytesToCopy -= run;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
19
BurnOutSharp/External/libmspack/OAB/Enums.cs
vendored
19
BurnOutSharp/External/libmspack/OAB/Enums.cs
vendored
@@ -1,19 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.OAB
|
||||
{
|
||||
public enum Parameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of decompression buffer
|
||||
/// </summary>
|
||||
MSOABD_PARAM_DECOMPBUF = 0,
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace LibMSPackSharp.OAB
|
||||
{
|
||||
public class InternalFile
|
||||
{
|
||||
public SystemImpl OrigSys { get; set; }
|
||||
|
||||
public FileStream OrigFile { get; set; }
|
||||
|
||||
public uint CRC { get; set; }
|
||||
|
||||
public int Available { get; set; }
|
||||
}
|
||||
}
|
||||
118
BurnOutSharp/External/libmspack/SZDD/Compressor.cs
vendored
118
BurnOutSharp/External/libmspack/SZDD/Compressor.cs
vendored
@@ -1,118 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibMSPackSharp.SZDD
|
||||
{
|
||||
/// <summary>
|
||||
/// A compressor for the SZDD file format.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateSZDDCompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroySZDDCompressor(Compressor)"/>
|
||||
public class Compressor
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public SystemImpl System { get; set; }
|
||||
|
||||
public Error Error { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Reads an input file and creates a compressed output file in the
|
||||
/// SZDD compressed file format. The SZDD compression format is quick
|
||||
/// but gives poor compression. It is possible for the compressed output
|
||||
/// file to be larger than the input file.
|
||||
///
|
||||
/// Conventionally, SZDD compressed files have the final character in
|
||||
/// their filename replaced with an underscore, to show they are
|
||||
/// compressed. The missing character is stored in the compressed file
|
||||
/// itself. This is due to the restricted filename conventions of MS-DOS,
|
||||
/// most operating systems, such as UNIX, simply append another file
|
||||
/// extension to the existing filename. As mspack does not deal with
|
||||
/// filenames, this is left up to you. If you wish to set the missing
|
||||
/// character stored in the file header, use set_param() with the
|
||||
/// #MSSZDDC_PARAM_MISSINGCHAR parameter.
|
||||
///
|
||||
/// "Stream" compression (where the length of the input data is not
|
||||
/// known) is not possible. The length of the input data is stored in the
|
||||
/// header of the SZDD file and must therefore be known before any data
|
||||
/// is compressed. Due to technical limitations of the file format, the
|
||||
/// maximum size of uncompressed file that will be accepted is 2147483647
|
||||
/// bytes.
|
||||
/// </summary>
|
||||
/// <param name="self">
|
||||
/// a self-referential pointer to the msszdd_compressor
|
||||
/// instance being called
|
||||
/// </param>
|
||||
/// <param name="input">
|
||||
/// the name of the file to compressed. This is passed
|
||||
/// passed directly to mspack_system::open()
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// the name of the file to write compressed data to.
|
||||
/// This is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// the length of the uncompressed file, or -1 to indicate
|
||||
/// that this should be determined automatically by using
|
||||
/// mspack_system::seek() on the input file.
|
||||
/// </param>
|
||||
/// <returns>an error code, or MSPACK_ERR_OK if successful</returns>
|
||||
/// <see cref="SetParam"/>
|
||||
public Func<Compressor, string, string, long, Error> Compress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets an SZDD compression engine parameter.
|
||||
///
|
||||
/// The following parameters are defined:
|
||||
/// - #MSSZDDC_PARAM_CHARACTER: the "missing character", the last character
|
||||
/// in the uncompressed file's filename, which is traditionally replaced
|
||||
/// with an underscore to show the file is compressed. Traditionally,
|
||||
/// this can only be a character that is a valid part of an MS-DOS,
|
||||
/// filename, but libmspack permits any character between 0x00 and 0xFF
|
||||
/// to be stored. 0x00 is the default, and it represents "no character
|
||||
/// stored".
|
||||
/// </summary>
|
||||
/// <param name="self">
|
||||
/// a self-referential pointer to the msszdd_compressor
|
||||
/// instance being called
|
||||
/// </param>
|
||||
/// <param name="param">the parameter to set</param>
|
||||
/// <param name="value">the value to set the parameter to</param>
|
||||
/// <returns>
|
||||
/// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
|
||||
/// is a problem with either parameter or value.
|
||||
/// </returns>
|
||||
/// <see cref="Compress"/>
|
||||
public Func<Compressor, Parameters, int, Error> SetParam;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the error code set by the most recently called method.
|
||||
/// </summary>
|
||||
/// <param name="self">
|
||||
/// a self-referential pointer to the msszdd_compressor
|
||||
/// instance being called
|
||||
/// </param>
|
||||
/// <returns>the most recent error code</returns>
|
||||
/// <see cref="Compress"/>
|
||||
public Func<Compressor, Error> LastError;
|
||||
}
|
||||
}
|
||||
226
BurnOutSharp/External/libmspack/SZDD/Decompressor.cs
vendored
226
BurnOutSharp/External/libmspack/SZDD/Decompressor.cs
vendored
@@ -1,226 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LibMSPackSharp.Compression;
|
||||
using static LibMSPackSharp.Constants;
|
||||
|
||||
namespace LibMSPackSharp.SZDD
|
||||
{
|
||||
/// <summary>
|
||||
/// A decompressor for SZDD compressed files.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
/// <see cref="Library.CreateSZDDDecompressor(SystemImpl)"/>
|
||||
/// <see cref="Library.DestroySZDDDecompressor(Decompressor)"/>
|
||||
public class Decompressor : BaseDecompressor
|
||||
{
|
||||
#region Public Functionality
|
||||
|
||||
/// <summary>
|
||||
/// Opens a SZDD file and reads the header.
|
||||
///
|
||||
/// If the file opened is a valid SZDD file, all headers will be read and
|
||||
/// a msszddd_header structure will be returned.
|
||||
///
|
||||
/// In the case of an error occuring, NULL is returned and the error code
|
||||
/// is available from last_error().
|
||||
///
|
||||
/// The filename pointer should be considered "in use" until close() is
|
||||
/// called on the SZDD file.
|
||||
/// </summary>
|
||||
/// <param name="filename">
|
||||
/// The filename of the SZDD compressed file. This is
|
||||
/// passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>A pointer to a msszddd_header structure, or NULL on failure</returns>
|
||||
/// <see cref="Close(Header)"/>
|
||||
public Header Open(string filename)
|
||||
{
|
||||
FileStream fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ);
|
||||
Header hdr = new Header();
|
||||
if (fh != null && hdr != null)
|
||||
{
|
||||
hdr.FileHandle = fh;
|
||||
Error = ReadHeaders(fh, hdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fh == null)
|
||||
Error = Error.MSPACK_ERR_OPEN;
|
||||
if (hdr == null)
|
||||
Error = Error.MSPACK_ERR_NOMEMORY;
|
||||
}
|
||||
|
||||
if (Error != Error.MSPACK_ERR_OK)
|
||||
{
|
||||
System.Close(fh);
|
||||
hdr = null;
|
||||
}
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes a previously opened SZDD file.
|
||||
///
|
||||
/// This closes a SZDD file and frees the msszddd_header associated with
|
||||
/// it.
|
||||
///
|
||||
/// The SZDD header pointer is now invalid and cannot be used again.
|
||||
/// </summary>
|
||||
/// <param name="szdd">The SZDD file to close</param>
|
||||
/// <see cref="Open(string)"/>
|
||||
public void Close(Header hdr)
|
||||
{
|
||||
if (System == null || hdr == null)
|
||||
return;
|
||||
|
||||
// Close the file handle associated
|
||||
System.Close(hdr.FileHandle);
|
||||
|
||||
Error = Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the compressed data from a SZDD file.
|
||||
///
|
||||
/// This decompresses the compressed SZDD data stream and writes it to
|
||||
/// an output file.
|
||||
/// </summary>
|
||||
/// <param name="hdr">The SZDD file to extract data from</param>
|
||||
/// <param name="filename">
|
||||
/// The filename to write the decompressed data to. This
|
||||
/// is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Extract(Header hdr, string filename)
|
||||
{
|
||||
if (hdr == null)
|
||||
return Error = Error.MSPACK_ERR_ARGS;
|
||||
|
||||
FileStream fh = hdr.FileHandle;
|
||||
if (fh == null)
|
||||
return Error.MSPACK_ERR_ARGS;
|
||||
|
||||
// Seek to the compressed data
|
||||
long dataOffset = (hdr.Format == Format.MSSZDD_FMT_NORMAL) ? 14 : 12;
|
||||
if (System.Seek(fh, dataOffset, SeekMode.MSPACK_SYS_SEEK_START))
|
||||
return Error = Error.MSPACK_ERR_SEEK;
|
||||
|
||||
// Open file for output
|
||||
FileStream outfh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_WRITE);
|
||||
if (outfh == null)
|
||||
return Error = Error.MSPACK_ERR_OPEN;
|
||||
|
||||
// Decompress the data
|
||||
Error = LZSS.Decompress(
|
||||
System,
|
||||
fh,
|
||||
outfh,
|
||||
SZDD_INPUT_SIZE,
|
||||
hdr.Format == Format.MSSZDD_FMT_NORMAL
|
||||
? LZSSMode.LZSS_MODE_EXPAND
|
||||
: LZSSMode.LZSS_MODE_QBASIC);
|
||||
|
||||
// Close output file
|
||||
System.Close(outfh);
|
||||
|
||||
return Error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses an SZDD file to an output file in one step.
|
||||
///
|
||||
/// This opens an SZDD file as input, reads the header, then decompresses
|
||||
/// the compressed data immediately to an output file, finally closing
|
||||
/// both the input and output file. It is more convenient to use than
|
||||
/// open() then extract() then close(), if you do not need to know the
|
||||
/// SZDD output size or missing character.
|
||||
/// </summary>
|
||||
/// <param name="input">
|
||||
/// The filename of the input SZDD file. This is passed
|
||||
/// directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <param name="output">
|
||||
/// The filename to write the decompressed data to. This
|
||||
/// is passed directly to mspack_system::open().
|
||||
/// </param>
|
||||
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
|
||||
public Error Decompress(string input, string output)
|
||||
{
|
||||
Header hdr = Open(input) as Header;
|
||||
if (hdr == null)
|
||||
return Error;
|
||||
|
||||
Error error = Extract(hdr, output);
|
||||
Close(hdr);
|
||||
return Error = error;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Reads the headers of an SZDD format file
|
||||
/// </summary>
|
||||
private Error ReadHeaders(FileStream fh, Header hdr)
|
||||
{
|
||||
// Read and check signature
|
||||
byte[] buf = new byte[8];
|
||||
if (System.Read(fh, buf, 0, 8) != 8)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
if (buf.SequenceEqual(expandSignature))
|
||||
{
|
||||
// Common SZDD
|
||||
hdr.Format = Format.MSSZDD_FMT_NORMAL;
|
||||
|
||||
// Read the rest of the header
|
||||
if (System.Read(fh, buf, 0, 6) != 6)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
if (buf[0] != 0x41)
|
||||
return Error.MSPACK_ERR_DATAFORMAT;
|
||||
|
||||
hdr.MissingChar = (char)buf[1];
|
||||
hdr.Length = BitConverter.ToUInt32(buf, 2);
|
||||
}
|
||||
if (buf.SequenceEqual(qbasicSignature))
|
||||
{
|
||||
// Special QBasic SZDD
|
||||
hdr.Format = Format.MSSZDD_FMT_QBASIC;
|
||||
if (System.Read(fh, buf, 0, 4) != 4)
|
||||
return Error.MSPACK_ERR_READ;
|
||||
|
||||
hdr.MissingChar = '\0';
|
||||
hdr.Length = BitConverter.ToUInt32(buf, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Error.MSPACK_ERR_SIGNATURE;
|
||||
}
|
||||
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
32
BurnOutSharp/External/libmspack/SZDD/Enums.cs
vendored
32
BurnOutSharp/External/libmspack/SZDD/Enums.cs
vendored
@@ -1,32 +0,0 @@
|
||||
/* This file is part of libmspack.
|
||||
* (C) 2003-2018 Stuart Caie.
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* For further details, see the file COPYING.LIB distributed with libmspack
|
||||
*/
|
||||
|
||||
namespace LibMSPackSharp.SZDD
|
||||
{
|
||||
public enum Format
|
||||
{
|
||||
/// <summary>
|
||||
/// a regular SZDD file
|
||||
/// </summary>
|
||||
MSSZDD_FMT_NORMAL = 0,
|
||||
|
||||
/// <summary>
|
||||
/// a special QBasic SZDD file
|
||||
/// </summary>
|
||||
MSSZDD_FMT_QBASIC = 1,
|
||||
}
|
||||
|
||||
public enum Parameters
|
||||
{
|
||||
/// <summary>
|
||||
/// The missing character
|
||||
/// </summary>
|
||||
MSSZDDC_PARAM_MISSINGCHAR = 0,
|
||||
}
|
||||
}
|
||||
49
BurnOutSharp/External/libmspack/SZDD/Header.cs
vendored
49
BurnOutSharp/External/libmspack/SZDD/Header.cs
vendored
@@ -1,49 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace LibMSPackSharp.SZDD
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which represents an SZDD compressed file.
|
||||
///
|
||||
/// All fields are READ ONLY.
|
||||
/// </summary>
|
||||
public class Header : BaseHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The file format
|
||||
/// </summary>
|
||||
public Format Format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of data in the SZDD file once uncompressed.
|
||||
/// </summary>
|
||||
public long Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last character in the filename, traditionally replaced with an
|
||||
/// underscore to show the file is compressed. The null character is used
|
||||
/// to show that this character has not been stored (e.g. because the
|
||||
/// filename is not known). Generally, only characters that may appear in
|
||||
/// an MS-DOS filename (except ".") are valid.
|
||||
/// </summary>
|
||||
public char MissingChar { get; set; }
|
||||
|
||||
public FileStream FileHandle { get; set; }
|
||||
}
|
||||
}
|
||||
274
BurnOutSharp/External/libmspack/SystemImpl.cs
vendored
274
BurnOutSharp/External/libmspack/SystemImpl.cs
vendored
@@ -1,274 +0,0 @@
|
||||
/* libmspack -- a library for working with Microsoft compression formats.
|
||||
* (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
|
||||
*
|
||||
* libmspack is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace LibMSPackSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure which abstracts file I/O and memory management.
|
||||
///
|
||||
/// The library always uses the SystemImpl structure for interaction
|
||||
/// with the file system and to allocate, free and copy all memory.It also
|
||||
/// uses it to send literal messages to the library user.
|
||||
///
|
||||
/// When the library is compiled normally, passing null to a compressor or
|
||||
/// decompressor constructor will result in a default SystemImpl being
|
||||
/// used, where all methods are implemented with the standard C library.
|
||||
/// However, all constructors support being given a custom created
|
||||
/// SystemImpl structure, with the library user's own methods. This
|
||||
/// allows for more abstract interaction, such as reading and writing files
|
||||
/// directly to memory, or from a network socket or pipe.
|
||||
///
|
||||
/// Implementors of an SystemImpl structure should read all
|
||||
/// documentation entries for every structure member, and write methods
|
||||
/// which conform to those standards.
|
||||
/// </summary>
|
||||
public class SystemImpl
|
||||
{
|
||||
/// <summary>
|
||||
/// Opens a file for reading, writing, appending or updating.
|
||||
/// </summary>
|
||||
/// <param name="filename">
|
||||
/// the file to be opened. It is passed directly from the
|
||||
/// library caller without being modified, so it is up to
|
||||
/// the caller what this parameter actually represents.
|
||||
/// </param>
|
||||
/// <param name="mode">One of the <see cref="OpenMode"/> values</param>
|
||||
/// <returns>
|
||||
/// A pointer to a FileStream structure. This structure officially
|
||||
/// contains no members, its true contents are up to the
|
||||
/// SystemImpl implementor. It should contain whatever is needed
|
||||
/// for other SystemImpl methods to operate. Returning the null
|
||||
/// pointer indicates an error condition.
|
||||
/// </returns>
|
||||
public FileStream Open(string filename, OpenMode mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case OpenMode.MSPACK_SYS_OPEN_READ:
|
||||
return File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
|
||||
case OpenMode.MSPACK_SYS_OPEN_WRITE:
|
||||
return File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
|
||||
|
||||
case OpenMode.MSPACK_SYS_OPEN_UPDATE:
|
||||
return File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
|
||||
case OpenMode.MSPACK_SYS_OPEN_APPEND:
|
||||
return File.Open(filename, FileMode.Append, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Message(null, $"Could not open {filename}: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes a previously opened file. If any memory was allocated for this
|
||||
/// particular file handle, it should be freed at this time.
|
||||
/// </summary>
|
||||
/// <param name="file">the file to close</param>
|
||||
/// <see cref="Open(string, OpenMode)"/>
|
||||
public void Close(FileStream file) => file?.Close();
|
||||
|
||||
/// <summary>
|
||||
/// Reads a given number of bytes from an open file.
|
||||
/// </summary>
|
||||
/// <param name="file">the file to read from</param>
|
||||
/// <param name="buffer">the location where the read bytes should be stored</param>
|
||||
/// <param name="bytes">the number of bytes to read from the file.</param>
|
||||
/// <returns>
|
||||
/// the number of bytes successfully read (this can be less than
|
||||
/// the number requested), zero to mark the end of file, or less
|
||||
/// than zero to indicate an error. The library does not "retry"
|
||||
/// reads and assumes short reads are due to EOF, so you should
|
||||
/// avoid returning short reads because of transient errors.
|
||||
/// </returns>
|
||||
/// <see cref="Open(string, OpenMode)"/>
|
||||
/// <see cref="Write"/>
|
||||
public Func<FileStream, byte[], int, int, int> Read;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a given number of bytes to an open file.
|
||||
/// </summary>
|
||||
/// <param name="file">the file to write to</param>
|
||||
/// <param name="buffer">the location where the written bytes should be read from</param>
|
||||
/// <param name="bytes">the number of bytes to write to the file.</param>
|
||||
/// <returns>
|
||||
/// the number of bytes successfully written, this can be less
|
||||
/// than the number requested. Zero or less can indicate an error
|
||||
/// where no bytes at all could be written. All cases where less
|
||||
/// bytes were written than requested are considered by the library
|
||||
/// to be an error.
|
||||
/// </returns>
|
||||
/// <see cref="Open(string, OpenMode)"/>
|
||||
/// <see cref="Read"/>
|
||||
public Func<FileStream, byte[], int, int, int> Write;
|
||||
|
||||
/// <summary>
|
||||
/// Seeks to a specific file offset within an open file.
|
||||
///
|
||||
/// Sometimes the library needs to know the length of a file. It does
|
||||
/// this by seeking to the end of the file with seek(file, 0,
|
||||
/// MSPACK_SYS_SEEK_END), then calling Tell(). Implementations may want
|
||||
/// to make a special case for this.
|
||||
///
|
||||
/// Due to the potentially varying 32/64 bit datatype int on some
|
||||
/// architectures, the #MSPACK_SYS_SELFTEST macro MUST be used before
|
||||
/// using the library. If not, the error caused by the library passing an
|
||||
/// inappropriate stackframe to Seek() is subtle and hard to trace.
|
||||
/// </summary>
|
||||
/// <param name="file">the file to be seeked</param>
|
||||
/// <param name="offset">an offset to seek, measured in bytes</param>
|
||||
/// <param name="mode">One of the <see cref="SeekMode"/> values</param>
|
||||
/// <returns>zero for success, non-zero for an error</returns>
|
||||
/// <see cref="Open(string, OpenMode)"/>
|
||||
/// <see cref="Tell(FileStream)"/>
|
||||
public bool Seek(FileStream self, long offset, SeekMode mode)
|
||||
{
|
||||
if (self == null)
|
||||
return false;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case SeekMode.MSPACK_SYS_SEEK_START:
|
||||
try { self.Seek(offset, SeekOrigin.Begin); return true; }
|
||||
catch { return false; }
|
||||
|
||||
case SeekMode.MSPACK_SYS_SEEK_CUR:
|
||||
try { self.Seek(offset, SeekOrigin.Current); return true; }
|
||||
catch { return false; }
|
||||
|
||||
case SeekMode.MSPACK_SYS_SEEK_END:
|
||||
try { self.Seek(offset, SeekOrigin.End); return true; }
|
||||
catch { return false; }
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current file position (in bytes) of the given file.
|
||||
/// </summary>
|
||||
/// <param name="file">the file whose file position is wanted</param>
|
||||
/// <returns>the current file position of the file</returns>
|
||||
/// <see cref="Open(string, OpenMode)"/>
|
||||
/// <see cref="Seek(FileStream, long, SeekMode)"/>
|
||||
public long Tell(FileStream self) => self?.Position ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Used to send messages from the library to the user.
|
||||
///
|
||||
/// Occasionally, the library generates warnings or other messages in
|
||||
/// plain english to inform the human user. These are informational only
|
||||
/// and can be ignored if not wanted.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// may be a file handle returned from Open() if this message
|
||||
/// pertains to a specific open file, or null if not related to
|
||||
/// a specific file.
|
||||
/// </param>
|
||||
/// <param name="format">a printf() style format string. It does NOT include a trailing newline.</param>
|
||||
/// <see cref="Open(string, OpenMode)"/>
|
||||
public void Message(FileStream file, string format)
|
||||
{
|
||||
if (file != null)
|
||||
Console.Error.Write($"{file.Name}: ");
|
||||
|
||||
Console.Error.Write($"{format}\n");
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length of a file opened for reading
|
||||
/// </summary>
|
||||
public Error GetFileLength(FileStream file, out long length)
|
||||
{
|
||||
try
|
||||
{
|
||||
length = file?.Length ?? 0;
|
||||
return Error.MSPACK_ERR_OK;
|
||||
}
|
||||
catch
|
||||
{
|
||||
length = 0;
|
||||
return Error.MSPACK_ERR_SEEK;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a system structure
|
||||
/// </summary>
|
||||
public static bool ValidSystem(SystemImpl sys)
|
||||
{
|
||||
return (sys != null) && (sys.Read != null) && (sys.Write != null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Default Implementation
|
||||
|
||||
public static SystemImpl DefaultSystem => new SystemImpl()
|
||||
{
|
||||
Read = DefaultRead,
|
||||
Write = DefaultWrite,
|
||||
};
|
||||
|
||||
private static int DefaultRead(object file, byte[] buffer, int pointer, int bytes)
|
||||
{
|
||||
FileStream self = file as FileStream;
|
||||
if (self != null && buffer != null && bytes >= 0)
|
||||
{
|
||||
try { return self.Read(buffer, pointer, bytes); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int DefaultWrite(object file, byte[] buffer, int pointer, int bytes)
|
||||
{
|
||||
// Null output file means skip those bytes
|
||||
if (file == null)
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
FileStream self = file as FileStream;
|
||||
if (self != null && buffer != null && bytes >= 0)
|
||||
{
|
||||
try { self.Write(buffer, pointer, bytes); }
|
||||
catch { return -1; }
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1
LibMSPackSharp
Submodule
1
LibMSPackSharp
Submodule
Submodule LibMSPackSharp added at cc08388953
Reference in New Issue
Block a user