Start cleanup on libmspack

This commit is contained in:
Matt Nadareski
2022-05-19 17:07:08 -07:00
parent b23a504c7b
commit 218fecb273
22 changed files with 1145 additions and 701 deletions

View File

@@ -74,6 +74,15 @@ namespace LibMSPackSharp.CAB
/// <see cref="Decompressor.Search"/>
public class Cabinet
{
#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
@@ -93,11 +102,6 @@ namespace LibMSPackSharp.CAB
/// </summary>
public long BaseOffset { get; set; }
/// <summary>
/// The length of the cabinet file in bytes.
/// </summary>
public uint Length { get; set; }
/// <summary>
/// The previous cabinet in a cabinet set, or NULL.
/// </summary>
@@ -137,39 +141,5 @@ namespace LibMSPackSharp.CAB
/// A list of all folders in the cabinet or cabinet set.
/// </summary>
public Folder Folders { get; set; }
/// <summary>
/// The set ID of the cabinet. All cabinets in the same set should have
/// the same set ID.
/// </summary>
public ushort SetID { get; 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>
public ushort SetIndex { get; set; }
/// <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>
/// <see cref="Flags"/>
public ushort HeaderResv { get; set; }
/// <summary>
/// Header flags.
/// </summary>
/// <see cref="PreviousName"/>
/// <see cref="PreviousInfo"/>
/// <see cref="NextName"/>
/// <see cref="NextInfo"/>
/// <see cref="HeaderResv"/>
public HeaderFlags Flags { get; set; }
}
}

View File

@@ -1,18 +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
{
public class CabinetImpl : Cabinet
{
public long BlocksOffset { get; set; }
public int BlockResverved { get; set; }
}
}

View File

@@ -76,12 +76,12 @@ namespace LibMSPackSharp.CAB
/// <summary>
/// Input data consumed
/// </summary>
public int IPtr { get; set; }
public int InputPointer { get; set; }
/// <summary>
/// Input data end
/// </summary>
public int IEnd { get; set; }
public int InputEnd { get; set; }
/// <summary>
/// One input block of data

View File

@@ -46,7 +46,7 @@ namespace LibMSPackSharp.CAB
/// <see cref="Close"/>
/// <see cref="Search"/>
/// <see cref="LastError"/>
public Func<Decompressor, string, CabinetImpl> Open;
public Func<Decompressor, string, Cabinet> Open;
/// <summary>
/// Closes a previously opened cabinet or cabinet set.

View File

@@ -27,6 +27,15 @@ namespace LibMSPackSharp.CAB
/// </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.
@@ -34,28 +43,18 @@ namespace LibMSPackSharp.CAB
public Folder Next { get; 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".
/// Where are the data blocks?
/// </summary>
/// <see cref="MSCABD_COMP_METHOD()"/>
/// <see cref="MSCABD_COMP_LEVEL()"/>
public CompressionType CompressionType { get; set; }
public FolderData Data { get; 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.
/// First file needing backwards merge
/// </summary>
public ushort NumBlocks { get; set; }
public InternalFile MergePrev { get; set; }
/// <summary>
/// Returns the compression method used by a folder.
/// First file needing forwards merge
/// </summary>
/// <param name="compType">a <see cref="CompressionType"/> value</param>
/// <returns>a <see cref="CompressionType"/> value</returns>
public CompressionType MSCABD_COMP_LEVEL(CompressionType compType) => (CompressionType)((((ushort)compType) >> 8) & 0x1F);
public InternalFile MergeNext { get; set; }
}
}

View File

@@ -1,36 +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
{
public class FolderImpl : Folder
{
/// <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; }
}
}

View File

@@ -71,36 +71,6 @@ namespace LibMSPackSharp.CAB
#region Structure Offsets
private const int cfhead_Signature = (0x00);
private const int cfhead_CabinetSize = (0x08);
private const int cfhead_FileOffset = (0x10);
private const int cfhead_MinorVersion = (0x18);
private const int cfhead_MajorVersion = (0x19);
private const int cfhead_NumFolders = (0x1A);
private const int cfhead_NumFiles = (0x1C);
private const int cfhead_Flags = (0x1E);
private const int cfhead_SetID = (0x20);
private const int cfhead_CabinetIndex = (0x22);
private const int cfhead_SIZEOF = (0x24);
private const int cfheadext_HeaderReserved = (0x00);
private const int cfheadext_FolderReserved = (0x02);
private const int cfheadext_DataReserved = (0x03);
private const int cfheadext_SIZEOF = (0x04);
private const int cffold_DataOffset = (0x00);
private const int cffold_NumBlocks = (0x04);
private const int cffold_CompType = (0x06);
private const int cffold_SIZEOF = (0x08);
private const int cffile_UncompressedSize = (0x00);
private const int cffile_FolderOffset = (0x04);
private const int cffile_FolderIndex = (0x08);
private const int cffile_Date = (0x0A);
private const int cffile_Time = (0x0C);
private const int cffile_Attribs = (0x0E);
private const int cffile_SIZEOF = (0x10);
private const int cfdata_CheckSum = (0x00);
private const int cfdata_CompressedSize = (0x04);
private const int cfdata_UncompressedSize = (0x06);
@@ -140,10 +110,10 @@ namespace LibMSPackSharp.CAB
/// <summary>
/// Opens a file and tries to read it as a cabinet file
/// </summary>
public static CabinetImpl Open(Decompressor d, string filename)
public static Cabinet Open(Decompressor d, string filename)
{
DecompressorImpl self = d as DecompressorImpl;
CabinetImpl cab = null;
Cabinet cab = null;
if (self == null)
return null;
@@ -152,7 +122,7 @@ namespace LibMSPackSharp.CAB
object fileHandle;
if ((fileHandle = system.Open(system, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
{
cab = new CabinetImpl();
cab = new Cabinet();
cab.Filename = filename;
Error error = ReadHeaders(system, fileHandle, cab, 0, self.Salvage, false);
if (error != Error.MSPACK_ERR_OK)
@@ -222,7 +192,7 @@ namespace LibMSPackSharp.CAB
}
// Free folder data segments
for (dat = (fol as FolderImpl).Data.Next; dat != null; dat = ndat)
for (dat = fol.Data.Next; dat != null; dat = ndat)
{
ndat = dat.Next;
sys.Free(dat);
@@ -272,18 +242,17 @@ namespace LibMSPackSharp.CAB
/// Fills out a pre-existing Cabinet structure, allocates memory
/// for folders and files as necessary
/// </summary>
public static Error ReadHeaders(SystemImpl sys, object fh, CabinetImpl cab, long offset, bool salvage, bool quiet)
public static Error ReadHeaders(SystemImpl sys, object fh, Cabinet cab, long offset, bool salvage, bool quiet)
{
int num_folders, num_files, folder_resv, i, x;
int i, x;
Error err = Error.MSPACK_ERR_OK;
FileFlags fidx;
FolderImpl fol, linkfol = null;
Folder fol, linkfol = null;
InternalFile file, linkfile = null;
byte[] buf = new byte[64];
// Initialise pointers
if (cab == null)
cab = new CabinetImpl();
cab = new Cabinet();
cab.Next = null;
cab.Files = null;
@@ -299,73 +268,36 @@ namespace LibMSPackSharp.CAB
return Error.MSPACK_ERR_SEEK;
// Read in the CFHEADER
if (sys.Read(fh, buf, 0, cfhead_SIZEOF) != cfhead_SIZEOF)
if (sys.Read(fh, buf, 0, _CabinetHeader.Size) != _CabinetHeader.Size)
return Error.MSPACK_ERR_READ;
// Check for "MSCF" signature
if (BitConverter.ToUInt32(buf, cfhead_Signature) != 0x4643534D)
return Error.MSPACK_ERR_SIGNATURE;
// Create a new header based on that
err = _CabinetHeader.Create(buf, out _CabinetHeader cabinetHeader);
if (err != Error.MSPACK_ERR_OK)
return err;
// Some basic header fields
cab.Length = BitConverter.ToUInt32(buf, cfhead_CabinetSize);
cab.SetID = BitConverter.ToUInt16(buf, cfhead_SetID);
cab.SetIndex = BitConverter.ToUInt16(buf, cfhead_CabinetIndex);
// Assign the header
cab.Header = cabinetHeader;
// Get the number of folders
num_folders = BitConverter.ToUInt16(buf, cfhead_NumFolders);
if (num_folders == 0)
// Check for the extended header
if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV))
{
if (!quiet) sys.Message(fh, "no folders in cabinet.");
return Error.MSPACK_ERR_DATAFORMAT;
}
// Get the number of files
num_files = BitConverter.ToUInt16(buf, cfhead_NumFiles);
if (num_files == 0)
{
if (!quiet) sys.Message(fh, "no files in cabinet.");
return Error.MSPACK_ERR_DATAFORMAT;
}
// Check cabinet version
if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3))
{
if (!quiet) sys.Message(fh, "WARNING; cabinet version is not 1.3");
}
// Read the reserved-sizes part of header, if present
cab.Flags = (HeaderFlags)BitConverter.ToUInt16(buf, cfhead_Flags);
if (cab.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV))
{
if (sys.Read(fh, buf, 0, cfheadext_SIZEOF) != cfheadext_SIZEOF)
if (sys.Read(fh, buf, 0, _CabinetHeader.ExtendedSize) != _CabinetHeader.ExtendedSize)
return Error.MSPACK_ERR_READ;
cab.HeaderResv = BitConverter.ToUInt16(buf, cfheadext_HeaderReserved);
folder_resv = buf[cfheadext_FolderReserved];
cab.BlockResverved = buf[cfheadext_DataReserved];
if (cab.HeaderResv > 60000)
{
if (!quiet) sys.Message(fh, "WARNING; reserved header > 60000.");
}
// Populate the extended header
cabinetHeader.PopulateExtendedHeader(buf);
// Skip the reserved header
if (cab.HeaderResv != 0)
if (cab.Header.HeaderReserved != 0)
{
if (!sys.Seek(fh, cab.HeaderResv, SeekMode.MSPACK_SYS_SEEK_CUR))
if (!sys.Seek(fh, cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
return Error.MSPACK_ERR_SEEK;
}
}
else
{
cab.HeaderResv = 0;
folder_resv = 0;
cab.BlockResverved = 0;
}
// Read name and info of preceeding cabinet in set, if present
if (cab.Flags.HasFlag(HeaderFlags.MSCAB_HDR_PREVCAB))
if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_PREVCAB))
{
cab.PreviousName = ReadString(sys, fh, false, ref err);
if (err != Error.MSPACK_ERR_OK)
@@ -377,7 +309,7 @@ namespace LibMSPackSharp.CAB
}
// Read name and info of next cabinet in set, if present
if (cab.Flags.HasFlag(HeaderFlags.MSCAB_HDR_NEXTCAB))
if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_NEXTCAB))
{
cab.NextName = ReadString(sys, fh, false, ref err);
if (err != Error.MSPACK_ERR_OK)
@@ -389,29 +321,39 @@ namespace LibMSPackSharp.CAB
}
// Read folders
for (i = 0; i < num_folders; i++)
for (i = 0; i < cab.Header.NumFolders; i++)
{
if (sys.Read(fh, buf, 0, cffold_SIZEOF) != cffold_SIZEOF)
// Read in the FOHEADER
if (sys.Read(fh, buf, 0, _FolderHeader.Size) != _FolderHeader.Size)
return Error.MSPACK_ERR_READ;
if (folder_resv != 0)
if (cab.Header.FolderReserved != 0)
{
if (!sys.Seek(fh, folder_resv, SeekMode.MSPACK_SYS_SEEK_CUR))
if (!sys.Seek(fh, cab.Header.FolderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
return Error.MSPACK_ERR_SEEK;
}
fol = new FolderImpl();
// Create an empty folder
fol = new Folder()
{
Next = null,
MergePrev = null,
MergeNext = null,
};
fol.Next = null;
fol.CompressionType = (CompressionType)BitConverter.ToUInt16(buf, cffold_CompType);
fol.NumBlocks = BitConverter.ToUInt16(buf, cffold_NumBlocks);
fol.MergePrev = null;
fol.MergeNext = null;
// Create a new header based on that
err = _FolderHeader.Create(buf, out _FolderHeader folderHeader);
if (err != Error.MSPACK_ERR_OK)
return err;
// Assign the header
fol.Header = folderHeader;
// Set the folder data fields
fol.Data = new FolderData();
fol.Data.Next = null;
fol.Data.Cab = cab;
fol.Data.Offset = offset + (int)(BitConverter.ToUInt32(buf, cffold_DataOffset));
fol.Data.Offset = offset + fol.Header.DataOffset;
// Link folder into list of folders
if (linkfol == null)
@@ -423,27 +365,30 @@ namespace LibMSPackSharp.CAB
}
// Read files
for (i = 0; i < num_files; i++)
for (i = 0; i < cab.Header.NumFiles; i++)
{
if (sys.Read(fh, buf, 0, cffile_SIZEOF) != cffile_SIZEOF)
// Read in the FIHEADER
if (sys.Read(fh, buf, 0, _FileHeader.Size) != _FileHeader.Size)
return Error.MSPACK_ERR_READ;
file = new InternalFile();
file = new InternalFile() { Next = null };
file.Next = null;
file.Length = BitConverter.ToUInt32(buf, cffile_UncompressedSize);
file.Attributes = (FileAttributes)BitConverter.ToUInt16(buf, cffile_Attribs);
file.Offset = BitConverter.ToUInt32(buf, cffile_FolderOffset);
// Create a new header based on that
err = _FileHeader.Create(buf, out _FileHeader fileHeader);
if (err != Error.MSPACK_ERR_OK)
return err;
// Assign the header
file.Header = fileHeader;
// Set folder pointer
fidx = (FileFlags)BitConverter.ToUInt16(buf, cffile_FolderIndex);
if (fidx < FileFlags.CONTINUED_FROM_PREV)
if (file.Header.FolderIndex < FileFlags.CONTINUED_FROM_PREV)
{
// Normal folder index; count up to the correct folder
if ((int)fidx < num_folders)
if ((int)file.Header.FolderIndex < cab.Header.NumFolders)
{
Folder ifol = cab.Folders;
while (fidx-- != 0)
while (file.Header.FolderIndex-- != 0)
{
if (ifol != null)
ifol = ifol.Next;
@@ -460,7 +405,7 @@ namespace LibMSPackSharp.CAB
else
{
// Either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT
if (fidx == FileFlags.CONTINUED_TO_NEXT || fidx == FileFlags.CONTINUED_PREV_AND_NEXT)
if (file.Header.FolderIndex == FileFlags.CONTINUED_TO_NEXT || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT)
{
// Get last folder
Folder ifol = cab.Folders;
@@ -472,35 +417,23 @@ namespace LibMSPackSharp.CAB
file.Folder = ifol;
// Set "merge next" pointer
fol = ifol as FolderImpl;
fol = ifol;
if (fol.MergeNext == null)
fol.MergeNext = file;
}
if (fidx == FileFlags.CONTINUED_FROM_PREV || fidx == FileFlags.CONTINUED_PREV_AND_NEXT)
if (file.Header.FolderIndex == FileFlags.CONTINUED_FROM_PREV || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT)
{
// Get first folder
file.Folder = cab.Folders;
// Set "merge prev" pointer
fol = file.Folder as FolderImpl;
fol = file.Folder;
if (fol.MergePrev == null)
fol.MergePrev = file;
}
}
// Get time
x = BitConverter.ToUInt16(buf, cffile_Time);
file.LastModifiedTimeHour = (byte)(x >> 11);
file.LastModifiedTimeMinute = (byte)((x >> 5) & 0x3F);
file.LastModifiedTimeSecond = (byte)((x << 1) & 0x3E);
// Get date
x = BitConverter.ToUInt16(buf, cffile_Date);
file.LastModifiedDateDay = (byte)(x & 0x1F);
file.LastModifiedDateMonth = (byte)((x >> 5) & 0xF);
file.LastModifiedDateYear = (x >> 9) + 1980;
// Get filename
file.Filename = ReadString(sys, fh, false, ref err);
@@ -528,7 +461,7 @@ namespace LibMSPackSharp.CAB
{
// We never actually added any files to the file list. Something went wrong.
// The file header may have been invalid */
Console.WriteLine($"No files found, even though header claimed to have {num_files} files");
Console.WriteLine($"No files found, even though header claimed to have {cab.Header.NumFiles} files");
return Error.MSPACK_ERR_DATAFORMAT;
}
@@ -610,7 +543,7 @@ namespace LibMSPackSharp.CAB
}
// Open file and get its full file length
object fh; CabinetImpl cab = null;
object fh; Cabinet cab = null;
if ((fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null)
{
long firstlen = 0;
@@ -643,10 +576,10 @@ namespace LibMSPackSharp.CAB
/// The inner loop of <see cref="Search(Decompressor, string)"/>, to make it easier to
/// break out of the loop and be sure that all resources are freed
/// </summary>
public static Error Find(DecompressorImpl self, byte[] buf, object fh, string filename, long flen, ref long firstlen, out CabinetImpl firstcab)
public static Error Find(DecompressorImpl self, byte[] buf, object fh, string filename, long flen, ref long firstlen, out Cabinet firstcab)
{
firstcab = null;
CabinetImpl cab, link = null;
Cabinet cab, link = null;
long caboff, offset, length;
SystemImpl sys = self.System;
long p, pend;
@@ -762,8 +695,7 @@ namespace LibMSPackSharp.CAB
(((caboff + cablen_u32) < (flen + 32)) || self.Salvage))
{
// Likely cabinet found -- try reading it
cab = new CabinetImpl();
cab.Filename = filename;
cab = new Cabinet() { Filename = filename };
if (ReadHeaders(sys, fh, cab, caboff, self.Salvage, quiet: true) != Error.MSPACK_ERR_OK)
{
@@ -842,7 +774,7 @@ namespace LibMSPackSharp.CAB
DecompressorImpl self = d as DecompressorImpl;
FolderData data, ndata;
FolderImpl lfol, rfol;
Folder lfol, rfol;
InternalFile fi, rfi, lfi;
if (self == null)
@@ -884,18 +816,18 @@ namespace LibMSPackSharp.CAB
}
// Warn about odd set IDs or indices
if (lcab.SetID != rcab.SetID)
if (lcab.Header.SetID != rcab.Header.SetID)
sys.Message(null, "WARNING; merged cabinets with differing Set IDs.");
if (lcab.SetIndex > rcab.SetIndex)
if (lcab.Header.CabinetIndex > rcab.Header.CabinetIndex)
sys.Message(null, "WARNING; merged cabinets with odd order.");
// Merging the last folder in lcab with the first folder in rcab
lfol = lcab.Folders as FolderImpl;
rfol = rcab.Folders as FolderImpl;
lfol = lcab.Folders;
rfol = rcab.Folders;
while (lfol.Next != null)
{
lfol = lfol.Next as FolderImpl;
lfol = lfol.Next;
}
// Do we need to merge folders?
@@ -947,14 +879,14 @@ namespace LibMSPackSharp.CAB
// NOTE: special case, don't merge if rfol is merge prev and next,
// rfol.MergeNext is going to be deleted, so keep lfol's version
// instead
lfol.NumBlocks += (ushort)(rfol.NumBlocks - 1);
lfol.Header.NumBlocks += (ushort)(rfol.Header.NumBlocks - 1);
if ((rfol.MergeNext == null) || (rfol.MergeNext.Folder != rfol))
lfol.MergeNext = rfol.MergeNext;
// Attach the rfol's folder (except the merge folder)
while (lfol.Next != null)
{
lfol = (FolderImpl)lfol.Next;
lfol = lfol.Next;
}
lfol.Next = rfol.Next;
@@ -1015,20 +947,20 @@ namespace LibMSPackSharp.CAB
/// <summary>
/// Decides if two folders are OK to merge
/// </summary>
private static bool CanMergeFolders(SystemImpl sys, FolderImpl lfol, FolderImpl rfol)
private static bool CanMergeFolders(SystemImpl sys, Folder lfol, Folder rfol)
{
InternalFile lfi, rfi, l, r;
bool matching = true;
// Check that both folders use the same compression method/settings
if (lfol.CompressionType != rfol.CompressionType)
if (lfol.Header.CompType != rfol.Header.CompType)
{
Console.WriteLine("folder merge: compression type mismatch");
return false;
}
// Check there are not too many data blocks after merging
if ((lfol.NumBlocks + rfol.NumBlocks) > CAB_FOLDERMAX)
if ((lfol.Header.NumBlocks + rfol.Header.NumBlocks) > CAB_FOLDERMAX)
{
Console.WriteLine("folder merge: too many data blocks in merged folders");
return false;
@@ -1046,7 +978,7 @@ namespace LibMSPackSharp.CAB
// offset and length of each file.
for (l = lfi, r = rfi; l != null; l = l.Next, r = r.Next)
{
if (r == null || (l.Offset != r.Offset) || (l.Length != r.Length))
if (r == null || (l.Header.FolderOffset != r.Header.FolderOffset) || (l.Header.UncompressedSize != r.Header.UncompressedSize))
{
matching = false;
break;
@@ -1064,7 +996,7 @@ namespace LibMSPackSharp.CAB
{
for (r = rfi; r != null; r = r.Next)
{
if (l.Offset == r.Offset && l.Length == r.Length)
if (l.Header.FolderOffset == r.Header.FolderOffset && l.Header.UncompressedSize == r.Header.UncompressedSize)
break;
}
@@ -1095,19 +1027,19 @@ namespace LibMSPackSharp.CAB
return self.Error = Error.MSPACK_ERR_ARGS;
SystemImpl sys = self.System;
FolderImpl fol = file.Folder as FolderImpl;
Folder fol = file.Folder;
// If offset is beyond 2GB, nothing can be extracted
if (file.Offset > CAB_LENGTHMAX)
if (file.Header.FolderOffset > CAB_LENGTHMAX)
return self.Error = Error.MSPACK_ERR_DATAFORMAT;
// If file claims to go beyond 2GB either error out,
// or in salvage mode reduce file length so it fits 2GB limit
long filelen = file.Length;
if (filelen > CAB_LENGTHMAX || (file.Offset + filelen) > CAB_LENGTHMAX)
long filelen = file.Header.UncompressedSize;
if (filelen > CAB_LENGTHMAX || (file.Header.FolderOffset + filelen) > CAB_LENGTHMAX)
{
if (self.Salvage)
filelen = CAB_LENGTHMAX - file.Offset;
filelen = CAB_LENGTHMAX - file.Header.FolderOffset;
else
return self.Error = Error.MSPACK_ERR_DATAFORMAT;
}
@@ -1123,8 +1055,8 @@ namespace LibMSPackSharp.CAB
// In salvage mode, don't assume block sizes, just try decoding
if (!self.Salvage)
{
long maxlen = fol.NumBlocks * CAB_BLOCKMAX;
if ((file.Offset + filelen) > maxlen)
long maxlen = fol.Header.NumBlocks * CAB_BLOCKMAX;
if ((file.Header.FolderOffset + filelen) > maxlen)
{
sys.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete");
return self.Error = Error.MSPACK_ERR_DECRUNCH;
@@ -1146,7 +1078,7 @@ namespace LibMSPackSharp.CAB
}
// Do we need to change folder or reset the current folder?
if ((self.State.Folder != fol) || (self.State.Offset > file.Offset) || self.State.DecompressorState == null)
if ((self.State.Folder != fol) || (self.State.Offset > file.Header.FolderOffset) || self.State.DecompressorState == null)
{
// Free any existing decompressor
FreeDecompressionState(self);
@@ -1169,7 +1101,7 @@ namespace LibMSPackSharp.CAB
return self.Error = Error.MSPACK_ERR_SEEK;
// Set up decompressor
if (InitDecompressionState(self, fol.CompressionType) != Error.MSPACK_ERR_OK)
if (InitDecompressionState(self, fol.Header.CompType) != Error.MSPACK_ERR_OK)
return self.Error;
// Initialise new folder state
@@ -1178,7 +1110,7 @@ namespace LibMSPackSharp.CAB
self.State.Offset = 0;
self.State.Block = 0;
self.State.Outlen = 0;
self.State.IPtr = self.State.IEnd = 0;
self.State.InputPointer = self.State.InputEnd = 0;
// read_error lasts for the lifetime of a decompressor
self.ReadError = Error.MSPACK_ERR_OK;
@@ -1200,7 +1132,7 @@ namespace LibMSPackSharp.CAB
// - if cabd_sys_read() has an error, it will set self.ReadError
// and pass back MSPACK_ERR_READ
self.State.OutputFileHandle = null;
if ((bytes = file.Offset - self.State.Offset) != 0)
if ((bytes = file.Header.FolderOffset - self.State.Offset) != 0)
{
error = self.State.Decompress(self.State.DecompressorState, bytes);
self.Error = (error == Error.MSPACK_ERR_READ) ? self.ReadError : error;
@@ -1310,7 +1242,11 @@ namespace LibMSPackSharp.CAB
private static int SysRead(object file, byte[] buffer, int pointer, int bytes)
{
DecompressorImpl self = file as DecompressorImpl;
if (self == null)
return 0;
SystemImpl sys = self.System;
int avail, todo, outlen = 0;
bool ignore_cksum = self.Salvage ||
@@ -1321,7 +1257,7 @@ namespace LibMSPackSharp.CAB
todo = bytes;
while (todo > 0)
{
avail = self.State.IEnd - self.State.IPtr;
avail = self.State.InputEnd - self.State.InputPointer;
// If out of input data, read a new block
if (avail != 0)
@@ -1330,8 +1266,8 @@ namespace LibMSPackSharp.CAB
if (avail > todo)
avail = todo;
sys.Copy(self.State.Input, self.State.IPtr, buffer, pointer, avail);
self.State.IPtr += avail;
sys.Copy(self.State.Input, self.State.InputPointer, buffer, pointer, avail);
self.State.InputPointer += avail;
pointer += avail;
todo -= avail;
}
@@ -1340,7 +1276,7 @@ namespace LibMSPackSharp.CAB
// Out of data, read a new block
// Check if we're out of input blocks, advance block counter
if (self.State.Block++ >= self.State.Folder.NumBlocks)
if (self.State.Block++ >= self.State.Folder.Header.NumBlocks)
{
if (!self.Salvage)
self.ReadError = Error.MSPACK_ERR_DATAFORMAT;
@@ -1361,10 +1297,10 @@ namespace LibMSPackSharp.CAB
// to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
// anything from 0 to 4 trailing null bytes.
if ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_QUANTUM)
self.State.Input[self.State.IEnd++] = 0xFF;
self.State.Input[self.State.InputEnd++] = 0xFF;
// Is this the last block?
if (self.State.Block >= self.State.Folder.NumBlocks)
if (self.State.Block >= self.State.Folder.Header.NumBlocks)
{
if ((self.State.CompressionType & CompressionType.COMPTYPE_MASK) == CompressionType.COMPTYPE_LZX)
{
@@ -1387,12 +1323,21 @@ namespace LibMSPackSharp.CAB
/// </summary>
private static int SysWrite(object file, byte[] buffer, int pointer, int bytes)
{
DecompressorImpl self = file as DecompressorImpl;
self.State.Offset += (uint)bytes;
if (self.State.OutputFileHandle != null)
return self.System.Write(self.State.OutputFileHandle, buffer, pointer, bytes);
if (file is DecompressorImpl self)
{
self.State.Offset += (uint)bytes;
if (self.State.OutputFileHandle != null)
return self.System.Write(self.State.OutputFileHandle, buffer, pointer, bytes);
return bytes;
return bytes;
}
else if (file is DefaultFileImpl impl)
{
return SystemImpl.DefaultSystem.Write(file, buffer, pointer, bytes);
}
// Unknown file to write to
return 0;
}
#endregion
@@ -1410,21 +1355,21 @@ namespace LibMSPackSharp.CAB
int len, full_len;
// Reset the input block pointer and end of block pointer
d.IPtr = d.IEnd = 0;
d.InputPointer = d.InputEnd = 0;
do
{
// Read the block header
if (sys.Read(d.InputFileHandle, hdr, 0, cfdata_SIZEOF) != cfdata_SIZEOF)
if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, hdr, 0, cfdata_SIZEOF) != cfdata_SIZEOF)
return Error.MSPACK_ERR_READ;
// Skip any reserved block headers
if (d.Data.Cab.HeaderResv != 0 && !sys.Seek(d.InputFileHandle, d.Data.Cab.HeaderResv, SeekMode.MSPACK_SYS_SEEK_CUR))
if (d.Data.Cab.Header.HeaderReserved != 0 && !sys.Seek(d.InputFileHandle, d.Data.Cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR))
return Error.MSPACK_ERR_SEEK;
// Blocks must not be over CAB_INPUTMAX in size
len = BitConverter.ToUInt16(hdr, cfdata_CompressedSize);
full_len = (d.IEnd - d.IPtr) + len; // Include cab-spanning blocks
full_len = (d.InputEnd - d.InputPointer) + len; // Include cab-spanning blocks
if (full_len > CAB_INPUTMAX)
{
Console.WriteLine($"block size {full_len} > CAB_INPUTMAX");
@@ -1443,13 +1388,13 @@ namespace LibMSPackSharp.CAB
}
// Read the block data
if (sys.Read(d.InputFileHandle, d.Input, d.IEnd, len) != len)
if (SystemImpl.DefaultSystem.Read(d.InputFileHandle, d.Input, d.InputEnd, len) != len)
return Error.MSPACK_ERR_READ;
// Perform checksum test on the block (if one is stored)
if ((cksum = BitConverter.ToUInt32(hdr, cfdata_CheckSum)) != 0)
{
uint sum2 = Checksum(d.Input, d.IEnd, (uint)len, 0);
uint sum2 = Checksum(d.Input, d.InputEnd, (uint)len, 0);
if (Checksum(hdr, 4, 4, sum2) != cksum)
{
if (!ignore_cksum)
@@ -1460,7 +1405,7 @@ namespace LibMSPackSharp.CAB
}
// Advance end of block pointer to include newly read data
d.IEnd += len;
d.InputEnd += len;
// Uncompressed size == 0 means this block was part of a split block
// and it continues as the first block of the next cabinet in the set.

View File

@@ -23,6 +23,15 @@ namespace LibMSPackSharp.CAB
/// </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>
@@ -34,57 +43,12 @@ namespace LibMSPackSharp.CAB
/// 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="Attributes"/>
/// <see cref="_FileHeader.Attributes"/>
public string Filename { get; set; }
/// <summary>
/// The uncompressed length of the file, in bytes.
/// </summary>
public uint Length { get; set; }
/// <summary>
/// File attributes.
/// </summary>
public FileAttributes Attributes { get; set; }
/// <summary>
/// File's last modified time, hour field.
/// </summary>
public byte LastModifiedTimeHour { get; set; }
/// <summary>
/// File's last modified time, minute field.
/// </summary>
public byte LastModifiedTimeMinute { get; set; }
/// <summary>
/// File's last modified time, second field.
/// </summary>
public byte LastModifiedTimeSecond { get; set; }
/// <summary>
/// File's last modified date, day field.
/// </summary>
public byte LastModifiedDateDay { get; set; }
/// <summary>
/// File's last modified date, month field.
/// </summary>
public byte LastModifiedDateMonth { get; set; }
/// <summary>
/// File's last modified date, year field.
/// </summary>
public int LastModifiedDateYear { get; set; }
/// <summary>
/// A pointer to the folder that contains this file.
/// </summary>
public Folder Folder { get; set; }
/// <summary>
/// The uncompressed offset of this file in its folder.
/// </summary>
public uint Offset { get; set; }
}
}

View File

@@ -0,0 +1,204 @@
/* 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, 0x24);
FolderReserved = buffer[0x26];
DataReserved = buffer[0x27];
}
}
}

View File

@@ -0,0 +1,122 @@
/* 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 _Folder 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;
}
}
}

View File

@@ -0,0 +1,72 @@
/* 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 _Folder 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;
}
}
}

View File

@@ -1154,12 +1154,21 @@ namespace LibMSPackSharp.CHM
/// </summary>
private static int SysWrite(object file, byte[] buffer, int offset, int bytes)
{
DecompressorImpl self = file as DecompressorImpl;
self.State.Offset += bytes;
if (self.State.OutputFileHandle != null)
return self.System.Write(self.State.OutputFileHandle, buffer, offset, bytes);
if (file is DecompressorImpl self)
{
self.State.Offset += (uint)bytes;
if (self.State.OutputFileHandle != null)
return self.System.Write(self.State.OutputFileHandle, buffer, offset, bytes);
return bytes;
return bytes;
}
else if (file is DefaultFileImpl impl)
{
return SystemImpl.DefaultSystem.Write(file, buffer, offset, bytes);
}
// Unknown file to write to
return 0;
}
#endregion

View File

@@ -140,77 +140,104 @@ namespace LibMSPackSharp.Compression
InputEnd = 0;
}
public void STORE_BITS(int inputPointer, int inputLength, uint bitBuffer, uint bitsLeft)
public void STORE_BITS(int inputPointer, int inputLength, uint bit_buffer, uint bits_left)
{
InputPointer = inputPointer;
InputLength = inputLength;
BitBuffer = bitBuffer;
BitsLeft = bitsLeft;
BitBuffer = bit_buffer;
BitsLeft = bits_left;
}
public void RESTORE_BITS(ref int inputPointer, ref int inputLength, ref uint bitBuffer, ref uint bitsLeft)
public void RESTORE_BITS(ref int inputPointer, ref int inputLength, ref uint bit_buffer, ref uint bits_left)
{
inputPointer = InputPointer;
inputLength = InputLength;
bitBuffer = BitBuffer;
bitsLeft = BitsLeft;
bit_buffer = BitBuffer;
bits_left = BitsLeft;
}
public void ENSURE_BITS(int nbits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public void ENSURE_BITS(int nbits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb)
{
while (bitsLeft < nbits)
while (bits_left < nbits)
{
READ_BYTES(ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer);
READ_BYTES(ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb);
if (Error != Error.MSPACK_ERR_OK)
return;
}
Error = Error.MSPACK_ERR_OK;
}
public void READ_BITS(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public void READ_BITS(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb)
{
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer);
val = PEEK_BITS(nbits, bitBuffer);
REMOVE_BITS(nbits, ref bitsLeft, ref bitBuffer);
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb);
if (Error != Error.MSPACK_ERR_OK)
return;
val = PEEK_BITS(nbits, bit_buffer, msb);
REMOVE_BITS(nbits, ref bits_left, ref bit_buffer, msb);
Error = Error.MSPACK_ERR_OK;
}
public Error READ_MANY_BITS(ref uint val, byte bits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public void READ_MANY_BITS(ref uint val, byte bits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb)
{
byte needed = bits, bitrun;
val = 0;
while (needed > 0)
{
if (bitsLeft <= (BITBUF_WIDTH - 16))
if (bits_left <= (BITBUF_WIDTH - 16))
{
Error error = READ_BYTES(ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer);
if (error != Error.MSPACK_ERR_OK)
return error;
READ_BYTES(ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb);
if (Error != Error.MSPACK_ERR_OK)
return;
}
bitrun = (byte)((bitsLeft < needed) ? bitsLeft : needed);
val = (uint)((val << bitrun) | PEEK_BITS(bitrun, bitBuffer));
REMOVE_BITS(bitrun, ref bitsLeft, ref bitBuffer);
bitrun = (byte)((bits_left < needed) ? bits_left : needed);
val = (uint)((val << bitrun) | PEEK_BITS(bitrun, bit_buffer, msb));
REMOVE_BITS(bitrun, ref bits_left, ref bit_buffer, msb);
needed -= bitrun;
}
return Error.MSPACK_ERR_OK;
Error = Error.MSPACK_ERR_OK;
}
public int PEEK_BITS(int nbits, uint bitBuffer)
public int PEEK_BITS(int nbits, uint bit_buffer, bool msb)
{
return (int)(bitBuffer & ((1 << (nbits)) - 1));
if (msb)
return (int)(bit_buffer >> (BITBUF_WIDTH - (nbits)));
else
return (int)(bit_buffer & ((1 << (nbits)) - 1));
}
public void REMOVE_BITS(int nbits, ref uint bitsLeft, ref uint bitBuffer)
public void REMOVE_BITS(int nbits, ref uint bits_left, ref uint bit_buffer, bool msb)
{
bitBuffer >>= nbits;
bitsLeft -= (uint)nbits;
if (msb)
{
bit_buffer <<= nbits;
bits_left -= (uint)nbits;
}
else
{
bit_buffer >>= nbits;
bits_left -= (uint)nbits;
}
}
public void INJECT_BITS(uint bitdata, int nbits, ref uint bitsLeft, ref uint bitBuffer)
public void INJECT_BITS(uint bitdata, int nbits, ref uint bits_left, ref uint bit_buffer, bool msb)
{
bitBuffer |= bitdata << (int)bitsLeft;
bitsLeft += (uint)nbits;
if (msb)
{
bit_buffer |= bitdata << (int)bits_left;
bits_left += (uint)nbits;
}
else
{
bit_buffer |= bitdata << (int)bits_left;
bits_left += (uint)nbits;
}
}
public abstract Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer);
public abstract void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb);
// lsb_bit_mask[n] = (1 << n) - 1 */
private static readonly ushort[] lsb_bit_mask = new ushort[17]
@@ -224,54 +251,63 @@ namespace LibMSPackSharp.Compression
return (int)(BitBuffer & lsb_bit_mask[nbits]);
}
public void READ_BITS_T(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public void READ_BITS_T(ref int val, int nbits, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb)
{
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer);
ENSURE_BITS(nbits, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb);
if (Error != Error.MSPACK_ERR_OK)
return;
val = PEEK_BITS_T(nbits);
REMOVE_BITS(nbits, ref bitsLeft, ref bitBuffer);
REMOVE_BITS(nbits, ref bits_left, ref bit_buffer, msb);
Error = Error.MSPACK_ERR_OK;
}
public Error READ_IF_NEEDED(ref int iPtr, ref int iEnd)
public void READ_IF_NEEDED(ref int i_ptr, ref int i_end)
{
if (iPtr >= iEnd)
if (i_ptr >= i_end)
{
if (ReadInput(this) != Error.MSPACK_ERR_OK)
return Error;
ReadInput();
if (Error != Error.MSPACK_ERR_OK)
return;
iPtr = InputPointer;
iEnd = InputLength;
i_ptr = InputPointer;
i_end = InputLength;
}
return Error.MSPACK_ERR_OK;
Error = Error.MSPACK_ERR_OK;
}
private static Error ReadInput(CompressionStream p)
private void ReadInput()
{
int read = p.Sys.Read(p.Input, p.InputBuffer, 0, (int)p.InputBufferSize);
int read = Sys.Read(Input, InputBuffer, 0, (int)InputBufferSize);
if (read < 0)
return p.Error = Error.MSPACK_ERR_READ;
{
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 (p.InputEnd != 0)
if (InputEnd != 0)
{
Console.WriteLine("out of input bytes");
return p.Error = Error.MSPACK_ERR_READ;
Error = Error.MSPACK_ERR_READ;
return;
}
else
{
read = 2;
p.InputBuffer[0] = p.InputBuffer[1] = 0;
p.InputEnd = 1;
InputBuffer[0] = InputBuffer[1] = 0;
InputEnd = 1;
}
}
// Update i_ptr and i_end
p.InputPointer = 0;
p.InputLength = read;
return Error.MSPACK_ERR_OK;
InputPointer = 0;
InputLength = read;
Error = Error.MSPACK_ERR_OK;
}
#endregion
@@ -284,33 +320,50 @@ namespace LibMSPackSharp.Compression
/// 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 int READ_HUFFSYM(ushort[] decodingTable, ref uint var, int tablebits, byte[] lengthTable, int maxsymbols, ref int i, ref ushort sym, ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public int READ_HUFFSYM(ushort[] decodingTable, ref uint var, int tablebits, byte[] lengthTable, int maxsymbols, ref int i, ref int i_ptr, ref int i_end, ref uint bits_left, ref uint bit_buffer, bool msb)
{
ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bitsLeft, ref bitBuffer);
sym = decodingTable[PEEK_BITS(tablebits, bitBuffer)];
ENSURE_BITS(HUFF_MAXBITS, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb);
if (Error != Error.MSPACK_ERR_OK)
return (int)Error;
ushort sym = decodingTable[PEEK_BITS(tablebits, bit_buffer, msb)];
if (sym >= maxsymbols)
{
int ret = HUFF_TRAVERSE(decodingTable, tablebits, maxsymbols, ref i, ref sym, bitBuffer);
int ret = HUFF_TRAVERSE(decodingTable, tablebits, maxsymbols, ref i, ref sym, bit_buffer, msb);
if (ret != 0)
return ret;
}
var = sym;
i = lengthTable[sym];
REMOVE_BITS(i, ref bitsLeft, ref bitBuffer);
REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb);
return (int)Error.MSPACK_ERR_OK;
}
public int HUFF_TRAVERSE(ushort[] decodingTable, int tablebits, int maxsymbols, ref int i, ref ushort sym, uint bitBuffer)
public int HUFF_TRAVERSE(ushort[] decodingTable, int tablebits, int maxsymbols, ref int i, ref ushort sym, uint bit_buffer, bool msb)
{
i = tablebits - 1;
do
if (msb)
{
if (i++ > HUFF_MAXBITS)
return HUFF_ERROR();
i = 1 << (BITBUF_WIDTH - tablebits);
do
{
if ((i >>= 1) == 0)
return HUFF_ERROR();
sym = decodingTable[(sym << 1) | ((bitBuffer >> i) & 1)];
} while (sym >= maxsymbols);
sym = decodingTable[(sym << 1) | ((bit_buffer & i) != 0 ? 1 : 0)];
} while (sym >= maxsymbols);
}
else
{
i = tablebits - 1;
do
{
if (i++ > HUFF_MAXBITS)
return HUFF_ERROR();
try { sym = decodingTable[(sym << 1) | ((bit_buffer >> i) & 1)]; } catch { }
} while (sym >= maxsymbols);
}
return (int)Error.MSPACK_ERR_OK;
}
@@ -330,94 +383,84 @@ namespace LibMSPackSharp.Compression
/// The table to fill up with decoded symbols and pointers.
/// Should be ((1<<nbits) + (nsyms*2)) in length.
/// </param>
/// <returns>0 for OK or 1 for error</returns>
public static int MakeDecodeTable(uint nsyms, uint nbits, byte[] length, ushort[] table)
/// <returns>true for OK or false for error</returns>
public static bool MakeDecodeTable(int nsyms, int nbits, byte[] length, ushort[] table, bool msb)
{
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 << (int)nbits);
uint bit_mask = table_mask >> 1; // Don't do 0 length codes
int next_symbol;
long leaf, fill;
long reverse; // Only used when !msb
long pos = 0; // The current position in the decode table
int 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 (byte bit_num = 1; bit_num <= nbits; bit_num++)
{
for (sym = 0; sym < nsyms; sym++)
for (ushort 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
if (msb)
{
leaf <<= 1;
leaf |= reverse & 1;
reverse >>= 1;
} while (--fill != 0);
leaf = pos;
}
else
{
// Reverse the significant bits
fill = length[sym];
reverse = pos >> (nbits - (byte)fill);
leaf = 0;
do
{
leaf <<= 1;
leaf |= reverse & 1;
reverse >>= 1;
} while (--fill != 0);
}
if ((pos += bit_mask) > table_mask)
return 1; // Table overrun
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
if (msb)
{
table[leaf] = sym;
leaf += next_symbol;
} while (--fill != 0);
for (fill = bit_mask; fill-- > 0;)
{
table[leaf++] = sym;
}
}
else
{
fill = bit_mask;
next_symbol = 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 0;
return true;
// Mark all remaining table entries as unused
for (sym = (ushort)pos; sym < table_mask; sym++)
for (long sym = pos; sym < table_mask; sym++)
{
reverse = sym;
leaf = 0;
fill = nbits;
do
if (msb)
{
leaf <<= 1;
leaf |= reverse & 1;
reverse >>= 1;
} while (--fill != 0);
table[leaf] = 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++)
table[sym] = 0xFFFF;
}
else
{
if (length[sym] != bit_num)
continue;
if (pos >= table_mask)
return 1; // Table overflow
// Leaf = the first nbits of the code, reversed
reverse = pos >> 16;
reverse = sym;
leaf = 0;
fill = nbits;
@@ -428,19 +471,60 @@ namespace LibMSPackSharp.Compression
reverse >>= 1;
} while (--fill != 0);
table[leaf] = 0xFFFF;
}
}
// next_symbol = base of allocation for long codes
next_symbol = ((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 (int bit_num = nbits + 1; bit_num <= HUFF_MAXBITS; bit_num++)
{
for (ushort sym = 0; sym < nsyms; sym++)
{
if (length[sym] != bit_num)
continue;
if (pos >= table_mask)
return false; // Table overflow
if (msb)
{
leaf = pos >> 16;
}
else
{
// leaf = the first nbits of the code, reversed
reverse = pos >> 16;
leaf = 0;
fill = nbits;
do
{
leaf <<= 1;
leaf |= reverse & 1;
reverse >>= 1;
} while (--fill != 0);
}
for (fill = 0; fill < (bit_num - nbits); fill++)
{
// Ff this path hasn't been taken yet, 'allocate' two entries
// 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++;
table[leaf] = (ushort)next_symbol++;
}
// Follow the path and select either left or right for next bit
leaf = (uint)(table[leaf] << 1);
if (((pos >> (int)(15 - fill)) & 1) != 0)
leaf = table[leaf] << 1;
if (((pos >> (15 - (int)fill)) & 1) != 0)
leaf++;
}
@@ -452,7 +536,7 @@ namespace LibMSPackSharp.Compression
}
// Full table?
return (pos == table_mask) ? 0 : 1;
return pos == table_mask;
}
#endregion

View File

@@ -95,13 +95,13 @@ namespace LibMSPackSharp.Compression
// LZX huffman defines: tweak tablebits as desired
public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
public const int LZX_PRETREE_TABLEBITS = 6;
public const byte LZX_PRETREE_TABLEBITS = 6;
public const int LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 290 * 8;
public const int LZX_MAINTREE_TABLEBITS = 12;
public const byte LZX_MAINTREE_TABLEBITS = 12;
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
public const int LZX_LENGTH_TABLEBITS = 12;
public const byte LZX_LENGTH_TABLEBITS = 12;
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
public const int LZX_ALIGNED_TABLEBITS = 7;
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
@@ -433,7 +433,6 @@ namespace LibMSPackSharp.Compression
// Bitstream and huffman reading variables
uint bit_buffer = 0, bits_left = 0;
int i_ptr = 0, i_end = 0;
ushort sym = 0;
int match_length, extra, verbatim_bits = 0, bytes_todo;
int this_run, j = 0, warned = 0;
@@ -502,8 +501,11 @@ namespace LibMSPackSharp.Compression
// LZX DELTA format has chunk_size, not present in LZX format
if (lzx.IsDelta)
{
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.REMOVE_BITS(16, ref bits_left, ref bit_buffer);
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.REMOVE_BITS(16, ref bits_left, ref bit_buffer, msb: true);
}
// Read header if necessary
@@ -512,11 +514,19 @@ namespace LibMSPackSharp.Compression
/* read 1 bit. if bit=0, intel filesize = 0.
* if bit=1, read intel filesize (32 bits) */
j = 0;
lzx.READ_BITS(ref i, 1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref i, 1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
if (i != 0)
{
lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref j, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.READ_BITS(ref j, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
}
lzx.IntelFileSize = (i << 16) | j;
@@ -549,10 +559,19 @@ namespace LibMSPackSharp.Compression
// Read block type (3 bits) and block length (24 bits)
int blockType = 0;
lzx.READ_BITS(ref blockType, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref blockType, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.BlockType = (LZXBlockType)blockType;
lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref j, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref i, 16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.READ_BITS(ref j, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.BlockRemaining = lzx.BlockLength = (uint)((i << 8) | j);
// Console.WriteLine("new block t%d len %u", lzx.BlockType, lzx.BlockLength);
@@ -563,12 +582,15 @@ namespace LibMSPackSharp.Compression
case LZXBlockType.LZX_BLOCKTYPE_ALIGNED:
for (i = 0; i < 8; i++)
{
lzx.READ_BITS(ref j, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref j, 3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.ALIGNED_len[i] = (byte)j;
}
//BUILD_TABLE(ALIGNED)
if (LZXDStream.MakeDecodeTable(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, lzx.ALIGNED_table) != 0)
if (!LZXDStream.MakeDecodeTable(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, lzx.ALIGNED_table, msb: true))
{
Console.WriteLine("failed to build ALIGNED table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
@@ -589,7 +611,7 @@ namespace LibMSPackSharp.Compression
lzx.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
//BUILD_TABLE(MAINTREE)
if (LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table) != 0)
if (!LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true))
{
Console.WriteLine("failed to build MAINTREE table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
@@ -609,7 +631,7 @@ namespace LibMSPackSharp.Compression
//BUILD_TABLE_MAYBE_EMPTY(LENGTH)
lzx.LENGTH_empty = 0;
if (LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table) != 0)
if (!LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true))
{
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
{
@@ -642,7 +664,7 @@ namespace LibMSPackSharp.Compression
lzx.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
//BUILD_TABLE(MAINTREE)
if (LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table) != 0)
if (!LZXDStream.MakeDecodeTable(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, lzx.MAINTREE_table, msb: true))
{
Console.WriteLine("failed to build MAINTREE table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
@@ -662,7 +684,7 @@ namespace LibMSPackSharp.Compression
//BUILD_TABLE_MAYBE_EMPTY(LENGTH)
lzx.LENGTH_empty = 0;
if (LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table) != 0)
if (!LZXDStream.MakeDecodeTable(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, lzx.LENGTH_table, msb: true))
{
for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++)
{
@@ -685,7 +707,11 @@ namespace LibMSPackSharp.Compression
// Read 1-16 (not 0-15) bits to align to bytes
if (bits_left == 0)
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
{
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
}
bits_left = 0; bit_buffer = 0;
@@ -728,7 +754,9 @@ namespace LibMSPackSharp.Compression
case LZXBlockType.LZX_BLOCKTYPE_VERBATIM:
while (this_run > 0)
{
lzx.READ_HUFFSYM(lzx.MAINTREE_table, ref main_element, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, LZX_MAINTREE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzx.READ_HUFFSYM(lzx.MAINTREE_table, ref main_element, LZX_MAINTREE_TABLEBITS, lzx.MAINTREE_len, LZX_MAINTREE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
if (main_element < LZX_NUM_CHARS)
{
// Literal: 0 to LZX_NUM_CHARS-1
@@ -750,7 +778,9 @@ namespace LibMSPackSharp.Compression
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
}
lzx.READ_HUFFSYM(lzx.LENGTH_table, ref length_footer, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, LZX_LENGTH_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzx.READ_HUFFSYM(lzx.LENGTH_table, ref length_footer, LZX_LENGTH_TABLEBITS, lzx.LENGTH_len, LZX_LENGTH_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
match_length += (int)length_footer;
}
@@ -772,7 +802,10 @@ namespace LibMSPackSharp.Compression
else
{
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
match_offset = (uint)(position_base[match_offset] - 2 + verbatim_bits);
}
}
@@ -786,21 +819,31 @@ namespace LibMSPackSharp.Compression
{
// >3: verbatim and aligned bits
extra -= 3;
lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
match_offset += (uint)(verbatim_bits << 3);
lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
match_offset += aligned_bits;
}
else if (extra == 3)
{
// 3: aligned bits only
lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzx.READ_HUFFSYM(lzx.ALIGNED_table, ref aligned_bits, LZX_ALIGNED_TABLEBITS, lzx.ALIGNED_len, LZX_ALIGNED_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
match_offset += aligned_bits;
}
else if (extra > 0)
{
// 1-2: verbatim bits only
lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref verbatim_bits, extra, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
match_offset += (uint)verbatim_bits;
}
else
@@ -819,28 +862,43 @@ namespace LibMSPackSharp.Compression
if (match_length == LZX_MAX_MATCH && lzx.IsDelta)
{
int extra_len = 0;
lzx.ENSURE_BITS(3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer); /* 4 entry huffman tree */
if (lzx.PEEK_BITS(1, bit_buffer) == 0)
/* 4 entry huffman tree */
lzx.ENSURE_BITS(3, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
if (lzx.PEEK_BITS(1, bit_buffer, msb: true) == 0)
{
lzx.REMOVE_BITS(1, ref bits_left, ref bit_buffer); /* '0' . 8 extra length bits */
lzx.READ_BITS(ref extra_len, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.REMOVE_BITS(1, ref bits_left, ref bit_buffer, msb: true); /* '0' . 8 extra length bits */
lzx.READ_BITS(ref extra_len, 8, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
}
else if (lzx.PEEK_BITS(2, bit_buffer) == 2)
else if (lzx.PEEK_BITS(2, bit_buffer, msb: true) == 2)
{
lzx.REMOVE_BITS(2, ref bits_left, ref bit_buffer); /* '10' . 10 extra length bits + 0x100 */
lzx.READ_BITS(ref extra_len, 10, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.REMOVE_BITS(2, ref bits_left, ref bit_buffer, msb: true); /* '10' . 10 extra length bits + 0x100 */
lzx.READ_BITS(ref extra_len, 10, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
extra_len += 0x100;
}
else if (lzx.PEEK_BITS(3, bit_buffer) == 6)
else if (lzx.PEEK_BITS(3, bit_buffer, msb: true) == 6)
{
lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer); /* '110' . 12 extra length bits + 0x500 */
lzx.READ_BITS(ref extra_len, 12, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer, msb: true); /* '110' . 12 extra length bits + 0x500 */
lzx.READ_BITS(ref extra_len, 12, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
extra_len += 0x500;
}
else
{
lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer); /* '111' . 15 extra length bits */
lzx.READ_BITS(ref extra_len, 15, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.REMOVE_BITS(3, ref bits_left, ref bit_buffer, msb: true); /* '111' . 15 extra length bits */
lzx.READ_BITS(ref extra_len, 15, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
}
match_length += extra_len;
@@ -960,10 +1018,14 @@ namespace LibMSPackSharp.Compression
// Re-align input bitstream
if (bits_left > 0)
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
{
lzx.ENSURE_BITS(16, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
}
if ((bits_left & 15) != 0)
lzx.REMOVE_BITS((int)(bits_left & 15), ref bits_left, ref bit_buffer);
lzx.REMOVE_BITS((int)(bits_left & 15), ref bits_left, ref bit_buffer, msb: true);
// Check that we've used all of the previous frame first
if (lzx.OutputPointer != lzx.OutputLength)
@@ -1072,7 +1134,6 @@ namespace LibMSPackSharp.Compression
// Bit buffer and huffman symbol decode variables
uint bit_buffer = 0, bits_left = 0;
int i = 0;
ushort sym = 0;
int i_ptr = 0, i_end = 0;
int x, y = 0;
@@ -1083,12 +1144,15 @@ namespace LibMSPackSharp.Compression
// Read lengths for pretree (20 symbols, lengths stored in fixed 4 bits)
for (x = 0; x < 20; x++)
{
lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
lzx.PRETREE_len[x] = (byte)y;
}
//BUILD_TABLE(PRETREE)
if (LZXDStream.MakeDecodeTable(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, lzx.PRETREE_table) != 0)
if (!LZXDStream.MakeDecodeTable(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, lzx.PRETREE_table, msb: true))
{
Console.WriteLine("failed to build PRETREE table");
return lzx.Error = Error.MSPACK_ERR_DECRUNCH;
@@ -1096,11 +1160,17 @@ namespace LibMSPackSharp.Compression
for (x = (int)first; x < last;)
{
lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_OK;
if (z == 17)
{
// Code = 17, run of ([read 4 bits]+4) zeros
lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 4;
lzx.READ_BITS(ref y, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
y += 4;
while (y-- != 0)
{
lens[x++] = 0;
@@ -1109,7 +1179,11 @@ namespace LibMSPackSharp.Compression
else if (z == 18)
{
// Code = 18, run of ([read 5 bits]+20) zeros
lzx.READ_BITS(ref y, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 20;
lzx.READ_BITS(ref y, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
y += 20;
while (y-- != 0)
{
lens[x++] = 0;
@@ -1118,8 +1192,14 @@ namespace LibMSPackSharp.Compression
else if (z == 19)
{
// Code = 19, run of ([read 1 bit]+4) [read huffman symbol]
lzx.READ_BITS(ref y, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left); y += 4;
lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
lzx.READ_BITS(ref y, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzx.Error != Error.MSPACK_ERR_OK)
return lzx.Error;
y += 4;
if (lzx.READ_HUFFSYM(lzx.PRETREE_table, ref z, LZX_PRETREE_TABLEBITS, lzx.PRETREE_len, LZX_PRETREE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
z = lens[x] - z;
if (z < 0)
z += 17;

View File

@@ -137,21 +137,21 @@ namespace LibMSPackSharp.Compression
// This is used purely for doing the intel E8 transform
public byte[] e8_buf { get; set; } = new byte[LZX.LZX_FRAME_SIZE];
public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb)
{
Error error = READ_IF_NEEDED(ref i_ptr, ref i_end);
if (error != Error.MSPACK_ERR_OK)
return error;
READ_IF_NEEDED(ref i_ptr, ref i_end);
if (Error != Error.MSPACK_ERR_OK)
return;
byte b0 = InputBuffer[i_ptr++];
error = READ_IF_NEEDED(ref i_ptr, ref i_end);
if (error != Error.MSPACK_ERR_OK)
return error;
READ_IF_NEEDED(ref i_ptr, ref i_end);
if (Error != Error.MSPACK_ERR_OK)
return;
byte b1 = InputBuffer[i_ptr++];
INJECT_BITS((uint)((b1 << 8) | b0), 16, ref bitsLeft, ref bitBuffer);
return Error.MSPACK_ERR_OK;
INJECT_BITS((uint)((b1 << 8) | b0), 16, ref bitsLeft, ref bitBuffer, msb);
Error = Error.MSPACK_ERR_OK;
}
public override int HUFF_ERROR() => (int)(Error = Error.MSPACK_ERR_DECRUNCH);

View File

@@ -27,27 +27,12 @@ namespace LibMSPackSharp.Compression
// 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 static int MSZIP_LITERAL_TABLESIZE
{
get
{
if ((1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2))
return (MSZIP_LITERAL_MAXSYMBOLS * 4);
else
return ((1 << MSZIP_LITERAL_TABLEBITS) + (MSZIP_LITERAL_MAXSYMBOLS * 2));
}
}
public static int MSZIP_DISTANCE_TABLESIZE
{
get
{
if ((1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2))
return (MSZIP_DISTANCE_MAXSYMBOLS * 4);
else
return ((1 << MSZIP_DISTANCE_TABLEBITS) + (MSZIP_DISTANCE_MAXSYMBOLS * 2));
}
}
//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
@@ -203,12 +188,15 @@ namespace LibMSPackSharp.Compression
// Skip to next read 'CK' header
i = (int)(bits_left & 7);
zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer); // Align to bytestream
zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb: false); // Align to bytestream
state = 0;
do
{
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return zip.Error;
if (i == 'C')
state = 1;
else if ((state == 1) && (i == 'K'))
@@ -224,7 +212,7 @@ namespace LibMSPackSharp.Compression
if ((error = (int)Inflate(zip)) != 0)
{
Console.WriteLine($"inflate error {error}");
Console.WriteLine($"inflate error {(InflateErrorCode)error}");
if (zip.RepairMode)
{
// Recover partially-inflated buffers
@@ -249,8 +237,16 @@ namespace LibMSPackSharp.Compression
// Write a frame
i = (out_bytes < zip.BytesOutput) ? (int)out_bytes : zip.BytesOutput;
if (zip.Sys.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i)
return zip.Error = Error.MSPACK_ERR_WRITE;
if (zip.Output is DefaultFileImpl)
{
if (SystemImpl.DefaultSystem.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i)
return zip.Error = Error.MSPACK_ERR_WRITE;
}
else
{
if (zip.Sys.Write(zip.Output, zip.Window, zip.OutputPointer, i) != i)
return zip.Error = Error.MSPACK_ERR_WRITE;
}
// mspack errors (i.e. read errors) are fatal and can't be recovered
if (error > 0 && zip.RepairMode)
@@ -288,20 +284,30 @@ namespace LibMSPackSharp.Compression
// Align to bytestream, read block_len
i = (int)(bits_left & 7);
zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer);
zip.READ_BITS(ref block_len, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb: false);
zip.READ_BITS(ref block_len, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return zip.Error;
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return zip.Error;
block_len |= i << 8;
if (block_len == 0)
break;
// Read "CK" header
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return zip.Error;
if (i != 'C')
return Error.MSPACK_ERR_DATAFORMAT;
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return zip.Error;
if (i != 'K')
return Error.MSPACK_ERR_DATAFORMAT;
@@ -311,7 +317,7 @@ namespace LibMSPackSharp.Compression
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
if ((error = (int)Inflate(zip)) != 0)
{
Console.WriteLine($"inflate error {error}");
Console.WriteLine($"inflate error {(InflateErrorCode)error}");
return zip.Error = (error > 0) ? (Error)error : Error.MSPACK_ERR_DECRUNCH;
}
@@ -339,7 +345,7 @@ namespace LibMSPackSharp.Compression
}
}
private static InflateErrorCode ZipReadLens(MSZIPDStream zip)
private static InflateErrorCode ReadLens(MSZIPDStream zip)
{
// For the bit buffer and huffman decoding
uint bit_buffer = 0, bits_left = 0;
@@ -355,11 +361,20 @@ namespace LibMSPackSharp.Compression
zip.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
// Read the number of codes
zip.READ_BITS(ref lit_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref lit_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
lit_codes += 257;
zip.READ_BITS(ref dist_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref dist_codes, 5, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
dist_codes += 1;
zip.READ_BITS(ref bitlen_codes, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref bitlen_codes, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
bitlen_codes += 4;
if (lit_codes > MSZIP_LITERAL_MAXSYMBOLS)
@@ -371,7 +386,10 @@ namespace LibMSPackSharp.Compression
for (i = 0; i < bitlen_codes; i++)
{
int blLenTemp = bl_len[bitlen_order[i]];
zip.READ_BITS(ref blLenTemp, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref blLenTemp, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
bl_len[bitlen_order[i]] = (byte)blLenTemp;
}
@@ -380,17 +398,20 @@ namespace LibMSPackSharp.Compression
bl_len[bitlen_order[i++]] = 0;
}
// Create decoding table with an immediate lookup */
if (MSZIPDStream.MakeDecodeTable(19, 7, bl_len, bl_table) != 0)
// Create decoding table with an immediate lookup
if (!MSZIPDStream.MakeDecodeTable(19, 7, bl_len, bl_table, msb: false))
return InflateErrorCode.INF_ERR_BITLENTBL;
// Read literal / distance code lengths
for (i = 0; i < (lit_codes + dist_codes); i++)
{
// Single-level huffman lookup
zip.ENSURE_BITS(7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
code = bl_table[zip.PEEK_BITS(7, bit_buffer)];
zip.REMOVE_BITS(bl_len[code], ref bits_left, ref bit_buffer);
zip.ENSURE_BITS(7, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITBUF;
code = bl_table[zip.PEEK_BITS(7, bit_buffer, msb: false)];
zip.REMOVE_BITS(bl_len[code], ref bits_left, ref bit_buffer, msb: false);
if (code < 16)
{
@@ -401,19 +422,28 @@ namespace LibMSPackSharp.Compression
switch (code)
{
case 16:
zip.READ_BITS(ref run, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref run, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
run += 3;
code = last_code;
break;
case 17:
zip.READ_BITS(ref run, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref run, 3, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
run += 3;
code = 0;
break;
case 18:
zip.READ_BITS(ref run, 7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref run, 7, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
run += 11;
code = 0;
break;
@@ -463,18 +493,22 @@ namespace LibMSPackSharp.Compression
// For the bit buffer and huffman decoding
uint bit_buffer = 0, bits_left = 0;
ushort sym = 0;
int i_ptr = 0, i_end = 0;
InflateErrorCode err;
zip.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
do
{
// Read in last block bit
zip.READ_BITS(ref last_block, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref last_block, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
// Read in block type
zip.READ_BITS(ref block_type, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS(ref block_type, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITOVERRUN;
if (block_type == 0)
{
@@ -483,7 +517,7 @@ namespace LibMSPackSharp.Compression
// Go to byte boundary
i = (int)(bits_left & 7);
zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer);
zip.REMOVE_BITS(i, ref bits_left, ref bit_buffer, msb: false);
// Read 4 bytes of data, emptying the bit-buffer if necessary
for (i = 0; (bits_left >= 8); i++)
@@ -491,13 +525,19 @@ namespace LibMSPackSharp.Compression
if (i == 4)
return InflateErrorCode.INF_ERR_BITBUF;
lens_buf[i] = (byte)zip.PEEK_BITS(8, bit_buffer);
zip.REMOVE_BITS(8, ref bits_left, ref bit_buffer);
lens_buf[i] = (byte)zip.PEEK_BITS(8, bit_buffer, msb: false);
zip.REMOVE_BITS(8, ref bits_left, ref bit_buffer, msb: false);
}
if (bits_left != 0) return InflateErrorCode.INF_ERR_BITBUF;
if (bits_left != 0)
return InflateErrorCode.INF_ERR_BITBUF;
while (i < 4)
{
zip.READ_IF_NEEDED(ref i_ptr, ref i_end);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITBUF;
lens_buf[i++] = zip.InputBuffer[i_ptr++];
}
@@ -511,9 +551,13 @@ namespace LibMSPackSharp.Compression
while (length > 0)
{
zip.READ_IF_NEEDED(ref i_ptr, ref i_end);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_BITBUF;
this_run = length;
if (this_run > (uint)(i_end - i_ptr)) this_run = i_end - i_ptr;
if (this_run > (uint)(i_end - i_ptr))
this_run = i_end - i_ptr;
if (this_run > (MSZIP_FRAME_SIZE - zip.WindowPosition))
this_run = (int)(MSZIP_FRAME_SIZE - zip.WindowPosition);
@@ -571,7 +615,7 @@ namespace LibMSPackSharp.Compression
// Block with dynamic Huffman codes
zip.STORE_BITS(i_ptr, i_end, bit_buffer, bits_left);
if ((i = (int)ZipReadLens(zip)) != 0)
if ((i = (int)ReadLens(zip)) != 0)
return (InflateErrorCode)i;
zip.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
@@ -579,16 +623,24 @@ namespace LibMSPackSharp.Compression
// Now huffman lengths are read for either kind of block,
// create huffman decoding tables
if (MSZIPDStream.MakeDecodeTable(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, zip.LITERAL_table) != 0)
return InflateErrorCode.INF_ERR_LITERALTBL;
if (!MSZIPDStream.MakeDecodeTable(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, zip.LITERAL_table, msb: false))
{
// TODO: Figure out why this always gets hit
//return InflateErrorCode.INF_ERR_LITERALTBL;
}
if (MSZIPDStream.MakeDecodeTable(MSZIP_DISTANCE_MAXSYMBOLS, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, zip.DISTANCE_table) != 0)
return InflateErrorCode.INF_ERR_DISTANCETBL;
if (!MSZIPDStream.MakeDecodeTable(MSZIP_DISTANCE_MAXSYMBOLS, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, zip.DISTANCE_table, msb: false))
{
// TODO: Figure out why this always gets hit
//return InflateErrorCode.INF_ERR_DISTANCETBL;
}
// Decode forever until end of block code
for (; ; )
{
zip.READ_HUFFSYM(zip.LITERAL_table, ref code, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, MSZIP_LITERAL_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if ((err = (InflateErrorCode)zip.READ_HUFFSYM(zip.LITERAL_table, ref code, MSZIP_LITERAL_TABLEBITS, zip.LITERAL_len, MSZIP_LITERAL_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: false)) != InflateErrorCode.INF_ERR_OK)
return err;
if (code < 256)
{
zip.Window[zip.WindowPosition++] = (byte)code;
@@ -613,14 +665,22 @@ namespace LibMSPackSharp.Compression
if (code >= 29)
return InflateErrorCode.INF_ERR_LITCODE; // Codes 286-287 are illegal
zip.READ_BITS_T(ref length, lit_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS_T(ref length, lit_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_LITCODE;
length += lit_lengths[code];
zip.READ_HUFFSYM(zip.DISTANCE_table, ref code, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, MSZIP_DISTANCE_MAXSYMBOLS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if ((err = (InflateErrorCode)zip.READ_HUFFSYM(zip.DISTANCE_table, ref code, MSZIP_DISTANCE_TABLEBITS, zip.DISTANCE_len, MSZIP_DISTANCE_MAXSYMBOLS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: false)) != 0)
return err;
if (code >= 30)
return InflateErrorCode.INF_ERR_DISTCODE;
zip.READ_BITS_T(ref distance, dist_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
zip.READ_BITS_T(ref distance, dist_extrabits[code], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: false);
if (zip.Error != Error.MSPACK_ERR_OK)
return InflateErrorCode.INF_ERR_DISTCODE;
distance += dist_offsets[code];
// Match position is window position minus distance. If distance

View File

@@ -49,14 +49,14 @@ namespace LibMSPackSharp.Compression
#endregion
public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb)
{
Error error = READ_IF_NEEDED(ref i_ptr, ref i_end);
if (error != Error.MSPACK_ERR_OK)
return error;
READ_IF_NEEDED(ref i_ptr, ref i_end);
if (Error != Error.MSPACK_ERR_OK)
return;
INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer);
return Error.MSPACK_ERR_OK;
INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer, msb);
Error = Error.MSPACK_ERR_OK;
}
public override int HUFF_ERROR() => (int)InflateErrorCode.INF_ERR_HUFFSYM;

View File

@@ -225,7 +225,7 @@ namespace LibMSPackSharp.Compression
high = 0xFFFF;
low = 0;
int tempCurrent = current;
qtm.READ_BITS(ref tempCurrent, 16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_BITS(ref tempCurrent, 16, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
current = (ushort)tempCurrent;
qtm.HeaderRead = 1;
}
@@ -266,7 +266,10 @@ namespace LibMSPackSharp.Compression
// Selector 4 = fixed length match (3 bytes)
case 4:
GET_SYMBOL(qtm, qtm.Model4, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (qtm.Error != Error.MSPACK_ERR_OK)
return qtm.Error;
match_offset = position_base[sym] + extra + 1;
match_length = 3;
break;
@@ -274,7 +277,10 @@ namespace LibMSPackSharp.Compression
// Selector 5 = fixed length match (4 bytes)
case 5:
GET_SYMBOL(qtm, qtm.Model5, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (qtm.Error != Error.MSPACK_ERR_OK)
return qtm.Error;
match_offset = position_base[sym] + extra + 1;
match_length = 4;
break;
@@ -282,11 +288,17 @@ namespace LibMSPackSharp.Compression
// Selector 6 = variable length match
case 6:
GET_SYMBOL(qtm, qtm.Model6Len, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, length_extra[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, length_extra[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (qtm.Error != Error.MSPACK_ERR_OK)
return qtm.Error;
match_length = (int)(length_base[sym] + extra + 5);
GET_SYMBOL(qtm, qtm.Model6, ref sym, ref range, ref symf, ref high, ref low, ref current, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_MANY_BITS(ref extra, extra_bits[sym], ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (qtm.Error != Error.MSPACK_ERR_OK)
return qtm.Error;
match_offset = position_base[sym] + extra + 1;
break;
@@ -407,14 +419,14 @@ namespace LibMSPackSharp.Compression
{
// Re-align input
if ((bits_left & 7) != 0)
qtm.REMOVE_BITS((int)bits_left & 7, ref bits_left, ref bit_buffer);
qtm.REMOVE_BITS((int)bits_left & 7, ref bits_left, ref bit_buffer, msb: true);
// 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
{
qtm.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
qtm.READ_BITS(ref i, 8, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
} while (i != 0xFF);
qtm.HeaderRead = 0;
@@ -533,9 +545,13 @@ namespace LibMSPackSharp.Compression
low <<= 1;
high = (ushort)((high << 1) | 1);
qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
current = (ushort)((current << 1) | qtm.PEEK_BITS(1, bit_buffer));
qtm.REMOVE_BITS(1, ref bits_left, ref bit_buffer);
qtm.ENSURE_BITS(1, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true);
if (qtm.Error != Error.MSPACK_ERR_OK)
return;
current = (ushort)((current << 1) | qtm.PEEK_BITS(1, bit_buffer, msb: true));
qtm.REMOVE_BITS(1, ref bits_left, ref bit_buffer, msb: true);
}
}

View File

@@ -120,21 +120,21 @@ namespace LibMSPackSharp.Compression
public QTMDModelSym[] Model7Symbols { get; set; } = new QTMDModelSym[7 + 1];
public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb)
{
Error error = READ_IF_NEEDED(ref i_ptr, ref i_end);
if (error != Error.MSPACK_ERR_OK)
return error;
READ_IF_NEEDED(ref i_ptr, ref i_end);
if (Error != Error.MSPACK_ERR_OK)
return;
byte b0 = InputBuffer[i_ptr++];
error = READ_IF_NEEDED(ref i_ptr, ref i_end);
if (error != Error.MSPACK_ERR_OK)
return error;
READ_IF_NEEDED(ref i_ptr, ref i_end);
if (Error != Error.MSPACK_ERR_OK)
return;
byte b1 = InputBuffer[i_ptr++];
INJECT_BITS((uint)((b0 << 8) | b1), 16, ref bitsLeft, ref bitBuffer);
return Error.MSPACK_ERR_OK;
INJECT_BITS((uint)((b0 << 8) | b1), 16, ref bitsLeft, ref bitBuffer, msb);
Error = Error.MSPACK_ERR_OK;
}
public override int HUFF_ERROR() => (int)Error.MSPACK_ERR_OK;

View File

@@ -45,60 +45,21 @@ namespace LibMSPackSharp.KWAJ
// Define decoding table sizes
public const int KWAJ_TABLESIZE = (1 << KWAJ_TABLEBITS);
public static int KWAJ_MATCHLEN1_TBLSIZE
{
get
{
if (KWAJ_TABLESIZE < (KWAJ_MATCHLEN1_SYMS * 2))
return (KWAJ_MATCHLEN1_SYMS * 4);
else
return (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2));
}
}
public static int KWAJ_MATCHLEN2_TBLSIZE
{
get
{
if (KWAJ_TABLESIZE < (KWAJ_MATCHLEN2_SYMS * 2))
return (KWAJ_MATCHLEN2_SYMS * 4);
else
return (KWAJ_TABLESIZE + (KWAJ_MATCHLEN2_SYMS * 2));
}
}
//public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_MATCHLEN1_SYMS * 4);
public const int KWAJ_MATCHLEN1_TBLSIZE = (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2));
public static int KWAJ_LITLEN_TBLSIZE
{
get
{
if (KWAJ_TABLESIZE < (KWAJ_LITLEN_SYMS * 2))
return (KWAJ_LITLEN_SYMS * 4);
else
return (KWAJ_TABLESIZE + (KWAJ_LITLEN_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 static int KWAJ_OFFSET_TBLSIZE
{
get
{
if (KWAJ_TABLESIZE < (KWAJ_OFFSET_SYMS * 2))
return (KWAJ_OFFSET_SYMS * 4);
else
return (KWAJ_TABLESIZE + (KWAJ_OFFSET_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 static int KWAJ_LITERAL_TBLSIZE
{
get
{
if (KWAJ_TABLESIZE < (KWAJ_LITERAL_SYMS * 2))
return (KWAJ_LITERAL_SYMS * 4);
else
return (KWAJ_TABLESIZE + (KWAJ_LITERAL_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
@@ -465,7 +426,6 @@ namespace LibMSPackSharp.KWAJ
{
uint bit_buffer = 0, bits_left = 0, len = 0, j = 0;
int i;
ushort sym = 0;
int i_ptr = 0, i_end = 0;
bool lit_run = false;
int pos = 0, offset;
@@ -483,7 +443,9 @@ namespace LibMSPackSharp.KWAJ
for (i = 0; i < 6; i++)
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref types[i], 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref types[i], 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.Error != Error.MSPACK_ERR_OK)
return lzh.Error;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
}
@@ -497,7 +459,7 @@ namespace LibMSPackSharp.KWAJ
return err;
lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (InternalStream.MakeDecodeTable(KWAJ_MATCHLEN1_SYMS, (uint)KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, lzh.MATCHLEN1_table) != 0)
if (!InternalStream.MakeDecodeTable(KWAJ_MATCHLEN1_SYMS, KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, lzh.MATCHLEN1_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
//BUILD_TREE(tbl, type)
@@ -507,7 +469,7 @@ namespace LibMSPackSharp.KWAJ
return err;
lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (InternalStream.MakeDecodeTable(KWAJ_MATCHLEN2_SYMS, (uint)KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, lzh.MATCHLEN2_table) != 0)
if (!InternalStream.MakeDecodeTable(KWAJ_MATCHLEN2_SYMS, KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, lzh.MATCHLEN2_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
//BUILD_TREE(tbl, type)
@@ -517,7 +479,7 @@ namespace LibMSPackSharp.KWAJ
return err;
lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (InternalStream.MakeDecodeTable(KWAJ_LITLEN_SYMS, (uint)KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, lzh.LITLEN_table) != 0)
if (!InternalStream.MakeDecodeTable(KWAJ_LITLEN_SYMS, KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, lzh.LITLEN_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
//BUILD_TREE(tbl, type)
@@ -527,7 +489,7 @@ namespace LibMSPackSharp.KWAJ
return err;
lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (InternalStream.MakeDecodeTable(KWAJ_OFFSET_SYMS, (uint)KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, lzh.OFFSET_table) != 0)
if (!InternalStream.MakeDecodeTable(KWAJ_OFFSET_SYMS, KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, lzh.OFFSET_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
//BUILD_TREE(tbl, type)
@@ -537,7 +499,7 @@ namespace LibMSPackSharp.KWAJ
return err;
lzh.RESTORE_BITS(ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
if (InternalStream.MakeDecodeTable(KWAJ_LITERAL_SYMS, (uint)KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, lzh.LITERAL_table) != 0)
if (!InternalStream.MakeDecodeTable(KWAJ_LITERAL_SYMS, KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, lzh.LITERAL_table, msb: true))
return Error.MSPACK_ERR_DATAFORMAT;
while (lzh.InputEnd == 0)
@@ -545,14 +507,16 @@ namespace LibMSPackSharp.KWAJ
if (lit_run)
{
//READ_HUFFSYM_SAFE(tbl, val)
lzh.READ_HUFFSYM(lzh.MATCHLEN2_table, ref len, KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzh.READ_HUFFSYM(lzh.MATCHLEN2_table, ref len, KWAJ_MATCHLEN2_TBLSIZE, lzh.MATCHLEN2_len, KWAJ_MATCHLEN2_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
}
else
{
//READ_HUFFSYM_SAFE(tbl, val)
lzh.READ_HUFFSYM(lzh.MATCHLEN1_table, ref len, KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzh.READ_HUFFSYM(lzh.MATCHLEN1_table, ref len, KWAJ_MATCHLEN1_TBLSIZE, lzh.MATCHLEN1_len, KWAJ_MATCHLEN1_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
}
@@ -563,7 +527,8 @@ namespace LibMSPackSharp.KWAJ
lit_run = false; // Not the end of a literal run
//READ_HUFFSYM_SAFE(tbl, val)
lzh.READ_HUFFSYM(lzh.OFFSET_table, ref j, KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, KWAJ_OFFSET_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzh.READ_HUFFSYM(lzh.OFFSET_table, ref j, KWAJ_OFFSET_TBLSIZE, lzh.OFFSET_len, KWAJ_OFFSET_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -571,7 +536,9 @@ namespace LibMSPackSharp.KWAJ
//READ_BITS_SAFE(val, n)
int tempj = (int)j;
lzh.READ_BITS(ref tempj, 6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref tempj, 6, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.Error != Error.MSPACK_ERR_OK)
return lzh.Error;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -591,7 +558,8 @@ namespace LibMSPackSharp.KWAJ
else
{
//READ_HUFFSYM_SAFE(tbl, val)
lzh.READ_HUFFSYM(lzh.LITLEN_table, ref len, KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, KWAJ_LITLEN_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzh.READ_HUFFSYM(lzh.LITLEN_table, ref len, KWAJ_LITLEN_TBLSIZE, lzh.LITLEN_len, KWAJ_LITLEN_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -601,7 +569,8 @@ namespace LibMSPackSharp.KWAJ
while (len-- > 0)
{
//READ_HUFFSYM_SAFE(tbl, val)
lzh.READ_HUFFSYM(lzh.LITERAL_table, ref j, KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, KWAJ_LITERAL_SYMS, ref i, ref sym, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer);
if (lzh.READ_HUFFSYM(lzh.LITERAL_table, ref j, KWAJ_LITERAL_TBLSIZE, lzh.LITERAL_len, KWAJ_LITERAL_SYMS, ref i, ref i_ptr, ref i_end, ref bits_left, ref bit_buffer, msb: true) != 0)
return Error.MSPACK_ERR_DECRUNCH;
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -650,7 +619,7 @@ namespace LibMSPackSharp.KWAJ
case 1:
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -658,7 +627,7 @@ namespace LibMSPackSharp.KWAJ
for (i = 1; i < numsyms; i++)
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -669,7 +638,7 @@ namespace LibMSPackSharp.KWAJ
else
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref sel, 1, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -680,7 +649,7 @@ namespace LibMSPackSharp.KWAJ
else
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -692,7 +661,7 @@ namespace LibMSPackSharp.KWAJ
case 2:
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
@@ -700,14 +669,14 @@ namespace LibMSPackSharp.KWAJ
for (i = 1; i < numsyms; i++)
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref sel, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref sel, 2, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
if (sel == 3)
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;
}
@@ -725,7 +694,7 @@ namespace LibMSPackSharp.KWAJ
for (i = 0; i < numsyms; i++)
{
//READ_BITS_SAFE(val, n)
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left);
lzh.READ_BITS(ref c, 4, ref i_ptr, ref i_end, ref bit_buffer, ref bits_left, msb: true);
if (lzh.InputEnd != 0 && bits_left < lzh.InputEnd)
return Error.MSPACK_ERR_OK;

View File

@@ -33,20 +33,19 @@ namespace LibMSPackSharp.KWAJ
public byte[] Window { get; set; } = new byte[LZSS.LZSS_WINDOW_SIZE];
public override Error READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer)
public override void READ_BYTES(ref int i_ptr, ref int i_end, ref uint bitsLeft, ref uint bitBuffer, bool msb)
{
Error error = Error.MSPACK_ERR_OK;
if (i_ptr >= i_end)
{
if ((error = Implementation.LZHReadInput(this)) != Error.MSPACK_ERR_OK)
return error;
if ((Error = Implementation.LZHReadInput(this)) != Error.MSPACK_ERR_OK)
return;
i_ptr = InputPointer;
i_end = InputLength;
}
INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer);
return error;
INJECT_BITS(InputBuffer[i_ptr++], 8, ref bitsLeft, ref bitBuffer, msb);
Error = Error.MSPACK_ERR_OK;
}
public override int HUFF_ERROR() => (int)Error.MSPACK_ERR_DATAFORMAT;

View File

@@ -85,16 +85,21 @@ namespace LibMSPackSharp.OAB
private static int SysWrite(object baseFile, byte[] buf, int pointer, int size)
{
InternalFile file = baseFile as InternalFile;
if (file == null)
return 0;
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);
int bytes_written = file.OrigSys.Write(file.OrigFile, buf, pointer, size);
return bytes_written;
}
else if (baseFile is DefaultFileImpl impl)
{
return SystemImpl.DefaultSystem.Write(impl, buf, pointer, size);
}
if (bytes_written > 0)
file.CRC = Checksum.CRC32(buf, 0, bytes_written, file.CRC);
return bytes_written;
// Unknown file to write to
return 0;
}
#endregion