mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Extract out FileTypes namespace
This commit is contained in:
@@ -10,12 +10,11 @@ using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.FileTypes;
|
||||
using SabreTools.Filtering;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Logging;
|
||||
using SabreTools.Library.DatItems;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Library.Reports;
|
||||
using SabreTools.Skippers;
|
||||
using NaturalSort;
|
||||
@@ -2556,7 +2555,7 @@ namespace SabreTools.Library.DatFiles
|
||||
outputFormat = Header.ForcePacking.AsOutputFormat();
|
||||
|
||||
// Preload the Skipper list
|
||||
Transform.Init();
|
||||
SkipperMatch.Init();
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -2696,7 +2695,7 @@ namespace SabreTools.Library.DatFiles
|
||||
outputFormat = Header.ForcePacking.AsOutputFormat();
|
||||
|
||||
// Preload the Skipper list
|
||||
Transform.Init();
|
||||
SkipperMatch.Init();
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -2908,7 +2907,7 @@ namespace SabreTools.Library.DatFiles
|
||||
if (Header.HeaderSkipper != null)
|
||||
{
|
||||
// Check to see if we have a matching header first
|
||||
SkipperRule rule = Transform.GetMatchingRule(fileStream, Path.GetFileNameWithoutExtension(Header.HeaderSkipper));
|
||||
SkipperRule rule = SkipperMatch.GetMatchingRule(fileStream, Path.GetFileNameWithoutExtension(Header.HeaderSkipper));
|
||||
|
||||
// If there's a match, create the new file to write
|
||||
if (rule.Tests != null && rule.Tests.Count != 0)
|
||||
|
||||
@@ -5,9 +5,9 @@ using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.FileTypes;
|
||||
using SabreTools.Filtering;
|
||||
using SabreTools.Logging;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using NaturalSort;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
@@ -4,8 +4,8 @@ using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.FileTypes;
|
||||
using SabreTools.Filtering;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.FileTypes;
|
||||
using SabreTools.Filtering;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SabreTools.Library.DatItems
|
||||
|
||||
@@ -6,8 +6,8 @@ using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.FileTypes;
|
||||
using SabreTools.Filtering;
|
||||
using SabreTools.Library.FileTypes;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
|
||||
214
SabreTools.Library/External/Compress/File/File.cs
vendored
214
SabreTools.Library/External/Compress/File/File.cs
vendored
@@ -1,214 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Compress.Utils;
|
||||
using Path = RVIO.Path;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.File
|
||||
{
|
||||
public class File : ICompress
|
||||
{
|
||||
private FileInfo _fileInfo;
|
||||
private Stream _inStream;
|
||||
private byte[] _crc;
|
||||
|
||||
public string ZipFilename => _fileInfo?.FullName ?? string.Empty;
|
||||
|
||||
public long TimeStamp => _fileInfo?.LastWriteTime ?? 0;
|
||||
|
||||
public ZipOpenType ZipOpen { get; private set; }
|
||||
|
||||
|
||||
public ZipStatus ZipStatus { get; private set; }
|
||||
|
||||
public int LocalFilesCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public string Filename(int i)
|
||||
{
|
||||
return Path.GetFileName(ZipFilename);
|
||||
}
|
||||
|
||||
public bool IsDirectory(int i)
|
||||
{
|
||||
return RVIO.Directory.Exists(ZipFilename);
|
||||
}
|
||||
|
||||
public ulong UncompressedSize(int i)
|
||||
{
|
||||
return _fileInfo != null ? (ulong)_fileInfo.Length : 0;
|
||||
}
|
||||
|
||||
public ulong? LocalHeader(int i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ZipReturn FileStatus(int i)
|
||||
{
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public byte[] CRC32(int i)
|
||||
{
|
||||
return _crc;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename)
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.Closed)
|
||||
{
|
||||
return ZipReturn.ZipFileAlreadyOpen;
|
||||
}
|
||||
|
||||
DirUtil.CreateDirForFile(newFilename);
|
||||
_fileInfo = new FileInfo(newFilename);
|
||||
|
||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _inStream);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenWrite;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
public void ZipFileClose()
|
||||
{
|
||||
if (ZipOpen == ZipOpenType.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZipOpen == ZipOpenType.OpenRead)
|
||||
{
|
||||
if (_inStream != null)
|
||||
{
|
||||
_inStream.Close();
|
||||
_inStream.Dispose();
|
||||
}
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
return;
|
||||
}
|
||||
|
||||
_inStream.Flush();
|
||||
_inStream.Close();
|
||||
_inStream.Dispose();
|
||||
_fileInfo = new FileInfo(_fileInfo.FullName);
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileOpen(string newFilename, long timestamp, bool readHeaders)
|
||||
{
|
||||
ZipFileClose();
|
||||
ZipStatus = ZipStatus.None;
|
||||
_fileInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (!RVIO.File.Exists(newFilename))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorFileNotFound;
|
||||
}
|
||||
_fileInfo = new FileInfo(newFilename);
|
||||
if (timestamp != -1 && _fileInfo.LastWriteTime != timestamp)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorTimeStamp;
|
||||
}
|
||||
int errorCode = FileStream.OpenFileRead(newFilename, out _inStream);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
if (errorCode == 32)
|
||||
{
|
||||
return ZipReturn.ZipFileLocked;
|
||||
}
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipFileNameToLong;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
|
||||
if (!readHeaders)
|
||||
{
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
//return ZipFileReadHeaders();
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileOpen(Stream inStream)
|
||||
{
|
||||
ZipFileClose();
|
||||
ZipStatus = ZipStatus.None;
|
||||
_fileInfo = null;
|
||||
_inStream = inStream;
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
|
||||
//return ZipFileReadHeaders();
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
||||
{
|
||||
_crc = crc32;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public void ZipFileCloseFailed()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong streamSize)
|
||||
{
|
||||
_inStream.Position = 0;
|
||||
stream = _inStream;
|
||||
streamSize = (ulong)_fileInfo.Length;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, uint? datetime, out Stream stream)
|
||||
{
|
||||
_inStream.Position = 0;
|
||||
stream = _inStream;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCloseReadStream()
|
||||
{
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Compress
|
||||
{
|
||||
public interface ICompress
|
||||
{
|
||||
int LocalFilesCount();
|
||||
|
||||
string Filename(int i);
|
||||
ulong? LocalHeader(int i);
|
||||
ulong UncompressedSize(int i);
|
||||
byte[] CRC32(int i);
|
||||
|
||||
bool IsDirectory(int i);
|
||||
|
||||
ZipOpenType ZipOpen { get; }
|
||||
|
||||
ZipReturn ZipFileOpen(string newFilename, long timestamp = -1, bool readHeaders = true);
|
||||
|
||||
ZipReturn ZipFileOpen(Stream inStream);
|
||||
void ZipFileClose();
|
||||
|
||||
ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong streamSize);
|
||||
ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, uint? datetime, out Stream stream);
|
||||
ZipReturn ZipFileCloseReadStream();
|
||||
|
||||
|
||||
ZipStatus ZipStatus { get; }
|
||||
|
||||
string ZipFilename { get; }
|
||||
long TimeStamp { get; }
|
||||
|
||||
void ZipFileAddZeroLengthFile();
|
||||
|
||||
ZipReturn ZipFileCreate(string newFilename);
|
||||
ZipReturn ZipFileCloseWriteStream(byte[] crc32);
|
||||
void ZipFileCloseFailed();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
public class DataErrorException : Exception
|
||||
{
|
||||
public DataErrorException() : base("Data Error") { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
internal class InvalidParamException : Exception
|
||||
{
|
||||
public InvalidParamException() : base("Invalid Parameter") { }
|
||||
}
|
||||
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
};
|
||||
|
||||
internal interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress);
|
||||
};
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
internal enum CoderPropID
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 - x - 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 - x - 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 - x - 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker
|
||||
};
|
||||
|
||||
|
||||
internal interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
|
||||
};
|
||||
|
||||
internal interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(System.IO.Stream outStream);
|
||||
}
|
||||
|
||||
internal interface ISetDecoderProperties
|
||||
{
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001,2004-2005 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This package is based on the work done by Keiron Liddle, Aftex Software
|
||||
* <keiron@aftexsw.com> to whom the Ant project is very grateful for his
|
||||
* great code.
|
||||
*/
|
||||
|
||||
namespace Compress.SevenZip.Compress.BZip2
|
||||
{
|
||||
/**
|
||||
* Base class for both the compress and decompress classes.
|
||||
* Holds common arrays, and static data.
|
||||
*
|
||||
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
|
||||
*/
|
||||
internal class BZip2Constants
|
||||
{
|
||||
|
||||
public const int baseBlockSize = 100000;
|
||||
public const int MAX_ALPHA_SIZE = 258;
|
||||
public const int MAX_CODE_LEN = 23;
|
||||
public const int RUNA = 0;
|
||||
public const int RUNB = 1;
|
||||
public const int N_GROUPS = 6;
|
||||
public const int G_SIZE = 50;
|
||||
public const int N_ITERS = 4;
|
||||
public const int MAX_SELECTORS = (2 + (900000 / G_SIZE));
|
||||
public const int NUM_OVERSHOOT_BYTES = 20;
|
||||
|
||||
public static int[] rNums = {
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,138 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2001,2004-2005 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This package is based on the work done by Keiron Liddle), Aftex Software
|
||||
* <keiron@aftexsw.com> to whom the Ant project is very grateful for his
|
||||
* great code.
|
||||
*/
|
||||
|
||||
namespace Compress.SevenZip.Compress.BZip2
|
||||
{
|
||||
/**
|
||||
* A simple class the hold and calculate the CRC for sanity checking
|
||||
* of the data.
|
||||
*
|
||||
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
|
||||
*/
|
||||
internal class CRC
|
||||
{
|
||||
private static readonly int[] crc32Table = {
|
||||
unchecked((int)0x00000000), unchecked((int)0x04c11db7), unchecked((int)0x09823b6e), unchecked((int)0x0d4326d9),
|
||||
unchecked((int)0x130476dc), unchecked((int)0x17c56b6b), unchecked((int)0x1a864db2), unchecked((int)0x1e475005),
|
||||
unchecked((int)0x2608edb8), unchecked((int)0x22c9f00f), unchecked((int)0x2f8ad6d6), unchecked((int)0x2b4bcb61),
|
||||
unchecked((int)0x350c9b64), unchecked((int)0x31cd86d3), unchecked((int)0x3c8ea00a), unchecked((int)0x384fbdbd),
|
||||
unchecked((int)0x4c11db70), unchecked((int)0x48d0c6c7), unchecked((int)0x4593e01e), unchecked((int)0x4152fda9),
|
||||
unchecked((int)0x5f15adac), unchecked((int)0x5bd4b01b), unchecked((int)0x569796c2), unchecked((int)0x52568b75),
|
||||
unchecked((int)0x6a1936c8), unchecked((int)0x6ed82b7f), unchecked((int)0x639b0da6), unchecked((int)0x675a1011),
|
||||
unchecked((int)0x791d4014), unchecked((int)0x7ddc5da3), unchecked((int)0x709f7b7a), unchecked((int)0x745e66cd),
|
||||
unchecked((int)0x9823b6e0), unchecked((int)0x9ce2ab57), unchecked((int)0x91a18d8e), unchecked((int)0x95609039),
|
||||
unchecked((int)0x8b27c03c), unchecked((int)0x8fe6dd8b), unchecked((int)0x82a5fb52), unchecked((int)0x8664e6e5),
|
||||
unchecked((int)0xbe2b5b58), unchecked((int)0xbaea46ef), unchecked((int)0xb7a96036), unchecked((int)0xb3687d81),
|
||||
unchecked((int)0xad2f2d84), unchecked((int)0xa9ee3033), unchecked((int)0xa4ad16ea), unchecked((int)0xa06c0b5d),
|
||||
unchecked((int)0xd4326d90), unchecked((int)0xd0f37027), unchecked((int)0xddb056fe), unchecked((int)0xd9714b49),
|
||||
unchecked((int)0xc7361b4c), unchecked((int)0xc3f706fb), unchecked((int)0xceb42022), unchecked((int)0xca753d95),
|
||||
unchecked((int)0xf23a8028), unchecked((int)0xf6fb9d9f), unchecked((int)0xfbb8bb46), unchecked((int)0xff79a6f1),
|
||||
unchecked((int)0xe13ef6f4), unchecked((int)0xe5ffeb43), unchecked((int)0xe8bccd9a), unchecked((int)0xec7dd02d),
|
||||
unchecked((int)0x34867077), unchecked((int)0x30476dc0), unchecked((int)0x3d044b19), unchecked((int)0x39c556ae),
|
||||
unchecked((int)0x278206ab), unchecked((int)0x23431b1c), unchecked((int)0x2e003dc5), unchecked((int)0x2ac12072),
|
||||
unchecked((int)0x128e9dcf), unchecked((int)0x164f8078), unchecked((int)0x1b0ca6a1), unchecked((int)0x1fcdbb16),
|
||||
unchecked((int)0x018aeb13), unchecked((int)0x054bf6a4), unchecked((int)0x0808d07d), unchecked((int)0x0cc9cdca),
|
||||
unchecked((int)0x7897ab07), unchecked((int)0x7c56b6b0), unchecked((int)0x71159069), unchecked((int)0x75d48dde),
|
||||
unchecked((int)0x6b93dddb), unchecked((int)0x6f52c06c), unchecked((int)0x6211e6b5), unchecked((int)0x66d0fb02),
|
||||
unchecked((int)0x5e9f46bf), unchecked((int)0x5a5e5b08), unchecked((int)0x571d7dd1), unchecked((int)0x53dc6066),
|
||||
unchecked((int)0x4d9b3063), unchecked((int)0x495a2dd4), unchecked((int)0x44190b0d), unchecked((int)0x40d816ba),
|
||||
unchecked((int)0xaca5c697), unchecked((int)0xa864db20), unchecked((int)0xa527fdf9), unchecked((int)0xa1e6e04e),
|
||||
unchecked((int)0xbfa1b04b), unchecked((int)0xbb60adfc), unchecked((int)0xb6238b25), unchecked((int)0xb2e29692),
|
||||
unchecked((int)0x8aad2b2f), unchecked((int)0x8e6c3698), unchecked((int)0x832f1041), unchecked((int)0x87ee0df6),
|
||||
unchecked((int)0x99a95df3), unchecked((int)0x9d684044), unchecked((int)0x902b669d), unchecked((int)0x94ea7b2a),
|
||||
unchecked((int)0xe0b41de7), unchecked((int)0xe4750050), unchecked((int)0xe9362689), unchecked((int)0xedf73b3e),
|
||||
unchecked((int)0xf3b06b3b), unchecked((int)0xf771768c), unchecked((int)0xfa325055), unchecked((int)0xfef34de2),
|
||||
unchecked((int)0xc6bcf05f), unchecked((int)0xc27dede8), unchecked((int)0xcf3ecb31), unchecked((int)0xcbffd686),
|
||||
unchecked((int)0xd5b88683), unchecked((int)0xd1799b34), unchecked((int)0xdc3abded), unchecked((int)0xd8fba05a),
|
||||
unchecked((int)0x690ce0ee), unchecked((int)0x6dcdfd59), unchecked((int)0x608edb80), unchecked((int)0x644fc637),
|
||||
unchecked((int)0x7a089632), unchecked((int)0x7ec98b85), unchecked((int)0x738aad5c), unchecked((int)0x774bb0eb),
|
||||
unchecked((int)0x4f040d56), unchecked((int)0x4bc510e1), unchecked((int)0x46863638), unchecked((int)0x42472b8f),
|
||||
unchecked((int)0x5c007b8a), unchecked((int)0x58c1663d), unchecked((int)0x558240e4), unchecked((int)0x51435d53),
|
||||
unchecked((int)0x251d3b9e), unchecked((int)0x21dc2629), unchecked((int)0x2c9f00f0), unchecked((int)0x285e1d47),
|
||||
unchecked((int)0x36194d42), unchecked((int)0x32d850f5), unchecked((int)0x3f9b762c), unchecked((int)0x3b5a6b9b),
|
||||
unchecked((int)0x0315d626), unchecked((int)0x07d4cb91), unchecked((int)0x0a97ed48), unchecked((int)0x0e56f0ff),
|
||||
unchecked((int)0x1011a0fa), unchecked((int)0x14d0bd4d), unchecked((int)0x19939b94), unchecked((int)0x1d528623),
|
||||
unchecked((int)0xf12f560e), unchecked((int)0xf5ee4bb9), unchecked((int)0xf8ad6d60), unchecked((int)0xfc6c70d7),
|
||||
unchecked((int)0xe22b20d2), unchecked((int)0xe6ea3d65), unchecked((int)0xeba91bbc), unchecked((int)0xef68060b),
|
||||
unchecked((int)0xd727bbb6), unchecked((int)0xd3e6a601), unchecked((int)0xdea580d8), unchecked((int)0xda649d6f),
|
||||
unchecked((int)0xc423cd6a), unchecked((int)0xc0e2d0dd), unchecked((int)0xcda1f604), unchecked((int)0xc960ebb3),
|
||||
unchecked((int)0xbd3e8d7e), unchecked((int)0xb9ff90c9), unchecked((int)0xb4bcb610), unchecked((int)0xb07daba7),
|
||||
unchecked((int)0xae3afba2), unchecked((int)0xaafbe615), unchecked((int)0xa7b8c0cc), unchecked((int)0xa379dd7b),
|
||||
unchecked((int)0x9b3660c6), unchecked((int)0x9ff77d71), unchecked((int)0x92b45ba8), unchecked((int)0x9675461f),
|
||||
unchecked((int)0x8832161a), unchecked((int)0x8cf30bad), unchecked((int)0x81b02d74), unchecked((int)0x857130c3),
|
||||
unchecked((int)0x5d8a9099), unchecked((int)0x594b8d2e), unchecked((int)0x5408abf7), unchecked((int)0x50c9b640),
|
||||
unchecked((int)0x4e8ee645), unchecked((int)0x4a4ffbf2), unchecked((int)0x470cdd2b), unchecked((int)0x43cdc09c),
|
||||
unchecked((int)0x7b827d21), unchecked((int)0x7f436096), unchecked((int)0x7200464f), unchecked((int)0x76c15bf8),
|
||||
unchecked((int)0x68860bfd), unchecked((int)0x6c47164a), unchecked((int)0x61043093), unchecked((int)0x65c52d24),
|
||||
unchecked((int)0x119b4be9), unchecked((int)0x155a565e), unchecked((int)0x18197087), unchecked((int)0x1cd86d30),
|
||||
unchecked((int)0x029f3d35), unchecked((int)0x065e2082), unchecked((int)0x0b1d065b), unchecked((int)0x0fdc1bec),
|
||||
unchecked((int)0x3793a651), unchecked((int)0x3352bbe6), unchecked((int)0x3e119d3f), unchecked((int)0x3ad08088),
|
||||
unchecked((int)0x2497d08d), unchecked((int)0x2056cd3a), unchecked((int)0x2d15ebe3), unchecked((int)0x29d4f654),
|
||||
unchecked((int)0xc5a92679), unchecked((int)0xc1683bce), unchecked((int)0xcc2b1d17), unchecked((int)0xc8ea00a0),
|
||||
unchecked((int)0xd6ad50a5), unchecked((int)0xd26c4d12), unchecked((int)0xdf2f6bcb), unchecked((int)0xdbee767c),
|
||||
unchecked((int)0xe3a1cbc1), unchecked((int)0xe760d676), unchecked((int)0xea23f0af), unchecked((int)0xeee2ed18),
|
||||
unchecked((int)0xf0a5bd1d), unchecked((int)0xf464a0aa), unchecked((int)0xf9278673), unchecked((int)0xfde69bc4),
|
||||
unchecked((int)0x89b8fd09), unchecked((int)0x8d79e0be), unchecked((int)0x803ac667), unchecked((int)0x84fbdbd0),
|
||||
unchecked((int)0x9abc8bd5), unchecked((int)0x9e7d9662), unchecked((int)0x933eb0bb), unchecked((int)0x97ffad0c),
|
||||
unchecked((int)0xafb010b1), unchecked((int)0xab710d06), unchecked((int)0xa6322bdf), unchecked((int)0xa2f33668),
|
||||
unchecked((int)0xbcb4666d), unchecked((int)0xb8757bda), unchecked((int)0xb5365d03), unchecked((int)0xb1f740b4)
|
||||
};
|
||||
|
||||
public CRC()
|
||||
{
|
||||
InitialiseCRC();
|
||||
}
|
||||
|
||||
internal void InitialiseCRC()
|
||||
{
|
||||
globalCrc = unchecked((int)0xffffffff);
|
||||
}
|
||||
|
||||
internal int GetFinalCRC()
|
||||
{
|
||||
return ~globalCrc;
|
||||
}
|
||||
|
||||
internal int GetGlobalCRC()
|
||||
{
|
||||
return globalCrc;
|
||||
}
|
||||
|
||||
internal void SetGlobalCRC(int newCrc)
|
||||
{
|
||||
globalCrc = newCrc;
|
||||
}
|
||||
|
||||
internal void UpdateCRC(int inCh)
|
||||
{
|
||||
int temp = (globalCrc >> 24) ^ inCh;
|
||||
if (temp < 0)
|
||||
{
|
||||
temp = 256 + temp;
|
||||
}
|
||||
globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];
|
||||
}
|
||||
|
||||
internal int globalCrc;
|
||||
}
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
using System;
|
||||
using Compress.SevenZip.Common;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZ
|
||||
{
|
||||
internal class BinTree : InWindow
|
||||
{
|
||||
UInt32 _cyclicBufferPos;
|
||||
UInt32 _cyclicBufferSize = 0;
|
||||
UInt32 _matchMaxLen;
|
||||
|
||||
UInt32[] _son;
|
||||
UInt32[] _hash;
|
||||
|
||||
UInt32 _cutValue = 0xFF;
|
||||
UInt32 _hashMask;
|
||||
UInt32 _hashSizeSum = 0;
|
||||
|
||||
bool HASH_ARRAY = true;
|
||||
|
||||
const UInt32 kHash2Size = 1 << 10;
|
||||
const UInt32 kHash3Size = 1 << 16;
|
||||
const UInt32 kBT2HashSize = 1 << 16;
|
||||
const UInt32 kStartMaxLen = 1;
|
||||
const UInt32 kHash3Offset = kHash2Size;
|
||||
const UInt32 kEmptyHashValue = 0;
|
||||
const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
|
||||
|
||||
UInt32 kNumHashDirectBytes = 0;
|
||||
UInt32 kMinMatchCheck = 4;
|
||||
UInt32 kFixHashSize = kHash2Size + kHash3Size;
|
||||
|
||||
public void SetType(int numHashBytes)
|
||||
{
|
||||
HASH_ARRAY = (numHashBytes > 2);
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
kNumHashDirectBytes = 0;
|
||||
kMinMatchCheck = 4;
|
||||
kFixHashSize = kHash2Size + kHash3Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNumHashDirectBytes = 2;
|
||||
kMinMatchCheck = 2 + 1;
|
||||
kFixHashSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
|
||||
public new void ReleaseStream() { base.ReleaseStream(); }
|
||||
|
||||
public new void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (UInt32 i = 0; i < _hashSizeSum; i++)
|
||||
_hash[i] = kEmptyHashValue;
|
||||
_cyclicBufferPos = 0;
|
||||
ReduceOffsets(-1);
|
||||
}
|
||||
|
||||
public new void MovePos()
|
||||
{
|
||||
if (++_cyclicBufferPos >= _cyclicBufferSize)
|
||||
_cyclicBufferPos = 0;
|
||||
base.MovePos();
|
||||
if (_pos == kMaxValForNormalize)
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
|
||||
|
||||
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{ return base.GetMatchLen(index, distance, limit); }
|
||||
|
||||
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
|
||||
|
||||
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
|
||||
{
|
||||
if (historySize > kMaxValForNormalize - 256)
|
||||
throw new Exception();
|
||||
_cutValue = 16 + (matchMaxLen >> 1);
|
||||
|
||||
UInt32 windowReservSize = (historySize + keepAddBufferBefore +
|
||||
matchMaxLen + keepAddBufferAfter) / 2 + 256;
|
||||
|
||||
base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
|
||||
|
||||
_matchMaxLen = matchMaxLen;
|
||||
|
||||
UInt32 cyclicBufferSize = historySize + 1;
|
||||
if (_cyclicBufferSize != cyclicBufferSize)
|
||||
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
|
||||
|
||||
UInt32 hs = kBT2HashSize;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= (hs >> 1);
|
||||
hs |= (hs >> 2);
|
||||
hs |= (hs >> 4);
|
||||
hs |= (hs >> 8);
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF;
|
||||
if (hs > (1 << 24))
|
||||
hs >>= 1;
|
||||
_hashMask = hs;
|
||||
hs++;
|
||||
hs += kFixHashSize;
|
||||
}
|
||||
if (hs != _hashSizeSum)
|
||||
_hash = new UInt32[_hashSizeSum = hs];
|
||||
}
|
||||
|
||||
public UInt32 GetMatches(UInt32[] distances)
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 offset = 0;
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
|
||||
UInt32 hashValue, hash2Value = 0, hash3Value = 0;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = Utils.CRC.CRC32Lookup[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
hash2Value = temp & (kHash2Size - 1);
|
||||
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
|
||||
hash3Value = temp & (kHash3Size - 1);
|
||||
hashValue = (temp ^ (Utils.CRC.CRC32Lookup[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 curMatch2 = _hash[hash2Value];
|
||||
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
|
||||
_hash[hash2Value] = _pos;
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
if (curMatch2 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
|
||||
{
|
||||
distances[offset++] = maxLen = 2;
|
||||
distances[offset++] = _pos - curMatch2 - 1;
|
||||
}
|
||||
if (curMatch3 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
|
||||
{
|
||||
if (curMatch3 == curMatch2)
|
||||
offset -= 2;
|
||||
distances[offset++] = maxLen = 3;
|
||||
distances[offset++] = _pos - curMatch3 - 1;
|
||||
curMatch2 = curMatch3;
|
||||
}
|
||||
if (offset != 0 && curMatch2 == curMatch)
|
||||
{
|
||||
offset -= 2;
|
||||
maxLen = kStartMaxLen;
|
||||
}
|
||||
}
|
||||
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
if (kNumHashDirectBytes != 0)
|
||||
{
|
||||
if (curMatch > matchMinPos)
|
||||
{
|
||||
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
|
||||
_bufferBase[cur + kNumHashDirectBytes])
|
||||
{
|
||||
distances[offset++] = maxLen = kNumHashDirectBytes;
|
||||
distances[offset++] = _pos - curMatch - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
distances[offset++] = maxLen = len;
|
||||
distances[offset++] = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Skip(UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
|
||||
UInt32 hashValue;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = Utils.CRC.CRC32Lookup[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
UInt32 hash2Value = temp & (kHash2Size - 1);
|
||||
_hash[hash2Value] = _pos;
|
||||
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
|
||||
UInt32 hash3Value = temp & (kHash3Size - 1);
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
hashValue = (temp ^ (Utils.CRC.CRC32Lookup[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
|
||||
{
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
value = kEmptyHashValue;
|
||||
else
|
||||
value -= subValue;
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
UInt32 subValue = _pos - _cyclicBufferSize;
|
||||
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
|
||||
NormalizeLinks(_hash, _hashSizeSum, subValue);
|
||||
ReduceOffsets((Int32)subValue);
|
||||
}
|
||||
|
||||
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZ
|
||||
{
|
||||
internal class InWindow
|
||||
{
|
||||
public Byte[] _bufferBase = null; // pointer to buffer with data
|
||||
System.IO.Stream _stream;
|
||||
UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
|
||||
bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
|
||||
|
||||
UInt32 _pointerToLastSafePosition;
|
||||
|
||||
public UInt32 _bufferOffset;
|
||||
|
||||
public UInt32 _blockSize; // Size of Allocated memory block
|
||||
public UInt32 _pos; // offset (from _buffer) of curent byte
|
||||
UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
|
||||
UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
|
||||
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
|
||||
|
||||
public void MoveBlock()
|
||||
{
|
||||
UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;
|
||||
// we need one additional byte, since MovePos moves on 1 byte.
|
||||
if (offset > 0)
|
||||
offset--;
|
||||
|
||||
UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;
|
||||
|
||||
// check negative offset ????
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
_bufferBase[i] = _bufferBase[offset + i];
|
||||
_bufferOffset -= offset;
|
||||
}
|
||||
|
||||
public virtual void ReadBlock()
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
return;
|
||||
while (true)
|
||||
{
|
||||
int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);
|
||||
if (size == 0)
|
||||
return;
|
||||
int numReadBytes = _stream != null ? _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size) : 0;
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
_posLimit = _streamPos;
|
||||
UInt32 pointerToPostion = _bufferOffset + _posLimit;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
_posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);
|
||||
|
||||
_streamEndWasReached = true;
|
||||
return;
|
||||
}
|
||||
_streamPos += (UInt32)numReadBytes;
|
||||
if (_streamPos >= _pos + _keepSizeAfter)
|
||||
_posLimit = _streamPos - _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
|
||||
void Free() { _bufferBase = null; }
|
||||
|
||||
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
|
||||
{
|
||||
_keepSizeBefore = keepSizeBefore;
|
||||
_keepSizeAfter = keepSizeAfter;
|
||||
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
|
||||
if (_bufferBase == null || _blockSize != blockSize)
|
||||
{
|
||||
Free();
|
||||
_blockSize = blockSize;
|
||||
_bufferBase = new Byte[_blockSize];
|
||||
}
|
||||
_pointerToLastSafePosition = _blockSize - keepSizeAfter;
|
||||
_streamEndWasReached = false;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
if (_streamEndWasReached)
|
||||
{
|
||||
_streamEndWasReached = false;
|
||||
if (IsDataStarved)
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
public void ReleaseStream() { _stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_bufferOffset = 0;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_streamEndWasReached = false;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
public void MovePos()
|
||||
{
|
||||
_pos++;
|
||||
if (_pos > _posLimit)
|
||||
{
|
||||
UInt32 pointerToPostion = _bufferOffset + _pos;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
MoveBlock();
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
|
||||
|
||||
// index + limit have not to exceed _keepSizeAfter;
|
||||
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
if ((_pos + index) + limit > _streamPos)
|
||||
limit = _streamPos - (UInt32)(_pos + index);
|
||||
distance++;
|
||||
// Byte *pby = _buffer + (size_t)_pos + index;
|
||||
UInt32 pby = _bufferOffset + _pos + (UInt32)index;
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++) ;
|
||||
return i;
|
||||
}
|
||||
|
||||
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
|
||||
|
||||
public void ReduceOffsets(Int32 subValue)
|
||||
{
|
||||
_bufferOffset += (UInt32)subValue;
|
||||
_posLimit -= (UInt32)subValue;
|
||||
_pos -= (UInt32)subValue;
|
||||
_streamPos -= (UInt32)subValue;
|
||||
}
|
||||
|
||||
public bool IsDataStarved
|
||||
{
|
||||
get
|
||||
{
|
||||
return _streamPos - _pos < _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
using Compress.SevenZip.Common;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZ
|
||||
{
|
||||
internal class OutWindow
|
||||
{
|
||||
byte[] _buffer = null;
|
||||
int _windowSize = 0;
|
||||
int _pos;
|
||||
int _streamPos;
|
||||
int _pendingLen;
|
||||
int _pendingDist;
|
||||
System.IO.Stream _stream;
|
||||
|
||||
public long Total;
|
||||
public long Limit;
|
||||
|
||||
public void Create(int windowSize)
|
||||
{
|
||||
if (_windowSize != windowSize)
|
||||
_buffer = new byte[windowSize];
|
||||
else
|
||||
_buffer[windowSize - 1] = 0;
|
||||
_windowSize = windowSize;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_pendingLen = 0;
|
||||
Total = 0;
|
||||
Limit = 0;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Create(_windowSize);
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
ReleaseStream();
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
public void Train(System.IO.Stream stream)
|
||||
{
|
||||
long len = stream.Length;
|
||||
int size = (len < _windowSize) ? (int)len : _windowSize;
|
||||
stream.Position = len - size;
|
||||
Total = 0;
|
||||
Limit = size;
|
||||
_pos = _windowSize - size;
|
||||
CopyStream(stream, size);
|
||||
if (_pos == _windowSize)
|
||||
_pos = 0;
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Flush();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (_stream == null)
|
||||
return;
|
||||
int size = _pos - _streamPos;
|
||||
if (size == 0)
|
||||
return;
|
||||
_stream.Write(_buffer, _streamPos, size);
|
||||
if (_pos >= _windowSize)
|
||||
_pos = 0;
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void CopyBlock(int distance, int len)
|
||||
{
|
||||
int size = len;
|
||||
int pos = _pos - distance - 1;
|
||||
if (pos < 0)
|
||||
pos += _windowSize;
|
||||
for (; size > 0 && _pos < _windowSize && Total < Limit; size--)
|
||||
{
|
||||
if (pos >= _windowSize)
|
||||
pos = 0;
|
||||
_buffer[_pos++] = _buffer[pos++];
|
||||
Total++;
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
_pendingLen = size;
|
||||
_pendingDist = distance;
|
||||
}
|
||||
|
||||
public void PutByte(byte b)
|
||||
{
|
||||
_buffer[_pos++] = b;
|
||||
Total++;
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
|
||||
public byte GetByte(int distance)
|
||||
{
|
||||
int pos = _pos - distance - 1;
|
||||
if (pos < 0)
|
||||
pos += _windowSize;
|
||||
return _buffer[pos];
|
||||
}
|
||||
|
||||
public int CopyStream(System.IO.Stream stream, int len)
|
||||
{
|
||||
int size = len;
|
||||
while (size > 0 && _pos < _windowSize && Total < Limit)
|
||||
{
|
||||
int curSize = _windowSize - _pos;
|
||||
if (curSize > Limit - Total)
|
||||
curSize = (int)(Limit - Total);
|
||||
if (curSize > size)
|
||||
curSize = size;
|
||||
int numReadBytes = stream.Read(_buffer, _pos, curSize);
|
||||
if (numReadBytes == 0)
|
||||
throw new DataErrorException();
|
||||
size -= numReadBytes;
|
||||
_pos += numReadBytes;
|
||||
Total += numReadBytes;
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
return len - size;
|
||||
}
|
||||
|
||||
public void SetLimit(long size)
|
||||
{
|
||||
Limit = Total + size;
|
||||
}
|
||||
|
||||
public bool HasSpace
|
||||
{
|
||||
get
|
||||
{
|
||||
return _pos < _windowSize && Total < Limit;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasPending
|
||||
{
|
||||
get
|
||||
{
|
||||
return _pendingLen > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_streamPos >= _pos)
|
||||
return 0;
|
||||
|
||||
int size = _pos - _streamPos;
|
||||
if (size > count)
|
||||
size = count;
|
||||
System.Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size);
|
||||
_streamPos += size;
|
||||
if (_streamPos >= _windowSize)
|
||||
{
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void CopyPending()
|
||||
{
|
||||
if (_pendingLen > 0)
|
||||
CopyBlock(_pendingDist, _pendingLen);
|
||||
}
|
||||
|
||||
public int AvailableBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return _pos - _streamPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
namespace Compress.SevenZip.Compress.LZMA
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
public const uint kNumRepDistances = 4;
|
||||
public const uint kNumStates = 12;
|
||||
|
||||
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
|
||||
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
|
||||
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
|
||||
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
|
||||
|
||||
public struct State
|
||||
{
|
||||
public uint Index;
|
||||
public void Init() { Index = 0; }
|
||||
public void UpdateChar()
|
||||
{
|
||||
if (Index < 4) Index = 0;
|
||||
else if (Index < 10) Index -= 3;
|
||||
else Index -= 6;
|
||||
}
|
||||
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
|
||||
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
|
||||
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
|
||||
public bool IsCharState() { return Index < 7; }
|
||||
}
|
||||
|
||||
public const int kNumPosSlotBits = 6;
|
||||
public const int kDicLogSizeMin = 0;
|
||||
// public const int kDicLogSizeMax = 30;
|
||||
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
|
||||
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
|
||||
|
||||
public const uint kMatchMinLen = 2;
|
||||
|
||||
public static uint GetLenToPosState(uint len)
|
||||
{
|
||||
len -= kMatchMinLen;
|
||||
if (len < kNumLenToPosStates)
|
||||
return len;
|
||||
return (uint)(kNumLenToPosStates - 1);
|
||||
}
|
||||
|
||||
public const int kNumAlignBits = 4;
|
||||
public const uint kAlignTableSize = 1 << kNumAlignBits;
|
||||
public const uint kAlignMask = (kAlignTableSize - 1);
|
||||
|
||||
public const uint kStartPosModelIndex = 4;
|
||||
public const uint kEndPosModelIndex = 14;
|
||||
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
|
||||
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
|
||||
|
||||
public const uint kNumLitPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumLitContextBitsMax = 8;
|
||||
|
||||
public const int kNumPosStatesBitsMax = 4;
|
||||
public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
|
||||
public const int kNumPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
|
||||
|
||||
public const int kNumLowLenBits = 3;
|
||||
public const int kNumMidLenBits = 3;
|
||||
public const int kNumHighLenBits = 8;
|
||||
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
|
||||
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
|
||||
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
|
||||
(1 << kNumHighLenBits);
|
||||
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
|
||||
}
|
||||
}
|
||||
@@ -1,404 +0,0 @@
|
||||
using System;
|
||||
using Compress.SevenZip.Common;
|
||||
using Compress.SevenZip.Compress.RangeCoder;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZMA
|
||||
{
|
||||
internal class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
||||
{
|
||||
class LenDecoder
|
||||
{
|
||||
BitDecoder m_Choice = new BitDecoder();
|
||||
BitDecoder m_Choice2 = new BitDecoder();
|
||||
BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
|
||||
uint m_NumPosStates = 0;
|
||||
|
||||
public void Create(uint numPosStates)
|
||||
{
|
||||
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
|
||||
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
|
||||
}
|
||||
m_NumPosStates = numPosStates;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (uint posState = 0; posState < m_NumPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState].Init();
|
||||
m_MidCoder[posState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
|
||||
{
|
||||
if (m_Choice.Decode(rangeDecoder) == 0)
|
||||
return m_LowCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
uint symbol = Base.kNumLowLenSymbols;
|
||||
if (m_Choice2.Decode(rangeDecoder) == 0)
|
||||
symbol += m_MidCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
symbol += Base.kNumMidLenSymbols;
|
||||
symbol += m_HighCoder.Decode(rangeDecoder);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LiteralDecoder
|
||||
{
|
||||
struct Decoder2
|
||||
{
|
||||
BitDecoder[] m_Decoders;
|
||||
public void Create() { m_Decoders = new BitDecoder[0x300]; }
|
||||
public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
uint matchBit = (uint)(matchByte >> 7) & 1;
|
||||
matchByte <<= 1;
|
||||
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
|
||||
symbol = (symbol << 1) | bit;
|
||||
if (matchBit != bit)
|
||||
{
|
||||
while (symbol < 0x100)
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
}
|
||||
|
||||
Decoder2[] m_Coders;
|
||||
int m_NumPrevBits;
|
||||
int m_NumPosBits;
|
||||
uint m_PosMask;
|
||||
|
||||
public void Create(int numPosBits, int numPrevBits)
|
||||
{
|
||||
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
|
||||
m_NumPosBits == numPosBits)
|
||||
return;
|
||||
m_NumPosBits = numPosBits;
|
||||
m_PosMask = ((uint)1 << numPosBits) - 1;
|
||||
m_NumPrevBits = numPrevBits;
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new Decoder2[numStates];
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Create();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
|
||||
uint GetState(uint pos, byte prevByte)
|
||||
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
|
||||
};
|
||||
|
||||
LZ.OutWindow m_OutWindow;
|
||||
|
||||
BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
|
||||
BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
|
||||
|
||||
BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
|
||||
|
||||
LenDecoder m_LenDecoder = new LenDecoder();
|
||||
LenDecoder m_RepLenDecoder = new LenDecoder();
|
||||
|
||||
LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
|
||||
|
||||
int m_DictionarySize;
|
||||
|
||||
uint m_PosStateMask;
|
||||
|
||||
Base.State state = new Base.State();
|
||||
uint rep0, rep1, rep2, rep3;
|
||||
|
||||
public Decoder()
|
||||
{
|
||||
m_DictionarySize = -1;
|
||||
for (int i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
|
||||
}
|
||||
|
||||
void CreateDictionary()
|
||||
{
|
||||
if (m_DictionarySize < 0)
|
||||
throw new InvalidParamException();
|
||||
m_OutWindow = new LZ.OutWindow();
|
||||
int blockSize = Math.Max(m_DictionarySize, (1 << 12));
|
||||
m_OutWindow.Create(blockSize);
|
||||
}
|
||||
|
||||
void SetLiteralProperties(int lp, int lc)
|
||||
{
|
||||
if (lp > 8)
|
||||
throw new InvalidParamException();
|
||||
if (lc > 8)
|
||||
throw new InvalidParamException();
|
||||
m_LiteralDecoder.Create(lp, lc);
|
||||
}
|
||||
|
||||
void SetPosBitsProperties(int pb)
|
||||
{
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
uint numPosStates = (uint)1 << pb;
|
||||
m_LenDecoder.Create(numPosStates);
|
||||
m_RepLenDecoder.Create(numPosStates);
|
||||
m_PosStateMask = numPosStates - 1;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
uint i;
|
||||
for (i = 0; i < Base.kNumStates; i++)
|
||||
{
|
||||
for (uint j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
uint index = (i << Base.kNumPosStatesBitsMax) + j;
|
||||
m_IsMatchDecoders[index].Init();
|
||||
m_IsRep0LongDecoders[index].Init();
|
||||
}
|
||||
m_IsRepDecoders[i].Init();
|
||||
m_IsRepG0Decoders[i].Init();
|
||||
m_IsRepG1Decoders[i].Init();
|
||||
m_IsRepG2Decoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
for (i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i].Init();
|
||||
// m_PosSpecDecoder.Init();
|
||||
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
|
||||
m_PosDecoders[i].Init();
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepLenDecoder.Init();
|
||||
m_PosAlignDecoder.Init();
|
||||
|
||||
state.Init();
|
||||
rep0 = 0;
|
||||
rep1 = 0;
|
||||
rep2 = 0;
|
||||
rep3 = 0;
|
||||
}
|
||||
|
||||
public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress)
|
||||
{
|
||||
if (m_OutWindow == null)
|
||||
CreateDictionary();
|
||||
m_OutWindow.Init(outStream);
|
||||
if (outSize > 0)
|
||||
m_OutWindow.SetLimit(outSize);
|
||||
else
|
||||
m_OutWindow.SetLimit(Int64.MaxValue - m_OutWindow.Total);
|
||||
|
||||
RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder();
|
||||
rangeDecoder.Init(inStream);
|
||||
|
||||
Code(m_DictionarySize, m_OutWindow, rangeDecoder);
|
||||
|
||||
m_OutWindow.ReleaseStream();
|
||||
rangeDecoder.ReleaseStream();
|
||||
|
||||
if (!rangeDecoder.IsFinished || (inSize > 0 && rangeDecoder.Total != inSize))
|
||||
throw new DataErrorException();
|
||||
if (m_OutWindow.HasPending)
|
||||
throw new DataErrorException();
|
||||
m_OutWindow = null;
|
||||
}
|
||||
|
||||
internal bool Code(int dictionarySize, LZ.OutWindow outWindow, RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
int dictionarySizeCheck = Math.Max(dictionarySize, 1);
|
||||
|
||||
outWindow.CopyPending();
|
||||
|
||||
while (outWindow.HasSpace)
|
||||
{
|
||||
uint posState = (uint)outWindow.Total & m_PosStateMask;
|
||||
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(rangeDecoder) == 0)
|
||||
{
|
||||
byte b;
|
||||
byte prevByte = outWindow.GetByte(0);
|
||||
if (!state.IsCharState())
|
||||
b = m_LiteralDecoder.DecodeWithMatchByte(rangeDecoder,
|
||||
(uint)outWindow.Total, prevByte, outWindow.GetByte((int)rep0));
|
||||
else
|
||||
b = m_LiteralDecoder.DecodeNormal(rangeDecoder, (uint)outWindow.Total, prevByte);
|
||||
outWindow.PutByte(b);
|
||||
state.UpdateChar();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint len;
|
||||
if (m_IsRepDecoders[state.Index].Decode(rangeDecoder) == 1)
|
||||
{
|
||||
if (m_IsRepG0Decoders[state.Index].Decode(rangeDecoder) == 0)
|
||||
{
|
||||
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(rangeDecoder) == 0)
|
||||
{
|
||||
state.UpdateShortRep();
|
||||
outWindow.PutByte(outWindow.GetByte((int)rep0));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
if (m_IsRepG1Decoders[state.Index].Decode(rangeDecoder) == 0)
|
||||
{
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsRepG2Decoders[state.Index].Decode(rangeDecoder) == 0)
|
||||
distance = rep2;
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
len = m_RepLenDecoder.Decode(rangeDecoder, posState) + Base.kMatchMinLen;
|
||||
state.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
len = Base.kMatchMinLen + m_LenDecoder.Decode(rangeDecoder, posState);
|
||||
state.UpdateMatch();
|
||||
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(rangeDecoder);
|
||||
if (posSlot >= Base.kStartPosModelIndex)
|
||||
{
|
||||
int numDirectBits = (int)((posSlot >> 1) - 1);
|
||||
rep0 = ((2 | (posSlot & 1)) << numDirectBits);
|
||||
if (posSlot < Base.kEndPosModelIndex)
|
||||
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
|
||||
rep0 - posSlot - 1, rangeDecoder, numDirectBits);
|
||||
else
|
||||
{
|
||||
rep0 += (rangeDecoder.DecodeDirectBits(
|
||||
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
|
||||
rep0 += m_PosAlignDecoder.ReverseDecode(rangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
rep0 = posSlot;
|
||||
}
|
||||
if (rep0 >= outWindow.Total || rep0 >= dictionarySizeCheck)
|
||||
{
|
||||
if (rep0 == 0xFFFFFFFF)
|
||||
return true;
|
||||
throw new DataErrorException();
|
||||
}
|
||||
outWindow.CopyBlock((int)rep0, (int)len);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetDecoderProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length < 1)
|
||||
throw new InvalidParamException();
|
||||
int lc = properties[0] % 9;
|
||||
int remainder = properties[0] / 9;
|
||||
int lp = remainder % 5;
|
||||
int pb = remainder / 5;
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
SetLiteralProperties(lp, lc);
|
||||
SetPosBitsProperties(pb);
|
||||
Init();
|
||||
if (properties.Length >= 5)
|
||||
{
|
||||
m_DictionarySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_DictionarySize += properties[1 + i] << (i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
public void Train(System.IO.Stream stream)
|
||||
{
|
||||
if (m_OutWindow == null)
|
||||
CreateDictionary();
|
||||
m_OutWindow.Train(stream);
|
||||
}
|
||||
|
||||
/*
|
||||
public override bool CanRead { get { return true; }}
|
||||
public override bool CanWrite { get { return true; }}
|
||||
public override bool CanSeek { get { return true; }}
|
||||
public override long Length { get { return 0; }}
|
||||
public override long Position
|
||||
{
|
||||
get { return 0; }
|
||||
set { }
|
||||
}
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void SetLength(long value) {}
|
||||
*/
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,57 +0,0 @@
|
||||
using Compress.SevenZip.Common;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZMA
|
||||
{
|
||||
public class LzmaEncoderProperties
|
||||
{
|
||||
internal CoderPropID[] propIDs;
|
||||
internal object[] properties;
|
||||
|
||||
public LzmaEncoderProperties()
|
||||
: this(false)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaEncoderProperties(bool eos)
|
||||
: this(eos, 1 << 20)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaEncoderProperties(bool eos, int dictionary)
|
||||
: this(eos, dictionary, 32)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes)
|
||||
{
|
||||
int posStateBits = 2;
|
||||
int litContextBits = 4;
|
||||
int litPosBits = 0;
|
||||
int algorithm = 2;
|
||||
string mf = "bt4";
|
||||
|
||||
propIDs = new CoderPropID[]
|
||||
{
|
||||
CoderPropID.DictionarySize,
|
||||
CoderPropID.PosStateBits,
|
||||
CoderPropID.LitContextBits,
|
||||
CoderPropID.LitPosBits,
|
||||
CoderPropID.Algorithm,
|
||||
CoderPropID.NumFastBytes,
|
||||
CoderPropID.MatchFinder,
|
||||
CoderPropID.EndMarker
|
||||
};
|
||||
properties = new object[]
|
||||
{
|
||||
dictionary,
|
||||
posStateBits,
|
||||
litContextBits,
|
||||
litPosBits,
|
||||
algorithm,
|
||||
numFastBytes,
|
||||
mf,
|
||||
eos
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Compress.SevenZip.Common;
|
||||
using Compress.SevenZip.Compress.LZ;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZMA
|
||||
{
|
||||
public class LzmaStream : Stream
|
||||
{
|
||||
private Stream inputStream;
|
||||
private long inputSize;
|
||||
private long outputSize;
|
||||
|
||||
private int dictionarySize;
|
||||
private OutWindow outWindow = new OutWindow();
|
||||
private RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder();
|
||||
private Decoder decoder;
|
||||
|
||||
private long position = 0;
|
||||
private bool endReached = false;
|
||||
private long availableBytes;
|
||||
private long rangeDecoderLimit;
|
||||
private long inputPosition = 0;
|
||||
|
||||
// LZMA2
|
||||
private bool isLZMA2;
|
||||
private bool uncompressedChunk = false;
|
||||
private bool needDictReset = true;
|
||||
private bool needProps = true;
|
||||
private byte[] props = new byte[5];
|
||||
|
||||
private Encoder encoder;
|
||||
|
||||
public LzmaStream(byte[] properties, Stream inputStream)
|
||||
: this(properties, inputStream, -1, -1, null, properties.Length < 5)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaStream(byte[] properties, Stream inputStream, long inputSize)
|
||||
: this(properties, inputStream, inputSize, -1, null, properties.Length < 5)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize)
|
||||
: this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize,
|
||||
Stream presetDictionary, bool isLZMA2)
|
||||
{
|
||||
this.inputStream = inputStream;
|
||||
this.inputSize = inputSize;
|
||||
this.outputSize = outputSize;
|
||||
this.isLZMA2 = isLZMA2;
|
||||
|
||||
if (!isLZMA2)
|
||||
{
|
||||
dictionarySize = BitConverter.ToInt32(properties, 1);
|
||||
outWindow.Create(dictionarySize);
|
||||
if (presetDictionary != null)
|
||||
outWindow.Train(presetDictionary);
|
||||
|
||||
rangeDecoder.Init(inputStream);
|
||||
|
||||
decoder = new Decoder();
|
||||
decoder.SetDecoderProperties(properties);
|
||||
props = properties;
|
||||
|
||||
availableBytes = outputSize < 0 ? long.MaxValue : outputSize;
|
||||
rangeDecoderLimit = inputSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionarySize = 2 | (properties[0] & 1);
|
||||
dictionarySize <<= (properties[0] >> 1) + 11;
|
||||
|
||||
outWindow.Create(dictionarySize);
|
||||
if (presetDictionary != null)
|
||||
{
|
||||
outWindow.Train(presetDictionary);
|
||||
needDictReset = false;
|
||||
}
|
||||
|
||||
props = new byte[1];
|
||||
availableBytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public LzmaStream(LzmaEncoderProperties properties, bool isLZMA2, Stream outputStream)
|
||||
: this(properties, isLZMA2, null, outputStream)
|
||||
{
|
||||
}
|
||||
|
||||
public LzmaStream(LzmaEncoderProperties properties, bool isLZMA2, Stream presetDictionary, Stream outputStream)
|
||||
{
|
||||
this.isLZMA2 = isLZMA2;
|
||||
availableBytes = 0;
|
||||
endReached = true;
|
||||
|
||||
if (isLZMA2)
|
||||
throw new NotImplementedException();
|
||||
|
||||
encoder = new Encoder();
|
||||
encoder.SetCoderProperties(properties.propIDs, properties.properties);
|
||||
MemoryStream propStream = new MemoryStream(5);
|
||||
encoder.WriteCoderProperties(propStream);
|
||||
props = propStream.ToArray();
|
||||
|
||||
encoder.SetStreams(null, outputStream, -1, -1);
|
||||
if (presetDictionary != null)
|
||||
encoder.Train(presetDictionary);
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return encoder == null; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return encoder != null; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (encoder != null)
|
||||
position = encoder.Code(null, true);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return position + availableBytes; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (endReached)
|
||||
return 0;
|
||||
|
||||
int total = 0;
|
||||
while (total < count)
|
||||
{
|
||||
if (availableBytes == 0)
|
||||
{
|
||||
if (isLZMA2)
|
||||
decodeChunkHeader();
|
||||
else
|
||||
endReached = true;
|
||||
if (endReached)
|
||||
break;
|
||||
}
|
||||
|
||||
int toProcess = count - total;
|
||||
if (toProcess > availableBytes)
|
||||
toProcess = (int)availableBytes;
|
||||
|
||||
outWindow.SetLimit(toProcess);
|
||||
if (uncompressedChunk)
|
||||
{
|
||||
inputPosition += outWindow.CopyStream(inputStream, toProcess);
|
||||
}
|
||||
else if (decoder.Code(dictionarySize, outWindow, rangeDecoder)
|
||||
&& outputSize < 0)
|
||||
{
|
||||
availableBytes = outWindow.AvailableBytes;
|
||||
}
|
||||
|
||||
int read = outWindow.Read(buffer, offset, toProcess);
|
||||
total += read;
|
||||
offset += read;
|
||||
position += read;
|
||||
availableBytes -= read;
|
||||
|
||||
if (availableBytes == 0 && !uncompressedChunk)
|
||||
{
|
||||
rangeDecoder.ReleaseStream();
|
||||
if (!rangeDecoder.IsFinished || (rangeDecoderLimit >= 0 && rangeDecoder.Total != rangeDecoderLimit))
|
||||
throw new DataErrorException();
|
||||
inputPosition += rangeDecoder.Total;
|
||||
if (outWindow.HasPending)
|
||||
throw new DataErrorException();
|
||||
}
|
||||
}
|
||||
|
||||
if (endReached)
|
||||
{
|
||||
if (inputSize >= 0 && inputPosition != inputSize)
|
||||
throw new DataErrorException();
|
||||
if (outputSize >= 0 && position != outputSize)
|
||||
throw new DataErrorException();
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
private void decodeChunkHeader()
|
||||
{
|
||||
int control = inputStream.ReadByte();
|
||||
inputPosition++;
|
||||
|
||||
if (control == 0x00)
|
||||
{
|
||||
endReached = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (control >= 0xE0 || control == 0x01)
|
||||
{
|
||||
needProps = true;
|
||||
needDictReset = false;
|
||||
outWindow.Reset();
|
||||
}
|
||||
else if (needDictReset)
|
||||
throw new DataErrorException();
|
||||
|
||||
if (control >= 0x80)
|
||||
{
|
||||
uncompressedChunk = false;
|
||||
|
||||
availableBytes = (control & 0x1F) << 16;
|
||||
availableBytes += (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1;
|
||||
inputPosition += 2;
|
||||
|
||||
rangeDecoderLimit = (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1;
|
||||
inputPosition += 2;
|
||||
|
||||
if (control >= 0xC0)
|
||||
{
|
||||
needProps = false;
|
||||
props[0] = (byte)inputStream.ReadByte();
|
||||
inputPosition++;
|
||||
|
||||
decoder = new Decoder();
|
||||
decoder.SetDecoderProperties(props);
|
||||
}
|
||||
else if (needProps)
|
||||
throw new DataErrorException();
|
||||
else if (control >= 0xA0)
|
||||
{
|
||||
decoder = new Decoder();
|
||||
decoder.SetDecoderProperties(props);
|
||||
}
|
||||
|
||||
rangeDecoder.Init(inputStream);
|
||||
}
|
||||
else if (control > 0x02)
|
||||
throw new DataErrorException();
|
||||
else
|
||||
{
|
||||
uncompressedChunk = true;
|
||||
availableBytes = (inputStream.ReadByte() << 8) + inputStream.ReadByte() + 1;
|
||||
inputPosition += 2;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
byte[] tmpBuff = new byte[1024];
|
||||
long sizeToGo = offset;
|
||||
while (sizeToGo > 0)
|
||||
{
|
||||
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
|
||||
Read(tmpBuff, 0, sizenow);
|
||||
sizeToGo -= sizenow;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (encoder != null)
|
||||
position = encoder.Code(new MemoryStream(buffer, offset, count), false);
|
||||
}
|
||||
|
||||
public byte[] Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return props;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class FreqData : Pointer
|
||||
{
|
||||
internal const int Size = 6;
|
||||
|
||||
// struct FreqData
|
||||
// {
|
||||
// ushort SummFreq;
|
||||
// STATE _PACK_ATTR * Stats;
|
||||
// };
|
||||
|
||||
internal FreqData(byte[] Memory)
|
||||
: base(Memory)
|
||||
{
|
||||
}
|
||||
|
||||
internal int SummFreq
|
||||
{
|
||||
get
|
||||
{
|
||||
return Utility.readShortLittleEndian(Memory, Address) & 0xffff;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address, (short)value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal FreqData Initialize(byte[] mem)
|
||||
{
|
||||
return base.Initialize<FreqData>(mem);
|
||||
}
|
||||
|
||||
internal void IncrementSummFreq(int dSummFreq)
|
||||
{
|
||||
Utility.incShortLittleEndian(Memory, Address, (short)dSummFreq);
|
||||
}
|
||||
|
||||
internal int GetStats()
|
||||
{
|
||||
return Utility.readIntLittleEndian(Memory, Address + 2);
|
||||
}
|
||||
|
||||
internal virtual void SetStats(State state)
|
||||
{
|
||||
SetStats(state.Address);
|
||||
}
|
||||
|
||||
internal void SetStats(int state)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address + 2, state);
|
||||
}
|
||||
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("FreqData[");
|
||||
buffer.Append("\n Address=");
|
||||
buffer.Append(Address);
|
||||
buffer.Append("\n size=");
|
||||
buffer.Append(Size);
|
||||
buffer.Append("\n summFreq=");
|
||||
buffer.Append(SummFreq);
|
||||
buffer.Append("\n stats=");
|
||||
buffer.Append(GetStats());
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,945 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Decoder = Compress.SevenZip.Compress.RangeCoder.Decoder;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class ModelPPM
|
||||
{
|
||||
private void InitBlock()
|
||||
{
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
SEE2Cont[i] = new SEE2Context[16];
|
||||
}
|
||||
for (int i2 = 0; i2 < 128; i2++)
|
||||
{
|
||||
binSumm[i2] = new int[64];
|
||||
}
|
||||
}
|
||||
public SubAllocator SubAlloc
|
||||
{
|
||||
get
|
||||
{
|
||||
return subAlloc;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public SEE2Context DummySEE2Cont
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummySEE2Cont;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int InitRL
|
||||
{
|
||||
get
|
||||
{
|
||||
return initRL;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int EscCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return escCount;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.escCount = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int[] CharMask
|
||||
{
|
||||
get
|
||||
{
|
||||
return charMask;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int NumMasked
|
||||
{
|
||||
get
|
||||
{
|
||||
return numMasked;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.numMasked = value;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int PrevSuccess
|
||||
{
|
||||
get
|
||||
{
|
||||
return prevSuccess;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.prevSuccess = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int InitEsc
|
||||
{
|
||||
get
|
||||
{
|
||||
return initEsc;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.initEsc = value;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int RunLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return runLength;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.runLength = value;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int HiBitsFlag
|
||||
{
|
||||
get
|
||||
{
|
||||
return hiBitsFlag;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.hiBitsFlag = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int[][] BinSumm
|
||||
{
|
||||
get
|
||||
{
|
||||
return binSumm;
|
||||
}
|
||||
|
||||
}
|
||||
internal RangeCoder Coder
|
||||
{
|
||||
get
|
||||
{
|
||||
return coder;
|
||||
}
|
||||
|
||||
}
|
||||
internal State FoundState
|
||||
{
|
||||
get
|
||||
{
|
||||
return foundState;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public byte[] Heap
|
||||
{
|
||||
get
|
||||
{
|
||||
return subAlloc.Heap;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int OrderFall
|
||||
{
|
||||
get
|
||||
{
|
||||
return orderFall;
|
||||
}
|
||||
|
||||
}
|
||||
public const int MAX_O = 64; /* maximum allowed model order */
|
||||
|
||||
public const int INT_BITS = 7;
|
||||
|
||||
public const int PERIOD_BITS = 7;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'TOT_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public static readonly int TOT_BITS = INT_BITS + PERIOD_BITS;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'INTERVAL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public static readonly int INTERVAL = 1 << INT_BITS;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'BIN_SCALE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public static readonly int BIN_SCALE = 1 << TOT_BITS;
|
||||
|
||||
public const int MAX_FREQ = 124;
|
||||
|
||||
private SEE2Context[][] SEE2Cont = new SEE2Context[25][];
|
||||
|
||||
private SEE2Context dummySEE2Cont;
|
||||
|
||||
private PPMContext minContext; //medContext
|
||||
|
||||
private PPMContext maxContext;
|
||||
|
||||
private State foundState; // found next state transition
|
||||
|
||||
private int numMasked, initEsc, orderFall, maxOrder, runLength, initRL;
|
||||
|
||||
private int[] charMask = new int[256];
|
||||
|
||||
private int[] NS2Indx = new int[256];
|
||||
|
||||
private int[] NS2BSIndx = new int[256];
|
||||
|
||||
private int[] HB2Flag = new int[256];
|
||||
|
||||
// byte EscCount, PrevSuccess, HiBitsFlag;
|
||||
private int escCount, prevSuccess, hiBitsFlag;
|
||||
|
||||
private int[][] binSumm = new int[128][]; // binary SEE-contexts
|
||||
|
||||
private RangeCoder coder;
|
||||
|
||||
private SubAllocator subAlloc = new SubAllocator();
|
||||
|
||||
private static int[] InitBinEsc = new int[] { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051 };
|
||||
|
||||
// Temp fields
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState1 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState2 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState3 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState4 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private StateRef tempStateRef1 = new StateRef();
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private StateRef tempStateRef2 = new StateRef();
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private PPMContext tempPPMContext1 = new PPMContext(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private PPMContext tempPPMContext2 = new PPMContext(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private PPMContext tempPPMContext3 = new PPMContext(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private PPMContext tempPPMContext4 = new PPMContext(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private int[] ps = new int[MAX_O];
|
||||
|
||||
public ModelPPM()
|
||||
{
|
||||
InitBlock();
|
||||
minContext = null;
|
||||
maxContext = null;
|
||||
//medContext = null;
|
||||
}
|
||||
|
||||
private void restartModelRare()
|
||||
{
|
||||
Utility.Fill(charMask, 0);
|
||||
subAlloc.initSubAllocator();
|
||||
initRL = -(maxOrder < 12 ? maxOrder : 12) - 1;
|
||||
int addr = subAlloc.allocContext();
|
||||
minContext.Address = addr;
|
||||
maxContext.Address = addr;
|
||||
minContext.setSuffix(0);
|
||||
orderFall = maxOrder;
|
||||
minContext.NumStats = 256;
|
||||
minContext.FreqData.SummFreq = minContext.NumStats + 1;
|
||||
|
||||
addr = subAlloc.allocUnits(256 / 2);
|
||||
foundState.Address = addr;
|
||||
minContext.FreqData.SetStats(addr);
|
||||
|
||||
State state = new State(subAlloc.Heap);
|
||||
addr = minContext.FreqData.GetStats();
|
||||
runLength = initRL;
|
||||
prevSuccess = 0;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
state.Address = addr + i * State.Size;
|
||||
state.Symbol = i;
|
||||
state.Freq = 1;
|
||||
state.SetSuccessor(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
for (int k = 0; k < 8; k++)
|
||||
{
|
||||
for (int m = 0; m < 64; m += 8)
|
||||
{
|
||||
binSumm[i][k + m] = BIN_SCALE - InitBinEsc[k] / (i + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
SEE2Cont[i][k].Initialize(5 * i + 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startModelRare(int MaxOrder)
|
||||
{
|
||||
int i, k, m, Step;
|
||||
escCount = 1;
|
||||
this.maxOrder = MaxOrder;
|
||||
restartModelRare();
|
||||
// Bug Fixed
|
||||
NS2BSIndx[0] = 0;
|
||||
NS2BSIndx[1] = 2;
|
||||
for (int j = 0; j < 9; j++)
|
||||
{
|
||||
NS2BSIndx[2 + j] = 4;
|
||||
}
|
||||
for (int j = 0; j < 256 - 11; j++)
|
||||
{
|
||||
NS2BSIndx[11 + j] = 6;
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
NS2Indx[i] = i;
|
||||
}
|
||||
for (m = i, k = 1, Step = 1; i < 256; i++)
|
||||
{
|
||||
NS2Indx[i] = m;
|
||||
if ((--k) == 0)
|
||||
{
|
||||
k = ++Step;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < 0x40; j++)
|
||||
{
|
||||
HB2Flag[j] = 0;
|
||||
}
|
||||
for (int j = 0; j < 0x100 - 0x40; j++)
|
||||
{
|
||||
HB2Flag[0x40 + j] = 0x08;
|
||||
}
|
||||
dummySEE2Cont.Shift = PERIOD_BITS;
|
||||
}
|
||||
|
||||
private void clearMask()
|
||||
{
|
||||
escCount = 1;
|
||||
Utility.Fill(charMask, 0);
|
||||
}
|
||||
|
||||
|
||||
public virtual int decodeChar()
|
||||
{
|
||||
// Debug
|
||||
//subAlloc.dumpHeap();
|
||||
|
||||
if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (minContext.NumStats != 1)
|
||||
{
|
||||
if (minContext.FreqData.GetStats() <= subAlloc.PText || minContext.FreqData.GetStats() > subAlloc.HeapEnd)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
if (!minContext.decodeSymbol1(this))
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
minContext.decodeBinSymbol(this);
|
||||
}
|
||||
coder.Decode();
|
||||
while (foundState.Address == 0)
|
||||
{
|
||||
coder.AriDecNormalize();
|
||||
do
|
||||
{
|
||||
orderFall++;
|
||||
minContext.Address = minContext.getSuffix(); // =MinContext->Suffix;
|
||||
if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
while (minContext.NumStats == numMasked);
|
||||
if (!minContext.decodeSymbol2(this))
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
coder.Decode();
|
||||
}
|
||||
int Symbol = foundState.Symbol;
|
||||
if ((orderFall == 0) && foundState.GetSuccessor() > subAlloc.PText)
|
||||
{
|
||||
// MinContext=MaxContext=FoundState->Successor;
|
||||
int addr = foundState.GetSuccessor();
|
||||
minContext.Address = addr;
|
||||
maxContext.Address = addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
updateModel();
|
||||
//this.foundState.Address=foundState.Address);//TODO just 4 debugging
|
||||
if (escCount == 0)
|
||||
{
|
||||
clearMask();
|
||||
}
|
||||
}
|
||||
coder.AriDecNormalize(); // ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
|
||||
return (Symbol);
|
||||
}
|
||||
|
||||
public virtual SEE2Context[][] getSEE2Cont()
|
||||
{
|
||||
return SEE2Cont;
|
||||
}
|
||||
|
||||
public virtual void incEscCount(int dEscCount)
|
||||
{
|
||||
EscCount = EscCount + dEscCount;
|
||||
}
|
||||
|
||||
public virtual void incRunLength(int dRunLength)
|
||||
{
|
||||
RunLength = RunLength + dRunLength;
|
||||
}
|
||||
|
||||
public virtual int[] getHB2Flag()
|
||||
{
|
||||
return HB2Flag;
|
||||
}
|
||||
|
||||
public virtual int[] getNS2BSIndx()
|
||||
{
|
||||
return NS2BSIndx;
|
||||
}
|
||||
|
||||
public virtual int[] getNS2Indx()
|
||||
{
|
||||
return NS2Indx;
|
||||
}
|
||||
|
||||
private int createSuccessors(bool Skip, State p1)
|
||||
{
|
||||
//State upState = tempState1.Initialize(null);
|
||||
StateRef upState = tempStateRef2;
|
||||
State tempState = tempState1.Initialize(Heap);
|
||||
|
||||
// PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
|
||||
PPMContext pc = tempPPMContext1.Initialize(Heap);
|
||||
pc.Address = minContext.Address;
|
||||
PPMContext upBranch = tempPPMContext2.Initialize(Heap);
|
||||
upBranch.Address = foundState.GetSuccessor();
|
||||
|
||||
// STATE * p, * ps[MAX_O], ** pps=ps;
|
||||
State p = tempState2.Initialize(Heap);
|
||||
int pps = 0;
|
||||
|
||||
bool noLoop = false;
|
||||
|
||||
if (!Skip)
|
||||
{
|
||||
ps[pps++] = foundState.Address; // *pps++ = FoundState;
|
||||
if (pc.getSuffix() == 0)
|
||||
{
|
||||
noLoop = true;
|
||||
}
|
||||
}
|
||||
if (!noLoop)
|
||||
{
|
||||
bool loopEntry = false;
|
||||
if (p1.Address != 0)
|
||||
{
|
||||
p.Address = p1.Address;
|
||||
pc.Address = pc.getSuffix(); // =pc->Suffix;
|
||||
loopEntry = true;
|
||||
}
|
||||
do
|
||||
{
|
||||
if (!loopEntry)
|
||||
{
|
||||
pc.Address = pc.getSuffix(); // pc=pc->Suffix;
|
||||
if (pc.NumStats != 1)
|
||||
{
|
||||
p.Address = pc.FreqData.GetStats(); // p=pc->U.Stats
|
||||
if (p.Symbol != foundState.Symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
p.IncrementAddress();
|
||||
}
|
||||
while (p.Symbol != foundState.Symbol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Address = pc.getOneState().Address; // p=&(pc->OneState);
|
||||
}
|
||||
} // LOOP_ENTRY:
|
||||
loopEntry = false;
|
||||
if (p.GetSuccessor() != upBranch.Address)
|
||||
{
|
||||
pc.Address = p.GetSuccessor(); // =p->Successor;
|
||||
break;
|
||||
}
|
||||
ps[pps++] = p.Address;
|
||||
}
|
||||
while (pc.getSuffix() != 0);
|
||||
} // NO_LOOP:
|
||||
if (pps == 0)
|
||||
{
|
||||
return pc.Address;
|
||||
}
|
||||
upState.Symbol = Heap[upBranch.Address]; // UpState.Symbol=*(byte*)
|
||||
// UpBranch;
|
||||
// UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1);
|
||||
upState.SetSuccessor(upBranch.Address + 1); //TODO check if +1 necessary
|
||||
if (pc.NumStats != 1)
|
||||
{
|
||||
if (pc.Address <= subAlloc.PText)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
p.Address = pc.FreqData.GetStats();
|
||||
if (p.Symbol != upState.Symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
p.IncrementAddress();
|
||||
}
|
||||
while (p.Symbol != upState.Symbol);
|
||||
}
|
||||
int cf = p.Freq - 1;
|
||||
int s0 = pc.FreqData.SummFreq - pc.NumStats - cf;
|
||||
// UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
|
||||
upState.Freq = 1 + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
upState.Freq = pc.getOneState().Freq; // UpState.Freq=pc->OneState.Freq;
|
||||
}
|
||||
do
|
||||
{
|
||||
// pc = pc->createChild(this,*--pps,UpState);
|
||||
tempState.Address = ps[--pps];
|
||||
pc.Address = pc.createChild(this, tempState, upState);
|
||||
if (pc.Address == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
while (pps != 0);
|
||||
return pc.Address;
|
||||
}
|
||||
|
||||
private void updateModelRestart()
|
||||
{
|
||||
restartModelRare();
|
||||
escCount = 0;
|
||||
}
|
||||
|
||||
private void updateModel()
|
||||
{
|
||||
//System.out.println("ModelPPM.updateModel()");
|
||||
// STATE fs = *FoundState, *p = NULL;
|
||||
StateRef fs = tempStateRef1;
|
||||
fs.Values = foundState;
|
||||
State p = tempState3.Initialize(Heap);
|
||||
State tempState = tempState4.Initialize(Heap);
|
||||
|
||||
PPMContext pc = tempPPMContext3.Initialize(Heap);
|
||||
PPMContext successor = tempPPMContext4.Initialize(Heap);
|
||||
|
||||
int ns1, ns, cf, sf, s0;
|
||||
pc.Address = minContext.getSuffix();
|
||||
if (fs.Freq < MAX_FREQ / 4 && pc.Address != 0)
|
||||
{
|
||||
if (pc.NumStats != 1)
|
||||
{
|
||||
p.Address = pc.FreqData.GetStats();
|
||||
if (p.Symbol != fs.Symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
p.IncrementAddress();
|
||||
}
|
||||
while (p.Symbol != fs.Symbol);
|
||||
tempState.Address = p.Address - State.Size;
|
||||
if (p.Freq >= tempState.Freq)
|
||||
{
|
||||
State.PPMDSwap(p, tempState);
|
||||
p.DecrementAddress();
|
||||
}
|
||||
}
|
||||
if (p.Freq < MAX_FREQ - 9)
|
||||
{
|
||||
p.IncrementFreq(2);
|
||||
pc.FreqData.IncrementSummFreq(2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Address = pc.getOneState().Address;
|
||||
if (p.Freq < 32)
|
||||
{
|
||||
p.IncrementFreq(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (orderFall == 0)
|
||||
{
|
||||
foundState.SetSuccessor(createSuccessors(true, p));
|
||||
minContext.Address = foundState.GetSuccessor();
|
||||
maxContext.Address = foundState.GetSuccessor();
|
||||
if (minContext.Address == 0)
|
||||
{
|
||||
updateModelRestart();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
subAlloc.Heap[subAlloc.PText] = (byte)fs.Symbol;
|
||||
subAlloc.incPText();
|
||||
successor.Address = subAlloc.PText;
|
||||
if (subAlloc.PText >= subAlloc.FakeUnitsStart)
|
||||
{
|
||||
updateModelRestart();
|
||||
return;
|
||||
}
|
||||
// // Debug
|
||||
// subAlloc.dumpHeap();
|
||||
if (fs.GetSuccessor() != 0)
|
||||
{
|
||||
if (fs.GetSuccessor() <= subAlloc.PText)
|
||||
{
|
||||
fs.SetSuccessor(createSuccessors(false, p));
|
||||
if (fs.GetSuccessor() == 0)
|
||||
{
|
||||
updateModelRestart();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (--orderFall == 0)
|
||||
{
|
||||
successor.Address = fs.GetSuccessor();
|
||||
if (maxContext.Address != minContext.Address)
|
||||
{
|
||||
subAlloc.decPText(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foundState.SetSuccessor(successor.Address);
|
||||
fs.SetSuccessor(minContext);
|
||||
}
|
||||
// // Debug
|
||||
// subAlloc.dumpHeap();
|
||||
ns = minContext.NumStats;
|
||||
s0 = minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1);
|
||||
for (pc.Address = maxContext.Address; pc.Address != minContext.Address; pc.Address = pc.getSuffix())
|
||||
{
|
||||
if ((ns1 = pc.NumStats) != 1)
|
||||
{
|
||||
if ((ns1 & 1) == 0)
|
||||
{
|
||||
//System.out.println(ns1);
|
||||
pc.FreqData.SetStats(subAlloc.expandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1)));
|
||||
if (pc.FreqData.GetStats() == 0)
|
||||
{
|
||||
updateModelRestart();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// bug fixed
|
||||
// int sum = ((2 * ns1 < ns) ? 1 : 0) +
|
||||
// 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData()
|
||||
// .getSummFreq() <= 8 * ns1) ? 1 : 0));
|
||||
int sum = ((2 * ns1 < ns) ? 1 : 0) + 2 * (((4 * ns1 <= ns) ? 1 : 0) & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0));
|
||||
pc.FreqData.IncrementSummFreq(sum);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Address = subAlloc.allocUnits(1);
|
||||
if (p.Address == 0)
|
||||
{
|
||||
updateModelRestart();
|
||||
return;
|
||||
}
|
||||
p.SetValues(pc.getOneState());
|
||||
pc.FreqData.SetStats(p);
|
||||
if (p.Freq < MAX_FREQ / 4 - 1)
|
||||
{
|
||||
p.IncrementFreq(p.Freq);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Freq = MAX_FREQ - 4;
|
||||
}
|
||||
pc.FreqData.SummFreq = (p.Freq + initEsc + (ns > 3 ? 1 : 0));
|
||||
}
|
||||
cf = 2 * fs.Freq * (pc.FreqData.SummFreq + 6);
|
||||
sf = s0 + pc.FreqData.SummFreq;
|
||||
if (cf < 6 * sf)
|
||||
{
|
||||
cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0);
|
||||
pc.FreqData.IncrementSummFreq(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) + (cf >= 15 * sf ? 1 : 0);
|
||||
pc.FreqData.IncrementSummFreq(cf);
|
||||
}
|
||||
p.Address = pc.FreqData.GetStats() + ns1 * State.Size;
|
||||
p.SetSuccessor(successor);
|
||||
p.Symbol = fs.Symbol;
|
||||
p.Freq = cf;
|
||||
pc.NumStats = ++ns1;
|
||||
}
|
||||
|
||||
int address = fs.GetSuccessor();
|
||||
maxContext.Address = address;
|
||||
minContext.Address = address;
|
||||
//TODO-----debug
|
||||
// int pos = minContext.getFreqData().getStats();
|
||||
// State a = new State(getHeap());
|
||||
// a.Address=pos);
|
||||
// pos+=State.size;
|
||||
// a.Address=pos);
|
||||
//--dbg end
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("ModelPPM[");
|
||||
buffer.Append("\n numMasked=");
|
||||
buffer.Append(numMasked);
|
||||
buffer.Append("\n initEsc=");
|
||||
buffer.Append(initEsc);
|
||||
buffer.Append("\n orderFall=");
|
||||
buffer.Append(orderFall);
|
||||
buffer.Append("\n maxOrder=");
|
||||
buffer.Append(maxOrder);
|
||||
buffer.Append("\n runLength=");
|
||||
buffer.Append(runLength);
|
||||
buffer.Append("\n initRL=");
|
||||
buffer.Append(initRL);
|
||||
buffer.Append("\n escCount=");
|
||||
buffer.Append(escCount);
|
||||
buffer.Append("\n prevSuccess=");
|
||||
buffer.Append(prevSuccess);
|
||||
buffer.Append("\n foundState=");
|
||||
buffer.Append(foundState);
|
||||
buffer.Append("\n coder=");
|
||||
buffer.Append(coder);
|
||||
buffer.Append("\n subAlloc=");
|
||||
buffer.Append(subAlloc);
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
// Debug
|
||||
// public void dumpHeap() {
|
||||
// subAlloc.dumpHeap();
|
||||
// }
|
||||
|
||||
internal bool decodeInit(Stream stream, int maxOrder, int maxMemory)
|
||||
{
|
||||
if (stream != null)
|
||||
coder = new RangeCoder(stream);
|
||||
|
||||
if (maxOrder == 1)
|
||||
{
|
||||
subAlloc.stopSubAllocator();
|
||||
return (false);
|
||||
}
|
||||
subAlloc.startSubAllocator(maxMemory);
|
||||
minContext = new PPMContext(Heap);
|
||||
//medContext = new PPMContext(Heap);
|
||||
maxContext = new PPMContext(Heap);
|
||||
foundState = new State(Heap);
|
||||
dummySEE2Cont = new SEE2Context();
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
SEE2Cont[i][j] = new SEE2Context();
|
||||
}
|
||||
}
|
||||
startModelRare(maxOrder);
|
||||
|
||||
return (minContext.Address != 0);
|
||||
}
|
||||
|
||||
internal void nextContext()
|
||||
{
|
||||
int addr = foundState.GetSuccessor();
|
||||
if (orderFall == 0 && addr > subAlloc.PText)
|
||||
{
|
||||
minContext.Address = addr;
|
||||
maxContext.Address = addr;
|
||||
}
|
||||
else
|
||||
updateModel();
|
||||
}
|
||||
|
||||
public int decodeChar(Decoder decoder)
|
||||
{
|
||||
if (minContext.NumStats != 1)
|
||||
{
|
||||
State s = tempState1.Initialize(Heap);
|
||||
s.Address = minContext.FreqData.GetStats();
|
||||
int i;
|
||||
int count, hiCnt;
|
||||
if ((count = (int)decoder.GetThreshold((uint)minContext.FreqData.SummFreq)) < (hiCnt = s.Freq))
|
||||
{
|
||||
byte symbol;
|
||||
decoder.Decode(0, (uint)s.Freq);
|
||||
symbol = (byte)s.Symbol;
|
||||
minContext.update1_0(this, s.Address);
|
||||
nextContext();
|
||||
return symbol;
|
||||
}
|
||||
prevSuccess = 0;
|
||||
i = minContext.NumStats - 1;
|
||||
do
|
||||
{
|
||||
s.IncrementAddress();
|
||||
if ((hiCnt += s.Freq) > count)
|
||||
{
|
||||
byte symbol;
|
||||
decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq);
|
||||
symbol = (byte)s.Symbol;
|
||||
minContext.update1(this, s.Address);
|
||||
nextContext();
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
while (--i > 0);
|
||||
if (count >= minContext.FreqData.SummFreq)
|
||||
return -2;
|
||||
hiBitsFlag = HB2Flag[foundState.Symbol];
|
||||
decoder.Decode((uint)hiCnt, (uint)(minContext.FreqData.SummFreq - hiCnt));
|
||||
for (i = 0; i < 256; i++)
|
||||
charMask[i] = -1;
|
||||
charMask[s.Symbol] = 0;
|
||||
i = minContext.NumStats - 1;
|
||||
do
|
||||
{
|
||||
s.DecrementAddress();
|
||||
charMask[s.Symbol] = 0;
|
||||
}
|
||||
while (--i > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
State rs = tempState1.Initialize(Heap);
|
||||
rs.Address = minContext.getOneState().Address;
|
||||
hiBitsFlag = getHB2Flag()[foundState.Symbol];
|
||||
int off1 = rs.Freq - 1;
|
||||
int off2 = minContext.getArrayIndex(this, rs);
|
||||
int bs = binSumm[off1][off2];
|
||||
if (decoder.DecodeBit((uint)bs, 14) == 0)
|
||||
{
|
||||
byte symbol;
|
||||
binSumm[off1][off2] = (bs + INTERVAL - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF;
|
||||
foundState.Address = rs.Address;
|
||||
symbol = (byte)rs.Symbol;
|
||||
rs.IncrementFreq((rs.Freq < 128) ? 1 : 0);
|
||||
prevSuccess = 1;
|
||||
incRunLength(1);
|
||||
nextContext();
|
||||
return symbol;
|
||||
}
|
||||
bs = (bs - minContext.getMean(bs, PERIOD_BITS, 2)) & 0xFFFF;
|
||||
binSumm[off1][off2] = bs;
|
||||
initEsc = PPMContext.ExpEscape[Utility.URShift(bs, 10)];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
charMask[i] = -1;
|
||||
charMask[rs.Symbol] = 0;
|
||||
prevSuccess = 0;
|
||||
}
|
||||
for (; ; )
|
||||
{
|
||||
State s = tempState1.Initialize(Heap);
|
||||
int i;
|
||||
int freqSum, count, hiCnt;
|
||||
SEE2Context see;
|
||||
int num, numMasked = minContext.NumStats;
|
||||
do
|
||||
{
|
||||
orderFall++;
|
||||
minContext.Address = minContext.getSuffix();
|
||||
if (minContext.Address <= subAlloc.PText || minContext.Address > subAlloc.HeapEnd)
|
||||
return -1;
|
||||
}
|
||||
while (minContext.NumStats == numMasked);
|
||||
hiCnt = 0;
|
||||
s.Address = minContext.FreqData.GetStats();
|
||||
i = 0;
|
||||
num = minContext.NumStats - numMasked;
|
||||
do
|
||||
{
|
||||
int k = charMask[s.Symbol];
|
||||
hiCnt += s.Freq & k;
|
||||
minContext.ps[i] = s.Address;
|
||||
s.IncrementAddress();
|
||||
i -= k;
|
||||
}
|
||||
while (i != num);
|
||||
|
||||
see = minContext.makeEscFreq(this, numMasked, out freqSum);
|
||||
freqSum += hiCnt;
|
||||
count = (int)decoder.GetThreshold((uint)freqSum);
|
||||
|
||||
if (count < hiCnt)
|
||||
{
|
||||
byte symbol;
|
||||
State ps = tempState2.Initialize(Heap);
|
||||
for (hiCnt = 0, i = 0, ps.Address = minContext.ps[i]; (hiCnt += ps.Freq) <= count; i++, ps.Address = minContext.ps[i]) ;
|
||||
s.Address = ps.Address;
|
||||
decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq);
|
||||
see.update();
|
||||
symbol = (byte)s.Symbol;
|
||||
minContext.update2(this, s.Address);
|
||||
updateModel();
|
||||
return symbol;
|
||||
}
|
||||
if (count >= freqSum)
|
||||
return -2;
|
||||
decoder.Decode((uint)hiCnt, (uint)(freqSum - hiCnt));
|
||||
see.Summ = see.Summ + freqSum;
|
||||
do
|
||||
{
|
||||
s.Address = minContext.ps[--i];
|
||||
charMask[s.Symbol] = 0;
|
||||
}
|
||||
while (i != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,563 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class PPMContext : Pointer
|
||||
{
|
||||
internal FreqData FreqData
|
||||
{
|
||||
get
|
||||
{
|
||||
return freqData;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.freqData.SummFreq = value.SummFreq;
|
||||
this.freqData.SetStats(value.GetStats());
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int NumStats
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
numStats = Utility.readShortLittleEndian(Memory, Address) & 0xffff;
|
||||
}
|
||||
return numStats;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.numStats = value & 0xffff;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address, (short)value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'unionSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
//UPGRADE_NOTE: The initialization of 'unionSize' was moved to static method 'SharpCompress.Unpack.PPM.PPMContext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
|
||||
private static readonly int unionSize;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public static readonly int size = 2 + unionSize + 4; // 12
|
||||
|
||||
// ushort NumStats;
|
||||
private int numStats; // determines if feqData or onstate is used
|
||||
|
||||
// (1==onestate)
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'freqData '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private FreqData freqData; // -\
|
||||
|
||||
// |-> union
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'oneState '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State oneState; // -/
|
||||
|
||||
private int suffix; // pointer ppmcontext
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public static readonly int[] ExpEscape = new int[] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
|
||||
// Temp fields
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState1 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState2 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState3 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState4 = new State(null);
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'tempState5 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private State tempState5 = new State(null);
|
||||
private PPMContext tempPPMContext = null;
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal int[] ps = new int[256];
|
||||
|
||||
public PPMContext(byte[] Memory)
|
||||
: base(Memory)
|
||||
{
|
||||
oneState = new State(Memory);
|
||||
freqData = new FreqData(Memory);
|
||||
}
|
||||
|
||||
internal PPMContext Initialize(byte[] mem)
|
||||
{
|
||||
oneState.Initialize(mem);
|
||||
freqData.Initialize(mem);
|
||||
return base.Initialize<PPMContext>(mem);
|
||||
}
|
||||
|
||||
internal State getOneState()
|
||||
{
|
||||
return oneState;
|
||||
}
|
||||
|
||||
internal void setOneState(StateRef oneState)
|
||||
{
|
||||
this.oneState.SetValues(oneState);
|
||||
}
|
||||
|
||||
internal int getSuffix()
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
suffix = Utility.readIntLittleEndian(Memory, Address + 8);
|
||||
}
|
||||
return suffix;
|
||||
}
|
||||
|
||||
internal void setSuffix(PPMContext suffix)
|
||||
{
|
||||
setSuffix(suffix.Address);
|
||||
}
|
||||
|
||||
internal void setSuffix(int suffix)
|
||||
{
|
||||
this.suffix = suffix;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address + 8, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
internal override int Address
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Address;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.Address = value;
|
||||
oneState.Address = value + 2;
|
||||
freqData.Address = value + 2;
|
||||
}
|
||||
}
|
||||
|
||||
private PPMContext getTempPPMContext(byte[] Memory)
|
||||
{
|
||||
if (tempPPMContext == null)
|
||||
{
|
||||
tempPPMContext = new PPMContext(null);
|
||||
}
|
||||
return tempPPMContext.Initialize(Memory);
|
||||
}
|
||||
|
||||
internal int createChild(ModelPPM model, State pStats, StateRef firstState)
|
||||
{
|
||||
PPMContext pc = getTempPPMContext(model.SubAlloc.Heap);
|
||||
pc.Address = model.SubAlloc.allocContext();
|
||||
if (pc != null)
|
||||
{
|
||||
pc.NumStats = 1;
|
||||
pc.setOneState(firstState);
|
||||
pc.setSuffix(this);
|
||||
pStats.SetSuccessor(pc);
|
||||
}
|
||||
return pc.Address;
|
||||
}
|
||||
|
||||
internal void rescale(ModelPPM model)
|
||||
{
|
||||
int OldNS = NumStats, i = NumStats - 1, Adder, EscFreq;
|
||||
// STATE* p1, * p;
|
||||
State p1 = new State(model.Heap);
|
||||
State p = new State(model.Heap);
|
||||
State temp = new State(model.Heap);
|
||||
|
||||
for (p.Address = model.FoundState.Address; p.Address != freqData.GetStats(); p.DecrementAddress())
|
||||
{
|
||||
temp.Address = p.Address - State.Size;
|
||||
State.PPMDSwap(p, temp);
|
||||
}
|
||||
temp.Address = freqData.GetStats();
|
||||
temp.IncrementFreq(4);
|
||||
freqData.IncrementSummFreq(4);
|
||||
EscFreq = freqData.SummFreq - p.Freq;
|
||||
Adder = (model.OrderFall != 0) ? 1 : 0;
|
||||
p.Freq = Utility.URShift((p.Freq + Adder), 1);
|
||||
freqData.SummFreq = p.Freq;
|
||||
do
|
||||
{
|
||||
p.IncrementAddress();
|
||||
EscFreq -= p.Freq;
|
||||
p.Freq = Utility.URShift((p.Freq + Adder), 1);
|
||||
freqData.IncrementSummFreq(p.Freq);
|
||||
temp.Address = p.Address - State.Size;
|
||||
if (p.Freq > temp.Freq)
|
||||
{
|
||||
p1.Address = p.Address;
|
||||
StateRef tmp = new StateRef();
|
||||
tmp.Values = p1;
|
||||
State temp2 = new State(model.Heap);
|
||||
State temp3 = new State(model.Heap);
|
||||
do
|
||||
{
|
||||
// p1[0]=p1[-1];
|
||||
temp2.Address = p1.Address - State.Size;
|
||||
p1.SetValues(temp2);
|
||||
p1.DecrementAddress();
|
||||
temp3.Address = p1.Address - State.Size;
|
||||
}
|
||||
while (p1.Address != freqData.GetStats() && tmp.Freq > temp3.Freq);
|
||||
p1.SetValues(tmp);
|
||||
}
|
||||
}
|
||||
while (--i != 0);
|
||||
if (p.Freq == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
i++;
|
||||
p.DecrementAddress();
|
||||
}
|
||||
while (p.Freq == 0);
|
||||
EscFreq += i;
|
||||
NumStats = NumStats - i;
|
||||
if (NumStats == 1)
|
||||
{
|
||||
StateRef tmp = new StateRef();
|
||||
temp.Address = freqData.GetStats();
|
||||
tmp.Values = temp;
|
||||
// STATE tmp=*U.Stats;
|
||||
do
|
||||
{
|
||||
// tmp.Freq-=(tmp.Freq >> 1)
|
||||
tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1));
|
||||
EscFreq = Utility.URShift(EscFreq, 1);
|
||||
}
|
||||
while (EscFreq > 1);
|
||||
model.SubAlloc.freeUnits(freqData.GetStats(), Utility.URShift((OldNS + 1), 1));
|
||||
oneState.SetValues(tmp);
|
||||
model.FoundState.Address = oneState.Address;
|
||||
return;
|
||||
}
|
||||
}
|
||||
EscFreq -= Utility.URShift(EscFreq, 1);
|
||||
freqData.IncrementSummFreq(EscFreq);
|
||||
int n0 = Utility.URShift((OldNS + 1), 1), n1 = Utility.URShift((NumStats + 1), 1);
|
||||
if (n0 != n1)
|
||||
{
|
||||
freqData.SetStats(model.SubAlloc.shrinkUnits(freqData.GetStats(), n0, n1));
|
||||
}
|
||||
model.FoundState.Address = freqData.GetStats();
|
||||
}
|
||||
|
||||
internal int getArrayIndex(ModelPPM Model, State rs)
|
||||
{
|
||||
PPMContext tempSuffix = getTempPPMContext(Model.SubAlloc.Heap);
|
||||
tempSuffix.Address = getSuffix();
|
||||
int ret = 0;
|
||||
ret += Model.PrevSuccess;
|
||||
ret += Model.getNS2BSIndx()[tempSuffix.NumStats - 1];
|
||||
ret += Model.HiBitsFlag + 2 * Model.getHB2Flag()[rs.Symbol];
|
||||
ret += ((Utility.URShift(Model.RunLength, 26)) & 0x20);
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal int getMean(int summ, int shift, int round)
|
||||
{
|
||||
return (Utility.URShift((summ + (1 << (shift - round))), (shift)));
|
||||
}
|
||||
|
||||
internal void decodeBinSymbol(ModelPPM model)
|
||||
{
|
||||
State rs = tempState1.Initialize(model.Heap);
|
||||
rs.Address = oneState.Address; // State&
|
||||
model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol];
|
||||
int off1 = rs.Freq - 1;
|
||||
int off2 = getArrayIndex(model, rs);
|
||||
int bs = model.BinSumm[off1][off2];
|
||||
if (model.Coder.GetCurrentShiftCount(ModelPPM.TOT_BITS) < bs)
|
||||
{
|
||||
model.FoundState.Address = rs.Address;
|
||||
rs.IncrementFreq((rs.Freq < 128) ? 1 : 0);
|
||||
model.Coder.SubRange.LowCount = 0;
|
||||
model.Coder.SubRange.HighCount = bs;
|
||||
bs = ((bs + ModelPPM.INTERVAL - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xffff);
|
||||
model.BinSumm[off1][off2] = bs;
|
||||
model.PrevSuccess = 1;
|
||||
model.incRunLength(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Coder.SubRange.LowCount = bs;
|
||||
bs = (bs - getMean(bs, ModelPPM.PERIOD_BITS, 2)) & 0xFFFF;
|
||||
model.BinSumm[off1][off2] = bs;
|
||||
model.Coder.SubRange.HighCount = ModelPPM.BIN_SCALE;
|
||||
model.InitEsc = ExpEscape[Utility.URShift(bs, 10)];
|
||||
model.NumMasked = 1;
|
||||
model.CharMask[rs.Symbol] = model.EscCount;
|
||||
model.PrevSuccess = 0;
|
||||
model.FoundState.Address = 0;
|
||||
}
|
||||
//int a = 0;//TODO just 4 debugging
|
||||
}
|
||||
|
||||
// public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2)
|
||||
// {
|
||||
// byte[] bytes = model.getSubAlloc().getHeap();
|
||||
// int p1 = state1.Address;
|
||||
// int p2 = state2.Address;
|
||||
//
|
||||
// for (int i = 0; i < StatePtr.size; i++) {
|
||||
// byte temp = bytes[p1+i];
|
||||
// bytes[p1+i] = bytes[p2+i];
|
||||
// bytes[p2+i] = temp;
|
||||
// }
|
||||
// state1.Address=p1);
|
||||
// state2.Address=p2);
|
||||
// }
|
||||
|
||||
internal void update1(ModelPPM model, int p)
|
||||
{
|
||||
model.FoundState.Address = p;
|
||||
model.FoundState.IncrementFreq(4);
|
||||
freqData.IncrementSummFreq(4);
|
||||
State p0 = tempState3.Initialize(model.Heap);
|
||||
State p1 = tempState4.Initialize(model.Heap);
|
||||
p0.Address = p;
|
||||
p1.Address = p - State.Size;
|
||||
if (p0.Freq > p1.Freq)
|
||||
{
|
||||
State.PPMDSwap(p0, p1);
|
||||
model.FoundState.Address = p1.Address;
|
||||
if (p1.Freq > ModelPPM.MAX_FREQ)
|
||||
rescale(model);
|
||||
}
|
||||
}
|
||||
|
||||
internal void update1_0(ModelPPM model, int p)
|
||||
{
|
||||
model.FoundState.Address = p;
|
||||
model.PrevSuccess = 2 * model.FoundState.Freq > freqData.SummFreq ? 1 : 0;
|
||||
model.incRunLength(model.PrevSuccess);
|
||||
freqData.IncrementSummFreq(4);
|
||||
model.FoundState.IncrementFreq(4);
|
||||
if (model.FoundState.Freq > ModelPPM.MAX_FREQ)
|
||||
rescale(model);
|
||||
}
|
||||
|
||||
internal bool decodeSymbol2(ModelPPM model)
|
||||
{
|
||||
long count;
|
||||
int hiCnt, i = NumStats - model.NumMasked;
|
||||
SEE2Context psee2c = makeEscFreq2(model, i);
|
||||
RangeCoder coder = model.Coder;
|
||||
// STATE* ps[256], ** pps=ps, * p=U.Stats-1;
|
||||
State p = tempState1.Initialize(model.Heap);
|
||||
State temp = tempState2.Initialize(model.Heap);
|
||||
p.Address = freqData.GetStats() - State.Size;
|
||||
int pps = 0;
|
||||
hiCnt = 0;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
p.IncrementAddress(); // p++;
|
||||
}
|
||||
while (model.CharMask[p.Symbol] == model.EscCount);
|
||||
hiCnt += p.Freq;
|
||||
ps[pps++] = p.Address;
|
||||
}
|
||||
while (--i != 0);
|
||||
coder.SubRange.incScale(hiCnt);
|
||||
count = coder.CurrentCount;
|
||||
if (count >= coder.SubRange.Scale)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
pps = 0;
|
||||
p.Address = ps[pps];
|
||||
if (count < hiCnt)
|
||||
{
|
||||
hiCnt = 0;
|
||||
while ((hiCnt += p.Freq) <= count)
|
||||
{
|
||||
p.Address = ps[++pps]; // p=*++pps;
|
||||
}
|
||||
coder.SubRange.HighCount = hiCnt;
|
||||
coder.SubRange.LowCount = hiCnt - p.Freq;
|
||||
psee2c.update();
|
||||
update2(model, p.Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
coder.SubRange.LowCount = hiCnt;
|
||||
coder.SubRange.HighCount = coder.SubRange.Scale;
|
||||
i = NumStats - model.NumMasked; // ->NumMasked;
|
||||
pps--;
|
||||
do
|
||||
{
|
||||
temp.Address = ps[++pps]; // (*++pps)
|
||||
model.CharMask[temp.Symbol] = model.EscCount;
|
||||
}
|
||||
while (--i != 0);
|
||||
psee2c.incSumm((int)coder.SubRange.Scale);
|
||||
model.NumMasked = NumStats;
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
internal void update2(ModelPPM model, int p)
|
||||
{
|
||||
State temp = tempState5.Initialize(model.Heap);
|
||||
temp.Address = p;
|
||||
model.FoundState.Address = p;
|
||||
model.FoundState.IncrementFreq(4);
|
||||
freqData.IncrementSummFreq(4);
|
||||
if (temp.Freq > ModelPPM.MAX_FREQ)
|
||||
{
|
||||
rescale(model);
|
||||
}
|
||||
model.incEscCount(1);
|
||||
model.RunLength = model.InitRL;
|
||||
}
|
||||
|
||||
private SEE2Context makeEscFreq2(ModelPPM model, int Diff)
|
||||
{
|
||||
SEE2Context psee2c;
|
||||
int numStats = NumStats;
|
||||
if (numStats != 256)
|
||||
{
|
||||
PPMContext suff = getTempPPMContext(model.Heap);
|
||||
suff.Address = getSuffix();
|
||||
int idx1 = model.getNS2Indx()[Diff - 1];
|
||||
int idx2 = 0;
|
||||
idx2 += ((Diff < suff.NumStats - numStats) ? 1 : 0);
|
||||
idx2 += 2 * ((freqData.SummFreq < 11 * numStats) ? 1 : 0);
|
||||
idx2 += 4 * ((model.NumMasked > Diff) ? 1 : 0);
|
||||
idx2 += model.HiBitsFlag;
|
||||
psee2c = model.getSEE2Cont()[idx1][idx2];
|
||||
model.Coder.SubRange.Scale = psee2c.Mean;
|
||||
}
|
||||
else
|
||||
{
|
||||
psee2c = model.DummySEE2Cont;
|
||||
model.Coder.SubRange.Scale = 1;
|
||||
}
|
||||
return psee2c;
|
||||
}
|
||||
|
||||
internal SEE2Context makeEscFreq(ModelPPM model, int numMasked, out int escFreq)
|
||||
{
|
||||
SEE2Context psee2c;
|
||||
int numStats = NumStats;
|
||||
int nonMasked = numStats - numMasked;
|
||||
if (numStats != 256)
|
||||
{
|
||||
PPMContext suff = getTempPPMContext(model.Heap);
|
||||
suff.Address = getSuffix();
|
||||
int idx1 = model.getNS2Indx()[nonMasked - 1];
|
||||
int idx2 = 0;
|
||||
idx2 += ((nonMasked < suff.NumStats - numStats) ? 1 : 0);
|
||||
idx2 += 2 * ((freqData.SummFreq < 11 * numStats) ? 1 : 0);
|
||||
idx2 += 4 * ((numMasked > nonMasked) ? 1 : 0);
|
||||
idx2 += model.HiBitsFlag;
|
||||
psee2c = model.getSEE2Cont()[idx1][idx2];
|
||||
escFreq = psee2c.Mean;
|
||||
}
|
||||
else
|
||||
{
|
||||
psee2c = model.DummySEE2Cont;
|
||||
escFreq = 1;
|
||||
}
|
||||
return psee2c;
|
||||
}
|
||||
|
||||
internal bool decodeSymbol1(ModelPPM model)
|
||||
{
|
||||
|
||||
RangeCoder coder = model.Coder;
|
||||
coder.SubRange.Scale = freqData.SummFreq;
|
||||
State p = new State(model.Heap);
|
||||
p.Address = freqData.GetStats();
|
||||
int i, HiCnt;
|
||||
long count = coder.CurrentCount;
|
||||
if (count >= coder.SubRange.Scale)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (count < (HiCnt = p.Freq))
|
||||
{
|
||||
coder.SubRange.HighCount = HiCnt;
|
||||
model.PrevSuccess = (2 * HiCnt > coder.SubRange.Scale) ? 1 : 0;
|
||||
model.incRunLength(model.PrevSuccess);
|
||||
HiCnt += 4;
|
||||
model.FoundState.Address = p.Address;
|
||||
model.FoundState.Freq = HiCnt;
|
||||
freqData.IncrementSummFreq(4);
|
||||
if (HiCnt > ModelPPM.MAX_FREQ)
|
||||
{
|
||||
rescale(model);
|
||||
}
|
||||
coder.SubRange.LowCount = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.FoundState.Address == 0)
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
model.PrevSuccess = 0;
|
||||
int numStats = NumStats;
|
||||
i = numStats - 1;
|
||||
while ((HiCnt += p.IncrementAddress().Freq) <= count)
|
||||
{
|
||||
if (--i == 0)
|
||||
{
|
||||
model.HiBitsFlag = model.getHB2Flag()[model.FoundState.Symbol];
|
||||
coder.SubRange.LowCount = HiCnt;
|
||||
model.CharMask[p.Symbol] = model.EscCount;
|
||||
model.NumMasked = numStats;
|
||||
i = numStats - 1;
|
||||
model.FoundState.Address = 0;
|
||||
do
|
||||
{
|
||||
model.CharMask[p.DecrementAddress().Symbol] = model.EscCount;
|
||||
}
|
||||
while (--i != 0);
|
||||
coder.SubRange.HighCount = coder.SubRange.Scale;
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
coder.SubRange.LowCount = HiCnt - p.Freq;
|
||||
coder.SubRange.HighCount = HiCnt;
|
||||
update1(model, p.Address);
|
||||
return (true);
|
||||
}
|
||||
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("PPMContext[");
|
||||
buffer.Append("\n Address=");
|
||||
buffer.Append(Address);
|
||||
buffer.Append("\n size=");
|
||||
buffer.Append(size);
|
||||
buffer.Append("\n numStats=");
|
||||
buffer.Append(NumStats);
|
||||
buffer.Append("\n Suffix=");
|
||||
buffer.Append(getSuffix());
|
||||
buffer.Append("\n freqData=");
|
||||
buffer.Append(freqData);
|
||||
buffer.Append("\n oneState=");
|
||||
buffer.Append(oneState);
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
static PPMContext()
|
||||
{
|
||||
unionSize = System.Math.Max(FreqData.Size, State.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal abstract class Pointer
|
||||
{
|
||||
/// <summary> Initialize the object with the array (may be null)</summary>
|
||||
/// <param name="mem">the byte array
|
||||
/// </param>
|
||||
internal Pointer(byte[] mem)
|
||||
{
|
||||
Memory = mem;
|
||||
}
|
||||
|
||||
internal byte[] Memory
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal virtual int Address
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
protected T Initialize<T>(byte[] mem)
|
||||
where T : Pointer
|
||||
{
|
||||
Memory = mem;
|
||||
Address = 0;
|
||||
return this as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class RangeCoder
|
||||
{
|
||||
internal const int TOP = 1 << 24;
|
||||
internal const int BOT = 1 << 15;
|
||||
internal const long UintMask = 0xFFFFffffL;
|
||||
|
||||
// uint low, code, range;
|
||||
private long low, code, range;
|
||||
private Stream stream;
|
||||
|
||||
internal RangeCoder(Stream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
this.SubRange = new SubRange();
|
||||
|
||||
low = code = 0L;
|
||||
range = 0xFFFFffffL;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
code = ((code << 8) | Char) & UintMask;
|
||||
}
|
||||
}
|
||||
|
||||
internal int CurrentCount
|
||||
{
|
||||
get
|
||||
{
|
||||
range = (range / SubRange.Scale) & UintMask;
|
||||
return (int)((code - low) / (range));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private long Char
|
||||
{
|
||||
get
|
||||
{
|
||||
if (stream != null)
|
||||
return stream.ReadByte();
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal SubRange SubRange
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
internal long GetCurrentShiftCount(int SHIFT)
|
||||
{
|
||||
range = Utility.URShift(range, SHIFT);
|
||||
return ((code - low) / (range)) & UintMask;
|
||||
}
|
||||
|
||||
internal void Decode()
|
||||
{
|
||||
low = (low + (range * SubRange.LowCount)) & UintMask;
|
||||
range = (range * (SubRange.HighCount - SubRange.LowCount)) & UintMask;
|
||||
}
|
||||
|
||||
internal void AriDecNormalize()
|
||||
{
|
||||
// while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true))
|
||||
// {
|
||||
// code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask;
|
||||
// range = (range << 8)&uintMask;
|
||||
// low = (low << 8)&uintMask;
|
||||
// }
|
||||
|
||||
// Rewrote for clarity
|
||||
bool c2 = false;
|
||||
while ((low ^ (low + range)) < TOP || (c2 = range < BOT))
|
||||
{
|
||||
if (c2)
|
||||
{
|
||||
range = (-low & (BOT - 1)) & UintMask;
|
||||
c2 = false;
|
||||
}
|
||||
code = ((code << 8) | Char) & UintMask;
|
||||
range = (range << 8) & UintMask;
|
||||
low = (low << 8) & UintMask;
|
||||
}
|
||||
}
|
||||
|
||||
// Debug
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("RangeCoder[");
|
||||
buffer.Append("\n low=");
|
||||
buffer.Append(low);
|
||||
buffer.Append("\n code=");
|
||||
buffer.Append(code);
|
||||
buffer.Append("\n range=");
|
||||
buffer.Append(range);
|
||||
buffer.Append("\n subrange=");
|
||||
buffer.Append(SubRange);
|
||||
buffer.Append("]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubRange
|
||||
{
|
||||
// uint LowCount, HighCount, scale;
|
||||
private long lowCount, highCount, scale;
|
||||
|
||||
internal void incScale(int dScale)
|
||||
{
|
||||
Scale = Scale + dScale;
|
||||
}
|
||||
|
||||
internal long HighCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return highCount;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.highCount = value & RangeCoder.UintMask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal long LowCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return lowCount & RangeCoder.UintMask;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.lowCount = value & RangeCoder.UintMask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal long Scale
|
||||
{
|
||||
get
|
||||
{
|
||||
return scale;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.scale = value & RangeCoder.UintMask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Debug
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("SubRange[");
|
||||
buffer.Append("\n lowCount=");
|
||||
buffer.Append(lowCount);
|
||||
buffer.Append("\n highCount=");
|
||||
buffer.Append(highCount);
|
||||
buffer.Append("\n scale=");
|
||||
buffer.Append(scale);
|
||||
buffer.Append("]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class RarMemBlock : Pointer
|
||||
{
|
||||
public const int size = 12;
|
||||
|
||||
private int stamp, NU;
|
||||
|
||||
private int next, prev; // Pointer RarMemBlock
|
||||
|
||||
public RarMemBlock(byte[] Memory)
|
||||
: base(Memory)
|
||||
{
|
||||
}
|
||||
|
||||
internal int Stamp
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
stamp = Utility.readShortLittleEndian(Memory, Address) & 0xffff;
|
||||
}
|
||||
return stamp;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.stamp = value;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address, (short)value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal void InsertAt(RarMemBlock p)
|
||||
{
|
||||
RarMemBlock temp = new RarMemBlock(Memory);
|
||||
SetPrev(p.Address);
|
||||
temp.Address = GetPrev();
|
||||
SetNext(temp.GetNext()); // prev.getNext();
|
||||
temp.SetNext(this); // prev.setNext(this);
|
||||
temp.Address = GetNext();
|
||||
temp.SetPrev(this); // next.setPrev(this);
|
||||
}
|
||||
|
||||
internal void Remove()
|
||||
{
|
||||
RarMemBlock temp = new RarMemBlock(Memory);
|
||||
temp.Address = GetPrev();
|
||||
temp.SetNext(GetNext()); // prev.setNext(next);
|
||||
temp.Address = GetNext();
|
||||
temp.SetPrev(GetPrev()); // next.setPrev(prev);
|
||||
// next = -1;
|
||||
// prev = -1;
|
||||
}
|
||||
|
||||
internal int GetNext()
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
next = Utility.readIntLittleEndian(Memory, Address + 4);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
internal void SetNext(RarMemBlock next)
|
||||
{
|
||||
SetNext(next.Address);
|
||||
}
|
||||
|
||||
internal void SetNext(int next)
|
||||
{
|
||||
this.next = next;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address + 4, next);
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetNU()
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
NU = Utility.readShortLittleEndian(Memory, Address + 2) & 0xffff;
|
||||
}
|
||||
return NU;
|
||||
}
|
||||
|
||||
internal void SetNU(int nu)
|
||||
{
|
||||
NU = nu & 0xffff;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address + 2, (short)nu);
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetPrev()
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
prev = Utility.readIntLittleEndian(Memory, Address + 8);
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
internal void SetPrev(RarMemBlock prev)
|
||||
{
|
||||
SetPrev(prev.Address);
|
||||
}
|
||||
|
||||
internal void SetPrev(int prev)
|
||||
{
|
||||
this.prev = prev;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address + 8, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class RarNode : Pointer
|
||||
{
|
||||
private int next; //rarnode pointer
|
||||
|
||||
public const int size = 4;
|
||||
|
||||
public RarNode(byte[] Memory)
|
||||
: base(Memory)
|
||||
{
|
||||
}
|
||||
|
||||
internal int GetNext()
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
next = Utility.readIntLittleEndian(Memory, Address);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
internal void SetNext(RarNode next)
|
||||
{
|
||||
SetNext(next.Address);
|
||||
}
|
||||
|
||||
internal void SetNext(int next)
|
||||
{
|
||||
this.next = next;
|
||||
if (Memory != null)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address, next);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("State[");
|
||||
buffer.Append("\n Address=");
|
||||
buffer.Append(Address);
|
||||
buffer.Append("\n size=");
|
||||
buffer.Append(size);
|
||||
buffer.Append("\n next=");
|
||||
buffer.Append(GetNext());
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class SEE2Context
|
||||
{
|
||||
virtual public int Mean
|
||||
{
|
||||
get
|
||||
{
|
||||
int retVal = Utility.URShift(summ, shift);
|
||||
summ -= retVal;
|
||||
return retVal + ((retVal == 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.count = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int Shift
|
||||
{
|
||||
get
|
||||
{
|
||||
return shift;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.shift = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int Summ
|
||||
{
|
||||
get
|
||||
{
|
||||
return summ;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.summ = value & 0xffff;
|
||||
}
|
||||
|
||||
}
|
||||
public const int size = 4;
|
||||
|
||||
// ushort Summ;
|
||||
private int summ;
|
||||
|
||||
// byte Shift;
|
||||
private int shift;
|
||||
|
||||
// byte Count;
|
||||
private int count;
|
||||
|
||||
public void Initialize(int initVal)
|
||||
{
|
||||
shift = (ModelPPM.PERIOD_BITS - 4) & 0xff;
|
||||
summ = (initVal << shift) & 0xffff;
|
||||
count = 4;
|
||||
}
|
||||
|
||||
public virtual void update()
|
||||
{
|
||||
if (shift < ModelPPM.PERIOD_BITS && --count == 0)
|
||||
{
|
||||
summ += summ;
|
||||
count = (3 << shift++);
|
||||
}
|
||||
summ &= 0xffff;
|
||||
count &= 0xff;
|
||||
shift &= 0xff;
|
||||
}
|
||||
|
||||
public virtual void incSumm(int dSumm)
|
||||
{
|
||||
Summ = Summ + dSumm;
|
||||
}
|
||||
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("SEE2Context[");
|
||||
buffer.Append("\n size=");
|
||||
buffer.Append(size);
|
||||
buffer.Append("\n summ=");
|
||||
buffer.Append(summ);
|
||||
buffer.Append("\n shift=");
|
||||
buffer.Append(shift);
|
||||
buffer.Append("\n count=");
|
||||
buffer.Append(count);
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class State : Pointer
|
||||
{
|
||||
internal const int Size = 6;
|
||||
|
||||
internal State(byte[] Memory)
|
||||
: base(Memory)
|
||||
{
|
||||
}
|
||||
|
||||
internal int Symbol
|
||||
{
|
||||
get
|
||||
{
|
||||
return Memory[Address] & 0xff;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Memory[Address] = (byte)value;
|
||||
}
|
||||
|
||||
}
|
||||
internal int Freq
|
||||
{
|
||||
get
|
||||
{
|
||||
return Memory[Address + 1] & 0xff;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Memory[Address + 1] = (byte)value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal State Initialize(byte[] mem)
|
||||
{
|
||||
return base.Initialize<State>(mem);
|
||||
}
|
||||
|
||||
internal void IncrementFreq(int dFreq)
|
||||
{
|
||||
Memory[Address + 1] = (byte)(Memory[Address + 1] + dFreq);
|
||||
}
|
||||
|
||||
internal int GetSuccessor()
|
||||
{
|
||||
return Utility.readIntLittleEndian(Memory, Address + 2);
|
||||
}
|
||||
|
||||
internal void SetSuccessor(PPMContext successor)
|
||||
{
|
||||
SetSuccessor(successor.Address);
|
||||
}
|
||||
|
||||
internal void SetSuccessor(int successor)
|
||||
{
|
||||
Utility.WriteLittleEndian(Memory, Address + 2, successor);
|
||||
}
|
||||
|
||||
internal void SetValues(StateRef state)
|
||||
{
|
||||
Symbol = state.Symbol;
|
||||
Freq = state.Freq;
|
||||
SetSuccessor(state.GetSuccessor());
|
||||
}
|
||||
|
||||
internal void SetValues(State ptr)
|
||||
{
|
||||
Array.Copy(ptr.Memory, ptr.Address, Memory, Address, Size);
|
||||
}
|
||||
|
||||
internal State DecrementAddress()
|
||||
{
|
||||
Address = Address - Size;
|
||||
return this;
|
||||
}
|
||||
|
||||
internal State IncrementAddress()
|
||||
{
|
||||
Address = Address + Size;
|
||||
return this;
|
||||
}
|
||||
|
||||
internal static void PPMDSwap(State ptr1, State ptr2)
|
||||
{
|
||||
byte[] mem1 = ptr1.Memory, mem2 = ptr2.Memory;
|
||||
for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < Size; i++, pos1++, pos2++)
|
||||
{
|
||||
byte temp = mem1[pos1];
|
||||
mem1[pos1] = mem2[pos2];
|
||||
mem2[pos2] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("State[");
|
||||
buffer.Append("\n Address=");
|
||||
buffer.Append(Address);
|
||||
buffer.Append("\n size=");
|
||||
buffer.Append(Size);
|
||||
buffer.Append("\n symbol=");
|
||||
buffer.Append(Symbol);
|
||||
buffer.Append("\n freq=");
|
||||
buffer.Append(Freq);
|
||||
buffer.Append("\n successor=");
|
||||
buffer.Append(GetSuccessor());
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class StateRef
|
||||
{
|
||||
private int symbol;
|
||||
|
||||
private int freq;
|
||||
|
||||
private int successor; // pointer ppmcontext
|
||||
|
||||
internal int Symbol
|
||||
{
|
||||
get
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.symbol = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
internal int Freq
|
||||
{
|
||||
get
|
||||
{
|
||||
return freq;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.freq = value & 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal State Values
|
||||
{
|
||||
set
|
||||
{
|
||||
Freq = value.Freq;
|
||||
SetSuccessor(value.GetSuccessor());
|
||||
Symbol = value.Symbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual void IncrementFreq(int dFreq)
|
||||
{
|
||||
freq = (freq + dFreq) & 0xff;
|
||||
}
|
||||
|
||||
public virtual void DecrementFreq(int dFreq)
|
||||
{
|
||||
freq = (freq - dFreq) & 0xff;
|
||||
}
|
||||
|
||||
public virtual int GetSuccessor()
|
||||
{
|
||||
return successor;
|
||||
}
|
||||
|
||||
public virtual void SetSuccessor(PPMContext successor)
|
||||
{
|
||||
SetSuccessor(successor.Address);
|
||||
}
|
||||
|
||||
public virtual void SetSuccessor(int successor)
|
||||
{
|
||||
this.successor = successor;
|
||||
}
|
||||
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("State[");
|
||||
buffer.Append("\n symbol=");
|
||||
buffer.Append(Symbol);
|
||||
buffer.Append("\n freq=");
|
||||
buffer.Append(Freq);
|
||||
buffer.Append("\n successor=");
|
||||
buffer.Append(GetSuccessor());
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,489 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
{
|
||||
internal class SubAllocator
|
||||
{
|
||||
virtual public int FakeUnitsStart
|
||||
{
|
||||
get
|
||||
{
|
||||
return fakeUnitsStart;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.fakeUnitsStart = value;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int HeapEnd
|
||||
{
|
||||
get
|
||||
{
|
||||
return heapEnd;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int PText
|
||||
{
|
||||
get
|
||||
{
|
||||
return pText;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
pText = value;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public int UnitsStart
|
||||
{
|
||||
get
|
||||
{
|
||||
return unitsStart;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.unitsStart = value;
|
||||
}
|
||||
|
||||
}
|
||||
virtual public byte[] Heap
|
||||
{
|
||||
get
|
||||
{
|
||||
return heap;
|
||||
}
|
||||
|
||||
}
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'N4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public const int N1 = 4;
|
||||
public const int N2 = 4;
|
||||
public const int N3 = 4;
|
||||
public static readonly int N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'N_INDEXES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
public static readonly int N_INDEXES = N1 + N2 + N3 + N4;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'UNIT_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
//UPGRADE_NOTE: The initialization of 'UNIT_SIZE' was moved to static method 'SharpCompress.Unpack.PPM.SubAllocator'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
|
||||
public static readonly int UNIT_SIZE;
|
||||
|
||||
public const int FIXED_UNIT_SIZE = 12;
|
||||
|
||||
private int subAllocatorSize;
|
||||
|
||||
// byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
|
||||
private int[] indx2Units = new int[N_INDEXES];
|
||||
private int[] units2Indx = new int[128];
|
||||
private int glueCount;
|
||||
|
||||
// byte *HeapStart,*LoUnit, *HiUnit;
|
||||
private int heapStart, loUnit, hiUnit;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
private RarNode[] freeList = new RarNode[N_INDEXES];
|
||||
|
||||
// byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
|
||||
private int pText, unitsStart, heapEnd, fakeUnitsStart;
|
||||
|
||||
private byte[] heap;
|
||||
|
||||
private int freeListPos;
|
||||
|
||||
private int tempMemBlockPos;
|
||||
|
||||
// Temp fields
|
||||
private RarNode tempRarNode = null;
|
||||
private RarMemBlock tempRarMemBlock1 = null;
|
||||
private RarMemBlock tempRarMemBlock2 = null;
|
||||
private RarMemBlock tempRarMemBlock3 = null;
|
||||
|
||||
public SubAllocator()
|
||||
{
|
||||
clean();
|
||||
}
|
||||
|
||||
public virtual void clean()
|
||||
{
|
||||
subAllocatorSize = 0;
|
||||
}
|
||||
|
||||
private void insertNode(int p, int indx)
|
||||
{
|
||||
RarNode temp = tempRarNode;
|
||||
temp.Address = p;
|
||||
temp.SetNext(freeList[indx].GetNext());
|
||||
freeList[indx].SetNext(temp);
|
||||
}
|
||||
|
||||
public virtual void incPText()
|
||||
{
|
||||
pText++;
|
||||
}
|
||||
|
||||
private int removeNode(int indx)
|
||||
{
|
||||
int retVal = freeList[indx].GetNext();
|
||||
RarNode temp = tempRarNode;
|
||||
temp.Address = retVal;
|
||||
freeList[indx].SetNext(temp.GetNext());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private int U2B(int NU)
|
||||
{
|
||||
return UNIT_SIZE * NU;
|
||||
}
|
||||
|
||||
/* memblockptr */
|
||||
private int MBPtr(int BasePtr, int Items)
|
||||
{
|
||||
return (BasePtr + U2B(Items));
|
||||
}
|
||||
|
||||
private void splitBlock(int pv, int oldIndx, int newIndx)
|
||||
{
|
||||
int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx];
|
||||
int p = pv + U2B(indx2Units[newIndx]);
|
||||
if (indx2Units[i = units2Indx[uDiff - 1]] != uDiff)
|
||||
{
|
||||
insertNode(p, --i);
|
||||
p += U2B(i = indx2Units[i]);
|
||||
uDiff -= i;
|
||||
}
|
||||
insertNode(p, units2Indx[uDiff - 1]);
|
||||
}
|
||||
|
||||
public virtual void stopSubAllocator()
|
||||
{
|
||||
if (subAllocatorSize != 0)
|
||||
{
|
||||
subAllocatorSize = 0;
|
||||
//ArrayFactory.BYTES_FACTORY.recycle(heap);
|
||||
heap = null;
|
||||
heapStart = 1;
|
||||
// rarfree(HeapStart);
|
||||
// Free temp fields
|
||||
tempRarNode = null;
|
||||
tempRarMemBlock1 = null;
|
||||
tempRarMemBlock2 = null;
|
||||
tempRarMemBlock3 = null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int GetAllocatedMemory()
|
||||
{
|
||||
return subAllocatorSize;
|
||||
}
|
||||
|
||||
|
||||
public virtual bool startSubAllocator(int SASize)
|
||||
{
|
||||
int t = SASize;
|
||||
if (subAllocatorSize == t)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
stopSubAllocator();
|
||||
int allocSize = t / FIXED_UNIT_SIZE * UNIT_SIZE + UNIT_SIZE;
|
||||
|
||||
// adding space for freelist (needed for poiters)
|
||||
// 1+ for null pointer
|
||||
int realAllocSize = 1 + allocSize + 4 * N_INDEXES;
|
||||
// adding space for an additional memblock
|
||||
tempMemBlockPos = realAllocSize;
|
||||
realAllocSize += RarMemBlock.size;
|
||||
|
||||
heap = new byte[realAllocSize];
|
||||
heapStart = 1;
|
||||
heapEnd = heapStart + allocSize - UNIT_SIZE;
|
||||
subAllocatorSize = t;
|
||||
// Bug fixed
|
||||
freeListPos = heapStart + allocSize;
|
||||
//UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'"
|
||||
//assert(realAllocSize - tempMemBlockPos == RarMemBlock.size): realAllocSize
|
||||
//+ + tempMemBlockPos + + RarMemBlock.size;
|
||||
|
||||
// Init freeList
|
||||
for (int i = 0, pos = freeListPos; i < freeList.Length; i++, pos += RarNode.size)
|
||||
{
|
||||
freeList[i] = new RarNode(heap);
|
||||
freeList[i].Address = pos;
|
||||
}
|
||||
|
||||
// Init temp fields
|
||||
tempRarNode = new RarNode(heap);
|
||||
tempRarMemBlock1 = new RarMemBlock(heap);
|
||||
tempRarMemBlock2 = new RarMemBlock(heap);
|
||||
tempRarMemBlock3 = new RarMemBlock(heap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void glueFreeBlocks()
|
||||
{
|
||||
RarMemBlock s0 = tempRarMemBlock1;
|
||||
s0.Address = tempMemBlockPos;
|
||||
RarMemBlock p = tempRarMemBlock2;
|
||||
RarMemBlock p1 = tempRarMemBlock3;
|
||||
int i, k, sz;
|
||||
if (loUnit != hiUnit)
|
||||
{
|
||||
heap[loUnit] = 0;
|
||||
}
|
||||
for (i = 0, s0.SetPrev(s0), s0.SetNext(s0); i < N_INDEXES; i++)
|
||||
{
|
||||
while (freeList[i].GetNext() != 0)
|
||||
{
|
||||
p.Address = removeNode(i); // =(RAR_MEM_BLK*)RemoveNode(i);
|
||||
p.InsertAt(s0); // p->insertAt(&s0);
|
||||
p.Stamp = 0xFFFF; // p->Stamp=0xFFFF;
|
||||
p.SetNU(indx2Units[i]); // p->NU=Indx2Units[i];
|
||||
}
|
||||
}
|
||||
for (p.Address = s0.GetNext(); p.Address != s0.Address; p.Address = p.GetNext())
|
||||
{
|
||||
// while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU
|
||||
// < 0x10000)
|
||||
// Bug fixed
|
||||
p1.Address = MBPtr(p.Address, p.GetNU());
|
||||
while (p1.Stamp == 0xFFFF && p.GetNU() + p1.GetNU() < 0x10000)
|
||||
{
|
||||
p1.Remove();
|
||||
p.SetNU(p.GetNU() + p1.GetNU()); // ->NU += p1->NU;
|
||||
p1.Address = MBPtr(p.Address, p.GetNU());
|
||||
}
|
||||
}
|
||||
// while ((p=s0.next) != &s0)
|
||||
// Bug fixed
|
||||
p.Address = s0.GetNext();
|
||||
while (p.Address != s0.Address)
|
||||
{
|
||||
for (p.Remove(), sz = p.GetNU(); sz > 128; sz -= 128, p.Address = MBPtr(p.Address, 128))
|
||||
{
|
||||
insertNode(p.Address, N_INDEXES - 1);
|
||||
}
|
||||
if (indx2Units[i = units2Indx[sz - 1]] != sz)
|
||||
{
|
||||
k = sz - indx2Units[--i];
|
||||
insertNode(MBPtr(p.Address, sz - k), k - 1);
|
||||
}
|
||||
insertNode(p.Address, i);
|
||||
p.Address = s0.GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
private int allocUnitsRare(int indx)
|
||||
{
|
||||
if (glueCount == 0)
|
||||
{
|
||||
glueCount = 255;
|
||||
glueFreeBlocks();
|
||||
if (freeList[indx].GetNext() != 0)
|
||||
{
|
||||
return removeNode(indx);
|
||||
}
|
||||
}
|
||||
int i = indx;
|
||||
do
|
||||
{
|
||||
if (++i == N_INDEXES)
|
||||
{
|
||||
glueCount--;
|
||||
i = U2B(indx2Units[indx]);
|
||||
int j = FIXED_UNIT_SIZE * indx2Units[indx];
|
||||
if (fakeUnitsStart - pText > j)
|
||||
{
|
||||
fakeUnitsStart -= j;
|
||||
unitsStart -= i;
|
||||
return unitsStart;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
while (freeList[i].GetNext() == 0);
|
||||
int retVal = removeNode(i);
|
||||
splitBlock(retVal, i, indx);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public virtual int allocUnits(int NU)
|
||||
{
|
||||
int indx = units2Indx[NU - 1];
|
||||
if (freeList[indx].GetNext() != 0)
|
||||
{
|
||||
return removeNode(indx);
|
||||
}
|
||||
int retVal = loUnit;
|
||||
loUnit += U2B(indx2Units[indx]);
|
||||
if (loUnit <= hiUnit)
|
||||
{
|
||||
return retVal;
|
||||
}
|
||||
loUnit -= U2B(indx2Units[indx]);
|
||||
return allocUnitsRare(indx);
|
||||
}
|
||||
|
||||
public virtual int allocContext()
|
||||
{
|
||||
if (hiUnit != loUnit)
|
||||
return (hiUnit -= UNIT_SIZE);
|
||||
if (freeList[0].GetNext() != 0)
|
||||
{
|
||||
return removeNode(0);
|
||||
}
|
||||
return allocUnitsRare(0);
|
||||
}
|
||||
|
||||
public virtual int expandUnits(int oldPtr, int OldNU)
|
||||
{
|
||||
int i0 = units2Indx[OldNU - 1];
|
||||
int i1 = units2Indx[OldNU - 1 + 1];
|
||||
if (i0 == i1)
|
||||
{
|
||||
return oldPtr;
|
||||
}
|
||||
int ptr = allocUnits(OldNU + 1);
|
||||
if (ptr != 0)
|
||||
{
|
||||
// memcpy(ptr,OldPtr,U2B(OldNU));
|
||||
Array.Copy(heap, oldPtr, heap, ptr, U2B(OldNU));
|
||||
insertNode(oldPtr, i0);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public virtual int shrinkUnits(int oldPtr, int oldNU, int newNU)
|
||||
{
|
||||
// System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " +
|
||||
// OldNU + ", " + NewNU + ")");
|
||||
int i0 = units2Indx[oldNU - 1];
|
||||
int i1 = units2Indx[newNU - 1];
|
||||
if (i0 == i1)
|
||||
{
|
||||
return oldPtr;
|
||||
}
|
||||
if (freeList[i1].GetNext() != 0)
|
||||
{
|
||||
int ptr = removeNode(i1);
|
||||
// memcpy(ptr,OldPtr,U2B(NewNU));
|
||||
// for (int i = 0; i < U2B(NewNU); i++) {
|
||||
// heap[ptr + i] = heap[OldPtr + i];
|
||||
// }
|
||||
Array.Copy(heap, oldPtr, heap, ptr, U2B(newNU));
|
||||
insertNode(oldPtr, i0);
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
splitBlock(oldPtr, i0, i1);
|
||||
return oldPtr;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void freeUnits(int ptr, int OldNU)
|
||||
{
|
||||
insertNode(ptr, units2Indx[OldNU - 1]);
|
||||
}
|
||||
|
||||
public virtual void decPText(int dPText)
|
||||
{
|
||||
PText = PText - dPText;
|
||||
}
|
||||
|
||||
public virtual void initSubAllocator()
|
||||
{
|
||||
int i, k;
|
||||
Utility.Fill(heap, freeListPos, freeListPos + sizeOfFreeList(), (byte)0);
|
||||
|
||||
pText = heapStart;
|
||||
|
||||
int size2 = FIXED_UNIT_SIZE * (subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7);
|
||||
int realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE;
|
||||
int size1 = subAllocatorSize - size2;
|
||||
int realSize1 = size1 / FIXED_UNIT_SIZE * UNIT_SIZE + size1 % FIXED_UNIT_SIZE;
|
||||
hiUnit = heapStart + subAllocatorSize;
|
||||
loUnit = unitsStart = heapStart + realSize1;
|
||||
fakeUnitsStart = heapStart + size1;
|
||||
hiUnit = loUnit + realSize2;
|
||||
|
||||
for (i = 0, k = 1; i < N1; i++, k += 1)
|
||||
{
|
||||
indx2Units[i] = k & 0xff;
|
||||
}
|
||||
for (k++; i < N1 + N2; i++, k += 2)
|
||||
{
|
||||
indx2Units[i] = k & 0xff;
|
||||
}
|
||||
for (k++; i < N1 + N2 + N3; i++, k += 3)
|
||||
{
|
||||
indx2Units[i] = k & 0xff;
|
||||
}
|
||||
for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4)
|
||||
{
|
||||
indx2Units[i] = k & 0xff;
|
||||
}
|
||||
|
||||
for (glueCount = 0, k = 0, i = 0; k < 128; k++)
|
||||
{
|
||||
i += ((indx2Units[i] < (k + 1)) ? 1 : 0);
|
||||
units2Indx[k] = i & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
private int sizeOfFreeList()
|
||||
{
|
||||
return freeList.Length * RarNode.size;
|
||||
}
|
||||
|
||||
// Debug
|
||||
// public void dumpHeap() {
|
||||
// File file = new File("P:\\test\\heapdumpj");
|
||||
// OutputStream out = null;
|
||||
// try {
|
||||
// out = new FileOutputStream(file);
|
||||
// out.write(heap, heapStart, heapEnd - heapStart);
|
||||
// out.flush();
|
||||
// System.out.println("Heap dumped to " + file.getAbsolutePath());
|
||||
// }
|
||||
// catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// finally {
|
||||
// FileUtil.close(out);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Debug
|
||||
public override System.String ToString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("SubAllocator[");
|
||||
buffer.Append("\n subAllocatorSize=");
|
||||
buffer.Append(subAllocatorSize);
|
||||
buffer.Append("\n glueCount=");
|
||||
buffer.Append(glueCount);
|
||||
buffer.Append("\n heapStart=");
|
||||
buffer.Append(heapStart);
|
||||
buffer.Append("\n loUnit=");
|
||||
buffer.Append(loUnit);
|
||||
buffer.Append("\n hiUnit=");
|
||||
buffer.Append(hiUnit);
|
||||
buffer.Append("\n pText=");
|
||||
buffer.Append(pText);
|
||||
buffer.Append("\n unitsStart=");
|
||||
buffer.Append(unitsStart);
|
||||
buffer.Append("\n]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
static SubAllocator()
|
||||
{
|
||||
UNIT_SIZE = System.Math.Max(PPMContext.size, RarMemBlock.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,457 +0,0 @@
|
||||
#region Using
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
|
||||
/// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with
|
||||
/// instances of <see cref="Pointer"/> (which simply contain a single address value, representing a location
|
||||
/// in the large array). Callers can then cast <see cref="Pointer"/> to one of the following structures (all
|
||||
/// of which also simply contain a single address value):
|
||||
internal class Allocator
|
||||
{
|
||||
private const uint UnitSize = 12;
|
||||
private const uint LocalOffset = 4; // reserve the first four bytes for Pointer.Zero
|
||||
private const uint NodeOffset = LocalOffset + MemoryNode.Size; // reserve space for a single memory node
|
||||
private const uint HeapOffset = NodeOffset + IndexCount * MemoryNode.Size; // reserve space for the array of memory nodes
|
||||
private const uint N1 = 4;
|
||||
private const uint N2 = 4;
|
||||
private const uint N3 = 4;
|
||||
private const uint N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4;
|
||||
private const uint IndexCount = N1 + N2 + N3 + N4;
|
||||
|
||||
private static readonly byte[] indexToUnits;
|
||||
private static readonly byte[] unitsToIndex;
|
||||
|
||||
public uint AllocatorSize;
|
||||
public uint GlueCount;
|
||||
public Pointer BaseUnit;
|
||||
public Pointer LowUnit;
|
||||
public Pointer HighUnit;
|
||||
public Pointer Text;
|
||||
public Pointer Heap;
|
||||
public MemoryNode[] MemoryNodes;
|
||||
|
||||
public byte[] Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static read-only arrays used by the <see cref="Allocator"/>.
|
||||
/// </summary>
|
||||
static Allocator()
|
||||
{
|
||||
// Construct the static index to units lookup array. It will contain the following values.
|
||||
//
|
||||
// 1 2 3 4 6 8 10 12 15 18 21 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108
|
||||
// 112 116 120 124 128
|
||||
|
||||
uint index;
|
||||
uint unitCount;
|
||||
|
||||
indexToUnits = new byte[IndexCount];
|
||||
|
||||
for (index = 0, unitCount = 1; index < N1; index++, unitCount += 1)
|
||||
indexToUnits[index] = (byte)unitCount;
|
||||
|
||||
for (unitCount++; index < N1 + N2; index++, unitCount += 2)
|
||||
indexToUnits[index] = (byte)unitCount;
|
||||
|
||||
for (unitCount++; index < N1 + N2 + N3; index++, unitCount += 3)
|
||||
indexToUnits[index] = (byte)unitCount;
|
||||
|
||||
for (unitCount++; index < N1 + N2 + N3 + N4; index++, unitCount += 4)
|
||||
indexToUnits[index] = (byte)unitCount;
|
||||
|
||||
// Construct the static units to index lookup array. It will contain the following values.
|
||||
//
|
||||
// 00 01 02 03 04 04 05 05 06 06 07 07 08 08 08 09 09 09 10 10 10 11 11 11 12 12 12 12 13 13 13 13
|
||||
// 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 19 20 20 20 20 21 21 21 21
|
||||
// 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 27 27 27 27 28 28 28 28 29 29 29 29
|
||||
// 30 30 30 30 31 31 31 31 32 32 32 32 33 33 33 33 34 34 34 34 35 35 35 35 36 36 36 36 37 37 37 37
|
||||
|
||||
unitsToIndex = new byte[128];
|
||||
|
||||
for (unitCount = index = 0; unitCount < 128; unitCount++)
|
||||
{
|
||||
index += (uint)((indexToUnits[index] < unitCount + 1) ? 1 : 0);
|
||||
unitsToIndex[unitCount] = (byte)index;
|
||||
}
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public Allocator()
|
||||
{
|
||||
MemoryNodes = new MemoryNode[IndexCount];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying
|
||||
/// and re-creating it).
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
for (int index = 0; index < IndexCount; index++)
|
||||
{
|
||||
MemoryNodes[index] = new MemoryNode((uint)(NodeOffset + index * MemoryNode.Size), Memory);
|
||||
MemoryNodes[index].Stamp = 0;
|
||||
MemoryNodes[index].Next = MemoryNode.Zero;
|
||||
MemoryNodes[index].UnitCount = 0;
|
||||
}
|
||||
|
||||
Text = Heap;
|
||||
|
||||
uint difference = UnitSize * (AllocatorSize / 8 / UnitSize * 7);
|
||||
|
||||
HighUnit = Heap + AllocatorSize;
|
||||
LowUnit = HighUnit - difference;
|
||||
BaseUnit = HighUnit - difference;
|
||||
|
||||
GlueCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the allocator (create a single, large array of bytes).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that .NET will create that array on the large object heap (because it is so large).
|
||||
/// </remarks>
|
||||
/// <param name="allocatorSize"></param>
|
||||
public void Start(int allocatorSize)
|
||||
{
|
||||
uint size = (uint)allocatorSize;
|
||||
if (AllocatorSize != size)
|
||||
{
|
||||
Stop();
|
||||
Memory = new byte[HeapOffset + size]; // the single, large array of bytes
|
||||
Heap = new Pointer(HeapOffset, Memory); // reserve bytes in the range 0 .. HeapOffset - 1
|
||||
AllocatorSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the allocator (free the single, large array of bytes). This can safely be called multiple times (without
|
||||
/// intervening calls to <see cref="Start"/>).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Because the array is on the large object heap it may not be freed immediately.
|
||||
/// </remarks>
|
||||
public void Stop()
|
||||
{
|
||||
if (AllocatorSize != 0)
|
||||
{
|
||||
AllocatorSize = 0;
|
||||
Memory = null;
|
||||
Heap = Pointer.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine how much memory (from the single, large array) is currenly in use.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public uint GetMemoryUsed()
|
||||
{
|
||||
uint memoryUsed = AllocatorSize - (HighUnit - LowUnit) - (BaseUnit - Text);
|
||||
for (uint index = 0; index < IndexCount; index++)
|
||||
memoryUsed -= UnitSize * indexToUnits[index] * MemoryNodes[index].Stamp;
|
||||
return memoryUsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocate a given number of units from the single, large array. Each unit is <see cref="UnitSize"/> bytes
|
||||
/// in size.
|
||||
/// </summary>
|
||||
/// <param name="unitCount"></param>
|
||||
/// <returns></returns>
|
||||
public Pointer AllocateUnits(uint unitCount)
|
||||
{
|
||||
uint index = unitsToIndex[unitCount - 1];
|
||||
if (MemoryNodes[index].Available)
|
||||
return MemoryNodes[index].Remove();
|
||||
|
||||
Pointer allocatedBlock = LowUnit;
|
||||
LowUnit += indexToUnits[index] * UnitSize;
|
||||
if (LowUnit <= HighUnit)
|
||||
return allocatedBlock;
|
||||
|
||||
LowUnit -= indexToUnits[index] * UnitSize;
|
||||
return AllocateUnitsRare(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocate enough space for a PpmContext instance in the single, large array.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Pointer AllocateContext()
|
||||
{
|
||||
if (HighUnit != LowUnit)
|
||||
return (HighUnit -= UnitSize);
|
||||
else if (MemoryNodes[0].Available)
|
||||
return MemoryNodes[0].Remove();
|
||||
else
|
||||
return AllocateUnitsRare(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increase the size of an existing allocation (represented by a <see cref="Pointer"/>).
|
||||
/// </summary>
|
||||
/// <param name="oldPointer"></param>
|
||||
/// <param name="oldUnitCount"></param>
|
||||
/// <returns></returns>
|
||||
public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount)
|
||||
{
|
||||
uint oldIndex = unitsToIndex[oldUnitCount - 1];
|
||||
uint newIndex = unitsToIndex[oldUnitCount];
|
||||
|
||||
if (oldIndex == newIndex)
|
||||
return oldPointer;
|
||||
|
||||
Pointer pointer = AllocateUnits(oldUnitCount + 1);
|
||||
|
||||
if (pointer != Pointer.Zero)
|
||||
{
|
||||
CopyUnits(pointer, oldPointer, oldUnitCount);
|
||||
MemoryNodes[oldIndex].Insert(oldPointer, oldUnitCount);
|
||||
}
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrease the size of an existing allocation (represented by a <see cref="Pointer"/>).
|
||||
/// </summary>
|
||||
/// <param name="oldPointer"></param>
|
||||
/// <param name="oldUnitCount"></param>
|
||||
/// <param name="newUnitCount"></param>
|
||||
/// <returns></returns>
|
||||
public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount)
|
||||
{
|
||||
uint oldIndex = unitsToIndex[oldUnitCount - 1];
|
||||
uint newIndex = unitsToIndex[newUnitCount - 1];
|
||||
|
||||
if (oldIndex == newIndex)
|
||||
return oldPointer;
|
||||
|
||||
if (MemoryNodes[newIndex].Available)
|
||||
{
|
||||
Pointer pointer = MemoryNodes[newIndex].Remove();
|
||||
CopyUnits(pointer, oldPointer, newUnitCount);
|
||||
MemoryNodes[oldIndex].Insert(oldPointer, indexToUnits[oldIndex]);
|
||||
return pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitBlock(oldPointer, oldIndex, newIndex);
|
||||
return oldPointer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free previously allocated space (the location and amount of space to free must be specified by using
|
||||
/// a <see cref="Pointer"/> to indicate the location and a number of units to indicate the amount).
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="unitCount"></param>
|
||||
public void FreeUnits(Pointer pointer, uint unitCount)
|
||||
{
|
||||
uint index = unitsToIndex[unitCount - 1];
|
||||
MemoryNodes[index].Insert(pointer, indexToUnits[index]);
|
||||
}
|
||||
|
||||
public void SpecialFreeUnits(Pointer pointer)
|
||||
{
|
||||
if (pointer != BaseUnit)
|
||||
{
|
||||
MemoryNodes[0].Insert(pointer, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryNode memoryNode = pointer;
|
||||
memoryNode.Stamp = uint.MaxValue;
|
||||
BaseUnit += UnitSize;
|
||||
}
|
||||
}
|
||||
|
||||
public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount)
|
||||
{
|
||||
uint index = unitsToIndex[unitCount - 1];
|
||||
|
||||
if (oldPointer > BaseUnit + 16 * 1024 || oldPointer > MemoryNodes[index].Next)
|
||||
return oldPointer;
|
||||
|
||||
Pointer pointer = MemoryNodes[index].Remove();
|
||||
CopyUnits(pointer, oldPointer, unitCount);
|
||||
unitCount = indexToUnits[index];
|
||||
|
||||
if (oldPointer != BaseUnit)
|
||||
MemoryNodes[index].Insert(oldPointer, unitCount);
|
||||
else
|
||||
BaseUnit += unitCount * UnitSize;
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expand the space allocated (in the single, large array) for the bytes of the data (ie. the "text") that is
|
||||
/// being encoded or decoded.
|
||||
/// </summary>
|
||||
public void ExpandText()
|
||||
{
|
||||
MemoryNode memoryNode;
|
||||
uint[] counts = new uint[IndexCount];
|
||||
|
||||
while ((memoryNode = BaseUnit).Stamp == uint.MaxValue)
|
||||
{
|
||||
BaseUnit = memoryNode + memoryNode.UnitCount;
|
||||
counts[unitsToIndex[memoryNode.UnitCount - 1]]++;
|
||||
memoryNode.Stamp = 0;
|
||||
}
|
||||
|
||||
for (uint index = 0; index < IndexCount; index++)
|
||||
{
|
||||
for (memoryNode = MemoryNodes[index]; counts[index] != 0; memoryNode = memoryNode.Next)
|
||||
{
|
||||
while (memoryNode.Next.Stamp == 0)
|
||||
{
|
||||
memoryNode.Unlink();
|
||||
MemoryNodes[index].Stamp--;
|
||||
if (--counts[index] == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private Pointer AllocateUnitsRare(uint index)
|
||||
{
|
||||
if (GlueCount == 0)
|
||||
{
|
||||
GlueFreeBlocks();
|
||||
if (MemoryNodes[index].Available)
|
||||
return MemoryNodes[index].Remove();
|
||||
}
|
||||
|
||||
uint oldIndex = index;
|
||||
do
|
||||
{
|
||||
if (++oldIndex == IndexCount)
|
||||
{
|
||||
GlueCount--;
|
||||
oldIndex = indexToUnits[index] * UnitSize;
|
||||
return (BaseUnit - Text > oldIndex) ? (BaseUnit -= oldIndex) : Pointer.Zero;
|
||||
}
|
||||
} while (!MemoryNodes[oldIndex].Available);
|
||||
|
||||
Pointer allocatedBlock = MemoryNodes[oldIndex].Remove();
|
||||
SplitBlock(allocatedBlock, oldIndex, index);
|
||||
return allocatedBlock;
|
||||
}
|
||||
|
||||
private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex)
|
||||
{
|
||||
uint unitCountDifference = (uint)(indexToUnits[oldIndex] - indexToUnits[newIndex]);
|
||||
Pointer newPointer = pointer + indexToUnits[newIndex] * UnitSize;
|
||||
|
||||
uint index = unitsToIndex[unitCountDifference - 1];
|
||||
if (indexToUnits[index] != unitCountDifference)
|
||||
{
|
||||
uint unitCount = indexToUnits[--index];
|
||||
MemoryNodes[index].Insert(newPointer, unitCount);
|
||||
newPointer += unitCount * UnitSize;
|
||||
unitCountDifference -= unitCount;
|
||||
}
|
||||
|
||||
MemoryNodes[unitsToIndex[unitCountDifference - 1]].Insert(newPointer, unitCountDifference);
|
||||
}
|
||||
|
||||
private void GlueFreeBlocks()
|
||||
{
|
||||
MemoryNode memoryNode = new MemoryNode(LocalOffset, Memory);
|
||||
memoryNode.Stamp = 0;
|
||||
memoryNode.Next = MemoryNode.Zero;
|
||||
memoryNode.UnitCount = 0;
|
||||
|
||||
MemoryNode memoryNode0;
|
||||
MemoryNode memoryNode1;
|
||||
MemoryNode memoryNode2;
|
||||
|
||||
if (LowUnit != HighUnit)
|
||||
LowUnit[0] = 0;
|
||||
|
||||
// Find all unused memory nodes.
|
||||
|
||||
memoryNode1 = memoryNode;
|
||||
for (uint index = 0; index < IndexCount; index++)
|
||||
{
|
||||
while (MemoryNodes[index].Available)
|
||||
{
|
||||
memoryNode0 = MemoryNodes[index].Remove();
|
||||
if (memoryNode0.UnitCount != 0)
|
||||
{
|
||||
while ((memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp == uint.MaxValue)
|
||||
{
|
||||
memoryNode0.UnitCount = memoryNode0.UnitCount + memoryNode2.UnitCount;
|
||||
memoryNode2.UnitCount = 0;
|
||||
}
|
||||
memoryNode1.Link(memoryNode0);
|
||||
memoryNode1 = memoryNode0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coalesce the memory represented by the unused memory nodes.
|
||||
|
||||
while (memoryNode.Available)
|
||||
{
|
||||
memoryNode0 = memoryNode.Remove();
|
||||
uint unitCount = memoryNode0.UnitCount;
|
||||
if (unitCount != 0)
|
||||
{
|
||||
for (; unitCount > 128; unitCount -= 128, memoryNode0 += 128)
|
||||
MemoryNodes[IndexCount - 1].Insert(memoryNode0, 128);
|
||||
|
||||
uint index = unitsToIndex[unitCount - 1];
|
||||
if (indexToUnits[index] != unitCount)
|
||||
{
|
||||
uint unitCountDifference = unitCount - indexToUnits[--index];
|
||||
MemoryNodes[unitCountDifference - 1].Insert(memoryNode0 + (unitCount - unitCountDifference), unitCountDifference);
|
||||
}
|
||||
|
||||
MemoryNodes[index].Insert(memoryNode0, indexToUnits[index]);
|
||||
}
|
||||
}
|
||||
|
||||
GlueCount = 1 << 13;
|
||||
}
|
||||
|
||||
private void CopyUnits(Pointer target, Pointer source, uint unitCount)
|
||||
{
|
||||
do
|
||||
{
|
||||
target[0] = source[0];
|
||||
target[1] = source[1];
|
||||
target[2] = source[2];
|
||||
target[3] = source[3];
|
||||
target[4] = source[4];
|
||||
target[5] = source[5];
|
||||
target[6] = source[6];
|
||||
target[7] = source[7];
|
||||
target[8] = source[8];
|
||||
target[9] = source[9];
|
||||
target[10] = source[10];
|
||||
target[11] = source[11];
|
||||
target += UnitSize;
|
||||
source += UnitSize;
|
||||
} while (--unitCount != 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
#region Using
|
||||
|
||||
using System.IO;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple range coder.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that in most cases fields are used rather than properties for performance reasons (for example,
|
||||
/// <see cref="Scale"/> is a field rather than a property).
|
||||
/// </remarks>
|
||||
internal class Coder
|
||||
{
|
||||
private const uint RangeTop = 1 << 24;
|
||||
private const uint RangeBottom = 1 << 15;
|
||||
private uint low;
|
||||
private uint code;
|
||||
private uint range;
|
||||
|
||||
public uint LowCount;
|
||||
public uint HighCount;
|
||||
public uint Scale;
|
||||
|
||||
public void RangeEncoderInitialize()
|
||||
{
|
||||
low = 0;
|
||||
range = uint.MaxValue;
|
||||
}
|
||||
|
||||
public void RangeEncoderNormalize(Stream stream)
|
||||
{
|
||||
while ((low ^ (low + range)) < RangeTop || range < RangeBottom && ((range = (uint)-low & (RangeBottom - 1)) != 0 || true))
|
||||
{
|
||||
stream.WriteByte((byte)(low >> 24));
|
||||
range <<= 8;
|
||||
low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void RangeEncodeSymbol()
|
||||
{
|
||||
low += LowCount * (range /= Scale);
|
||||
range *= HighCount - LowCount;
|
||||
}
|
||||
|
||||
public void RangeShiftEncodeSymbol(int rangeShift)
|
||||
{
|
||||
low += LowCount * (range >>= rangeShift);
|
||||
range *= HighCount - LowCount;
|
||||
}
|
||||
|
||||
public void RangeEncoderFlush(Stream stream)
|
||||
{
|
||||
for (uint index = 0; index < 4; index++)
|
||||
{
|
||||
stream.WriteByte((byte)(low >> 24));
|
||||
low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void RangeDecoderInitialize(Stream stream)
|
||||
{
|
||||
low = 0;
|
||||
code = 0;
|
||||
range = uint.MaxValue;
|
||||
for (uint index = 0; index < 4; index++)
|
||||
code = (code << 8) | (byte)stream.ReadByte();
|
||||
}
|
||||
|
||||
public void RangeDecoderNormalize(Stream stream)
|
||||
{
|
||||
while ((low ^ (low + range)) < RangeTop || range < RangeBottom && ((range = (uint)-low & (RangeBottom - 1)) != 0 || true))
|
||||
{
|
||||
code = (code << 8) | (byte)stream.ReadByte();
|
||||
range <<= 8;
|
||||
low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public uint RangeGetCurrentCount()
|
||||
{
|
||||
return (code - low) / (range /= Scale);
|
||||
}
|
||||
|
||||
public uint RangeGetCurrentShiftCount(int rangeShift)
|
||||
{
|
||||
return (code - low) / (range >>= rangeShift);
|
||||
}
|
||||
|
||||
public void RangeRemoveSubrange()
|
||||
{
|
||||
low += range * LowCount;
|
||||
range *= HighCount - LowCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
#region Using
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure containing a single address. The address represents a location in the <see cref="Memory"/>
|
||||
/// array. That location in the <see cref="Memory"/> array contains information itself describing a section
|
||||
/// of the <see cref="Memory"/> array (ie. a block of memory).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This must be a structure rather than a class because several places in the associated code assume that
|
||||
/// <see cref="MemoryNode"/> is a value type (meaning that assignment creates a completely new copy of
|
||||
/// the instance rather than just copying a reference to the same instance).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// MemoryNode
|
||||
/// 4 Stamp
|
||||
/// 4 Next
|
||||
/// 4 UnitCount
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that <see cref="Address"/> is a field rather than a property for performance reasons.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal struct MemoryNode
|
||||
{
|
||||
public uint Address;
|
||||
public byte[] Memory;
|
||||
public static readonly MemoryNode Zero = new MemoryNode(0, null);
|
||||
public const int Size = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MemoryNode"/> structure.
|
||||
/// </summary>
|
||||
public MemoryNode(uint address, byte[] memory)
|
||||
{
|
||||
Address = address;
|
||||
Memory = memory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the stamp.
|
||||
/// </summary>
|
||||
public uint Stamp
|
||||
{
|
||||
get { return ((uint)Memory[Address]) | ((uint)Memory[Address + 1]) << 8 | ((uint)Memory[Address + 2]) << 16 | ((uint)Memory[Address + 3]) << 24; }
|
||||
set
|
||||
{
|
||||
Memory[Address] = (byte)value;
|
||||
Memory[Address + 1] = (byte)(value >> 8);
|
||||
Memory[Address + 2] = (byte)(value >> 16);
|
||||
Memory[Address + 3] = (byte)(value >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the next memory node.
|
||||
/// </summary>
|
||||
public MemoryNode Next
|
||||
{
|
||||
get { return new MemoryNode(((uint)Memory[Address + 4]) | ((uint)Memory[Address + 5]) << 8 | ((uint)Memory[Address + 6]) << 16 | ((uint)Memory[Address + 7]) << 24, Memory); }
|
||||
set
|
||||
{
|
||||
Memory[Address + 4] = (byte)value.Address;
|
||||
Memory[Address + 5] = (byte)(value.Address >> 8);
|
||||
Memory[Address + 6] = (byte)(value.Address >> 16);
|
||||
Memory[Address + 7] = (byte)(value.Address >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unit count.
|
||||
/// </summary>
|
||||
public uint UnitCount
|
||||
{
|
||||
get { return ((uint)Memory[Address + 8]) | ((uint)Memory[Address + 9]) << 8 | ((uint)Memory[Address + 10]) << 16 | ((uint)Memory[Address + 11]) << 24; }
|
||||
set
|
||||
{
|
||||
Memory[Address + 8] = (byte)value;
|
||||
Memory[Address + 9] = (byte)(value >> 8);
|
||||
Memory[Address + 10] = (byte)(value >> 16);
|
||||
Memory[Address + 11] = (byte)(value >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether there is a next memory node available.
|
||||
/// </summary>
|
||||
public bool Available
|
||||
{
|
||||
get { return Next.Address != 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Link in the provided memory node.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
public void Link(MemoryNode memoryNode)
|
||||
{
|
||||
memoryNode.Next = Next;
|
||||
Next = memoryNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unlink this memory node.
|
||||
/// </summary>
|
||||
public void Unlink()
|
||||
{
|
||||
Next = Next.Next;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert the memory node into the linked list.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
/// <param name="unitCount"></param>
|
||||
public void Insert(MemoryNode memoryNode, uint unitCount)
|
||||
{
|
||||
Link(memoryNode);
|
||||
memoryNode.Stamp = uint.MaxValue;
|
||||
memoryNode.UnitCount = unitCount;
|
||||
Stamp++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove this memory node from the linked list.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public MemoryNode Remove()
|
||||
{
|
||||
MemoryNode next = Next;
|
||||
Unlink();
|
||||
Stamp--;
|
||||
return next;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow a pointer to be implicitly converted to a memory node.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator MemoryNode(Pointer pointer)
|
||||
{
|
||||
return new MemoryNode(pointer.Address, pointer.Memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like addition on a memory node.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static MemoryNode operator +(MemoryNode memoryNode, int offset)
|
||||
{
|
||||
memoryNode.Address = (uint)(memoryNode.Address + offset * Size);
|
||||
return memoryNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like addition on a memory node.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static MemoryNode operator +(MemoryNode memoryNode, uint offset)
|
||||
{
|
||||
memoryNode.Address += offset * Size;
|
||||
return memoryNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like subtraction on a memory node.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static MemoryNode operator -(MemoryNode memoryNode, int offset)
|
||||
{
|
||||
memoryNode.Address = (uint)(memoryNode.Address - offset * Size);
|
||||
return memoryNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like subtraction on a memory node.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static MemoryNode operator -(MemoryNode memoryNode, uint offset)
|
||||
{
|
||||
memoryNode.Address -= offset * Size;
|
||||
return memoryNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two memory nodes.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode1"></param>
|
||||
/// <param name="memoryNode2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2)
|
||||
{
|
||||
return memoryNode1.Address == memoryNode2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two memory nodes.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode1"></param>
|
||||
/// <param name="memoryNode2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2)
|
||||
{
|
||||
return memoryNode1.Address != memoryNode2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this instance and a specified object are equal.
|
||||
/// </summary>
|
||||
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
|
||||
/// <param name="obj">Another object to compare to.</param>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is MemoryNode)
|
||||
{
|
||||
MemoryNode memoryNode = (MemoryNode)obj;
|
||||
return memoryNode.Address == Address;
|
||||
}
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Address.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,819 +0,0 @@
|
||||
#region Using
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#endregion
|
||||
|
||||
// This is a port of Dmitry Shkarin's PPMd Variant I Revision 1.
|
||||
// Ported by Michael Bone (mjbone03@yahoo.com.au).
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// The model.
|
||||
/// </summary>
|
||||
internal partial class Model
|
||||
{
|
||||
public const uint Signature = 0x84acaf8fU;
|
||||
public const char Variant = 'I';
|
||||
public const int MaximumOrder = 16; // maximum allowed model order
|
||||
|
||||
private const byte UpperFrequency = 5;
|
||||
private const byte IntervalBitCount = 7;
|
||||
private const byte PeriodBitCount = 7;
|
||||
private const byte TotalBitCount = IntervalBitCount + PeriodBitCount;
|
||||
private const uint Interval = 1 << IntervalBitCount;
|
||||
private const uint BinaryScale = 1 << TotalBitCount;
|
||||
private const uint MaximumFrequency = 124;
|
||||
private const uint OrderBound = 9;
|
||||
|
||||
private See2Context[,] see2Contexts;
|
||||
private See2Context emptySee2Context;
|
||||
private PpmContext maximumContext;
|
||||
private ushort[,] binarySummary = new ushort[25, 64]; // binary SEE-contexts
|
||||
private byte[] numberStatisticsToBinarySummaryIndex = new byte[256];
|
||||
private byte[] probabilities = new byte[260];
|
||||
private byte[] characterMask = new byte[256];
|
||||
private byte escapeCount;
|
||||
private int modelOrder;
|
||||
private int orderFall;
|
||||
private int initialEscape;
|
||||
private int initialRunLength;
|
||||
private int runLength;
|
||||
private byte previousSuccess;
|
||||
private byte numberMasked;
|
||||
private ModelRestorationMethod method;
|
||||
private PpmState foundState; // found next state transition
|
||||
|
||||
private Allocator Allocator;
|
||||
private Coder Coder;
|
||||
private PpmContext minimumContext;
|
||||
private byte numberStatistics;
|
||||
private PpmState[] decodeStates = new PpmState[256];
|
||||
|
||||
private static readonly ushort[] InitialBinaryEscapes = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051 };
|
||||
private static readonly byte[] ExponentialEscapes = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public Model()
|
||||
{
|
||||
// Construct the conversion table for number statistics. Initially it will contain the following values.
|
||||
//
|
||||
// 0 2 4 4 4 4 4 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
// 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
|
||||
|
||||
numberStatisticsToBinarySummaryIndex[0] = 2 * 0;
|
||||
numberStatisticsToBinarySummaryIndex[1] = 2 * 1;
|
||||
for (int index = 2; index < 11; index++)
|
||||
numberStatisticsToBinarySummaryIndex[index] = 2 * 2;
|
||||
for (int index = 11; index < 256; index++)
|
||||
numberStatisticsToBinarySummaryIndex[index] = 2 * 3;
|
||||
|
||||
// Construct the probability table. Initially it will contain the following values (depending on the value of
|
||||
// the upper frequency).
|
||||
//
|
||||
// 00 01 02 03 04 05 06 06 07 07 07 08 08 08 08 09 09 09 09 09 10 10 10 10 10 10 11 11 11 11 11 11
|
||||
// 11 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 15 15 15 15
|
||||
// 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17 17 17 17 17
|
||||
// 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 20 20 20
|
||||
// 20 20 20 20 20 20 20 20 20 20 20 20 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 22 22
|
||||
// 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23
|
||||
// 23 23 23 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 25 25 25 25 25 25 25 25 25
|
||||
// 25 25 25 25 25 25 25 25 25 25 25 25 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26
|
||||
// 26 26 27 27
|
||||
|
||||
uint count = 1;
|
||||
uint step = 1;
|
||||
uint probability = UpperFrequency;
|
||||
|
||||
for (int index = 0; index < UpperFrequency; index++)
|
||||
probabilities[index] = (byte)index;
|
||||
|
||||
for (int index = UpperFrequency; index < 260; index++)
|
||||
{
|
||||
probabilities[index] = (byte)probability;
|
||||
count--;
|
||||
if (count == 0)
|
||||
{
|
||||
step++;
|
||||
count = step;
|
||||
probability++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the context array.
|
||||
|
||||
see2Contexts = new See2Context[24, 32];
|
||||
for (int index1 = 0; index1 < 24; index1++)
|
||||
for (int index2 = 0; index2 < 32; index2++)
|
||||
see2Contexts[index1, index2] = new See2Context();
|
||||
|
||||
// Set the signature (identifying the algorithm).
|
||||
|
||||
emptySee2Context = new See2Context();
|
||||
emptySee2Context.Summary = (ushort)(Signature & 0x0000ffff);
|
||||
emptySee2Context.Shift = (byte)((Signature >> 16) & 0x000000ff);
|
||||
emptySee2Context.Count = (byte)(Signature >> 24);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode (ie. compress) a given source stream, writing the encoded result to the target stream.
|
||||
/// </summary>
|
||||
public void Encode(Stream target, Stream source, PpmdProperties properties)
|
||||
{
|
||||
if (target == null)
|
||||
throw new ArgumentNullException("target");
|
||||
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
|
||||
EncodeStart(properties);
|
||||
EncodeBlock(target, source, true);
|
||||
}
|
||||
|
||||
internal Coder EncodeStart(PpmdProperties properties)
|
||||
{
|
||||
Allocator = properties.Allocator;
|
||||
Coder = new Coder();
|
||||
Coder.RangeEncoderInitialize();
|
||||
StartModel(properties.ModelOrder, properties.ModelRestorationMethod);
|
||||
return Coder;
|
||||
}
|
||||
|
||||
internal void EncodeBlock(Stream target, Stream source, bool final)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
minimumContext = maximumContext;
|
||||
numberStatistics = minimumContext.NumberStatistics;
|
||||
|
||||
int c = source.ReadByte();
|
||||
if (c < 0 && !final)
|
||||
return;
|
||||
|
||||
if (numberStatistics != 0)
|
||||
{
|
||||
EncodeSymbol1(c, minimumContext);
|
||||
Coder.RangeEncodeSymbol();
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodeBinarySymbol(c, minimumContext);
|
||||
Coder.RangeShiftEncodeSymbol(TotalBitCount);
|
||||
}
|
||||
|
||||
while (foundState == PpmState.Zero)
|
||||
{
|
||||
Coder.RangeEncoderNormalize(target);
|
||||
do
|
||||
{
|
||||
orderFall++;
|
||||
minimumContext = minimumContext.Suffix;
|
||||
if (minimumContext == PpmContext.Zero)
|
||||
goto StopEncoding;
|
||||
} while (minimumContext.NumberStatistics == numberMasked);
|
||||
EncodeSymbol2(c, minimumContext);
|
||||
Coder.RangeEncodeSymbol();
|
||||
}
|
||||
|
||||
if (orderFall == 0 && (Pointer)foundState.Successor >= Allocator.BaseUnit)
|
||||
{
|
||||
maximumContext = foundState.Successor;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateModel(minimumContext);
|
||||
if (escapeCount == 0)
|
||||
ClearMask();
|
||||
}
|
||||
|
||||
Coder.RangeEncoderNormalize(target);
|
||||
}
|
||||
|
||||
StopEncoding:
|
||||
Coder.RangeEncoderFlush(target);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dencode (ie. decompress) a given source stream, writing the decoded result to the target stream.
|
||||
/// </summary>
|
||||
public void Decode(Stream target, Stream source, PpmdProperties properties)
|
||||
{
|
||||
if (target == null)
|
||||
throw new ArgumentNullException("target");
|
||||
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
|
||||
DecodeStart(source, properties);
|
||||
byte[] buffer = new byte[65536];
|
||||
int read;
|
||||
while ((read = DecodeBlock(source, buffer, 0, buffer.Length)) != 0)
|
||||
target.Write(buffer, 0, read);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
internal Coder DecodeStart(Stream source, PpmdProperties properties)
|
||||
{
|
||||
Allocator = properties.Allocator;
|
||||
Coder = new Coder();
|
||||
Coder.RangeDecoderInitialize(source);
|
||||
StartModel(properties.ModelOrder, properties.ModelRestorationMethod);
|
||||
minimumContext = maximumContext;
|
||||
numberStatistics = minimumContext.NumberStatistics;
|
||||
return Coder;
|
||||
}
|
||||
|
||||
internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (minimumContext == PpmContext.Zero)
|
||||
return 0;
|
||||
|
||||
int total = 0;
|
||||
while (total < count)
|
||||
{
|
||||
if (numberStatistics != 0)
|
||||
DecodeSymbol1(minimumContext);
|
||||
else
|
||||
DecodeBinarySymbol(minimumContext);
|
||||
|
||||
Coder.RangeRemoveSubrange();
|
||||
|
||||
while (foundState == PpmState.Zero)
|
||||
{
|
||||
Coder.RangeDecoderNormalize(source);
|
||||
do
|
||||
{
|
||||
orderFall++;
|
||||
minimumContext = minimumContext.Suffix;
|
||||
if (minimumContext == PpmContext.Zero)
|
||||
goto StopDecoding;
|
||||
} while (minimumContext.NumberStatistics == numberMasked);
|
||||
DecodeSymbol2(minimumContext);
|
||||
Coder.RangeRemoveSubrange();
|
||||
}
|
||||
|
||||
buffer[offset] = foundState.Symbol;
|
||||
offset++;
|
||||
total++;
|
||||
|
||||
if (orderFall == 0 && (Pointer)foundState.Successor >= Allocator.BaseUnit)
|
||||
{
|
||||
maximumContext = foundState.Successor;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateModel(minimumContext);
|
||||
if (escapeCount == 0)
|
||||
ClearMask();
|
||||
}
|
||||
|
||||
minimumContext = maximumContext;
|
||||
numberStatistics = minimumContext.NumberStatistics;
|
||||
Coder.RangeDecoderNormalize(source);
|
||||
}
|
||||
|
||||
StopDecoding:
|
||||
return total;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Initialise the model (unless the model order is set to 1 in which case the model should be cleared so that
|
||||
/// the statistics are carried over, allowing "solid" mode compression).
|
||||
/// </summary>
|
||||
private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod)
|
||||
{
|
||||
Array.Clear(characterMask, 0, characterMask.Length);
|
||||
escapeCount = 1;
|
||||
|
||||
// Compress in "solid" mode if the model order value is set to 1 (this will examine the current PPM context
|
||||
// structures to determine the value of orderFall).
|
||||
|
||||
if (modelOrder < 2)
|
||||
{
|
||||
orderFall = this.modelOrder;
|
||||
for (PpmContext context = maximumContext; context.Suffix != PpmContext.Zero; context = context.Suffix)
|
||||
orderFall--;
|
||||
return;
|
||||
}
|
||||
|
||||
this.modelOrder = modelOrder;
|
||||
orderFall = modelOrder;
|
||||
method = modelRestorationMethod;
|
||||
Allocator.Initialize();
|
||||
initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1;
|
||||
runLength = initialRunLength;
|
||||
|
||||
// Allocate the context structure.
|
||||
|
||||
maximumContext = Allocator.AllocateContext();
|
||||
maximumContext.Suffix = PpmContext.Zero;
|
||||
maximumContext.NumberStatistics = 255;
|
||||
maximumContext.SummaryFrequency = (ushort)(maximumContext.NumberStatistics + 2);
|
||||
maximumContext.Statistics = Allocator.AllocateUnits(256 / 2); // allocates enough space for 256 PPM states (each is 6 bytes)
|
||||
|
||||
previousSuccess = 0;
|
||||
for (int index = 0; index < 256; index++)
|
||||
{
|
||||
PpmState state = maximumContext.Statistics[index];
|
||||
state.Symbol = (byte)index;
|
||||
state.Frequency = 1;
|
||||
state.Successor = PpmContext.Zero;
|
||||
}
|
||||
|
||||
uint probability = 0;
|
||||
for (int index1 = 0; probability < 25; probability++)
|
||||
{
|
||||
while (probabilities[index1] == probability)
|
||||
index1++;
|
||||
for (int index2 = 0; index2 < 8; index2++)
|
||||
binarySummary[probability, index2] = (ushort)(BinaryScale - InitialBinaryEscapes[index2] / (index1 + 1));
|
||||
for (int index2 = 8; index2 < 64; index2 += 8)
|
||||
for (int index3 = 0; index3 < 8; index3++)
|
||||
binarySummary[probability, index2 + index3] = binarySummary[probability, index3];
|
||||
}
|
||||
|
||||
probability = 0;
|
||||
for (uint index1 = 0; probability < 24; probability++)
|
||||
{
|
||||
while (probabilities[index1 + 3] == probability + 3)
|
||||
index1++;
|
||||
for (int index2 = 0; index2 < 32; index2++)
|
||||
see2Contexts[probability, index2].Initialize(2 * index1 + 5);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateModel(PpmContext minimumContext)
|
||||
{
|
||||
PpmState state = PpmState.Zero;
|
||||
PpmContext Successor;
|
||||
PpmContext currentContext = maximumContext;
|
||||
uint numberStatistics;
|
||||
uint ns1;
|
||||
uint cf;
|
||||
uint sf;
|
||||
uint s0;
|
||||
uint foundStateFrequency = foundState.Frequency;
|
||||
byte foundStateSymbol = foundState.Symbol;
|
||||
byte symbol;
|
||||
byte flag;
|
||||
|
||||
PpmContext foundStateSuccessor = foundState.Successor;
|
||||
PpmContext context = minimumContext.Suffix;
|
||||
|
||||
if ((foundStateFrequency < MaximumFrequency / 4) && (context != PpmContext.Zero))
|
||||
{
|
||||
if (context.NumberStatistics != 0)
|
||||
{
|
||||
state = context.Statistics;
|
||||
if (state.Symbol != foundStateSymbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
symbol = state[1].Symbol;
|
||||
state++;
|
||||
} while (symbol != foundStateSymbol);
|
||||
if (state[0].Frequency >= state[-1].Frequency)
|
||||
{
|
||||
Swap(state[0], state[-1]);
|
||||
state--;
|
||||
}
|
||||
}
|
||||
cf = (uint)((state.Frequency < MaximumFrequency - 9) ? 2 : 0);
|
||||
state.Frequency += (byte)cf;
|
||||
context.SummaryFrequency += (byte)cf;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = context.FirstState;
|
||||
state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (orderFall == 0 && foundStateSuccessor != PpmContext.Zero)
|
||||
{
|
||||
foundState.Successor = CreateSuccessors(true, state, minimumContext);
|
||||
if (foundState.Successor == PpmContext.Zero)
|
||||
goto RestartModel;
|
||||
maximumContext = foundState.Successor;
|
||||
return;
|
||||
}
|
||||
|
||||
Allocator.Text[0] = foundStateSymbol;
|
||||
Allocator.Text++;
|
||||
Successor = Allocator.Text;
|
||||
|
||||
if (Allocator.Text >= Allocator.BaseUnit)
|
||||
goto RestartModel;
|
||||
|
||||
if (foundStateSuccessor != PpmContext.Zero)
|
||||
{
|
||||
if (foundStateSuccessor < Allocator.BaseUnit)
|
||||
foundStateSuccessor = CreateSuccessors(false, state, minimumContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
foundStateSuccessor = ReduceOrder(state, minimumContext);
|
||||
}
|
||||
|
||||
if (foundStateSuccessor == PpmContext.Zero)
|
||||
goto RestartModel;
|
||||
|
||||
if (--orderFall == 0)
|
||||
{
|
||||
Successor = foundStateSuccessor;
|
||||
Allocator.Text -= (maximumContext != minimumContext) ? 1 : 0;
|
||||
}
|
||||
else if (method > ModelRestorationMethod.Freeze)
|
||||
{
|
||||
Successor = foundStateSuccessor;
|
||||
Allocator.Text = Allocator.Heap;
|
||||
orderFall = 0;
|
||||
}
|
||||
|
||||
numberStatistics = minimumContext.NumberStatistics;
|
||||
s0 = minimumContext.SummaryFrequency - numberStatistics - foundStateFrequency;
|
||||
flag = (byte)((foundStateSymbol >= 0x40) ? 0x08 : 0x00);
|
||||
for (; currentContext != minimumContext; currentContext = currentContext.Suffix)
|
||||
{
|
||||
ns1 = currentContext.NumberStatistics;
|
||||
if (ns1 != 0)
|
||||
{
|
||||
if ((ns1 & 1) != 0)
|
||||
{
|
||||
state = Allocator.ExpandUnits(currentContext.Statistics, (ns1 + 1) >> 1);
|
||||
if (state == PpmState.Zero)
|
||||
goto RestartModel;
|
||||
currentContext.Statistics = state;
|
||||
}
|
||||
currentContext.SummaryFrequency += (ushort)((3 * ns1 + 1 < numberStatistics) ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = Allocator.AllocateUnits(1);
|
||||
if (state == PpmState.Zero)
|
||||
goto RestartModel;
|
||||
Copy(state, currentContext.FirstState);
|
||||
currentContext.Statistics = state;
|
||||
if (state.Frequency < MaximumFrequency / 4 - 1)
|
||||
state.Frequency += state.Frequency;
|
||||
else
|
||||
state.Frequency = (byte)(MaximumFrequency - 4);
|
||||
currentContext.SummaryFrequency = (ushort)(state.Frequency + initialEscape + ((numberStatistics > 2) ? 1 : 0));
|
||||
}
|
||||
|
||||
cf = (uint)(2 * foundStateFrequency * (currentContext.SummaryFrequency + 6));
|
||||
sf = s0 + currentContext.SummaryFrequency;
|
||||
|
||||
if (cf < 6 * sf)
|
||||
{
|
||||
cf = (uint)(1 + ((cf > sf) ? 1 : 0) + ((cf >= 4 * sf) ? 1 : 0));
|
||||
currentContext.SummaryFrequency += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf = (uint)(4 + ((cf > 9 * sf) ? 1 : 0) + ((cf > 12 * sf) ? 1 : 0) + ((cf > 15 * sf) ? 1 : 0));
|
||||
currentContext.SummaryFrequency += (ushort)cf;
|
||||
}
|
||||
|
||||
state = currentContext.Statistics + (++currentContext.NumberStatistics);
|
||||
state.Successor = Successor;
|
||||
state.Symbol = foundStateSymbol;
|
||||
state.Frequency = (byte)cf;
|
||||
currentContext.Flags |= flag;
|
||||
}
|
||||
|
||||
maximumContext = foundStateSuccessor;
|
||||
return;
|
||||
|
||||
RestartModel:
|
||||
RestoreModel(currentContext, minimumContext, foundStateSuccessor);
|
||||
}
|
||||
|
||||
private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context)
|
||||
{
|
||||
PpmContext upBranch = foundState.Successor;
|
||||
PpmState[] states = new PpmState[MaximumOrder];
|
||||
uint stateIndex = 0;
|
||||
byte symbol = foundState.Symbol;
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
states[stateIndex++] = foundState;
|
||||
if (context.Suffix == PpmContext.Zero)
|
||||
goto NoLoop;
|
||||
}
|
||||
|
||||
bool gotoLoopEntry = false;
|
||||
if (state != PpmState.Zero)
|
||||
{
|
||||
context = context.Suffix;
|
||||
gotoLoopEntry = true;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (gotoLoopEntry)
|
||||
{
|
||||
gotoLoopEntry = false;
|
||||
goto LoopEntry;
|
||||
}
|
||||
|
||||
context = context.Suffix;
|
||||
if (context.NumberStatistics != 0)
|
||||
{
|
||||
byte temporary;
|
||||
state = context.Statistics;
|
||||
if (state.Symbol != symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
temporary = state[1].Symbol;
|
||||
state++;
|
||||
} while (temporary != symbol);
|
||||
}
|
||||
temporary = (byte)((state.Frequency < MaximumFrequency - 9) ? 1 : 0);
|
||||
state.Frequency += temporary;
|
||||
context.SummaryFrequency += temporary;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = context.FirstState;
|
||||
state.Frequency += (byte)(((context.Suffix.NumberStatistics == 0) ? 1 : 0) & ((state.Frequency < 24) ? 1 : 0));
|
||||
}
|
||||
|
||||
LoopEntry:
|
||||
if (state.Successor != upBranch)
|
||||
{
|
||||
context = state.Successor;
|
||||
break;
|
||||
}
|
||||
states[stateIndex++] = state;
|
||||
} while (context.Suffix != PpmContext.Zero);
|
||||
|
||||
NoLoop:
|
||||
if (stateIndex == 0)
|
||||
return context;
|
||||
|
||||
byte localNumberStatistics = 0;
|
||||
byte localFlags = (byte)((symbol >= 0x40) ? 0x10 : 0x00);
|
||||
symbol = upBranch.NumberStatistics;
|
||||
byte localSymbol = symbol;
|
||||
byte localFrequency;
|
||||
PpmContext localSuccessor = ((Pointer)upBranch) + 1;
|
||||
localFlags |= (byte)((symbol >= 0x40) ? 0x08 : 0x00);
|
||||
|
||||
if (context.NumberStatistics != 0)
|
||||
{
|
||||
state = context.Statistics;
|
||||
if (state.Symbol != symbol)
|
||||
{
|
||||
byte temporary;
|
||||
do
|
||||
{
|
||||
temporary = state[1].Symbol;
|
||||
state++;
|
||||
} while (temporary != symbol);
|
||||
}
|
||||
uint cf = (uint)(state.Frequency - 1);
|
||||
uint s0 = (uint)(context.SummaryFrequency - context.NumberStatistics - cf);
|
||||
localFrequency = (byte)(1 + ((2 * cf <= s0) ? (uint)((5 * cf > s0) ? 1 : 0) : ((cf + 2 * s0 - 3) / s0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
localFrequency = context.FirstStateFrequency;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
PpmContext currentContext = Allocator.AllocateContext();
|
||||
if (currentContext == PpmContext.Zero)
|
||||
return PpmContext.Zero;
|
||||
currentContext.NumberStatistics = localNumberStatistics;
|
||||
currentContext.Flags = localFlags;
|
||||
currentContext.FirstStateSymbol = localSymbol;
|
||||
currentContext.FirstStateFrequency = localFrequency;
|
||||
currentContext.FirstStateSuccessor = localSuccessor;
|
||||
currentContext.Suffix = context;
|
||||
context = currentContext;
|
||||
states[--stateIndex].Successor = context;
|
||||
} while (stateIndex != 0);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private PpmContext ReduceOrder(PpmState state, PpmContext context)
|
||||
{
|
||||
PpmState currentState;
|
||||
PpmState[] states = new PpmState[MaximumOrder];
|
||||
uint stateIndex = 0;
|
||||
PpmContext currentContext = context;
|
||||
PpmContext UpBranch = Allocator.Text;
|
||||
byte temporary;
|
||||
byte symbol = foundState.Symbol;
|
||||
|
||||
states[stateIndex++] = foundState;
|
||||
foundState.Successor = UpBranch;
|
||||
orderFall++;
|
||||
|
||||
bool gotoLoopEntry = false;
|
||||
if (state != PpmState.Zero)
|
||||
{
|
||||
context = context.Suffix;
|
||||
gotoLoopEntry = true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (gotoLoopEntry)
|
||||
{
|
||||
gotoLoopEntry = false;
|
||||
goto LoopEntry;
|
||||
}
|
||||
|
||||
if (context.Suffix == PpmContext.Zero)
|
||||
{
|
||||
if (method > ModelRestorationMethod.Freeze)
|
||||
{
|
||||
do
|
||||
{
|
||||
states[--stateIndex].Successor = context;
|
||||
} while (stateIndex != 0);
|
||||
Allocator.Text = Allocator.Heap + 1;
|
||||
orderFall = 1;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
context = context.Suffix;
|
||||
if (context.NumberStatistics != 0)
|
||||
{
|
||||
state = context.Statistics;
|
||||
if (state.Symbol != symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
temporary = state[1].Symbol;
|
||||
state++;
|
||||
} while (temporary != symbol);
|
||||
}
|
||||
temporary = (byte)((state.Frequency < MaximumFrequency - 9) ? 2 : 0);
|
||||
state.Frequency += temporary;
|
||||
context.SummaryFrequency += temporary;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = context.FirstState;
|
||||
state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0);
|
||||
}
|
||||
|
||||
LoopEntry:
|
||||
if (state.Successor != PpmContext.Zero)
|
||||
break;
|
||||
states[stateIndex++] = state;
|
||||
state.Successor = UpBranch;
|
||||
orderFall++;
|
||||
}
|
||||
|
||||
if (method > ModelRestorationMethod.Freeze)
|
||||
{
|
||||
context = state.Successor;
|
||||
do
|
||||
{
|
||||
states[--stateIndex].Successor = context;
|
||||
} while (stateIndex != 0);
|
||||
Allocator.Text = Allocator.Heap + 1;
|
||||
orderFall = 1;
|
||||
return context;
|
||||
}
|
||||
else if (state.Successor <= UpBranch)
|
||||
{
|
||||
currentState = foundState;
|
||||
foundState = state;
|
||||
state.Successor = CreateSuccessors(false, PpmState.Zero, context);
|
||||
foundState = currentState;
|
||||
}
|
||||
|
||||
if (orderFall == 1 && currentContext == maximumContext)
|
||||
{
|
||||
foundState.Successor = state.Successor;
|
||||
Allocator.Text--;
|
||||
}
|
||||
|
||||
return state.Successor;
|
||||
}
|
||||
|
||||
private void RestoreModel(PpmContext context, PpmContext minimumContext, PpmContext foundStateSuccessor)
|
||||
{
|
||||
PpmContext currentContext;
|
||||
|
||||
Allocator.Text = Allocator.Heap;
|
||||
for (currentContext = maximumContext; currentContext != context; currentContext = currentContext.Suffix)
|
||||
{
|
||||
if (--currentContext.NumberStatistics == 0)
|
||||
{
|
||||
currentContext.Flags = (byte)((currentContext.Flags & 0x10) + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00));
|
||||
PpmState state = currentContext.Statistics;
|
||||
Copy(currentContext.FirstState, state);
|
||||
Allocator.SpecialFreeUnits(state);
|
||||
currentContext.FirstStateFrequency = (byte)((currentContext.FirstStateFrequency + 11) >> 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
Refresh((uint)((currentContext.NumberStatistics + 3) >> 1), false, currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
for (; currentContext != minimumContext; currentContext = currentContext.Suffix)
|
||||
{
|
||||
if (currentContext.NumberStatistics == 0)
|
||||
currentContext.FirstStateFrequency -= (byte)(currentContext.FirstStateFrequency >> 1);
|
||||
else if ((currentContext.SummaryFrequency += 4) > 128 + 4 * currentContext.NumberStatistics)
|
||||
Refresh((uint)((currentContext.NumberStatistics + 2) >> 1), true, currentContext);
|
||||
}
|
||||
|
||||
if (method > ModelRestorationMethod.Freeze)
|
||||
{
|
||||
maximumContext = foundStateSuccessor;
|
||||
Allocator.GlueCount += (uint)(((Allocator.MemoryNodes[1].Stamp & 1) == 0) ? 1 : 0);
|
||||
}
|
||||
else if (method == ModelRestorationMethod.Freeze)
|
||||
{
|
||||
while (maximumContext.Suffix != PpmContext.Zero)
|
||||
maximumContext = maximumContext.Suffix;
|
||||
|
||||
RemoveBinaryContexts(0, maximumContext);
|
||||
method = (ModelRestorationMethod)(method + 1);
|
||||
Allocator.GlueCount = 0;
|
||||
orderFall = modelOrder;
|
||||
}
|
||||
else if (method == ModelRestorationMethod.Restart || Allocator.GetMemoryUsed() < (Allocator.AllocatorSize >> 1))
|
||||
{
|
||||
StartModel(modelOrder, method);
|
||||
escapeCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (maximumContext.Suffix != PpmContext.Zero)
|
||||
maximumContext = maximumContext.Suffix;
|
||||
|
||||
do
|
||||
{
|
||||
CutOff(0, maximumContext);
|
||||
Allocator.ExpandText();
|
||||
} while (Allocator.GetMemoryUsed() > 3 * (Allocator.AllocatorSize >> 2));
|
||||
|
||||
Allocator.GlueCount = 0;
|
||||
orderFall = modelOrder;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Swap(PpmState state1, PpmState state2)
|
||||
{
|
||||
byte swapSymbol = state1.Symbol;
|
||||
byte swapFrequency = state1.Frequency;
|
||||
PpmContext swapSuccessor = state1.Successor;
|
||||
|
||||
state1.Symbol = state2.Symbol;
|
||||
state1.Frequency = state2.Frequency;
|
||||
state1.Successor = state2.Successor;
|
||||
|
||||
state2.Symbol = swapSymbol;
|
||||
state2.Frequency = swapFrequency;
|
||||
state2.Successor = swapSuccessor;
|
||||
}
|
||||
|
||||
private static void Copy(PpmState state1, PpmState state2)
|
||||
{
|
||||
state1.Symbol = state2.Symbol;
|
||||
state1.Frequency = state2.Frequency;
|
||||
state1.Successor = state2.Successor;
|
||||
}
|
||||
|
||||
private static int Mean(int sum, int shift, int round)
|
||||
{
|
||||
return (sum + (1 << (shift - round))) >> shift;
|
||||
}
|
||||
|
||||
private void ClearMask()
|
||||
{
|
||||
escapeCount = 1;
|
||||
Array.Clear(characterMask, 0, characterMask.Length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#region Using
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// The method used to adjust the model when the memory limit is reached.
|
||||
/// </summary>
|
||||
internal enum ModelRestorationMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Restart the model from scratch (this is the default).
|
||||
/// </summary>
|
||||
Restart = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Cut off the model (nearly twice as slow).
|
||||
/// </summary>
|
||||
CutOff = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Freeze the context tree (in some cases may result in poor compression).
|
||||
/// </summary>
|
||||
Freeze = 2
|
||||
}
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
#region Using
|
||||
|
||||
using System;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// A structure containing a single address representing a position in the <see cref="Memory"/> array. This
|
||||
/// is intended to mimic the behaviour of a pointer in C/C++.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This must be a structure rather than a class because several places in the associated code assume that
|
||||
/// <see cref="Pointer"/> is a value type (meaning that assignment creates a completely new copy of the
|
||||
/// instance rather than just copying a reference to the same instance).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that <see cref="Address"/> is a field rather than a property for performance reasons.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal struct Pointer
|
||||
{
|
||||
public uint Address;
|
||||
public byte[] Memory;
|
||||
public static readonly Pointer Zero = new Pointer(0, null);
|
||||
public const int Size = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Pointer"/> structure.
|
||||
/// </summary>
|
||||
public Pointer(uint address, byte[] memory)
|
||||
{
|
||||
Address = address;
|
||||
Memory = memory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the byte at the given <paramref name="offset"/>.
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public byte this[int offset]
|
||||
{
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
if (Address == 0)
|
||||
throw new InvalidOperationException("The pointer being indexed is a null pointer.");
|
||||
#endif
|
||||
return Memory[Address + offset];
|
||||
}
|
||||
set
|
||||
{
|
||||
#if DEBUG
|
||||
if (Address == 0)
|
||||
throw new InvalidOperationException("The pointer being indexed is a null pointer.");
|
||||
#endif
|
||||
Memory[Address + offset] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow a <see cref="MemoryNode"/> to be implicitly converted to a <see cref="Pointer"/>.
|
||||
/// </summary>
|
||||
/// <param name="memoryNode"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator Pointer(MemoryNode memoryNode)
|
||||
{
|
||||
return new Pointer(memoryNode.Address, memoryNode.Memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow a <see cref="Model.PpmContext"/> to be implicitly converted to a <see cref="Pointer"/>.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator Pointer(Model.PpmContext context)
|
||||
{
|
||||
return new Pointer(context.Address, context.Memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow a <see cref="PpmState"/> to be implicitly converted to a <see cref="Pointer"/>.
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator Pointer(PpmState state)
|
||||
{
|
||||
return new Pointer(state.Address, state.Memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increase the address of a pointer by the given number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer operator +(Pointer pointer, int offset)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer.Address == 0)
|
||||
throw new InvalidOperationException("The pointer is a null pointer.");
|
||||
#endif
|
||||
pointer.Address = (uint)(pointer.Address + offset);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increase the address of a pointer by the given number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer operator +(Pointer pointer, uint offset)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer.Address == 0)
|
||||
throw new InvalidOperationException("The pointer is a null pointer.");
|
||||
#endif
|
||||
pointer.Address += offset;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increment the address of a pointer.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer operator ++(Pointer pointer)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer.Address == 0)
|
||||
throw new InvalidOperationException("The pointer being incremented is a null pointer.");
|
||||
#endif
|
||||
pointer.Address++;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrease the address of a pointer by the given number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer operator -(Pointer pointer, int offset)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer.Address == 0)
|
||||
throw new InvalidOperationException("The pointer is a null pointer.");
|
||||
#endif
|
||||
pointer.Address = (uint)(pointer.Address - offset);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrease the address of a pointer by the given number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer operator -(Pointer pointer, uint offset)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer.Address == 0)
|
||||
throw new InvalidOperationException("The pointer is a null pointer.");
|
||||
#endif
|
||||
pointer.Address -= offset;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrement the address of a pointer.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer operator --(Pointer pointer)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer.Address == 0)
|
||||
throw new InvalidOperationException("The pointer being decremented is a null pointer.");
|
||||
#endif
|
||||
pointer.Address--;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtract two pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns>The number of bytes between the two pointers.</returns>
|
||||
public static uint operator -(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer1.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the left of the subtraction operator is a null pointer.");
|
||||
if (pointer2.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the right of the subtraction operator is a null pointer.");
|
||||
#endif
|
||||
return pointer1.Address - pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator <(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer1.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the left of the less than operator is a null pointer.");
|
||||
if (pointer2.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the right of the less than operator is a null pointer.");
|
||||
#endif
|
||||
return pointer1.Address < pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator <=(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer1.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the left of the less than or equal to operator is a null pointer.");
|
||||
if (pointer2.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the right of the less than or equal to operator is a null pointer.");
|
||||
#endif
|
||||
return pointer1.Address <= pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator >(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer1.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the left of the greater than operator is a null pointer.");
|
||||
if (pointer2.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the right of the greater than operator is a null pointer.");
|
||||
#endif
|
||||
return pointer1.Address > pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator >=(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
#if DEBUG
|
||||
if (pointer1.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the left of the greater than or equal to operator is a null pointer.");
|
||||
if (pointer2.Address == 0)
|
||||
throw new InvalidOperationException("The pointer to the right of the greater than or equal to operator is a null pointer.");
|
||||
#endif
|
||||
return pointer1.Address >= pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator ==(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
return pointer1.Address == pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two pointers.
|
||||
/// </summary>
|
||||
/// <param name="pointer1"></param>
|
||||
/// <param name="pointer2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator !=(Pointer pointer1, Pointer pointer2)
|
||||
{
|
||||
return pointer1.Address != pointer2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this instance and a specified object are equal.
|
||||
/// </summary>
|
||||
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
|
||||
/// <param name="obj">Another object to compare to.</param>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Pointer)
|
||||
{
|
||||
Pointer pointer = (Pointer)obj;
|
||||
return pointer.Address == Address;
|
||||
}
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Address.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,787 +0,0 @@
|
||||
#region Using
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// The PPM context structure. This is tightly coupled with <see cref="Model"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This must be a structure rather than a class because several places in the associated code assume that
|
||||
/// <see cref="PpmContext"/> is a value type (meaning that assignment creates a completely new copy of
|
||||
/// the instance rather than just copying a reference to the same instance).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal partial class Model
|
||||
{
|
||||
/// <summary>
|
||||
/// The structure which represents the current PPM context. This is 12 bytes in size.
|
||||
/// </summary>
|
||||
internal struct PpmContext
|
||||
{
|
||||
public uint Address;
|
||||
public byte[] Memory;
|
||||
public static readonly PpmContext Zero = new PpmContext(0, null);
|
||||
public const int Size = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PpmContext"/> structure.
|
||||
/// </summary>
|
||||
public PpmContext(uint address, byte[] memory)
|
||||
{
|
||||
Address = address;
|
||||
Memory = memory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number statistics.
|
||||
/// </summary>
|
||||
public byte NumberStatistics
|
||||
{
|
||||
get { return Memory[Address]; }
|
||||
set { Memory[Address] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flags.
|
||||
/// </summary>
|
||||
public byte Flags
|
||||
{
|
||||
get { return Memory[Address + 1]; }
|
||||
set { Memory[Address + 1] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the summary frequency.
|
||||
/// </summary>
|
||||
public ushort SummaryFrequency
|
||||
{
|
||||
get { return (ushort)(((ushort)Memory[Address + 2]) | ((ushort)Memory[Address + 3]) << 8); }
|
||||
set
|
||||
{
|
||||
Memory[Address + 2] = (byte)value;
|
||||
Memory[Address + 3] = (byte)(value >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the statistics.
|
||||
/// </summary>
|
||||
public PpmState Statistics
|
||||
{
|
||||
get { return new PpmState(((uint)Memory[Address + 4]) | ((uint)Memory[Address + 5]) << 8 | ((uint)Memory[Address + 6]) << 16 | ((uint)Memory[Address + 7]) << 24, Memory); }
|
||||
set
|
||||
{
|
||||
Memory[Address + 4] = (byte)value.Address;
|
||||
Memory[Address + 5] = (byte)(value.Address >> 8);
|
||||
Memory[Address + 6] = (byte)(value.Address >> 16);
|
||||
Memory[Address + 7] = (byte)(value.Address >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the suffix.
|
||||
/// </summary>
|
||||
public PpmContext Suffix
|
||||
{
|
||||
get { return new PpmContext(((uint)Memory[Address + 8]) | ((uint)Memory[Address + 9]) << 8 | ((uint)Memory[Address + 10]) << 16 | ((uint)Memory[Address + 11]) << 24, Memory); }
|
||||
set
|
||||
{
|
||||
Memory[Address + 8] = (byte)value.Address;
|
||||
Memory[Address + 9] = (byte)(value.Address >> 8);
|
||||
Memory[Address + 10] = (byte)(value.Address >> 16);
|
||||
Memory[Address + 11] = (byte)(value.Address >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The first PPM state associated with the PPM context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members
|
||||
/// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and
|
||||
/// Successor members of PpmState, since they also add up to 6 bytes).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes)
|
||||
/// 1 context.NumberStatistics
|
||||
/// 1 context.Flags
|
||||
/// 2 context.SummaryFrequency
|
||||
/// 4 context.Statistics (pointer to PpmState)
|
||||
/// 4 context.Suffix (pointer to PpmContext)
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// PpmState (total of 6 bytes)
|
||||
/// 1 Symbol
|
||||
/// 1 Frequency
|
||||
/// 4 Successor (pointer to PpmContext)
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
public PpmState FirstState
|
||||
{
|
||||
get { return new PpmState(Address + 2, Memory); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same
|
||||
/// information can be obtained using the Symbol property on the PPM state provided by the
|
||||
/// <see cref="FirstState"/> property.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "The property getter is provided for completeness.")]
|
||||
public byte FirstStateSymbol
|
||||
{
|
||||
get { return Memory[Address + 2]; }
|
||||
set { Memory[Address + 2] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same
|
||||
/// information can be obtained using the Frequency property on the PPM state provided by the
|
||||
///context.FirstState property.
|
||||
/// </summary>
|
||||
public byte FirstStateFrequency
|
||||
{
|
||||
get { return Memory[Address + 3]; }
|
||||
set { Memory[Address + 3] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the successor of the first PPM state. This is provided for convenience. The same
|
||||
/// information can be obtained using the Successor property on the PPM state provided by the
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "The property getter is provided for completeness.")]
|
||||
public PpmContext FirstStateSuccessor
|
||||
{
|
||||
get { return new PpmContext(((uint)Memory[Address + 4]) | ((uint)Memory[Address + 5]) << 8 | ((uint)Memory[Address + 6]) << 16 | ((uint)Memory[Address + 7]) << 24, Memory); }
|
||||
set
|
||||
{
|
||||
Memory[Address + 4] = (byte)value.Address;
|
||||
Memory[Address + 5] = (byte)(value.Address >> 8);
|
||||
Memory[Address + 6] = (byte)(value.Address >> 16);
|
||||
Memory[Address + 7] = (byte)(value.Address >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow a pointer to be implicitly converted to a PPM context.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator PpmContext(Pointer pointer)
|
||||
{
|
||||
return new PpmContext(pointer.Address, pointer.Memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like addition on a PPM context.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static PpmContext operator +(PpmContext context, int offset)
|
||||
{
|
||||
context.Address = (uint)(context.Address + offset * Size);
|
||||
return context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like subtraction on a PPM context.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static PpmContext operator -(PpmContext context, int offset)
|
||||
{
|
||||
context.Address = (uint)(context.Address - offset * Size);
|
||||
return context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM contexts.
|
||||
/// </summary>
|
||||
/// <param name="context1"></param>
|
||||
/// <param name="context2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator <=(PpmContext context1, PpmContext context2)
|
||||
{
|
||||
return context1.Address <= context2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM contexts.
|
||||
/// </summary>
|
||||
/// <param name="context1"></param>
|
||||
/// <param name="context2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator >=(PpmContext context1, PpmContext context2)
|
||||
{
|
||||
return context1.Address >= context2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM contexts.
|
||||
/// </summary>
|
||||
/// <param name="context1"></param>
|
||||
/// <param name="context2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator ==(PpmContext context1, PpmContext context2)
|
||||
{
|
||||
return context1.Address == context2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM contexts.
|
||||
/// </summary>
|
||||
/// <param name="context1"></param>
|
||||
/// <param name="context2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator !=(PpmContext context1, PpmContext context2)
|
||||
{
|
||||
return context1.Address != context2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this instance and a specified object are equal.
|
||||
/// </summary>
|
||||
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
|
||||
/// <param name="obj">Another object to compare to.</param>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is PpmContext)
|
||||
{
|
||||
PpmContext context = (PpmContext)obj;
|
||||
return context.Address == Address;
|
||||
}
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Address.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private void EncodeBinarySymbol(int symbol, PpmContext context)
|
||||
{
|
||||
PpmState state = context.FirstState;
|
||||
int index1 = probabilities[state.Frequency - 1];
|
||||
int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + context.Flags + ((runLength >> 26) & 0x20);
|
||||
|
||||
if (state.Symbol == symbol)
|
||||
{
|
||||
foundState = state;
|
||||
state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0);
|
||||
Coder.LowCount = 0;
|
||||
Coder.HighCount = binarySummary[index1, index2];
|
||||
binarySummary[index1, index2] += (ushort)(Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2));
|
||||
previousSuccess = 1;
|
||||
runLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Coder.LowCount = binarySummary[index1, index2];
|
||||
binarySummary[index1, index2] -= (ushort)Mean(binarySummary[index1, index2], PeriodBitCount, 2);
|
||||
Coder.HighCount = BinaryScale;
|
||||
initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10];
|
||||
characterMask[state.Symbol] = escapeCount;
|
||||
previousSuccess = 0;
|
||||
numberMasked = 0;
|
||||
foundState = PpmState.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void EncodeSymbol1(int symbol, PpmContext context)
|
||||
{
|
||||
uint lowCount;
|
||||
uint index = context.Statistics.Symbol;
|
||||
PpmState state = context.Statistics;
|
||||
Coder.Scale = context.SummaryFrequency;
|
||||
if (index == symbol)
|
||||
{
|
||||
Coder.HighCount = state.Frequency;
|
||||
previousSuccess = (byte)((2 * Coder.HighCount >= Coder.Scale) ? 1 : 0);
|
||||
foundState = state;
|
||||
foundState.Frequency += 4;
|
||||
context.SummaryFrequency += 4;
|
||||
runLength += previousSuccess;
|
||||
if (state.Frequency > MaximumFrequency)
|
||||
Rescale(context);
|
||||
Coder.LowCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
lowCount = state.Frequency;
|
||||
index = context.NumberStatistics;
|
||||
previousSuccess = 0;
|
||||
while ((++state).Symbol != symbol)
|
||||
{
|
||||
lowCount += state.Frequency;
|
||||
if (--index == 0)
|
||||
{
|
||||
Coder.LowCount = lowCount;
|
||||
characterMask[state.Symbol] = escapeCount;
|
||||
numberMasked = context.NumberStatistics;
|
||||
index = context.NumberStatistics;
|
||||
foundState = PpmState.Zero;
|
||||
do
|
||||
{
|
||||
characterMask[(--state).Symbol] = escapeCount;
|
||||
} while (--index != 0);
|
||||
Coder.HighCount = Coder.Scale;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Coder.HighCount = (Coder.LowCount = lowCount) + state.Frequency;
|
||||
Update1(state, context);
|
||||
}
|
||||
|
||||
private void EncodeSymbol2(int symbol, PpmContext context)
|
||||
{
|
||||
See2Context see2Context = MakeEscapeFrequency(context);
|
||||
uint currentSymbol;
|
||||
uint lowCount = 0;
|
||||
uint index = (uint)(context.NumberStatistics - numberMasked);
|
||||
PpmState state = context.Statistics - 1;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
currentSymbol = state[1].Symbol;
|
||||
state++;
|
||||
} while (characterMask[currentSymbol] == escapeCount);
|
||||
characterMask[currentSymbol] = escapeCount;
|
||||
if (currentSymbol == symbol)
|
||||
goto SymbolFound;
|
||||
lowCount += state.Frequency;
|
||||
} while (--index != 0);
|
||||
|
||||
Coder.LowCount = lowCount;
|
||||
Coder.Scale += Coder.LowCount;
|
||||
Coder.HighCount = Coder.Scale;
|
||||
see2Context.Summary += (ushort)Coder.Scale;
|
||||
numberMasked = context.NumberStatistics;
|
||||
return;
|
||||
|
||||
SymbolFound:
|
||||
Coder.LowCount = lowCount;
|
||||
lowCount += state.Frequency;
|
||||
Coder.HighCount = lowCount;
|
||||
for (PpmState p1 = state; --index != 0;)
|
||||
{
|
||||
do
|
||||
{
|
||||
currentSymbol = p1[1].Symbol;
|
||||
p1++;
|
||||
} while (characterMask[currentSymbol] == escapeCount);
|
||||
lowCount += p1.Frequency;
|
||||
}
|
||||
Coder.Scale += lowCount;
|
||||
see2Context.Update();
|
||||
Update2(state, context);
|
||||
}
|
||||
|
||||
private void DecodeBinarySymbol(PpmContext context)
|
||||
{
|
||||
PpmState state = context.FirstState;
|
||||
int index1 = probabilities[state.Frequency - 1];
|
||||
int index2 = numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + previousSuccess + context.Flags + ((runLength >> 26) & 0x20);
|
||||
|
||||
if (Coder.RangeGetCurrentShiftCount(TotalBitCount) < binarySummary[index1, index2])
|
||||
{
|
||||
foundState = state;
|
||||
state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0);
|
||||
Coder.LowCount = 0;
|
||||
Coder.HighCount = binarySummary[index1, index2];
|
||||
binarySummary[index1, index2] += (ushort)(Interval - Mean(binarySummary[index1, index2], PeriodBitCount, 2));
|
||||
previousSuccess = 1;
|
||||
runLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Coder.LowCount = binarySummary[index1, index2];
|
||||
binarySummary[index1, index2] -= (ushort)Mean(binarySummary[index1, index2], PeriodBitCount, 2);
|
||||
Coder.HighCount = BinaryScale;
|
||||
initialEscape = ExponentialEscapes[binarySummary[index1, index2] >> 10];
|
||||
characterMask[state.Symbol] = escapeCount;
|
||||
previousSuccess = 0;
|
||||
numberMasked = 0;
|
||||
foundState = PpmState.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void DecodeSymbol1(PpmContext context)
|
||||
{
|
||||
uint index;
|
||||
uint count;
|
||||
uint highCount = context.Statistics.Frequency;
|
||||
PpmState state = context.Statistics;
|
||||
Coder.Scale = context.SummaryFrequency;
|
||||
|
||||
count = Coder.RangeGetCurrentCount();
|
||||
if (count < highCount)
|
||||
{
|
||||
Coder.HighCount = highCount;
|
||||
previousSuccess = (byte)((2 * Coder.HighCount >= Coder.Scale) ? 1 : 0);
|
||||
foundState = state;
|
||||
highCount += 4;
|
||||
foundState.Frequency = (byte)highCount;
|
||||
context.SummaryFrequency += 4;
|
||||
runLength += previousSuccess;
|
||||
if (highCount > MaximumFrequency)
|
||||
Rescale(context);
|
||||
Coder.LowCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
index = context.NumberStatistics;
|
||||
previousSuccess = 0;
|
||||
while ((highCount += (++state).Frequency) <= count)
|
||||
{
|
||||
if (--index == 0)
|
||||
{
|
||||
Coder.LowCount = highCount;
|
||||
characterMask[state.Symbol] = escapeCount;
|
||||
numberMasked = context.NumberStatistics;
|
||||
index = context.NumberStatistics;
|
||||
foundState = PpmState.Zero;
|
||||
do
|
||||
{
|
||||
characterMask[(--state).Symbol] = escapeCount;
|
||||
} while (--index != 0);
|
||||
Coder.HighCount = Coder.Scale;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Coder.HighCount = highCount;
|
||||
Coder.LowCount = Coder.HighCount - state.Frequency;
|
||||
Update1(state, context);
|
||||
}
|
||||
|
||||
private void DecodeSymbol2(PpmContext context)
|
||||
{
|
||||
See2Context see2Context = MakeEscapeFrequency(context);
|
||||
uint currentSymbol;
|
||||
uint count;
|
||||
uint highCount = 0;
|
||||
uint index = (uint)(context.NumberStatistics - numberMasked);
|
||||
uint stateIndex = 0;
|
||||
PpmState state = context.Statistics - 1;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
currentSymbol = state[1].Symbol;
|
||||
state++;
|
||||
} while (characterMask[currentSymbol] == escapeCount);
|
||||
highCount += state.Frequency;
|
||||
decodeStates[stateIndex++] = state; // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons)
|
||||
} while (--index != 0);
|
||||
|
||||
Coder.Scale += highCount;
|
||||
count = Coder.RangeGetCurrentCount();
|
||||
stateIndex = 0;
|
||||
state = decodeStates[stateIndex];
|
||||
if (count < highCount)
|
||||
{
|
||||
highCount = 0;
|
||||
while ((highCount += state.Frequency) <= count)
|
||||
state = decodeStates[++stateIndex];
|
||||
Coder.HighCount = highCount;
|
||||
Coder.LowCount = Coder.HighCount - state.Frequency;
|
||||
see2Context.Update();
|
||||
Update2(state, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
Coder.LowCount = highCount;
|
||||
Coder.HighCount = Coder.Scale;
|
||||
index = (uint)(context.NumberStatistics - numberMasked);
|
||||
numberMasked = context.NumberStatistics;
|
||||
do
|
||||
{
|
||||
characterMask[decodeStates[stateIndex].Symbol] = escapeCount;
|
||||
stateIndex++;
|
||||
} while (--index != 0);
|
||||
see2Context.Summary += (ushort)Coder.Scale;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update1(PpmState state, PpmContext context)
|
||||
{
|
||||
foundState = state;
|
||||
foundState.Frequency += 4;
|
||||
context.SummaryFrequency += 4;
|
||||
if (state[0].Frequency > state[-1].Frequency)
|
||||
{
|
||||
Swap(state[0], state[-1]);
|
||||
foundState = --state;
|
||||
if (state.Frequency > MaximumFrequency)
|
||||
Rescale(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update2(PpmState state, PpmContext context)
|
||||
{
|
||||
foundState = state;
|
||||
foundState.Frequency += 4;
|
||||
context.SummaryFrequency += 4;
|
||||
if (state.Frequency > MaximumFrequency)
|
||||
Rescale(context);
|
||||
escapeCount++;
|
||||
runLength = initialRunLength;
|
||||
}
|
||||
|
||||
private See2Context MakeEscapeFrequency(PpmContext context)
|
||||
{
|
||||
uint numberStatistics = (uint)2 * context.NumberStatistics;
|
||||
See2Context see2Context;
|
||||
|
||||
if (context.NumberStatistics != 0xff)
|
||||
{
|
||||
// Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second
|
||||
// dimension of the see2Contexts array is always in the range 0 .. 31).
|
||||
|
||||
numberStatistics = context.Suffix.NumberStatistics;
|
||||
int index1 = probabilities[context.NumberStatistics + 2] - 3;
|
||||
int index2 = ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) + ((2 * context.NumberStatistics < numberStatistics + numberMasked) ? 2 : 0) + context.Flags;
|
||||
see2Context = see2Contexts[index1, index2];
|
||||
Coder.Scale = see2Context.Mean();
|
||||
}
|
||||
else
|
||||
{
|
||||
see2Context = emptySee2Context;
|
||||
Coder.Scale = 1;
|
||||
}
|
||||
|
||||
return see2Context;
|
||||
}
|
||||
|
||||
private void Rescale(PpmContext context)
|
||||
{
|
||||
uint oldUnitCount;
|
||||
int adder;
|
||||
uint escapeFrequency;
|
||||
uint index = context.NumberStatistics;
|
||||
|
||||
byte localSymbol;
|
||||
byte localFrequency;
|
||||
PpmContext localSuccessor;
|
||||
PpmState p1;
|
||||
PpmState state;
|
||||
|
||||
for (state = foundState; state != context.Statistics; state--)
|
||||
Swap(state[0], state[-1]);
|
||||
|
||||
state.Frequency += 4;
|
||||
context.SummaryFrequency += 4;
|
||||
escapeFrequency = (uint)(context.SummaryFrequency - state.Frequency);
|
||||
adder = (orderFall != 0 || method > ModelRestorationMethod.Freeze) ? 1 : 0;
|
||||
state.Frequency = (byte)((state.Frequency + adder) >> 1);
|
||||
context.SummaryFrequency = state.Frequency;
|
||||
|
||||
do
|
||||
{
|
||||
escapeFrequency -= (++state).Frequency;
|
||||
state.Frequency = (byte)((state.Frequency + adder) >> 1);
|
||||
context.SummaryFrequency += state.Frequency;
|
||||
if (state[0].Frequency > state[-1].Frequency)
|
||||
{
|
||||
p1 = state;
|
||||
localSymbol = p1.Symbol;
|
||||
localFrequency = p1.Frequency;
|
||||
localSuccessor = p1.Successor;
|
||||
do
|
||||
{
|
||||
Copy(p1[0], p1[-1]);
|
||||
} while (localFrequency > (--p1)[-1].Frequency);
|
||||
p1.Symbol = localSymbol;
|
||||
p1.Frequency = localFrequency;
|
||||
p1.Successor = localSuccessor;
|
||||
}
|
||||
} while (--index != 0);
|
||||
|
||||
if (state.Frequency == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
index++;
|
||||
} while ((--state).Frequency == 0);
|
||||
|
||||
escapeFrequency += index;
|
||||
oldUnitCount = (uint)((context.NumberStatistics + 2) >> 1);
|
||||
context.NumberStatistics -= (byte)index;
|
||||
if (context.NumberStatistics == 0)
|
||||
{
|
||||
localSymbol = context.Statistics.Symbol;
|
||||
localFrequency = context.Statistics.Frequency;
|
||||
localSuccessor = context.Statistics.Successor;
|
||||
localFrequency = (byte)((2 * localFrequency + escapeFrequency - 1) / escapeFrequency);
|
||||
if (localFrequency > MaximumFrequency / 3)
|
||||
localFrequency = (byte)(MaximumFrequency / 3);
|
||||
Allocator.FreeUnits(context.Statistics, oldUnitCount);
|
||||
context.FirstStateSymbol = localSymbol;
|
||||
context.FirstStateFrequency = localFrequency;
|
||||
context.FirstStateSuccessor = localSuccessor;
|
||||
context.Flags = (byte)((context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00));
|
||||
foundState = context.FirstState;
|
||||
return;
|
||||
}
|
||||
|
||||
context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)((context.NumberStatistics + 2) >> 1));
|
||||
context.Flags &= 0xf7;
|
||||
index = context.NumberStatistics;
|
||||
state = context.Statistics;
|
||||
context.Flags |= (byte)((state.Symbol >= 0x40) ? 0x08 : 0x00);
|
||||
do
|
||||
{
|
||||
context.Flags |= (byte)(((++state).Symbol >= 0x40) ? 0x08 : 0x00);
|
||||
} while (--index != 0);
|
||||
}
|
||||
|
||||
escapeFrequency -= (escapeFrequency >> 1);
|
||||
context.SummaryFrequency += (ushort)escapeFrequency;
|
||||
context.Flags |= 0x04;
|
||||
foundState = context.Statistics;
|
||||
}
|
||||
|
||||
private void Refresh(uint oldUnitCount, bool scale, PpmContext context)
|
||||
{
|
||||
int index = context.NumberStatistics;
|
||||
int escapeFrequency;
|
||||
int scaleValue = (scale ? 1 : 0);
|
||||
|
||||
context.Statistics = Allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)((index + 2) >> 1));
|
||||
PpmState statistics = context.Statistics;
|
||||
context.Flags = (byte)((context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00));
|
||||
escapeFrequency = context.SummaryFrequency - statistics.Frequency;
|
||||
statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue);
|
||||
context.SummaryFrequency = statistics.Frequency;
|
||||
|
||||
do
|
||||
{
|
||||
escapeFrequency -= (++statistics).Frequency;
|
||||
statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue);
|
||||
context.SummaryFrequency += statistics.Frequency;
|
||||
context.Flags |= (byte)((statistics.Symbol >= 0x40) ? 0x08 : 0x00);
|
||||
} while (--index != 0);
|
||||
|
||||
escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue;
|
||||
context.SummaryFrequency += (ushort)escapeFrequency;
|
||||
}
|
||||
|
||||
private PpmContext CutOff(int order, PpmContext context)
|
||||
{
|
||||
int index;
|
||||
PpmState state;
|
||||
|
||||
if (context.NumberStatistics == 0)
|
||||
{
|
||||
state = context.FirstState;
|
||||
if ((Pointer)state.Successor >= Allocator.BaseUnit)
|
||||
{
|
||||
if (order < modelOrder)
|
||||
state.Successor = CutOff(order + 1, state.Successor);
|
||||
else
|
||||
state.Successor = PpmContext.Zero;
|
||||
|
||||
if (state.Successor == PpmContext.Zero && order > OrderBound)
|
||||
{
|
||||
Allocator.SpecialFreeUnits(context);
|
||||
return PpmContext.Zero;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
else
|
||||
{
|
||||
Allocator.SpecialFreeUnits(context);
|
||||
return PpmContext.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
uint unitCount = (uint)((context.NumberStatistics + 2) >> 1);
|
||||
context.Statistics = Allocator.MoveUnitsUp(context.Statistics, unitCount);
|
||||
index = context.NumberStatistics;
|
||||
for (state = context.Statistics + index; state >= context.Statistics; state--)
|
||||
{
|
||||
if (state.Successor < Allocator.BaseUnit)
|
||||
{
|
||||
state.Successor = PpmContext.Zero;
|
||||
Swap(state, context.Statistics[index--]);
|
||||
}
|
||||
else if (order < modelOrder)
|
||||
state.Successor = CutOff(order + 1, state.Successor);
|
||||
else
|
||||
state.Successor = PpmContext.Zero;
|
||||
}
|
||||
|
||||
if (index != context.NumberStatistics && order != 0)
|
||||
{
|
||||
context.NumberStatistics = (byte)index;
|
||||
state = context.Statistics;
|
||||
if (index < 0)
|
||||
{
|
||||
Allocator.FreeUnits(state, unitCount);
|
||||
Allocator.SpecialFreeUnits(context);
|
||||
return PpmContext.Zero;
|
||||
}
|
||||
else if (index == 0)
|
||||
{
|
||||
context.Flags = (byte)((context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00));
|
||||
Copy(context.FirstState, state);
|
||||
Allocator.FreeUnits(state, unitCount);
|
||||
context.FirstStateFrequency = (byte)((context.FirstStateFrequency + 11) >> 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
Refresh(unitCount, context.SummaryFrequency > 16 * index, context);
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private PpmContext RemoveBinaryContexts(int order, PpmContext context)
|
||||
{
|
||||
if (context.NumberStatistics == 0)
|
||||
{
|
||||
PpmState state = context.FirstState;
|
||||
if ((Pointer)state.Successor >= Allocator.BaseUnit && order < modelOrder)
|
||||
state.Successor = RemoveBinaryContexts(order + 1, state.Successor);
|
||||
else
|
||||
state.Successor = PpmContext.Zero;
|
||||
if ((state.Successor == PpmContext.Zero) && (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff))
|
||||
{
|
||||
Allocator.FreeUnits(context, 1);
|
||||
return PpmContext.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
for (PpmState state = context.Statistics + context.NumberStatistics; state >= context.Statistics; state--)
|
||||
{
|
||||
if ((Pointer)state.Successor >= Allocator.BaseUnit && order < modelOrder)
|
||||
state.Successor = RemoveBinaryContexts(order + 1, state.Successor);
|
||||
else
|
||||
state.Successor = PpmContext.Zero;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
#region Using
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// PPM state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This must be a structure rather than a class because several places in the associated code assume that
|
||||
/// <see cref="PpmState"/> is a value type (meaning that assignment creates a completely new copy of the
|
||||
/// instance rather than just copying a reference to the same instance).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that <see cref="Address"/> is a field rather than a property for performance reasons.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal struct PpmState
|
||||
{
|
||||
public uint Address;
|
||||
public byte[] Memory;
|
||||
public static readonly PpmState Zero = new PpmState(0, null);
|
||||
public const int Size = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PpmState"/> structure.
|
||||
/// </summary>
|
||||
public PpmState(uint address, byte[] memory)
|
||||
{
|
||||
Address = address;
|
||||
Memory = memory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the symbol.
|
||||
/// </summary>
|
||||
public byte Symbol
|
||||
{
|
||||
get { return Memory[Address]; }
|
||||
set { Memory[Address] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the frequency.
|
||||
/// </summary>
|
||||
public byte Frequency
|
||||
{
|
||||
get { return Memory[Address + 1]; }
|
||||
set { Memory[Address + 1] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the successor.
|
||||
/// </summary>
|
||||
public Model.PpmContext Successor
|
||||
{
|
||||
get { return new Model.PpmContext(((uint)Memory[Address + 2]) | ((uint)Memory[Address + 3]) << 8 | ((uint)Memory[Address + 4]) << 16 | ((uint)Memory[Address + 5]) << 24, Memory); }
|
||||
set
|
||||
{
|
||||
Memory[Address + 2] = (byte)value.Address;
|
||||
Memory[Address + 3] = (byte)(value.Address >> 8);
|
||||
Memory[Address + 4] = (byte)(value.Address >> 16);
|
||||
Memory[Address + 5] = (byte)(value.Address >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="PpmState"/> at the <paramref name="offset"/> relative to this
|
||||
/// <see cref="PpmState"/>.
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public PpmState this[int offset]
|
||||
{
|
||||
get { return new PpmState((uint)(Address + offset * Size), Memory); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow a pointer to be implicitly converted to a PPM state.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public static implicit operator PpmState(Pointer pointer)
|
||||
{
|
||||
return new PpmState(pointer.Address, pointer.Memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like addition on a PPM state.
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static PpmState operator +(PpmState state, int offset)
|
||||
{
|
||||
state.Address = (uint)(state.Address + offset * Size);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like incrementing on a PPM state.
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <returns></returns>
|
||||
public static PpmState operator ++(PpmState state)
|
||||
{
|
||||
state.Address += Size;
|
||||
return state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like subtraction on a PPM state.
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static PpmState operator -(PpmState state, int offset)
|
||||
{
|
||||
state.Address = (uint)(state.Address - offset * Size);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow pointer-like decrementing on a PPM state.
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <returns></returns>
|
||||
public static PpmState operator --(PpmState state)
|
||||
{
|
||||
state.Address -= Size;
|
||||
return state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM states.
|
||||
/// </summary>
|
||||
/// <param name="state1"></param>
|
||||
/// <param name="state2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator <=(PpmState state1, PpmState state2)
|
||||
{
|
||||
return state1.Address <= state2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM states.
|
||||
/// </summary>
|
||||
/// <param name="state1"></param>
|
||||
/// <param name="state2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator >=(PpmState state1, PpmState state2)
|
||||
{
|
||||
return state1.Address >= state2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM states.
|
||||
/// </summary>
|
||||
/// <param name="state1"></param>
|
||||
/// <param name="state2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator ==(PpmState state1, PpmState state2)
|
||||
{
|
||||
return state1.Address == state2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two PPM states.
|
||||
/// </summary>
|
||||
/// <param name="state1"></param>
|
||||
/// <param name="state2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator !=(PpmState state1, PpmState state2)
|
||||
{
|
||||
return state1.Address != state2.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this instance and a specified object are equal.
|
||||
/// </summary>
|
||||
/// <returns>true if obj and this instance are the same type and represent the same value; otherwise, false.</returns>
|
||||
/// <param name="obj">Another object to compare to.</param>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is PpmState)
|
||||
{
|
||||
PpmState state = (PpmState)obj;
|
||||
return state.Address == Address;
|
||||
}
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Address.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#region Using
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This must be a class rather than a structure because MakeEscapeFrequency returns a See2Context
|
||||
/// instance from the see2Contexts array. The caller (for example, EncodeSymbol2) then updates the
|
||||
/// returned See2Context instance and expects the updates to be reflected in the see2Contexts array.
|
||||
/// This would not happen if this were a structure.
|
||||
/// </para>
|
||||
/// <remarks>
|
||||
/// Note that in most cases fields are used rather than properties for performance reasons (for example,
|
||||
/// <see cref="Shift"/> is a field rather than a property).
|
||||
/// </remarks>
|
||||
/// </remarks>
|
||||
internal class See2Context
|
||||
{
|
||||
private const byte PeriodBitCount = 7;
|
||||
|
||||
public ushort Summary;
|
||||
public byte Shift;
|
||||
public byte Count;
|
||||
|
||||
public void Initialize(uint initialValue)
|
||||
{
|
||||
Shift = PeriodBitCount - 4;
|
||||
Summary = (ushort)(initialValue << Shift);
|
||||
Count = 7;
|
||||
}
|
||||
|
||||
public uint Mean()
|
||||
{
|
||||
uint value = (uint)(Summary >> Shift);
|
||||
Summary = (ushort)(Summary - value);
|
||||
return (uint)(value + ((value == 0) ? 1 : 0));
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (Shift < PeriodBitCount && --Count == 0)
|
||||
{
|
||||
Summary += Summary;
|
||||
Count = (byte)(3 << Shift++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd
|
||||
{
|
||||
public enum PpmdVersion
|
||||
{
|
||||
H,
|
||||
H7z,
|
||||
I1,
|
||||
}
|
||||
|
||||
public class PpmdProperties
|
||||
{
|
||||
public PpmdVersion Version = PpmdVersion.I1;
|
||||
public int ModelOrder;
|
||||
internal I1.ModelRestorationMethod ModelRestorationMethod;
|
||||
|
||||
private int allocatorSize;
|
||||
internal I1.Allocator Allocator;
|
||||
|
||||
public PpmdProperties()
|
||||
: this(16 << 20, 6)
|
||||
{
|
||||
}
|
||||
|
||||
public PpmdProperties(int allocatorSize, int modelOrder)
|
||||
: this(allocatorSize, modelOrder, I1.ModelRestorationMethod.Restart)
|
||||
{
|
||||
}
|
||||
|
||||
internal PpmdProperties(int allocatorSize, int modelOrder, I1.ModelRestorationMethod modelRestorationMethod)
|
||||
{
|
||||
AllocatorSize = allocatorSize;
|
||||
ModelOrder = modelOrder;
|
||||
ModelRestorationMethod = modelRestorationMethod;
|
||||
}
|
||||
|
||||
public PpmdProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length == 2)
|
||||
{
|
||||
ushort props = BitConverter.ToUInt16(properties, 0);
|
||||
AllocatorSize = (((props >> 4) & 0xff) + 1) << 20;
|
||||
ModelOrder = (props & 0x0f) + 1;
|
||||
ModelRestorationMethod = (I1.ModelRestorationMethod)(props >> 12);
|
||||
}
|
||||
else if (properties.Length == 5)
|
||||
{
|
||||
Version = PpmdVersion.H7z;
|
||||
AllocatorSize = BitConverter.ToInt32(properties, 1);
|
||||
ModelOrder = properties[0];
|
||||
}
|
||||
}
|
||||
|
||||
public int AllocatorSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return allocatorSize;
|
||||
}
|
||||
set
|
||||
{
|
||||
allocatorSize = value;
|
||||
if (Version == PpmdVersion.I1)
|
||||
{
|
||||
if (Allocator == null)
|
||||
Allocator = new I1.Allocator();
|
||||
Allocator.Start(allocatorSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return BitConverter.GetBytes((ushort)((ModelOrder - 1) + (((AllocatorSize >> 20) - 1) << 4) + ((ushort)ModelRestorationMethod << 12)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Compress.SevenZip.Compress.RangeCoder;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd
|
||||
{
|
||||
public class PpmdStream : Stream
|
||||
{
|
||||
private PpmdProperties properties;
|
||||
private Stream stream;
|
||||
private bool compress;
|
||||
private I1.Model model;
|
||||
private H.ModelPPM modelH;
|
||||
private Decoder decoder;
|
||||
private long position = 0;
|
||||
|
||||
public PpmdStream(PpmdProperties properties, Stream stream, bool compress)
|
||||
{
|
||||
this.properties = properties;
|
||||
this.stream = stream;
|
||||
this.compress = compress;
|
||||
|
||||
if (properties.Version == PpmdVersion.I1)
|
||||
{
|
||||
model = new I1.Model();
|
||||
if (compress)
|
||||
model.EncodeStart(properties);
|
||||
else
|
||||
model.DecodeStart(stream, properties);
|
||||
}
|
||||
if (properties.Version == PpmdVersion.H)
|
||||
{
|
||||
modelH = new H.ModelPPM();
|
||||
if (compress)
|
||||
throw new NotImplementedException();
|
||||
else
|
||||
modelH.decodeInit(stream, properties.ModelOrder, properties.AllocatorSize);
|
||||
}
|
||||
if (properties.Version == PpmdVersion.H7z)
|
||||
{
|
||||
modelH = new H.ModelPPM();
|
||||
if (compress)
|
||||
throw new NotImplementedException();
|
||||
else
|
||||
modelH.decodeInit(null, properties.ModelOrder, properties.AllocatorSize);
|
||||
decoder = new Decoder();
|
||||
decoder.Init(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return !compress; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return compress; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
if (isDisposing)
|
||||
{
|
||||
if (compress)
|
||||
model.EncodeBlock(stream, new MemoryStream(), true);
|
||||
}
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (compress)
|
||||
return 0;
|
||||
int size = 0;
|
||||
if (properties.Version == PpmdVersion.I1)
|
||||
size = model.DecodeBlock(stream, buffer, offset, count);
|
||||
if (properties.Version == PpmdVersion.H)
|
||||
{
|
||||
int c;
|
||||
while (size < count && (c = modelH.decodeChar()) >= 0)
|
||||
{
|
||||
buffer[offset++] = (byte)c;
|
||||
size++;
|
||||
}
|
||||
}
|
||||
if (properties.Version == PpmdVersion.H7z)
|
||||
{
|
||||
int c;
|
||||
while (size < count && (c = modelH.decodeChar(decoder)) >= 0)
|
||||
{
|
||||
buffer[offset++] = (byte)c;
|
||||
size++;
|
||||
}
|
||||
}
|
||||
position += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
byte[] tmpBuff = new byte[1024];
|
||||
long sizeToGo = offset;
|
||||
while (sizeToGo > 0)
|
||||
{
|
||||
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
|
||||
Read(tmpBuff, 0, sizenow);
|
||||
sizeToGo -= sizenow;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (compress)
|
||||
model.EncodeBlock(stream, new MemoryStream(buffer, offset, count), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,467 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd
|
||||
{
|
||||
internal static class Utility
|
||||
{
|
||||
public static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> items)
|
||||
{
|
||||
return new ReadOnlyCollection<T>(items.ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static int URShift(int number, int bits)
|
||||
{
|
||||
if (number >= 0)
|
||||
return number >> bits;
|
||||
else
|
||||
return (number >> bits) + (2 << ~bits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static int URShift(int number, long bits)
|
||||
{
|
||||
return URShift(number, (int)bits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static long URShift(long number, int bits)
|
||||
{
|
||||
if (number >= 0)
|
||||
return number >> bits;
|
||||
else
|
||||
return (number >> bits) + (2L << ~bits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static long URShift(long number, long bits)
|
||||
{
|
||||
return URShift(number, (int)bits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the array with an specific value from an specific index to an specific index.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to be filled.</param>
|
||||
/// <param name="fromindex">The first index to be filled.</param>
|
||||
/// <param name="toindex">The last index to be filled.</param>
|
||||
/// <param name="val">The value to fill the array with.</param>
|
||||
public static void Fill<T>(T[] array, int fromindex, int toindex, T val) where T : struct
|
||||
{
|
||||
if (array.Length == 0)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
if (fromindex > toindex)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
if ((fromindex < 0) || ((System.Array)array).Length < toindex)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
for (int index = (fromindex > 0) ? fromindex-- : fromindex; index < toindex; index++)
|
||||
{
|
||||
array[index] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the array with an specific value.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to be filled.</param>
|
||||
/// <param name="val">The value to fill the array with.</param>
|
||||
public static void Fill<T>(T[] array, T val) where T : struct
|
||||
{
|
||||
Fill(array, 0, array.Length, val);
|
||||
}
|
||||
|
||||
public static void SetSize(this List<byte> list, int count)
|
||||
{
|
||||
if (count > list.Count)
|
||||
{
|
||||
for (int i = list.Count; i < count; i++)
|
||||
{
|
||||
list.Add(0x0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] temp = new byte[count];
|
||||
list.CopyTo(temp, 0);
|
||||
list.Clear();
|
||||
list.AddRange(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Read a int value from the byte array at the given position (Big Endian)
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="array">the array to read from
|
||||
/// </param>
|
||||
/// <param name="pos">the offset
|
||||
/// </param>
|
||||
/// <returns> the value
|
||||
/// </returns>
|
||||
public static int readIntBigEndian(byte[] array, int pos)
|
||||
{
|
||||
int temp = 0;
|
||||
temp |= array[pos] & 0xff;
|
||||
temp <<= 8;
|
||||
temp |= array[pos + 1] & 0xff;
|
||||
temp <<= 8;
|
||||
temp |= array[pos + 2] & 0xff;
|
||||
temp <<= 8;
|
||||
temp |= array[pos + 3] & 0xff;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary> Read a short value from the byte array at the given position (little
|
||||
/// Endian)
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="array">the array to read from
|
||||
/// </param>
|
||||
/// <param name="pos">the offset
|
||||
/// </param>
|
||||
/// <returns> the value
|
||||
/// </returns>
|
||||
public static short readShortLittleEndian(byte[] array, int pos)
|
||||
{
|
||||
return BitConverter.ToInt16(array, pos);
|
||||
}
|
||||
|
||||
/// <summary> Read an int value from the byte array at the given position (little
|
||||
/// Endian)
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="array">the array to read from
|
||||
/// </param>
|
||||
/// <param name="pos">the offset
|
||||
/// </param>
|
||||
/// <returns> the value
|
||||
/// </returns>
|
||||
public static int readIntLittleEndian(byte[] array, int pos)
|
||||
{
|
||||
return BitConverter.ToInt32(array, pos);
|
||||
}
|
||||
|
||||
/// <summary> Write an int value into the byte array at the given position (Big endian)
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="array">the array
|
||||
/// </param>
|
||||
/// <param name="pos">the offset
|
||||
/// </param>
|
||||
/// <param name="value">the value to write
|
||||
/// </param>
|
||||
public static void writeIntBigEndian(byte[] array, int pos, int value)
|
||||
{
|
||||
array[pos] = (byte)((Utility.URShift(value, 24)) & 0xff);
|
||||
array[pos + 1] = (byte)((Utility.URShift(value, 16)) & 0xff);
|
||||
array[pos + 2] = (byte)((Utility.URShift(value, 8)) & 0xff);
|
||||
array[pos + 3] = (byte)((value) & 0xff);
|
||||
}
|
||||
|
||||
/// <summary> Write a short value into the byte array at the given position (little
|
||||
/// endian)
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="array">the array
|
||||
/// </param>
|
||||
/// <param name="pos">the offset
|
||||
/// </param>
|
||||
/// <param name="value">the value to write
|
||||
/// </param>
|
||||
public static void WriteLittleEndian(byte[] array, int pos, short value)
|
||||
{
|
||||
byte[] newBytes = BitConverter.GetBytes(value);
|
||||
Array.Copy(newBytes, 0, array, pos, newBytes.Length);
|
||||
}
|
||||
|
||||
/// <summary> Increment a short value at the specified position by the specified amount
|
||||
/// (little endian).
|
||||
/// </summary>
|
||||
public static void incShortLittleEndian(byte[] array, int pos, short incrementValue)
|
||||
{
|
||||
short existingValue = BitConverter.ToInt16(array, pos);
|
||||
existingValue += incrementValue;
|
||||
WriteLittleEndian(array, pos, existingValue);
|
||||
//int c = Utility.URShift(((array[pos] & 0xff) + (dv & 0xff)), 8);
|
||||
//array[pos] = (byte)(array[pos] + (dv & 0xff));
|
||||
//if ((c > 0) || ((dv & 0xff00) != 0))
|
||||
//{
|
||||
// array[pos + 1] = (byte)(array[pos + 1] + ((Utility.URShift(dv, 8)) & 0xff) + c);
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary> Write an int value into the byte array at the given position (little
|
||||
/// endian)
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="array">the array
|
||||
/// </param>
|
||||
/// <param name="pos">the offset
|
||||
/// </param>
|
||||
/// <param name="value">the value to write
|
||||
/// </param>
|
||||
public static void WriteLittleEndian(byte[] array, int pos, int value)
|
||||
{
|
||||
byte[] newBytes = BitConverter.GetBytes(value);
|
||||
Array.Copy(newBytes, 0, array, pos, newBytes.Length);
|
||||
}
|
||||
|
||||
public static void Initialize<T>(this T[] array, Func<T> func)
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = func();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRange<T>(this ICollection<T> destination, IEnumerable<T> source)
|
||||
{
|
||||
foreach (T item in source)
|
||||
{
|
||||
destination.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
|
||||
{
|
||||
foreach (T item in items)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> AsEnumerable<T>(this T item)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
|
||||
public static void CheckNotNull(this object obj, string name)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
throw new ArgumentNullException(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckNotNullOrEmpty(this string obj, string name)
|
||||
{
|
||||
obj.CheckNotNull(name);
|
||||
if (obj.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("String is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Skip(this Stream source, long advanceAmount)
|
||||
{
|
||||
byte[] buffer = new byte[32 * 1024];
|
||||
int read = 0;
|
||||
int readCount = 0;
|
||||
do
|
||||
{
|
||||
readCount = buffer.Length;
|
||||
if (readCount > advanceAmount)
|
||||
{
|
||||
readCount = (int)advanceAmount;
|
||||
}
|
||||
read = source.Read(buffer, 0, readCount);
|
||||
if (read < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
advanceAmount -= read;
|
||||
if (advanceAmount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public static void SkipAll(this Stream source)
|
||||
{
|
||||
byte[] buffer = new byte[32 * 1024];
|
||||
do
|
||||
{
|
||||
} while (source.Read(buffer, 0, buffer.Length) == buffer.Length);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] UInt32ToBigEndianBytes(uint x)
|
||||
{
|
||||
return new byte[] {
|
||||
(byte)((x >> 24) & 0xff),
|
||||
(byte)((x >> 16) & 0xff),
|
||||
(byte)((x >> 8) & 0xff),
|
||||
(byte)(x & 0xff) };
|
||||
}
|
||||
|
||||
public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime)
|
||||
{
|
||||
int year = iDate / 512 + 1980;
|
||||
int month = iDate % 512 / 32;
|
||||
int day = iDate % 512 % 32;
|
||||
int hour = iTime / 2048;
|
||||
int minute = iTime % 2048 / 32;
|
||||
int second = iTime % 2048 % 32 * 2;
|
||||
|
||||
if (iDate == UInt16.MaxValue || month == 0 || day == 0)
|
||||
{
|
||||
year = 1980;
|
||||
month = 1;
|
||||
day = 1;
|
||||
}
|
||||
|
||||
if (iTime == UInt16.MaxValue)
|
||||
{
|
||||
hour = minute = second = 0;
|
||||
}
|
||||
|
||||
DateTime dt;
|
||||
try
|
||||
{
|
||||
dt = new DateTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
catch
|
||||
{
|
||||
dt = new DateTime();
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static uint DateTimeToDosTime(this DateTime? dateTime)
|
||||
{
|
||||
if (dateTime == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (uint)(
|
||||
(dateTime.Value.Second / 2) | (dateTime.Value.Minute << 5) | (dateTime.Value.Hour << 11) |
|
||||
(dateTime.Value.Day << 16) | (dateTime.Value.Month << 21) | ((dateTime.Value.Year - 1980) << 25));
|
||||
}
|
||||
|
||||
|
||||
public static DateTime DosDateToDateTime(UInt32 iTime)
|
||||
{
|
||||
return DosDateToDateTime((UInt16)(iTime / 65536),
|
||||
(UInt16)(iTime % 65536));
|
||||
}
|
||||
|
||||
public static DateTime DosDateToDateTime(Int32 iTime)
|
||||
{
|
||||
return DosDateToDateTime((UInt32)iTime);
|
||||
}
|
||||
|
||||
public static long TransferTo(this Stream source, Stream destination)
|
||||
{
|
||||
byte[] array = new byte[4096];
|
||||
int count;
|
||||
long total = 0;
|
||||
while ((count = source.Read(array, 0, array.Length)) != 0)
|
||||
{
|
||||
total += count;
|
||||
destination.Write(array, 0, count);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public static bool ReadFully(this Stream stream, byte[] buffer)
|
||||
{
|
||||
int total = 0;
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
|
||||
public static string TrimNulls(this string source)
|
||||
{
|
||||
return source.Replace('\0', ' ').Trim();
|
||||
}
|
||||
|
||||
public static bool BinaryEquals(this byte[] source, byte[] target)
|
||||
{
|
||||
if (source.Length != target.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < source.Length; ++i)
|
||||
{
|
||||
if (source[i] != target[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if PORTABLE
|
||||
public static void CopyTo(this byte[] array, byte[] destination, int index)
|
||||
{
|
||||
Array.Copy(array, 0, destination, index, array.Length);
|
||||
}
|
||||
|
||||
public static long HostToNetworkOrder(long host)
|
||||
{
|
||||
return (int)((long)HostToNetworkOrder((int)host)
|
||||
& unchecked((long)(unchecked((ulong)-1))) << 32
|
||||
| ((long)HostToNetworkOrder((int)((int)host >> 32)) & unchecked((long)(unchecked((ulong)-1)))));
|
||||
}
|
||||
public static int HostToNetworkOrder(int host)
|
||||
{
|
||||
return (int)((int)(HostToNetworkOrder((short)host) & -1) << 16 | (HostToNetworkOrder((short)(host >> 16)) & -1));
|
||||
}
|
||||
public static short HostToNetworkOrder(short host)
|
||||
{
|
||||
return (short)((int)(host & 255) << 8 | ((int)host >> 8 & 255));
|
||||
}
|
||||
public static long NetworkToHostOrder(long network)
|
||||
{
|
||||
return HostToNetworkOrder(network);
|
||||
}
|
||||
public static int NetworkToHostOrder(int network)
|
||||
{
|
||||
return HostToNetworkOrder(network);
|
||||
}
|
||||
public static short NetworkToHostOrder(short network)
|
||||
{
|
||||
return HostToNetworkOrder(network);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.RangeCoder
|
||||
{
|
||||
internal class Encoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
|
||||
System.IO.Stream Stream;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
uint _cacheSize;
|
||||
byte _cache;
|
||||
|
||||
//long StartPosition;
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
//StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
ShiftLow();
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Dispose();
|
||||
}
|
||||
|
||||
public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte)(temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
}
|
||||
while (--_cacheSize != 0);
|
||||
_cache = (byte)(((uint)Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint)Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
Low += Range;
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
Range = newBound;
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return -1;
|
||||
//return _cacheSize + Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Decoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
public uint Range;
|
||||
public uint Code = 0;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public System.IO.Stream Stream;
|
||||
public long Total;
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Total = 5;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Dispose();
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
Total++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
Total++;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}
|
||||
|
||||
public void Decode(uint start, uint size)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte)Stream.ReadByte();
|
||||
range <<= 8;
|
||||
Total++;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public bool IsFinished
|
||||
{
|
||||
get
|
||||
{
|
||||
return Code == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.RangeCoder
|
||||
{
|
||||
internal struct BitEncoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
const int kNumMoveBits = 5;
|
||||
const int kNumMoveReducingBits = 2;
|
||||
public const int kNumBitPriceShiftBits = 6;
|
||||
|
||||
uint Prob;
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public void UpdateModel(uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
|
||||
public void Encode(Encoder encoder, uint symbol)
|
||||
{
|
||||
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
||||
// UpdateModel(symbol);
|
||||
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (symbol == 0)
|
||||
{
|
||||
encoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Low += newBound;
|
||||
encoder.Range -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
if (encoder.Range < Encoder.kTopValue)
|
||||
{
|
||||
encoder.Range <<= 8;
|
||||
encoder.ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
|
||||
|
||||
static BitEncoder()
|
||||
{
|
||||
const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
|
||||
for (int i = kNumBits - 1; i >= 0; i--)
|
||||
{
|
||||
UInt32 start = (UInt32)1 << (kNumBits - i - 1);
|
||||
UInt32 end = (UInt32)1 << (kNumBits - i);
|
||||
for (UInt32 j = start; j < end; j++)
|
||||
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
|
||||
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetPrice(uint symbol)
|
||||
{
|
||||
return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
|
||||
}
|
||||
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
|
||||
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
|
||||
}
|
||||
|
||||
internal struct BitDecoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
const int kNumMoveBits = 5;
|
||||
|
||||
uint Prob;
|
||||
|
||||
public void UpdateModel(int numMoveBits, uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> numMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> numMoveBits;
|
||||
}
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;
|
||||
if (rangeDecoder.Code < newBound)
|
||||
{
|
||||
rangeDecoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
rangeDecoder.Total++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder.Range -= newBound;
|
||||
rangeDecoder.Code -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
rangeDecoder.Total++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.RangeCoder
|
||||
{
|
||||
internal struct BitTreeEncoder
|
||||
{
|
||||
BitEncoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct BitTreeDecoder
|
||||
{
|
||||
BitDecoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
return m - ((uint)1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
RangeCoder.Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = Zstandard.Net.ZstandardInterop;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// A Zstandard dictionary improves the compression ratio and speed on small data dramatically.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Zstandard dictionary is calculated with a high number of small sample data.
|
||||
/// Please refer to the Zstandard documentation for more details.
|
||||
/// </remarks>
|
||||
/// <seealso cref="System.IDisposable" />
|
||||
public sealed class ZstandardDictionary : IDisposable
|
||||
{
|
||||
private byte[] dictionary;
|
||||
private IntPtr ddict;
|
||||
private Dictionary<int, IntPtr> cdicts = new Dictionary<int, IntPtr>();
|
||||
private object lockObject = new object();
|
||||
private bool isDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary raw data.</param>
|
||||
public ZstandardDictionary(byte[] dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionaryPath">The dictionary path.</param>
|
||||
public ZstandardDictionary(string dictionaryPath)
|
||||
{
|
||||
this.dictionary = File.ReadAllBytes(dictionaryPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dictionaryStream">The dictionary stream.</param>
|
||||
public ZstandardDictionary(Stream dictionaryStream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
dictionaryStream.CopyTo(memoryStream);
|
||||
this.dictionary = memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="ZstandardDictionary"/> class.
|
||||
/// </summary>
|
||||
~ZstandardDictionary()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
private void Dispose(bool dispose)
|
||||
{
|
||||
if (this.isDisposed == false)
|
||||
{
|
||||
this.isDisposed = true;
|
||||
|
||||
if (this.ddict != IntPtr.Zero)
|
||||
{
|
||||
Interop.ZSTD_freeDDict(this.ddict);
|
||||
this.ddict = IntPtr.Zero;
|
||||
}
|
||||
|
||||
foreach (var kv in this.cdicts.ToList())
|
||||
{
|
||||
Interop.ZSTD_freeCDict(kv.Value);
|
||||
this.cdicts.Remove(kv.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compression dictionary for the specified compression level.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <returns>
|
||||
/// The IntPtr to the compression dictionary.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
|
||||
internal IntPtr GetCompressionDictionary(int compressionLevel)
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZstandardDictionary));
|
||||
}
|
||||
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (this.cdicts.TryGetValue(compressionLevel, out var cdict) == false)
|
||||
{
|
||||
this.cdicts[compressionLevel] = cdict = this.CreateCompressionDictionary(compressionLevel);
|
||||
}
|
||||
|
||||
return cdict;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the decompression dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The IntPtr to the decompression dictionary.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
|
||||
internal IntPtr GetDecompressionDictionary()
|
||||
{
|
||||
if (this.isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ZstandardDictionary));
|
||||
}
|
||||
|
||||
lock (this.lockObject)
|
||||
{
|
||||
if (this.ddict == IntPtr.Zero)
|
||||
{
|
||||
this.ddict = this.CreateDecompressionDictionary();
|
||||
}
|
||||
|
||||
return this.ddict;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new compression dictionary.
|
||||
/// </summary>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <returns>
|
||||
/// The IntPtr to the compression dictionary.
|
||||
/// </returns>
|
||||
private IntPtr CreateCompressionDictionary(int compressionLevel)
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
|
||||
var dictSize = new UIntPtr((uint)this.dictionary.Length);
|
||||
return Interop.ZSTD_createCDict(dictBuffer, dictSize, compressionLevel);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new decompression dictionary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The IntPtr to the decompression dictionary.
|
||||
/// </returns>
|
||||
private IntPtr CreateDecompressionDictionary()
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
|
||||
var dictSize = new UIntPtr((uint)this.dictionary.Length);
|
||||
return Interop.ZSTD_createDDict(dictBuffer, dictSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
internal static class ZstandardInterop
|
||||
{
|
||||
static ZstandardInterop()
|
||||
{
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
{
|
||||
var root = Path.GetDirectoryName(typeof(ZstandardInterop).Assembly.Location);
|
||||
var path = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
var file = Path.Combine(root, path, "libzstd.dll");
|
||||
LoadLibraryEx(file, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class Buffer
|
||||
{
|
||||
public IntPtr Data = IntPtr.Zero;
|
||||
public UIntPtr Size = UIntPtr.Zero;
|
||||
public UIntPtr Position = UIntPtr.Zero;
|
||||
}
|
||||
|
||||
public static void ThrowIfError(UIntPtr code)
|
||||
{
|
||||
if (ZSTD_isError(code))
|
||||
{
|
||||
var errorPtr = ZSTD_getErrorName(code);
|
||||
var errorMsg = Marshal.PtrToStringAnsi(errorPtr);
|
||||
throw new IOException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[Flags]
|
||||
private enum LoadLibraryFlags : uint
|
||||
{
|
||||
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
|
||||
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
|
||||
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
|
||||
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
|
||||
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
|
||||
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
|
||||
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
|
||||
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
|
||||
LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
|
||||
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
|
||||
}
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern uint ZSTD_versionNumber();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int ZSTD_maxCLevel();
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createCStream();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initCStream(IntPtr zcs, int compressionLevel);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeCStream(IntPtr zcs);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_CStreamInSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_CStreamOutSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_compressStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createCDict(IntPtr dictBuffer, UIntPtr dictSize, int compressionLevel);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeCDict(IntPtr cdict);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initCStream_usingCDict(IntPtr zcs, IntPtr cdict);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createDStream();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initDStream(IntPtr zds);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeDStream(IntPtr zds);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_DStreamInSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_DStreamOutSize();
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_decompressStream(IntPtr zds, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr ZSTD_createDDict(IntPtr dictBuffer, UIntPtr dictSize);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_freeDDict(IntPtr ddict);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_initDStream_usingDDict(IntPtr zds, IntPtr ddict);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_flushStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UIntPtr ZSTD_endStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern bool ZSTD_isError(UIntPtr code);
|
||||
|
||||
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr ZSTD_getErrorName(UIntPtr code);
|
||||
}
|
||||
}
|
||||
@@ -1,398 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = Zstandard.Net.ZstandardInterop;
|
||||
|
||||
namespace Zstandard.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods and properties for compressing and decompressing streams by using the Zstandard algorithm.
|
||||
/// </summary>
|
||||
public class ZstandardStream : Stream
|
||||
{
|
||||
private Stream stream;
|
||||
private CompressionMode mode;
|
||||
private Boolean leaveOpen;
|
||||
private Boolean isClosed = false;
|
||||
private Boolean isDisposed = false;
|
||||
private Boolean isInitialized = false;
|
||||
|
||||
private IntPtr zstream;
|
||||
private uint zstreamInputSize;
|
||||
private uint zstreamOutputSize;
|
||||
|
||||
private byte[] data;
|
||||
private bool dataDepleted = false;
|
||||
private bool dataSkipRead = false;
|
||||
private int dataPosition = 0;
|
||||
private int dataSize = 0;
|
||||
|
||||
private long position = 0;
|
||||
|
||||
private Interop.Buffer outputBuffer = new Interop.Buffer();
|
||||
private Interop.Buffer inputBuffer = new Interop.Buffer();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression mode, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress.</param>
|
||||
/// <param name="mode">One of the enumeration values that indicates whether to compress or decompress the stream.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
|
||||
public ZstandardStream(Stream stream, CompressionMode mode, bool leaveOpen = false)
|
||||
{
|
||||
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
this.mode = mode;
|
||||
this.leaveOpen = leaveOpen;
|
||||
position = 0;
|
||||
|
||||
if (mode == CompressionMode.Compress)
|
||||
{
|
||||
this.zstreamInputSize = Interop.ZSTD_CStreamInSize().ToUInt32();
|
||||
this.zstreamOutputSize = Interop.ZSTD_CStreamOutSize().ToUInt32();
|
||||
this.zstream = Interop.ZSTD_createCStream();
|
||||
this.data = new byte[(int)this.zstreamOutputSize];
|
||||
}
|
||||
|
||||
if (mode == CompressionMode.Decompress)
|
||||
{
|
||||
this.zstreamInputSize = Interop.ZSTD_DStreamInSize().ToUInt32();
|
||||
this.zstreamOutputSize = Interop.ZSTD_DStreamOutSize().ToUInt32();
|
||||
this.zstream = Interop.ZSTD_createDStream();
|
||||
this.data = new byte[(int)this.zstreamInputSize];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression level, and optionally leaves the stream open.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to compress.</param>
|
||||
/// <param name="compressionLevel">The compression level.</param>
|
||||
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
|
||||
public ZstandardStream(Stream stream, int compressionLevel, bool leaveOpen = false) : this(stream, CompressionMode.Compress, leaveOpen)
|
||||
{
|
||||
this.CompressionLevel = compressionLevel;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The version of the native Zstd library.
|
||||
/// </summary>
|
||||
public static Version Version
|
||||
{
|
||||
get
|
||||
{
|
||||
var version = (int)Interop.ZSTD_versionNumber();
|
||||
return new Version((version / 10000) % 100, (version / 100) % 100, version % 100);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum compression level supported by the native Zstd library.
|
||||
/// </summary>
|
||||
public static int MaxCompressionLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return Interop.ZSTD_maxCLevel();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression level to use, the default is 6.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To get the maximum compression level see <see cref="MaxCompressionLevel"/>.
|
||||
/// </remarks>
|
||||
public int CompressionLevel { get; set; } = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression dictionary tp use, the default is null.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The compression dictionary.
|
||||
/// </value>
|
||||
public ZstandardDictionary CompressionDictionary { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead => this.stream.CanRead && this.mode == CompressionMode.Decompress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite => this.stream.CanWrite && this.mode == CompressionMode.Compress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current stream supports seeking.
|
||||
/// </summary>
|
||||
public override bool CanSeek => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the stream.
|
||||
/// </summary>
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the current stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get => position;
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (this.isDisposed == false)
|
||||
{
|
||||
if (!this.isClosed) ReleaseResources(flushStream: false);
|
||||
this.isDisposed = true;
|
||||
this.data = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (this.isClosed) return;
|
||||
|
||||
try
|
||||
{
|
||||
ReleaseResources(flushStream: true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isClosed = true;
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseResources(bool flushStream)
|
||||
{
|
||||
if (this.mode == CompressionMode.Compress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (flushStream)
|
||||
{
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_endStream(zcs, buffer)));
|
||||
this.stream.Flush();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interop.ZSTD_freeCStream(this.zstream);
|
||||
if (!this.leaveOpen) this.stream.Close();
|
||||
}
|
||||
}
|
||||
else if (this.mode == CompressionMode.Decompress)
|
||||
{
|
||||
Interop.ZSTD_freeDStream(this.zstream);
|
||||
if (!this.leaveOpen) this.stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
if (this.mode == CompressionMode.Compress)
|
||||
{
|
||||
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
|
||||
this.stream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.CanRead == false) throw new NotSupportedException();
|
||||
|
||||
// prevent the buffers from being moved around by the garbage collector
|
||||
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
var length = 0;
|
||||
|
||||
if (this.isInitialized == false)
|
||||
{
|
||||
this.isInitialized = true;
|
||||
|
||||
var result = this.CompressionDictionary == null
|
||||
? Interop.ZSTD_initDStream(this.zstream)
|
||||
: Interop.ZSTD_initDStream_usingDDict(this.zstream, this.CompressionDictionary.GetDecompressionDictionary());
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
var inputSize = this.dataSize - this.dataPosition;
|
||||
|
||||
// read data from input stream
|
||||
if (inputSize <= 0 && !this.dataDepleted && !this.dataSkipRead)
|
||||
{
|
||||
this.dataSize = this.stream.Read(this.data, 0, (int)this.zstreamInputSize);
|
||||
this.dataDepleted = this.dataSize <= 0;
|
||||
this.dataPosition = 0;
|
||||
inputSize = this.dataDepleted ? 0 : this.dataSize;
|
||||
|
||||
// skip stream.Read until the internal buffer is depleted
|
||||
// avoids a Read timeout for applications that know the exact number of bytes in the stream
|
||||
this.dataSkipRead = true;
|
||||
}
|
||||
|
||||
// configure the inputBuffer
|
||||
this.inputBuffer.Data = inputSize <= 0 ? IntPtr.Zero : Marshal.UnsafeAddrOfPinnedArrayElement(this.data, this.dataPosition);
|
||||
this.inputBuffer.Size = inputSize <= 0 ? UIntPtr.Zero : new UIntPtr((uint)inputSize);
|
||||
this.inputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// configure the outputBuffer
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
|
||||
this.outputBuffer.Size = new UIntPtr((uint)count);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// decompress inputBuffer to outputBuffer
|
||||
Interop.ThrowIfError(Interop.ZSTD_decompressStream(this.zstream, this.outputBuffer, this.inputBuffer));
|
||||
|
||||
// calculate progress in outputBuffer
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
if (outputBufferPosition == 0)
|
||||
{
|
||||
// the internal buffer is depleted, we're either done
|
||||
if (this.dataDepleted) break;
|
||||
|
||||
// or we need more bytes
|
||||
this.dataSkipRead = false;
|
||||
}
|
||||
length += outputBufferPosition;
|
||||
offset += outputBufferPosition;
|
||||
count -= outputBufferPosition;
|
||||
|
||||
// calculate progress in inputBuffer
|
||||
var inputBufferPosition = (int)inputBuffer.Position.ToUInt32();
|
||||
this.dataPosition += inputBufferPosition;
|
||||
}
|
||||
|
||||
position += length;
|
||||
return length;
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc1.Free();
|
||||
alloc2.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.CanWrite == false) throw new NotSupportedException();
|
||||
|
||||
// prevent the buffers from being moved around by the garbage collector
|
||||
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.isInitialized == false)
|
||||
{
|
||||
this.isInitialized = true;
|
||||
|
||||
var result = this.CompressionDictionary == null
|
||||
? Interop.ZSTD_initCStream(this.zstream, this.CompressionLevel)
|
||||
: Interop.ZSTD_initCStream_usingCDict(this.zstream, this.CompressionDictionary.GetCompressionDictionary(this.CompressionLevel));
|
||||
|
||||
Interop.ThrowIfError(result);
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
var inputSize = Math.Min((uint)count, this.zstreamInputSize);
|
||||
|
||||
// configure the outputBuffer
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
|
||||
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// configure the inputBuffer
|
||||
this.inputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
|
||||
this.inputBuffer.Size = new UIntPtr((uint)inputSize);
|
||||
this.inputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
// compress inputBuffer to outputBuffer
|
||||
Interop.ThrowIfError(Interop.ZSTD_compressStream(this.zstream, this.outputBuffer, this.inputBuffer));
|
||||
|
||||
// write data to output stream
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
this.stream.Write(this.data, 0, outputBufferPosition);
|
||||
|
||||
// calculate progress in inputBuffer
|
||||
var inputBufferPosition = (int)this.inputBuffer.Position.ToUInt32();
|
||||
offset += inputBufferPosition;
|
||||
count -= inputBufferPosition;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc1.Free();
|
||||
alloc2.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
byte[] tmpBuff = new byte[1024];
|
||||
long sizeToGo = offset;
|
||||
while (sizeToGo > 0)
|
||||
{
|
||||
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
|
||||
Read(tmpBuff, 0, sizenow);
|
||||
sizeToGo -= sizenow;
|
||||
}
|
||||
|
||||
position += offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
private void ProcessStream(Action<IntPtr, Interop.Buffer> outputAction)
|
||||
{
|
||||
var alloc = GCHandle.Alloc(this.data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
|
||||
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
|
||||
this.outputBuffer.Position = UIntPtr.Zero;
|
||||
|
||||
outputAction(this.zstream, this.outputBuffer);
|
||||
|
||||
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
|
||||
this.stream.Write(this.data, 0, outputBufferPosition);
|
||||
}
|
||||
finally
|
||||
{
|
||||
alloc.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
{
|
||||
public class BCJ2Filter : Stream
|
||||
{
|
||||
private Stream baseStream;
|
||||
|
||||
private long position = 0;
|
||||
private byte[] output = new byte[4];
|
||||
private int outputOffset = 0;
|
||||
private int outputCount = 0;
|
||||
|
||||
private Stream control;
|
||||
private Stream data1;
|
||||
private Stream data2;
|
||||
|
||||
private ushort[] p = new ushort[256 + 2];
|
||||
private uint range, code;
|
||||
private byte prevByte = 0;
|
||||
|
||||
private const int kNumTopBits = 24;
|
||||
private const int kTopValue = 1 << kNumTopBits;
|
||||
|
||||
private const int kNumBitModelTotalBits = 11;
|
||||
private const int kBitModelTotal = 1 << kNumBitModelTotalBits;
|
||||
private const int kNumMoveBits = 5;
|
||||
|
||||
private static bool IsJ(byte b0, byte b1)
|
||||
{
|
||||
return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1);
|
||||
}
|
||||
|
||||
private static bool IsJcc(byte b0, byte b1)
|
||||
{
|
||||
return b0 == 0x0F && (b1 & 0xF0) == 0x80;
|
||||
}
|
||||
|
||||
public BCJ2Filter(Stream baseStream, Stream data1, Stream data2, Stream control)
|
||||
{
|
||||
this.control = control;
|
||||
this.data1 = data1;
|
||||
this.data2 = data2;
|
||||
this.baseStream = baseStream;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < p.Length; i++)
|
||||
p[i] = kBitModelTotal >> 1;
|
||||
|
||||
code = 0;
|
||||
range = 0xFFFFFFFF;
|
||||
|
||||
byte[] controlbuf = new byte[5];
|
||||
control.Read(controlbuf, 0, 5);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
code = (code << 8) | controlbuf[i];
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return baseStream.Length + data1.Length + data2.Length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int size = 0;
|
||||
byte b = 0;
|
||||
|
||||
while (size < count)
|
||||
{
|
||||
while (outputOffset < outputCount)
|
||||
{
|
||||
b = output[outputOffset++];
|
||||
buffer[offset++] = b;
|
||||
size++;
|
||||
position++;
|
||||
|
||||
prevByte = b;
|
||||
if (size == count)
|
||||
return size;
|
||||
}
|
||||
|
||||
b = (byte)baseStream.ReadByte();
|
||||
buffer[offset++] = b;
|
||||
size++;
|
||||
position++;
|
||||
|
||||
if (!IsJ(prevByte, b))
|
||||
prevByte = b;
|
||||
else
|
||||
{
|
||||
int prob;
|
||||
if (b == 0xE8)
|
||||
prob = prevByte;
|
||||
else if (b == 0xE9)
|
||||
prob = 256;
|
||||
else
|
||||
prob = 257;
|
||||
|
||||
uint bound = (range >> kNumBitModelTotalBits) * p[prob];
|
||||
if (code < bound)
|
||||
{
|
||||
range = bound;
|
||||
p[prob] += (ushort)((kBitModelTotal - p[prob]) >> kNumMoveBits);
|
||||
if (range < kTopValue)
|
||||
{
|
||||
range <<= 8;
|
||||
code = (code << 8) | (byte)control.ReadByte();
|
||||
}
|
||||
prevByte = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
range -= bound;
|
||||
code -= bound;
|
||||
p[prob] -= (ushort)(p[prob] >> kNumMoveBits);
|
||||
if (range < kTopValue)
|
||||
{
|
||||
range <<= 8;
|
||||
code = (code << 8) | (byte)control.ReadByte();
|
||||
}
|
||||
|
||||
uint dest;
|
||||
if (b == 0xE8)
|
||||
dest = (uint)((data1.ReadByte() << 24) | (data1.ReadByte() << 16) | (data1.ReadByte() << 8) | data1.ReadByte());
|
||||
else
|
||||
dest = (uint)((data2.ReadByte() << 24) | (data2.ReadByte() << 16) | (data2.ReadByte() << 8) | data2.ReadByte());
|
||||
dest -= (uint)(position + 4);
|
||||
|
||||
output[0] = (byte)dest;
|
||||
output[1] = (byte)(dest >> 8);
|
||||
output[2] = (byte)(dest >> 16);
|
||||
output[3] = (byte)(dest >> 24);
|
||||
outputOffset = 0;
|
||||
outputCount = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
const int bufferSize = 10240;
|
||||
byte[] seekBuffer = new byte[bufferSize];
|
||||
long seekToGo = offset;
|
||||
while (seekToGo > 0)
|
||||
{
|
||||
long get = seekToGo > bufferSize ? bufferSize : seekToGo;
|
||||
Read(seekBuffer, 0, (int)get);
|
||||
seekToGo -= get;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
{
|
||||
public class BCJFilter : Filter
|
||||
{
|
||||
private static readonly bool[] MASK_TO_ALLOWED_STATUS = new bool[] { true, true, true, false, true, false, false, false };
|
||||
private static readonly int[] MASK_TO_BIT_NUMBER = new int[] { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
private int pos;
|
||||
private int prevMask = 0;
|
||||
|
||||
public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5)
|
||||
{
|
||||
pos = 5;
|
||||
}
|
||||
|
||||
private static bool test86MSByte(byte b)
|
||||
{
|
||||
return b == 0x00 || b == 0xFF;
|
||||
}
|
||||
|
||||
protected override int Transform(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int prevPos = offset - 1;
|
||||
int end = offset + count - 5;
|
||||
int i;
|
||||
|
||||
for (i = offset; i <= end; ++i)
|
||||
{
|
||||
if ((buffer[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
prevPos = i - prevPos;
|
||||
if ((prevPos & ~3) != 0)
|
||||
{ // (unsigned)prevPos > 3
|
||||
prevMask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << (prevPos - 1)) & 7;
|
||||
if (prevMask != 0)
|
||||
{
|
||||
if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte(
|
||||
buffer[i + 4 - MASK_TO_BIT_NUMBER[prevMask]]))
|
||||
{
|
||||
prevPos = i;
|
||||
prevMask = (prevMask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prevPos = i;
|
||||
|
||||
if (test86MSByte(buffer[i + 4]))
|
||||
{
|
||||
int src = buffer[i + 1]
|
||||
| (buffer[i + 2] << 8)
|
||||
| (buffer[i + 3] << 16)
|
||||
| (buffer[i + 4] << 24);
|
||||
int dest;
|
||||
while (true)
|
||||
{
|
||||
if (isEncoder)
|
||||
dest = src + (pos + i - offset);
|
||||
else
|
||||
dest = src - (pos + i - offset);
|
||||
|
||||
if (prevMask == 0)
|
||||
break;
|
||||
|
||||
int index = MASK_TO_BIT_NUMBER[prevMask] * 8;
|
||||
if (!test86MSByte((byte)(dest >> (24 - index))))
|
||||
break;
|
||||
|
||||
src = dest ^ ((1 << (32 - index)) - 1);
|
||||
}
|
||||
|
||||
buffer[i + 1] = (byte)dest;
|
||||
buffer[i + 2] = (byte)(dest >> 8);
|
||||
buffer[i + 3] = (byte)(dest >> 16);
|
||||
buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1));
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
prevPos = i - prevPos;
|
||||
prevMask = ((prevPos & ~3) != 0) ? 0 : prevMask << (prevPos - 1);
|
||||
|
||||
i -= offset;
|
||||
pos += i;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
{
|
||||
public class Delta : Stream
|
||||
{
|
||||
private readonly Stream _baseStream;
|
||||
private long _position;
|
||||
private readonly byte[] _bVal;
|
||||
private readonly int _dSize;
|
||||
private int _bIndex;
|
||||
|
||||
// properties values are 0,1,3
|
||||
public Delta(byte[] properties, Stream inputStream)
|
||||
{
|
||||
_dSize = properties[0] + 1;
|
||||
_bVal = new byte[_dSize];
|
||||
|
||||
_baseStream = inputStream;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
const int bufferSize = 10240;
|
||||
byte[] seekBuffer = new byte[bufferSize];
|
||||
long seekToGo = offset;
|
||||
while (seekToGo > 0)
|
||||
{
|
||||
long get = seekToGo > bufferSize ? bufferSize : seekToGo;
|
||||
Read(seekBuffer, 0, (int)get);
|
||||
seekToGo -= get;
|
||||
}
|
||||
return _position;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int read = _baseStream.Read(buffer, offset, count);
|
||||
|
||||
for (int i = 0; i < read; i++)
|
||||
{
|
||||
buffer[i] = _bVal[_bIndex] = (byte)(buffer[i] + _bVal[_bIndex]);
|
||||
_bIndex = (_bIndex + 1) % _dSize;
|
||||
}
|
||||
|
||||
_position += read;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public override long Length
|
||||
{
|
||||
get { return _baseStream.Length; }
|
||||
}
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
{
|
||||
public abstract class Filter : Stream
|
||||
{
|
||||
protected bool isEncoder;
|
||||
protected Stream baseStream;
|
||||
|
||||
private byte[] tail;
|
||||
private byte[] window;
|
||||
private int transformed = 0;
|
||||
private int read = 0;
|
||||
private bool endReached = false;
|
||||
private long position = 0;
|
||||
|
||||
protected Filter(bool isEncoder, Stream baseStream, int lookahead)
|
||||
{
|
||||
this.isEncoder = isEncoder;
|
||||
this.baseStream = baseStream;
|
||||
tail = new byte[lookahead - 1];
|
||||
window = new byte[tail.Length * 2];
|
||||
}
|
||||
|
||||
public Stream BaseStream
|
||||
{ get { return baseStream; } }
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return !isEncoder; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return isEncoder; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { return baseStream.Length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
if (transformed > 0)
|
||||
{
|
||||
int copySize = transformed;
|
||||
if (copySize > count)
|
||||
copySize = count;
|
||||
Buffer.BlockCopy(tail, 0, buffer, offset, copySize);
|
||||
transformed -= copySize;
|
||||
read -= copySize;
|
||||
offset += copySize;
|
||||
count -= copySize;
|
||||
size += copySize;
|
||||
Buffer.BlockCopy(tail, copySize, tail, 0, read);
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
position += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int inSize = read;
|
||||
if (inSize > count)
|
||||
inSize = count;
|
||||
Buffer.BlockCopy(tail, 0, buffer, offset, inSize);
|
||||
read -= inSize;
|
||||
Buffer.BlockCopy(tail, inSize, tail, 0, read);
|
||||
while (!endReached && inSize < count)
|
||||
{
|
||||
int baseRead = baseStream.Read(buffer, offset + inSize, count - inSize);
|
||||
inSize += baseRead;
|
||||
if (baseRead == 0)
|
||||
endReached = true;
|
||||
}
|
||||
while (!endReached && read < tail.Length)
|
||||
{
|
||||
int baseRead = baseStream.Read(tail, read, tail.Length - read);
|
||||
read += baseRead;
|
||||
if (baseRead == 0)
|
||||
endReached = true;
|
||||
}
|
||||
|
||||
if (inSize > tail.Length)
|
||||
{
|
||||
transformed = Transform(buffer, offset, inSize);
|
||||
offset += transformed;
|
||||
count -= transformed;
|
||||
size += transformed;
|
||||
inSize -= transformed;
|
||||
transformed = 0;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
position += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(buffer, offset, window, 0, inSize);
|
||||
Buffer.BlockCopy(tail, 0, window, inSize, read);
|
||||
if (inSize + read > tail.Length)
|
||||
transformed = Transform(window, 0, inSize + read);
|
||||
else
|
||||
transformed = inSize + read;
|
||||
Buffer.BlockCopy(window, 0, buffer, offset, inSize);
|
||||
Buffer.BlockCopy(window, inSize, tail, 0, read);
|
||||
size += inSize;
|
||||
transformed -= inSize;
|
||||
|
||||
position += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin != SeekOrigin.Current)
|
||||
throw new NotImplementedException();
|
||||
|
||||
const int bufferSize = 10240;
|
||||
byte[] seekBuffer = new byte[bufferSize];
|
||||
long seekToGo = offset;
|
||||
while (seekToGo > 0)
|
||||
{
|
||||
long get = seekToGo > bufferSize ? bufferSize : seekToGo;
|
||||
Read(seekBuffer, 0, (int)get);
|
||||
seekToGo -= get;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
Transform(buffer, offset, count);
|
||||
baseStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
protected abstract int Transform(byte[] buffer, int offset, int count);
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Structure;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ : ICompress
|
||||
{
|
||||
public static bool supportZstd
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static void TestForZstd()
|
||||
{
|
||||
supportZstd = RVIO.File.Exists("libzstd.dll");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class LocalFile
|
||||
{
|
||||
public string FileName;
|
||||
public ulong UncompressedSize;
|
||||
public bool IsDirectory;
|
||||
public byte[] CRC;
|
||||
public int StreamIndex;
|
||||
public ulong StreamOffset;
|
||||
public ZipReturn FileStatus = ZipReturn.ZipUntested;
|
||||
}
|
||||
|
||||
|
||||
private List<LocalFile> _localFiles = new List<LocalFile>();
|
||||
|
||||
private FileInfo _zipFileInfo;
|
||||
|
||||
private Stream _zipFs;
|
||||
|
||||
private SignatureHeader _signatureHeader;
|
||||
|
||||
private bool _compressed = true;
|
||||
|
||||
|
||||
private long _baseOffset;
|
||||
|
||||
public string ZipFilename => _zipFileInfo != null ? _zipFileInfo.FullName : string.Empty;
|
||||
|
||||
public long TimeStamp => _zipFileInfo?.LastWriteTime ?? 0;
|
||||
|
||||
public ZipOpenType ZipOpen { get; private set; }
|
||||
public ZipStatus ZipStatus { get; private set; }
|
||||
|
||||
public int LocalFilesCount()
|
||||
{
|
||||
return _localFiles.Count;
|
||||
}
|
||||
|
||||
public string Filename(int i)
|
||||
{
|
||||
return _localFiles[i].FileName;
|
||||
}
|
||||
|
||||
public ulong? LocalHeader(int i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ulong UncompressedSize(int i)
|
||||
{
|
||||
return _localFiles[i].UncompressedSize;
|
||||
}
|
||||
|
||||
public int StreamIndex(int i)
|
||||
{
|
||||
return _localFiles[i].StreamIndex;
|
||||
|
||||
}
|
||||
|
||||
public ZipReturn FileStatus(int i)
|
||||
{
|
||||
return _localFiles[i].FileStatus;
|
||||
}
|
||||
|
||||
public byte[] CRC32(int i)
|
||||
{
|
||||
return _localFiles[i].CRC;
|
||||
}
|
||||
|
||||
public void ZipFileCloseFailed()
|
||||
{
|
||||
switch (ZipOpen)
|
||||
{
|
||||
case ZipOpenType.Closed:
|
||||
return;
|
||||
case ZipOpenType.OpenRead:
|
||||
ZipFileCloseReadStream();
|
||||
if (_zipFs != null)
|
||||
{
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
break;
|
||||
case ZipOpenType.OpenWrite:
|
||||
_zipFs.Flush();
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
if (_zipFileInfo != null)
|
||||
RVIO.File.Delete(_zipFileInfo.FullName);
|
||||
_zipFileInfo = null;
|
||||
break;
|
||||
}
|
||||
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
public bool IsDirectory(int i)
|
||||
{
|
||||
return _localFiles[i].IsDirectory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void ZipFileClose()
|
||||
{
|
||||
switch (ZipOpen)
|
||||
{
|
||||
case ZipOpenType.Closed:
|
||||
return;
|
||||
case ZipOpenType.OpenRead:
|
||||
ZipFileCloseReadStream();
|
||||
if (_zipFs != null)
|
||||
{
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
return;
|
||||
case ZipOpenType.OpenWrite:
|
||||
CloseWriting7Zip();
|
||||
if (_zipFileInfo != null)
|
||||
_zipFileInfo = new FileInfo(_zipFileInfo.FullName);
|
||||
break;
|
||||
}
|
||||
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
|
||||
private Header _header;
|
||||
|
||||
public StringBuilder HeaderReport()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (_header == null)
|
||||
{
|
||||
sb.AppendLine("Null Header");
|
||||
return sb;
|
||||
}
|
||||
|
||||
_header.Report(ref sb);
|
||||
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
public ZipReturn ZipFileOpen(string filename, long timestamp, bool readHeaders)
|
||||
{
|
||||
ZipFileClose();
|
||||
Debug.WriteLine(filename);
|
||||
#region open file stream
|
||||
|
||||
try
|
||||
{
|
||||
if (!RVIO.File.Exists(filename))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorFileNotFound;
|
||||
}
|
||||
_zipFileInfo = new FileInfo(filename);
|
||||
if ((timestamp != -1) && (_zipFileInfo.LastWriteTime != timestamp))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorTimeStamp;
|
||||
}
|
||||
int errorCode = FileStream.OpenFileRead(filename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipFileNameToLong;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
ZipStatus = ZipStatus.None;
|
||||
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileOpen(Stream inStream)
|
||||
{
|
||||
ZipFileClose();
|
||||
_zipFileInfo = null;
|
||||
_zipFs = inStream;
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
ZipStatus = ZipStatus.None;
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private ZipReturn ZipFileReadHeaders()
|
||||
{
|
||||
try
|
||||
{
|
||||
SignatureHeader signatureHeader = new SignatureHeader();
|
||||
if (!signatureHeader.Read(_zipFs))
|
||||
{
|
||||
return ZipReturn.ZipSignatureError;
|
||||
}
|
||||
|
||||
_baseOffset = _zipFs.Position;
|
||||
|
||||
_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
||||
byte[] mainHeader = new byte[signatureHeader.NextHeaderSize];
|
||||
_zipFs.Read(mainHeader, 0, (int)signatureHeader.NextHeaderSize);
|
||||
if (!CRC.VerifyDigest(signatureHeader.NextHeaderCRC, mainHeader, 0, (uint)signatureHeader.NextHeaderSize))
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
|
||||
if (signatureHeader.NextHeaderSize != 0)
|
||||
{
|
||||
_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
||||
ZipReturn zr = Header.ReadHeaderOrPackedHeader(_zipFs, _baseOffset, out _header);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ZipStatus = ZipStatus.None;
|
||||
ZipStatus |= IsRomVault7Z(_baseOffset, signatureHeader.NextHeaderOffset, signatureHeader.NextHeaderSize, signatureHeader.NextHeaderCRC) ? ZipStatus.TrrntZip : ZipStatus.None;
|
||||
|
||||
_zipFs.Seek(_baseOffset + (long)(signatureHeader.NextHeaderOffset + signatureHeader.NextHeaderSize), SeekOrigin.Begin);
|
||||
ZipStatus |= Istorrent7Z() ? ZipStatus.Trrnt7Zip : ZipStatus.None;
|
||||
PopulateLocalFiles(out _localFiles);
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorReadingFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void PopulateLocalFiles(out List<LocalFile> localFiles)
|
||||
{
|
||||
int emptyFileIndex = 0;
|
||||
int folderIndex = 0;
|
||||
int unpackedStreamsIndex = 0;
|
||||
ulong streamOffset = 0;
|
||||
localFiles = new List<LocalFile>();
|
||||
|
||||
if (_header == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _header.FileInfo.Names.Length; i++)
|
||||
{
|
||||
LocalFile lf = new LocalFile { FileName = _header.FileInfo.Names[i] };
|
||||
|
||||
if ((_header.FileInfo.EmptyStreamFlags == null) || !_header.FileInfo.EmptyStreamFlags[i])
|
||||
{
|
||||
lf.StreamIndex = folderIndex;
|
||||
lf.StreamOffset = streamOffset;
|
||||
lf.UncompressedSize = _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].UnpackedSize;
|
||||
lf.CRC = Util.uinttobytes(_header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].Crc);
|
||||
|
||||
streamOffset += lf.UncompressedSize;
|
||||
unpackedStreamsIndex++;
|
||||
|
||||
if (unpackedStreamsIndex >= _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo.Length)
|
||||
{
|
||||
folderIndex++;
|
||||
unpackedStreamsIndex = 0;
|
||||
streamOffset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lf.UncompressedSize = 0;
|
||||
lf.CRC = new byte[] { 0, 0, 0, 0 };
|
||||
lf.IsDirectory = (_header.FileInfo.EmptyFileFlags == null) || !_header.FileInfo.EmptyFileFlags[emptyFileIndex++];
|
||||
|
||||
if (lf.IsDirectory)
|
||||
{
|
||||
if (lf.FileName.Substring(lf.FileName.Length - 1, 1) != "/")
|
||||
{
|
||||
lf.FileName += "/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localFiles.Add(lf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using Compress.SevenZip.Compress.BZip2;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Compress.PPmd;
|
||||
using Compress.SevenZip.Filters;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Zstandard.Net;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
private int _streamIndex = -1;
|
||||
private Stream _stream;
|
||||
|
||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong unCompressedSize)
|
||||
{
|
||||
Debug.WriteLine("Opening File " + _localFiles[index].FileName);
|
||||
stream = null;
|
||||
unCompressedSize = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.OpenRead)
|
||||
{
|
||||
return ZipReturn.ZipErrorGettingDataStream;
|
||||
}
|
||||
|
||||
if (IsDirectory(index))
|
||||
{
|
||||
return ZipReturn.ZipTryingToAccessADirectory;
|
||||
}
|
||||
|
||||
unCompressedSize = _localFiles[index].UncompressedSize;
|
||||
int thisStreamIndex = _localFiles[index].StreamIndex;
|
||||
ulong streamOffset = _localFiles[index].StreamOffset;
|
||||
|
||||
if ((thisStreamIndex == _streamIndex) && (streamOffset >= (ulong)_stream.Position))
|
||||
{
|
||||
stream = _stream;
|
||||
stream.Seek((long)_localFiles[index].StreamOffset - _stream.Position, SeekOrigin.Current);
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
ZipFileCloseReadStream();
|
||||
_streamIndex = thisStreamIndex;
|
||||
|
||||
|
||||
Folder folder = _header.StreamsInfo.Folders[_streamIndex];
|
||||
|
||||
// first make the List of Decompressors streams
|
||||
int codersNeeded = folder.Coders.Length;
|
||||
|
||||
List<InStreamSourceInfo> allInputStreams = new List<InStreamSourceInfo>();
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
folder.Coders[i].DecoderStream = null;
|
||||
allInputStreams.AddRange(folder.Coders[i].InputStreamsSourceInfo);
|
||||
}
|
||||
|
||||
// now use the binding pairs to links the outputs to the inputs
|
||||
int bindPairsCount = folder.BindPairs.Length;
|
||||
for (int i = 0; i < bindPairsCount; i++)
|
||||
{
|
||||
allInputStreams[(int)folder.BindPairs[i].InIndex].InStreamSource = InStreamSource.CompStreamOutput;
|
||||
allInputStreams[(int)folder.BindPairs[i].InIndex].InStreamIndex = folder.BindPairs[i].OutIndex;
|
||||
folder.Coders[(int)folder.BindPairs[i].OutIndex].OutputUsedInternally = true;
|
||||
}
|
||||
|
||||
// next use the stream indises to connect the remaining input streams from the sourcefile
|
||||
int packedStreamsCount = folder.PackedStreamIndices.Length;
|
||||
for (int i = 0; i < packedStreamsCount; i++)
|
||||
{
|
||||
ulong packedStreamIndex = (ulong)i + folder.PackedStreamIndexBase;
|
||||
|
||||
// create and open the source file stream if needed
|
||||
if (_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream == null)
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream = CloneStream(_zipFs);
|
||||
}
|
||||
_header.StreamsInfo.PackedStreams[packedStreamIndex].PackedStream.Seek(
|
||||
_baseOffset + (long)_header.StreamsInfo.PackedStreams[packedStreamIndex].StreamPosition, SeekOrigin.Begin);
|
||||
|
||||
|
||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamSource = InStreamSource.FileStream;
|
||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamIndex = packedStreamIndex;
|
||||
}
|
||||
|
||||
List<Stream> inputCoders = new List<Stream>();
|
||||
|
||||
bool allCodersComplete = false;
|
||||
while (!allCodersComplete)
|
||||
{
|
||||
allCodersComplete = true;
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
Coder coder = folder.Coders[i];
|
||||
|
||||
// check is decoder already processed
|
||||
if (coder.DecoderStream != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
inputCoders.Clear();
|
||||
for (int j = 0; j < (int)coder.NumInStreams; j++)
|
||||
{
|
||||
if (coder.InputStreamsSourceInfo[j].InStreamSource == InStreamSource.FileStream)
|
||||
{
|
||||
inputCoders.Add(_header.StreamsInfo.PackedStreams[coder.InputStreamsSourceInfo[j].InStreamIndex].PackedStream);
|
||||
}
|
||||
else if (coder.InputStreamsSourceInfo[j].InStreamSource == InStreamSource.CompStreamOutput)
|
||||
{
|
||||
if (folder.Coders[coder.InputStreamsSourceInfo[j].InStreamIndex].DecoderStream == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
inputCoders.Add(folder.Coders[coder.InputStreamsSourceInfo[j].InStreamIndex].DecoderStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown input type so error
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputCoders.Count == (int)coder.NumInStreams)
|
||||
{
|
||||
// all inputs streams are available to make the decoder stream
|
||||
switch (coder.DecoderType)
|
||||
{
|
||||
case DecompressType.Stored:
|
||||
coder.DecoderStream = inputCoders[0];
|
||||
break;
|
||||
case DecompressType.Delta:
|
||||
coder.DecoderStream = new Delta(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.LZMA:
|
||||
coder.DecoderStream = new LzmaStream(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.LZMA2:
|
||||
coder.DecoderStream = new LzmaStream(folder.Coders[i].Properties, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.PPMd:
|
||||
coder.DecoderStream = new PpmdStream(new PpmdProperties(folder.Coders[i].Properties), inputCoders[0], false);
|
||||
break;
|
||||
case DecompressType.BZip2:
|
||||
coder.DecoderStream = new CBZip2InputStream(inputCoders[0], false);
|
||||
break;
|
||||
case DecompressType.BCJ:
|
||||
coder.DecoderStream = new BCJFilter(false, inputCoders[0]);
|
||||
break;
|
||||
case DecompressType.BCJ2:
|
||||
coder.DecoderStream = new BCJ2Filter(inputCoders[0], inputCoders[1], inputCoders[2], inputCoders[3]);
|
||||
break;
|
||||
case DecompressType.ZSTD:
|
||||
coder.DecoderStream = new ZstandardStream(inputCoders[0], CompressionMode.Decompress, true);
|
||||
break;
|
||||
default:
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
// if skipped a coder need to loop round again
|
||||
if (coder.DecoderStream == null)
|
||||
{
|
||||
allCodersComplete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// find the final output stream and return it.
|
||||
int outputStream = -1;
|
||||
for (int i = 0; i < codersNeeded; i++)
|
||||
{
|
||||
Coder coder = folder.Coders[i];
|
||||
if (!coder.OutputUsedInternally)
|
||||
{
|
||||
outputStream = i;
|
||||
}
|
||||
}
|
||||
|
||||
stream = folder.Coders[outputStream].DecoderStream;
|
||||
stream.Seek((long)_localFiles[index].StreamOffset, SeekOrigin.Current);
|
||||
|
||||
_stream = stream;
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ZipReturn.ZipErrorGettingDataStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Stream CloneStream(Stream s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case System.IO.FileStream _:
|
||||
int errorCode = FileStream.OpenFileRead(ZipFilename, out Stream streamOut);
|
||||
return errorCode != 0 ? null : streamOut;
|
||||
|
||||
case MemoryStream memStream:
|
||||
long pos = memStream.Position;
|
||||
memStream.Position = 0;
|
||||
byte[] newStream = new byte[memStream.Length];
|
||||
memStream.Read(newStream, 0, (int)memStream.Length);
|
||||
MemoryStream ret = new MemoryStream(newStream, false);
|
||||
memStream.Position = pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCloseReadStream()
|
||||
{
|
||||
if (_streamIndex != -1)
|
||||
{
|
||||
Folder folder = _header.StreamsInfo.Folders[_streamIndex];
|
||||
|
||||
foreach (Coder c in folder.Coders)
|
||||
{
|
||||
Stream ds = c?.DecoderStream;
|
||||
if (ds == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ds.Close();
|
||||
ds.Dispose();
|
||||
c.DecoderStream = null;
|
||||
}
|
||||
}
|
||||
_streamIndex = -1;
|
||||
|
||||
if (_header?.StreamsInfo != null)
|
||||
{
|
||||
foreach (PackedStreamInfo psi in _header.StreamsInfo.PackedStreams)
|
||||
{
|
||||
if (psi?.PackedStream == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
psi.PackedStream.Close();
|
||||
psi.PackedStream.Dispose();
|
||||
psi.PackedStream = null;
|
||||
}
|
||||
}
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
// not finalized yet, so do not use
|
||||
private void WriteRomVault7Zip(BinaryWriter bw, ulong headerPos, ulong headerLength, uint headerCRC)
|
||||
{
|
||||
const string sig = "RomVault7Z01";
|
||||
byte[] RV7Zid = Util.Enc.GetBytes(sig);
|
||||
|
||||
// RomVault 7Zip torrent header
|
||||
// 12 bytes : RomVault7Zip
|
||||
// 4 bytes : HeaderCRC
|
||||
// 8 bytes : HeaderPos
|
||||
// 8 bytes : HeaderLength
|
||||
|
||||
bw.Write(RV7Zid);
|
||||
bw.Write(headerCRC);
|
||||
bw.Write(headerPos);
|
||||
bw.Write(headerLength);
|
||||
|
||||
ZipStatus = ZipStatus.TrrntZip;
|
||||
}
|
||||
|
||||
private bool IsRomVault7Z(long testBaseOffset, ulong testHeaderPos, ulong testHeaderLength, uint testHeaderCRC)
|
||||
{
|
||||
long length = _zipFs.Length;
|
||||
if (length < 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_zipFs.Seek(_baseOffset + (long)testHeaderPos - 32, SeekOrigin.Begin);
|
||||
|
||||
const string sig = "RomVault7Z01";
|
||||
byte[] rv7Zid = Util.Enc.GetBytes(sig);
|
||||
|
||||
byte[] header = new byte[12];
|
||||
_zipFs.Read(header, 0, 12);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
if (header[i] != rv7Zid[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint headerCRC;
|
||||
ulong headerOffset; // is location of header in file
|
||||
ulong headerSize;
|
||||
using (BinaryReader br = new BinaryReader(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
headerCRC = br.ReadUInt32();
|
||||
headerOffset = br.ReadUInt64();
|
||||
headerSize = br.ReadUInt64();
|
||||
}
|
||||
|
||||
if (headerCRC != testHeaderCRC)
|
||||
return false;
|
||||
|
||||
if (headerOffset != testHeaderPos + (ulong)testBaseOffset)
|
||||
return false;
|
||||
|
||||
return headerSize == testHeaderLength;
|
||||
}
|
||||
private bool Istorrent7Z()
|
||||
{
|
||||
const int crcsz = 128;
|
||||
const int t7ZsigSize = 16 + 1 + 9 + 4 + 4;
|
||||
byte[] kSignature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
int kSignatureSize = kSignature.Length;
|
||||
const string sig = "\xa9\x9f\xd1\x57\x08\xa9\xd7\xea\x29\x64\xb2\x36\x1b\x83\x52\x33\x01torrent7z_0.9beta";
|
||||
byte[] t7Zid = Util.Enc.GetBytes(sig);
|
||||
int t7ZidSize = t7Zid.Length;
|
||||
|
||||
const int tmpbufsize = 256 + t7ZsigSize + 8 + 4;
|
||||
byte[] buffer = new byte[tmpbufsize];
|
||||
|
||||
// read fist 128 bytes, pad with zeros if less bytes
|
||||
int bufferPos = 0;
|
||||
_zipFs.Seek(0, SeekOrigin.Begin);
|
||||
int ar = _zipFs.Read(buffer, bufferPos, crcsz);
|
||||
if (ar < crcsz)
|
||||
{
|
||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||
}
|
||||
bufferPos = crcsz;
|
||||
|
||||
long foffs = _zipFs.Length;
|
||||
int endReadLength = crcsz + t7ZsigSize + 4;
|
||||
foffs = foffs < endReadLength ? 0 : foffs - endReadLength;
|
||||
|
||||
_zipFs.Seek(foffs, SeekOrigin.Begin);
|
||||
|
||||
ar = _zipFs.Read(buffer, bufferPos, endReadLength);
|
||||
if (ar < endReadLength)
|
||||
{
|
||||
if (ar >= t7ZsigSize + 4)
|
||||
{
|
||||
ar -= t7ZsigSize + 4;
|
||||
}
|
||||
if (ar < kSignatureSize)
|
||||
{
|
||||
ar = kSignatureSize;
|
||||
}
|
||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, crcsz * 2, t7ZsigSize + 4);
|
||||
}
|
||||
|
||||
foffs = _zipFs.Length;
|
||||
foffs -= t7ZsigSize + 4;
|
||||
|
||||
//memcpy(buffer, crcsz * 2, &foffs, 8);
|
||||
buffer[crcsz * 2 + 0] = (byte)((foffs >> 0) & 0xff);
|
||||
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
|
||||
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
|
||||
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
|
||||
buffer[crcsz * 2 + 4] = 0;
|
||||
buffer[crcsz * 2 + 5] = 0;
|
||||
buffer[crcsz * 2 + 6] = 0;
|
||||
buffer[crcsz * 2 + 7] = 0;
|
||||
|
||||
if (Util.memcmp(buffer, 0, kSignature, kSignatureSize))
|
||||
{
|
||||
t7Zid[16] = buffer[crcsz * 2 + 4 + 8 + 16];
|
||||
if (Util.memcmp(buffer, crcsz * 2 + 4 + 8, t7Zid, t7ZidSize))
|
||||
{
|
||||
uint inCrc32 = (uint)(buffer[crcsz * 2 + 8 + 0] +
|
||||
(buffer[crcsz * 2 + 8 + 1] << 8) +
|
||||
(buffer[crcsz * 2 + 8 + 2] << 16) +
|
||||
(buffer[crcsz * 2 + 8 + 3] << 24));
|
||||
|
||||
buffer[crcsz * 2 + 8 + 0] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 1] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 2] = 0xff;
|
||||
buffer[crcsz * 2 + 8 + 3] = 0xff;
|
||||
|
||||
uint calcCrc32 = Utils.CRC.CalculateDigest(buffer, 0, crcsz * 2 + 8 + t7ZsigSize + 4);
|
||||
|
||||
if (inCrc32 == calcCrc32)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
private Stream _lzmaStream;
|
||||
private ulong _packStreamStart;
|
||||
private ulong _packStreamSize;
|
||||
private ulong _unpackedStreamSize;
|
||||
private byte[] _codeMSbytes;
|
||||
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename)
|
||||
{
|
||||
return ZipFileCreate(newFilename, true);
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCreateFromUncompressedSize(string newFilename, ulong unCompressedSize)
|
||||
{
|
||||
return ZipFileCreate(newFilename, true, GetDictionarySizeFromUncompressedSize(unCompressedSize));
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename, bool compressOutput, int dictionarySize = 1 << 24, int numFastBytes = 64)
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.Closed)
|
||||
{
|
||||
return ZipReturn.ZipFileAlreadyOpen;
|
||||
}
|
||||
|
||||
DirUtil.CreateDirForFile(newFilename);
|
||||
_zipFileInfo = new FileInfo(newFilename);
|
||||
|
||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenWrite;
|
||||
|
||||
_signatureHeader = new SignatureHeader();
|
||||
_header = new Header();
|
||||
|
||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
_signatureHeader.Write(bw);
|
||||
}
|
||||
|
||||
_baseOffset = _zipFs.Position;
|
||||
|
||||
_compressed = compressOutput;
|
||||
|
||||
_unpackedStreamSize = 0;
|
||||
if (_compressed)
|
||||
{
|
||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, dictionarySize, numFastBytes);
|
||||
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
||||
_codeMSbytes = lzs.Properties;
|
||||
_lzmaStream = lzs;
|
||||
|
||||
|
||||
/*
|
||||
ZstandardStream zss = new ZstandardStream(_zipFs, 22, true);
|
||||
_codeMSbytes = new byte[] { 1, 4, 18, 0, 0 };
|
||||
_lzmaStream = zss;
|
||||
*/
|
||||
_packStreamStart = (ulong)_zipFs.Position;
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public void ZipFileAddDirectory(string filename)
|
||||
{
|
||||
string fName = filename;
|
||||
if (fName.Substring(fName.Length - 1, 1) == @"/")
|
||||
fName = fName.Substring(0, fName.Length - 1);
|
||||
|
||||
LocalFile lf = new LocalFile
|
||||
{
|
||||
FileName = fName,
|
||||
UncompressedSize = 0,
|
||||
IsDirectory = true,
|
||||
StreamOffset = 0
|
||||
};
|
||||
_localFiles.Add(lf);
|
||||
}
|
||||
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
// do nothing here for 7zip
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, uint? datetime, out Stream stream)
|
||||
{
|
||||
return ZipFileOpenWriteStream(filename, uncompressedSize, out stream);
|
||||
}
|
||||
|
||||
private ZipReturn ZipFileOpenWriteStream(string filename, ulong uncompressedSize, out Stream stream)
|
||||
{
|
||||
LocalFile lf = new LocalFile
|
||||
{
|
||||
FileName = filename,
|
||||
UncompressedSize = uncompressedSize,
|
||||
StreamOffset = (ulong)(_zipFs.Position - _signatureHeader.BaseOffset)
|
||||
};
|
||||
if (uncompressedSize == 0 && filename.Substring(filename.Length - 1, 1) == "/")
|
||||
{
|
||||
lf.FileName = filename.Substring(0, filename.Length - 1);
|
||||
lf.IsDirectory = true;
|
||||
}
|
||||
|
||||
_unpackedStreamSize += uncompressedSize;
|
||||
|
||||
_localFiles.Add(lf);
|
||||
stream = _compressed ? _lzmaStream : _zipFs;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
||||
{
|
||||
_localFiles[_localFiles.Count - 1].CRC = new[] { crc32[3], crc32[2], crc32[1], crc32[0] };
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
private static readonly int[] DictionarySizes =
|
||||
{
|
||||
0x10000,
|
||||
0x18000,
|
||||
0x20000,
|
||||
0x30000,
|
||||
0x40000,
|
||||
0x60000,
|
||||
0x80000,
|
||||
0xc0000,
|
||||
|
||||
0x100000,
|
||||
0x180000,
|
||||
0x200000,
|
||||
0x300000,
|
||||
0x400000,
|
||||
0x600000,
|
||||
0x800000,
|
||||
0xc00000,
|
||||
|
||||
0x1000000,
|
||||
0x1800000,
|
||||
0x2000000,
|
||||
0x3000000,
|
||||
0x4000000,
|
||||
0x6000000
|
||||
};
|
||||
|
||||
|
||||
private static int GetDictionarySizeFromUncompressedSize(ulong unCompressedSize)
|
||||
{
|
||||
foreach (int v in DictionarySizes)
|
||||
{
|
||||
if ((ulong)v >= unCompressedSize)
|
||||
return v;
|
||||
}
|
||||
|
||||
return DictionarySizes[DictionarySizes.Length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.SevenZip.Structure;
|
||||
using Compress.Utils;
|
||||
using Zstandard.Net;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public partial class SevenZ
|
||||
{
|
||||
private void Create7ZStructure()
|
||||
{
|
||||
int fileCount = _localFiles.Count;
|
||||
|
||||
//FileInfo
|
||||
_header.FileInfo = new Structure.FileInfo
|
||||
{
|
||||
Names = new string[fileCount]
|
||||
};
|
||||
|
||||
ulong emptyStreamCount = 0;
|
||||
ulong emptyFileCount = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
_header.FileInfo.Names[i] = _localFiles[i].FileName;
|
||||
|
||||
if (_localFiles[i].UncompressedSize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_localFiles[i].IsDirectory)
|
||||
{
|
||||
emptyFileCount += 1;
|
||||
}
|
||||
|
||||
emptyStreamCount += 1;
|
||||
}
|
||||
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
|
||||
|
||||
_header.FileInfo.EmptyStreamFlags = null;
|
||||
_header.FileInfo.EmptyFileFlags = null;
|
||||
_header.FileInfo.Attributes = null;
|
||||
|
||||
if (emptyStreamCount > 0)
|
||||
{
|
||||
if (emptyStreamCount != emptyFileCount) //then we found directories and need to set the attributes
|
||||
{
|
||||
_header.FileInfo.Attributes = new uint[fileCount];
|
||||
}
|
||||
|
||||
if (emptyFileCount > 0)
|
||||
{
|
||||
_header.FileInfo.EmptyFileFlags = new bool[emptyStreamCount];
|
||||
}
|
||||
|
||||
emptyStreamCount = 0;
|
||||
_header.FileInfo.EmptyStreamFlags = new bool[fileCount];
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_localFiles[i].IsDirectory)
|
||||
{
|
||||
if (_header.FileInfo.Attributes != null)
|
||||
_header.FileInfo.Attributes[i] = 0x10; // set attributes to directory
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_header.FileInfo.EmptyFileFlags != null)
|
||||
_header.FileInfo.EmptyFileFlags[emptyStreamCount] = true; // set empty file flag
|
||||
}
|
||||
|
||||
_header.FileInfo.EmptyStreamFlags[i] = true;
|
||||
emptyStreamCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//StreamsInfo
|
||||
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
||||
|
||||
//StreamsInfo.PackedStreamsInfo
|
||||
if (_compressed)
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
|
||||
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
|
||||
}
|
||||
else
|
||||
{
|
||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
|
||||
}
|
||||
}
|
||||
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
|
||||
|
||||
if (_compressed)
|
||||
{
|
||||
//StreamsInfo.Folders
|
||||
_header.StreamsInfo.Folders = new Folder[1];
|
||||
|
||||
//StreamsInfo.Folders.Coder
|
||||
// flags 0x23
|
||||
|
||||
Folder folder = new Folder
|
||||
{
|
||||
BindPairs = null,
|
||||
Coders = new[] {
|
||||
new Coder {
|
||||
Method = new byte[] { 3, 1, 1 },
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = _codeMSbytes
|
||||
}
|
||||
},
|
||||
PackedStreamIndices = new[] { (ulong)0 },
|
||||
UnpackedStreamSizes = new[] { _unpackedStreamSize },
|
||||
UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount],
|
||||
UnpackCRC = null
|
||||
};
|
||||
|
||||
switch (_lzmaStream)
|
||||
{
|
||||
case LzmaStream _:
|
||||
folder.Coders[0].Method = new byte[] { 3, 1, 1 };
|
||||
break;
|
||||
case ZstandardStream _:
|
||||
folder.Coders[0].Method = new byte[] { 4, 247, 17, 1 };
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
|
||||
{
|
||||
UnpackedSize = _localFiles[i].UncompressedSize,
|
||||
Crc = Util.bytestouint(_localFiles[i].CRC)
|
||||
};
|
||||
folder.UnpackedStreamInfo[fileIndex++] = unpackedStreamInfo;
|
||||
}
|
||||
_header.StreamsInfo.Folders[0] = folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
_header.StreamsInfo.Folders = new Folder[outFileCount];
|
||||
int fileIndex = 0;
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
if (_localFiles[i].UncompressedSize == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Folder folder = new Folder
|
||||
{
|
||||
BindPairs = null,
|
||||
Coders = new[] {
|
||||
new Coder {
|
||||
Method = new byte[] {0},
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = null
|
||||
}
|
||||
},
|
||||
PackedStreamIndices = new[] { (ulong)i },
|
||||
UnpackedStreamSizes = new[] { _localFiles[i].UncompressedSize },
|
||||
UnpackCRC = null,
|
||||
|
||||
UnpackedStreamInfo = new[] {
|
||||
new UnpackedStreamInfo {
|
||||
UnpackedSize = _localFiles[i].UncompressedSize,
|
||||
Crc = Util.bytestouint(_localFiles[i].CRC)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_header.StreamsInfo.Folders[fileIndex++] = folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void CloseWriting7Zip()
|
||||
{
|
||||
if (_compressed)
|
||||
{
|
||||
_lzmaStream.Close();
|
||||
}
|
||||
|
||||
_packStreamSize = (ulong)_zipFs.Position - _packStreamStart;
|
||||
|
||||
Create7ZStructure();
|
||||
|
||||
byte[] newHeaderByte;
|
||||
using (Stream headerMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter headerBw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
||||
{
|
||||
_header.WriteHeader(headerBw);
|
||||
|
||||
newHeaderByte = new byte[headerMem.Length];
|
||||
headerMem.Position = 0;
|
||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||
}
|
||||
}
|
||||
|
||||
uint mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||
|
||||
#region Header Compression
|
||||
long packedHeaderPos = _zipFs.Position;
|
||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
|
||||
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
||||
byte[] lzmaStreamProperties = lzs.Properties;
|
||||
lzs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
||||
lzs.Close();
|
||||
|
||||
StreamsInfo streamsInfo = new StreamsInfo
|
||||
{
|
||||
PackPosition = (ulong)(packedHeaderPos - _baseOffset),
|
||||
Folders = new[] {
|
||||
new Folder {
|
||||
BindPairs = new BindPair[0],
|
||||
Coders = new [] {
|
||||
new Coder {
|
||||
Method = new byte[] { 3, 1, 1 },
|
||||
NumInStreams = 1,
|
||||
NumOutStreams = 1,
|
||||
Properties = lzmaStreamProperties
|
||||
}
|
||||
},
|
||||
UnpackedStreamSizes = new[] {(ulong) newHeaderByte.Length},
|
||||
UnpackCRC = mainHeaderCRC
|
||||
}
|
||||
},
|
||||
PackedStreams = new[] {
|
||||
new PackedStreamInfo
|
||||
{
|
||||
PackedSize = (ulong)(_zipFs.Position - packedHeaderPos),
|
||||
StreamPosition = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using (Stream headerMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter bw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kEncodedHeader);
|
||||
streamsInfo.WriteHeader(bw);
|
||||
|
||||
newHeaderByte = new byte[headerMem.Length];
|
||||
headerMem.Position = 0;
|
||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||
|
||||
}
|
||||
}
|
||||
mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||
#endregion
|
||||
|
||||
|
||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
ulong headerPosition = (ulong)_zipFs.Position + 32; //tzip header is 32 bytes
|
||||
WriteRomVault7Zip(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||
|
||||
_zipFs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
||||
_signatureHeader.WriteFinal(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||
}
|
||||
_zipFs.Flush();
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class BindPair
|
||||
{
|
||||
public ulong InIndex;
|
||||
public ulong OutIndex;
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
InIndex = br.ReadEncodedUInt64();
|
||||
OutIndex = br.ReadEncodedUInt64();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
bw.WriteEncodedUInt64(InIndex);
|
||||
bw.WriteEncodedUInt64(OutIndex);
|
||||
}
|
||||
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine(" InIndex = " + InIndex);
|
||||
sb.AppendLine(" OutIndex = " + OutIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public enum InStreamSource
|
||||
{
|
||||
Unknown,
|
||||
FileStream,
|
||||
CompStreamOutput
|
||||
}
|
||||
|
||||
|
||||
public class InStreamSourceInfo
|
||||
{
|
||||
public InStreamSource InStreamSource = InStreamSource.Unknown;
|
||||
public ulong InStreamIndex;
|
||||
}
|
||||
|
||||
public enum DecompressType
|
||||
{
|
||||
Unknown,
|
||||
Stored,
|
||||
Delta,
|
||||
LZMA,
|
||||
BCJ,
|
||||
BCJ2,
|
||||
PPMd,
|
||||
BZip2,
|
||||
LZMA2,
|
||||
ZSTD
|
||||
}
|
||||
|
||||
|
||||
public class Coder
|
||||
{
|
||||
public byte[] Method;
|
||||
public ulong NumInStreams;
|
||||
public ulong NumOutStreams;
|
||||
public byte[] Properties;
|
||||
|
||||
/************Local Variables***********/
|
||||
public DecompressType DecoderType;
|
||||
public bool OutputUsedInternally = false;
|
||||
public InStreamSourceInfo[] InputStreamsSourceInfo;
|
||||
public Stream DecoderStream;
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
byte flags = br.ReadByte();
|
||||
int decompressionMethodIdSize = flags & 0xf;
|
||||
Method = br.ReadBytes(decompressionMethodIdSize);
|
||||
if ((flags & 0x10) != 0)
|
||||
{
|
||||
NumInStreams = br.ReadEncodedUInt64();
|
||||
NumOutStreams = br.ReadEncodedUInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
NumInStreams = 1;
|
||||
NumOutStreams = 1;
|
||||
}
|
||||
|
||||
if ((flags & 0x20) != 0)
|
||||
{
|
||||
ulong propSize = br.ReadEncodedUInt64();
|
||||
Properties = br.ReadBytes((int)propSize);
|
||||
}
|
||||
|
||||
if ((flags & 0x80) != 0)
|
||||
{
|
||||
throw new NotSupportedException("External flag");
|
||||
}
|
||||
|
||||
if (Method.Length == 1 && Method[0] == 0)
|
||||
{
|
||||
DecoderType = DecompressType.Stored;
|
||||
}
|
||||
else if (Method.Length == 1 && Method[0] == 3)
|
||||
{
|
||||
DecoderType = DecompressType.Delta;
|
||||
}
|
||||
else if (Method.Length == 3 && Method[0] == 3 && Method[1] == 1 && Method[2] == 1)
|
||||
{
|
||||
DecoderType = DecompressType.LZMA;
|
||||
}
|
||||
else if (Method.Length == 4 && Method[0] == 3 && Method[1] == 3 && Method[2] == 1 && Method[3] == 3)
|
||||
{
|
||||
DecoderType = DecompressType.BCJ;
|
||||
}
|
||||
else if (Method.Length == 4 && Method[0] == 3 && Method[1] == 3 && Method[2] == 1 && Method[3] == 27)
|
||||
{
|
||||
DecoderType = DecompressType.BCJ2;
|
||||
}
|
||||
else if (Method.Length == 3 && Method[0] == 3 && Method[1] == 4 && Method[2] == 1)
|
||||
{
|
||||
DecoderType = DecompressType.PPMd;
|
||||
}
|
||||
else if (Method.Length == 3 && Method[0] == 4 && Method[1] == 2 && Method[2] == 2)
|
||||
{
|
||||
DecoderType = DecompressType.BZip2;
|
||||
}
|
||||
else if (Method.Length == 1 && Method[0] == 33)
|
||||
{
|
||||
DecoderType = DecompressType.LZMA2;
|
||||
}
|
||||
else if (SevenZ.supportZstd && Method.Length == 4 && Method[0] == 4 && Method[1] == 247 && Method[2] == 17 && Method[3] == 1)
|
||||
{
|
||||
DecoderType = DecompressType.ZSTD;
|
||||
}
|
||||
|
||||
InputStreamsSourceInfo = new InStreamSourceInfo[NumInStreams];
|
||||
for (uint i = 0; i < NumInStreams; i++)
|
||||
{
|
||||
InputStreamsSourceInfo[i] = new InStreamSourceInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
byte flags = (byte)Method.Length;
|
||||
if ((NumInStreams != 1) || (NumOutStreams != 1))
|
||||
{
|
||||
flags = (byte)(flags | 0x10);
|
||||
}
|
||||
|
||||
if ((Properties != null) && (Properties.Length > 0))
|
||||
{
|
||||
flags = (byte)(flags | 0x20);
|
||||
}
|
||||
|
||||
bw.Write(flags);
|
||||
|
||||
bw.Write(Method);
|
||||
|
||||
if ((NumInStreams != 1) || (NumOutStreams != 1))
|
||||
{
|
||||
bw.WriteEncodedUInt64(NumInStreams);
|
||||
bw.WriteEncodedUInt64(NumOutStreams);
|
||||
}
|
||||
|
||||
if ((Properties != null) && (Properties.Length > 0))
|
||||
{
|
||||
bw.WriteEncodedUInt64((ulong)Properties.Length);
|
||||
bw.Write(Properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine($" Method[] = {Method.ToArrayString()} : {DecoderType}");
|
||||
sb.AppendLine($" NumInStreams = {NumInStreams}");
|
||||
sb.AppendLine($" NumOutStreams = {NumOutStreams}");
|
||||
sb.AppendLine($" Properties[] = {Properties.ToArrayString()}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class FileInfo
|
||||
{
|
||||
public string[] Names;
|
||||
public bool[] EmptyStreamFlags;
|
||||
public bool[] EmptyFileFlags;
|
||||
public uint[] Attributes;
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
ulong size = br.ReadEncodedUInt64();
|
||||
Names = new string[size];
|
||||
|
||||
ulong numEmptyFiles = 0;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
if (hp == HeaderProperty.kEnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ulong bytessize = br.ReadEncodedUInt64();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kName:
|
||||
if (br.ReadByte() != 0)
|
||||
{
|
||||
throw new Exception("Cannot be external");
|
||||
}
|
||||
|
||||
for (ulong i = 0; i < size; i++)
|
||||
{
|
||||
Names[i] = br.ReadName();
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kEmptyStream:
|
||||
EmptyStreamFlags = Util.ReadBoolFlags(br, (ulong)Names.Length);
|
||||
for (ulong i = 0; i < size; i++)
|
||||
{
|
||||
if (EmptyStreamFlags[i])
|
||||
{
|
||||
numEmptyFiles++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kEmptyFile:
|
||||
EmptyFileFlags = Util.ReadBoolFlags(br, numEmptyFiles);
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kWinAttributes:
|
||||
Attributes = Util.ReadUInt32Def(br, size);
|
||||
continue;
|
||||
|
||||
// don't know what this is.
|
||||
case HeaderProperty.kAnti:
|
||||
br.ReadBytes((int)bytessize);
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kCreationTime:
|
||||
case HeaderProperty.kLastAccessTime:
|
||||
case HeaderProperty.kLastWriteTime:
|
||||
br.ReadBytes((int)bytessize);
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kDummy:
|
||||
br.ReadBytes((int)bytessize);
|
||||
continue;
|
||||
|
||||
default:
|
||||
throw new Exception(hp.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kFilesInfo);
|
||||
bw.WriteEncodedUInt64((ulong)Names.Length);
|
||||
|
||||
|
||||
byte[] namebyte;
|
||||
using (MemoryStream nameMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter nameBw = new BinaryWriter(nameMem, Encoding.UTF8, true))
|
||||
{
|
||||
nameBw.Write((byte)0); //not external
|
||||
foreach (string name in Names)
|
||||
{
|
||||
nameBw.WriteName(name);
|
||||
}
|
||||
|
||||
namebyte = new byte[nameMem.Length];
|
||||
nameMem.Position = 0;
|
||||
nameMem.Read(namebyte, 0, namebyte.Length);
|
||||
}
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kName);
|
||||
bw.WriteEncodedUInt64((ulong)namebyte.Length);
|
||||
bw.Write(namebyte);
|
||||
|
||||
if (EmptyStreamFlags != null)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kEmptyStream);
|
||||
Util.WriteBoolFlags(bw, EmptyStreamFlags);
|
||||
}
|
||||
|
||||
if (EmptyFileFlags != null)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kEmptyFile);
|
||||
Util.WriteBoolFlags(bw, EmptyFileFlags);
|
||||
}
|
||||
|
||||
if (Attributes != null)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kWinAttributes);
|
||||
Util.WriteUint32Def(bw, Attributes);
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine(" FileInfo");
|
||||
sb.AppendLine(" ------");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,442 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class Folder
|
||||
{
|
||||
public Coder[] Coders;
|
||||
public BindPair[] BindPairs;
|
||||
public ulong PackedStreamIndexBase;
|
||||
public ulong[] PackedStreamIndices;
|
||||
public ulong[] UnpackedStreamSizes;
|
||||
public uint? UnpackCRC;
|
||||
public UnpackedStreamInfo[] UnpackedStreamInfo;
|
||||
|
||||
|
||||
private void ReadFolder(BinaryReader br)
|
||||
{
|
||||
ulong numCoders = br.ReadEncodedUInt64();
|
||||
|
||||
Coders = new Coder[numCoders];
|
||||
|
||||
int numInStreams = 0;
|
||||
int numOutStreams = 0;
|
||||
|
||||
for (ulong i = 0; i < numCoders; i++)
|
||||
{
|
||||
Coders[i] = new Coder();
|
||||
Coders[i].Read(br);
|
||||
|
||||
numInStreams += (int)Coders[i].NumInStreams;
|
||||
numOutStreams += (int)Coders[i].NumOutStreams;
|
||||
}
|
||||
|
||||
int numBindPairs = numOutStreams - 1;
|
||||
BindPairs = new BindPair[numBindPairs];
|
||||
for (int i = 0; i < numBindPairs; i++)
|
||||
{
|
||||
BindPairs[i] = new BindPair();
|
||||
BindPairs[i].Read(br);
|
||||
}
|
||||
|
||||
if (numInStreams < numBindPairs)
|
||||
{
|
||||
throw new NotSupportedException("Error");
|
||||
}
|
||||
|
||||
int numPackedStreams = numInStreams - numBindPairs;
|
||||
|
||||
PackedStreamIndices = new ulong[numPackedStreams];
|
||||
|
||||
if (numPackedStreams == 1)
|
||||
{
|
||||
uint pi = 0;
|
||||
for (uint j = 0; j < numInStreams; j++)
|
||||
{
|
||||
for (uint k = 0; k < BindPairs.Length; k++)
|
||||
{
|
||||
if (BindPairs[k].InIndex == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PackedStreamIndices[pi++] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint i = 0; i < numPackedStreams; i++)
|
||||
{
|
||||
PackedStreamIndices[i] = br.ReadEncodedUInt64();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadUnpackedStreamSize(BinaryReader br)
|
||||
{
|
||||
ulong outStreams = 0;
|
||||
foreach (Coder c in Coders)
|
||||
{
|
||||
outStreams += c.NumOutStreams;
|
||||
}
|
||||
|
||||
UnpackedStreamSizes = new ulong[outStreams];
|
||||
for (uint j = 0; j < outStreams; j++)
|
||||
{
|
||||
UnpackedStreamSizes[j] = br.ReadEncodedUInt64();
|
||||
}
|
||||
}
|
||||
|
||||
private ulong GetUnpackSize()
|
||||
{
|
||||
ulong outStreams = 0;
|
||||
foreach (Coder coder in Coders)
|
||||
{
|
||||
outStreams += coder.NumInStreams;
|
||||
}
|
||||
|
||||
for (ulong j = 0; j < outStreams; j++)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (BindPair bindPair in BindPairs)
|
||||
{
|
||||
if (bindPair.OutIndex != j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return UnpackedStreamSizes[j];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public static void ReadUnPackInfo(BinaryReader br, out Folder[] Folders)
|
||||
{
|
||||
Folders = null;
|
||||
for (; ; )
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kFolder:
|
||||
{
|
||||
ulong numFolders = br.ReadEncodedUInt64();
|
||||
|
||||
Folders = new Folder[numFolders];
|
||||
|
||||
byte external = br.ReadByte();
|
||||
switch (external)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ulong folderIndex = 0;
|
||||
for (uint i = 0; i < numFolders; i++)
|
||||
{
|
||||
Folders[i] = new Folder();
|
||||
Folders[i].ReadFolder(br);
|
||||
Folders[i].PackedStreamIndexBase = folderIndex;
|
||||
folderIndex += (ulong)Folders[i].PackedStreamIndices.Length;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
throw new NotSupportedException("External flag");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
case HeaderProperty.kCodersUnPackSize:
|
||||
{
|
||||
for (uint i = 0; i < Folders.Length; i++)
|
||||
{
|
||||
Folders[i].ReadUnpackedStreamSize(br);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case HeaderProperty.kCRC:
|
||||
{
|
||||
uint?[] crcs;
|
||||
Util.UnPackCRCs(br, (ulong)Folders.Length, out crcs);
|
||||
for (int i = 0; i < Folders.Length; i++)
|
||||
{
|
||||
Folders[i].UnpackCRC = crcs[i];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case HeaderProperty.kEnd:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new Exception(hp.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReadSubStreamsInfo(BinaryReader br, ref Folder[] Folders)
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kNumUnPackStream:
|
||||
{
|
||||
for (int f = 0; f < Folders.Length; f++)
|
||||
{
|
||||
int numStreams = (int)br.ReadEncodedUInt64();
|
||||
Folders[f].UnpackedStreamInfo = new UnpackedStreamInfo[numStreams];
|
||||
for (int i = 0; i < numStreams; i++)
|
||||
{
|
||||
Folders[f].UnpackedStreamInfo[i] = new UnpackedStreamInfo();
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case HeaderProperty.kSize:
|
||||
{
|
||||
for (int f = 0; f < Folders.Length; f++)
|
||||
{
|
||||
Folder folder = Folders[f];
|
||||
|
||||
if (folder.UnpackedStreamInfo.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong sum = 0;
|
||||
for (int i = 0; i < folder.UnpackedStreamInfo.Length - 1; i++)
|
||||
{
|
||||
ulong size = br.ReadEncodedUInt64();
|
||||
folder.UnpackedStreamInfo[i].UnpackedSize = size;
|
||||
sum += size;
|
||||
}
|
||||
|
||||
folder.UnpackedStreamInfo[folder.UnpackedStreamInfo.Length - 1].UnpackedSize =
|
||||
folder.GetUnpackSize() - sum;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case HeaderProperty.kCRC:
|
||||
{
|
||||
ulong numCRC = 0;
|
||||
foreach (Folder folder in Folders)
|
||||
{
|
||||
if (folder.UnpackedStreamInfo == null)
|
||||
{
|
||||
folder.UnpackedStreamInfo = new UnpackedStreamInfo[1];
|
||||
folder.UnpackedStreamInfo[0] = new UnpackedStreamInfo();
|
||||
folder.UnpackedStreamInfo[0].UnpackedSize = folder.GetUnpackSize();
|
||||
}
|
||||
|
||||
if ((folder.UnpackedStreamInfo.Length != 1) || !folder.UnpackCRC.HasValue)
|
||||
{
|
||||
numCRC += (ulong)folder.UnpackedStreamInfo.Length;
|
||||
}
|
||||
}
|
||||
|
||||
int crcIndex = 0;
|
||||
uint?[] crc;
|
||||
Util.UnPackCRCs(br, numCRC, out crc);
|
||||
for (uint i = 0; i < Folders.Length; i++)
|
||||
{
|
||||
Folder folder = Folders[i];
|
||||
if ((folder.UnpackedStreamInfo.Length == 1) && folder.UnpackCRC.HasValue)
|
||||
{
|
||||
folder.UnpackedStreamInfo[0].Crc = folder.UnpackCRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint j = 0; j < folder.UnpackedStreamInfo.Length; j++, crcIndex++)
|
||||
{
|
||||
folder.UnpackedStreamInfo[j].Crc = crc[crcIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case HeaderProperty.kEnd:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new Exception(hp.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteFolder(BinaryWriter bw)
|
||||
{
|
||||
ulong numCoders = (ulong)Coders.Length;
|
||||
bw.WriteEncodedUInt64(numCoders);
|
||||
for (ulong i = 0; i < numCoders; i++)
|
||||
{
|
||||
Coders[i].Write(bw);
|
||||
}
|
||||
|
||||
ulong numBindingPairs = BindPairs == null ? 0 : (ulong)BindPairs.Length;
|
||||
for (ulong i = 0; i < numBindingPairs; i++)
|
||||
{
|
||||
BindPairs[i].Write(bw);
|
||||
}
|
||||
|
||||
//need to look at PAckedStreamIndices but don't need them for basic writing I am doing
|
||||
}
|
||||
|
||||
private void WriteUnpackedStreamSize(BinaryWriter bw)
|
||||
{
|
||||
ulong numUnpackedStreamSizes = (ulong)UnpackedStreamSizes.Length;
|
||||
for (ulong i = 0; i < numUnpackedStreamSizes; i++)
|
||||
{
|
||||
bw.WriteEncodedUInt64(UnpackedStreamSizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteUnPackInfo(BinaryWriter bw, Folder[] Folders)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kUnPackInfo);
|
||||
|
||||
bw.Write((byte)HeaderProperty.kFolder);
|
||||
ulong numFolders = (ulong)Folders.Length;
|
||||
bw.WriteEncodedUInt64(numFolders);
|
||||
bw.Write((byte)0); //External Flag
|
||||
for (ulong i = 0; i < numFolders; i++)
|
||||
{
|
||||
Folders[i].WriteFolder(bw);
|
||||
}
|
||||
|
||||
|
||||
bw.Write((byte)HeaderProperty.kCodersUnPackSize);
|
||||
for (ulong i = 0; i < numFolders; i++)
|
||||
{
|
||||
Folders[i].WriteUnpackedStreamSize(bw);
|
||||
}
|
||||
|
||||
bool hasCRC = false;
|
||||
uint?[] CRCs = new uint?[numFolders];
|
||||
for (ulong i = 0; i < numFolders; i++)
|
||||
{
|
||||
CRCs[i] = Folders[i].UnpackCRC;
|
||||
hasCRC |= (CRCs[i] != null);
|
||||
}
|
||||
|
||||
if (hasCRC)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kCRC);
|
||||
Util.WritePackedCRCs(bw, CRCs);
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
public static void WriteSubStreamsInfo(BinaryWriter bw, Folder[] Folders)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kSubStreamsInfo);
|
||||
|
||||
bw.Write((byte)HeaderProperty.kNumUnPackStream);
|
||||
for (int f = 0; f < Folders.Length; f++)
|
||||
{
|
||||
ulong numStreams = (ulong)Folders[f].UnpackedStreamInfo.Length;
|
||||
bw.WriteEncodedUInt64(numStreams);
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kSize);
|
||||
|
||||
for (int f = 0; f < Folders.Length; f++)
|
||||
{
|
||||
Folder folder = Folders[f];
|
||||
for (int i = 0; i < folder.UnpackedStreamInfo.Length - 1; i++)
|
||||
{
|
||||
bw.WriteEncodedUInt64(folder.UnpackedStreamInfo[i].UnpackedSize);
|
||||
}
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kCRC);
|
||||
bw.Write((byte)1); // crc flags default to true
|
||||
for (int f = 0; f < Folders.Length; f++)
|
||||
{
|
||||
Folder folder = Folders[f];
|
||||
for (int i = 0; i < folder.UnpackedStreamInfo.Length; i++)
|
||||
{
|
||||
bw.Write(Util.uinttobytes(folder.UnpackedStreamInfo[i].Crc));
|
||||
}
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
if (Coders == null)
|
||||
{
|
||||
sb.AppendLine(" Coders[] = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($" Coders[] = ({Coders.Length})");
|
||||
foreach (Coder c in Coders)
|
||||
{
|
||||
c.Report(ref sb);
|
||||
}
|
||||
}
|
||||
if (BindPairs == null)
|
||||
{
|
||||
sb.AppendLine(" BindPairs[] = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($" BindPairs[] = ({BindPairs.Length})");
|
||||
foreach (BindPair bp in BindPairs)
|
||||
{
|
||||
bp.Report(ref sb);
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine($" PackedStreamIndexBase = {PackedStreamIndexBase}");
|
||||
sb.AppendLine($" PackedStreamIndices[] = {PackedStreamIndices.ToArrayString()}");
|
||||
sb.AppendLine($" UnpackedStreamSizes[] = {UnpackedStreamSizes.ToArrayString()}");
|
||||
sb.AppendLine($" UnpackCRC = {UnpackCRC.ToHex()}");
|
||||
|
||||
if (UnpackedStreamInfo == null)
|
||||
{
|
||||
sb.AppendLine(" UnpackedStreamInfo[] = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($" UnpackedStreamInfo[{UnpackedStreamInfo.Length}]");
|
||||
foreach (UnpackedStreamInfo usi in UnpackedStreamInfo)
|
||||
{
|
||||
usi.Report(ref sb);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.SevenZip.Compress.LZMA;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class Header
|
||||
{
|
||||
public StreamsInfo StreamsInfo;
|
||||
public FileInfo FileInfo;
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kMainStreamsInfo:
|
||||
StreamsInfo = new StreamsInfo();
|
||||
StreamsInfo.Read(br);
|
||||
break;
|
||||
|
||||
case HeaderProperty.kFilesInfo:
|
||||
FileInfo = new FileInfo();
|
||||
FileInfo.Read(br);
|
||||
break;
|
||||
|
||||
case HeaderProperty.kEnd:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new Exception(hp.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kHeader);
|
||||
StreamsInfo.Write(bw);
|
||||
FileInfo.Write(bw);
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
public static ZipReturn ReadHeaderOrPackedHeader(Stream stream, long baseOffset, out Header header)
|
||||
{
|
||||
header = null;
|
||||
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.UTF8, true))
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kEncodedHeader:
|
||||
{
|
||||
StreamsInfo streamsInfo = new StreamsInfo();
|
||||
streamsInfo.Read(br);
|
||||
|
||||
if (streamsInfo.Folders.Length > 1)
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
Folder firstFolder = streamsInfo.Folders[0];
|
||||
if (firstFolder.Coders.Length > 1)
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
byte[] method = firstFolder.Coders[0].Method;
|
||||
if (!((method.Length == 3) && (method[0] == 3) && (method[1] == 1) && (method[2] == 1))) // LZMA
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
stream.Seek(baseOffset + (long)streamsInfo.PackPosition, SeekOrigin.Begin);
|
||||
using (LzmaStream decoder = new LzmaStream(firstFolder.Coders[0].Properties, stream))
|
||||
{
|
||||
ZipReturn zr = ReadHeaderOrPackedHeader(decoder, baseOffset, out header);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
case HeaderProperty.kHeader:
|
||||
{
|
||||
header = new Header();
|
||||
header.Read(br);
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
}
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine("Header");
|
||||
sb.AppendLine("------");
|
||||
if (StreamsInfo == null)
|
||||
{
|
||||
sb.AppendLine("StreamsInfo == null");
|
||||
}
|
||||
else
|
||||
{
|
||||
StreamsInfo.Report(ref sb);
|
||||
}
|
||||
|
||||
if (FileInfo == null)
|
||||
{
|
||||
sb.AppendLine("FileInfo == null");
|
||||
}
|
||||
else
|
||||
{
|
||||
FileInfo.Report(ref sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class PackedStreamInfo
|
||||
{
|
||||
public ulong PackedSize;
|
||||
public ulong? Crc;
|
||||
public ulong StreamPosition;
|
||||
public Stream PackedStream;
|
||||
|
||||
public static void Read(BinaryReader br, out ulong packPosition, out PackedStreamInfo[] packedStreams)
|
||||
{
|
||||
packPosition = br.ReadEncodedUInt64();
|
||||
|
||||
ulong numPackStreams = br.ReadEncodedUInt64();
|
||||
|
||||
packedStreams = new PackedStreamInfo[numPackStreams];
|
||||
for (ulong i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
packedStreams[i] = new PackedStreamInfo();
|
||||
}
|
||||
|
||||
ulong streamPosition = 0;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kSize:
|
||||
for (ulong i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
packedStreams[i].StreamPosition = streamPosition;
|
||||
packedStreams[i].PackedSize = br.ReadEncodedUInt64();
|
||||
streamPosition += packedStreams[i].PackedSize;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kCRC:
|
||||
for (ulong i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
packedStreams[i].Crc = br.ReadEncodedUInt64();
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kEnd:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new Exception(hp.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter bw, ulong packPosition, PackedStreamInfo[] packedStreams)
|
||||
{
|
||||
ulong numPackStreams = (ulong)packedStreams.Length;
|
||||
bw.Write((byte)HeaderProperty.kPackInfo);
|
||||
bw.WriteEncodedUInt64(packPosition);
|
||||
bw.WriteEncodedUInt64(numPackStreams);
|
||||
|
||||
bw.Write((byte)HeaderProperty.kSize);
|
||||
ulong streamPosition = 0;
|
||||
for (ulong i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
packedStreams[i].StreamPosition = streamPosition;
|
||||
bw.WriteEncodedUInt64(packedStreams[i].PackedSize);
|
||||
streamPosition += packedStreams[i].PackedSize;
|
||||
}
|
||||
|
||||
// Only checking the first CRC assuming all the reset will be the same
|
||||
if (packedStreams[0].Crc != null)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kCRC);
|
||||
for (ulong i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
bw.WriteEncodedUInt64(packedStreams[i].Crc ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine($" PackedSize = {PackedSize}");
|
||||
sb.AppendLine($" Crc = {Crc.ToHex()}");
|
||||
sb.AppendLine($" StreamPosition = {StreamPosition}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
internal class SignatureHeader
|
||||
{
|
||||
private static readonly byte[] Signature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
|
||||
private byte _major;
|
||||
private byte _minor;
|
||||
|
||||
private uint _startHeaderCRC;
|
||||
|
||||
public ulong NextHeaderOffset;
|
||||
public ulong NextHeaderSize;
|
||||
public uint NextHeaderCRC;
|
||||
|
||||
|
||||
private long _crcOffset;
|
||||
public long BaseOffset { get; private set; }
|
||||
|
||||
public bool Read(Stream stream)
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.UTF8, true))
|
||||
{
|
||||
byte[] signatureBytes = br.ReadBytes(6);
|
||||
if (!signatureBytes.Compare(Signature))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_major = br.ReadByte();
|
||||
_minor = br.ReadByte();
|
||||
|
||||
_startHeaderCRC = br.ReadUInt32();
|
||||
|
||||
long pos = br.BaseStream.Position;
|
||||
byte[] mainHeader = new byte[8 + 8 + 4];
|
||||
br.BaseStream.Read(mainHeader, 0, mainHeader.Length);
|
||||
if (!Utils.CRC.VerifyDigest(_startHeaderCRC, mainHeader, 0, (uint)mainHeader.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
br.BaseStream.Seek(pos, SeekOrigin.Begin);
|
||||
|
||||
NextHeaderOffset = br.ReadUInt64();
|
||||
NextHeaderSize = br.ReadUInt64();
|
||||
NextHeaderCRC = br.ReadUInt32();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
//SignatureHeader
|
||||
//~~~~~~~~~~~~~~~
|
||||
|
||||
bw.Write(Signature);
|
||||
|
||||
//ArchiveVersion
|
||||
//{
|
||||
bw.Write((byte)0); // BYTE Major
|
||||
bw.Write((byte)3); // BYTE Minor
|
||||
//};
|
||||
|
||||
_crcOffset = bw.BaseStream.Position;
|
||||
bw.Write((uint)0); //HeaderCRC
|
||||
|
||||
//StartHeader
|
||||
//{
|
||||
bw.Write((ulong)0); //NextHeaderOffset
|
||||
bw.Write((ulong)0); //NextHeaderSize
|
||||
bw.Write((uint)0); //NextHeaderCRC
|
||||
//}
|
||||
|
||||
BaseOffset = bw.BaseStream.Position;
|
||||
}
|
||||
|
||||
public void WriteFinal(BinaryWriter bw, ulong headerpos, ulong headerLength, uint headerCRC)
|
||||
{
|
||||
long fileEnd = bw.BaseStream.Position;
|
||||
|
||||
|
||||
byte[] sigHeaderBytes;
|
||||
using (MemoryStream sigHeaderMem = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter sigHeaderBw = new BinaryWriter(sigHeaderMem, Encoding.UTF8, true))
|
||||
{
|
||||
sigHeaderBw.Write((ulong)((long)headerpos - BaseOffset)); //NextHeaderOffset
|
||||
sigHeaderBw.Write(headerLength); //NextHeaderSize
|
||||
sigHeaderBw.Write(headerCRC); //NextHeaderCRC
|
||||
|
||||
sigHeaderBytes = new byte[sigHeaderMem.Length];
|
||||
sigHeaderMem.Position = 0;
|
||||
sigHeaderMem.Read(sigHeaderBytes, 0, sigHeaderBytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
uint sigHeaderCRC = Utils.CRC.CalculateDigest(sigHeaderBytes, 0, (uint)sigHeaderBytes.Length);
|
||||
|
||||
bw.BaseStream.Position = _crcOffset;
|
||||
bw.Write(sigHeaderCRC); //Header CRC
|
||||
bw.Write(sigHeaderBytes);
|
||||
|
||||
bw.BaseStream.Seek(fileEnd, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class StreamsInfo
|
||||
{
|
||||
public ulong PackPosition;
|
||||
public PackedStreamInfo[] PackedStreams;
|
||||
public Folder[] Folders;
|
||||
|
||||
public void Read(BinaryReader br)
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kPackInfo:
|
||||
PackedStreamInfo.Read(br, out PackPosition, out PackedStreams);
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kUnPackInfo:
|
||||
Folder.ReadUnPackInfo(br, out Folders);
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kSubStreamsInfo:
|
||||
Folder.ReadSubStreamsInfo(br, ref Folders);
|
||||
continue;
|
||||
|
||||
case HeaderProperty.kEnd:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new Exception(hp.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kMainStreamsInfo);
|
||||
PackedStreamInfo.Write(bw, PackPosition, PackedStreams);
|
||||
Folder.WriteUnPackInfo(bw, Folders);
|
||||
Folder.WriteSubStreamsInfo(bw, Folders);
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
public void WriteHeader(BinaryWriter bw)
|
||||
{
|
||||
PackedStreamInfo.Write(bw, PackPosition, PackedStreams);
|
||||
Folder.WriteUnPackInfo(bw, Folders);
|
||||
bw.Write((byte)HeaderProperty.kEnd);
|
||||
}
|
||||
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine(" StreamsInfo");
|
||||
sb.AppendLine(" -----------");
|
||||
sb.AppendLine($" PackPosition = {PackPosition}");
|
||||
if (PackedStreams == null)
|
||||
{
|
||||
sb.AppendLine($" PackedStreams[] = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($" PackedStreams[] = ({PackedStreams.Length})");
|
||||
foreach (PackedStreamInfo psi in PackedStreams)
|
||||
{
|
||||
psi.Report(ref sb);
|
||||
}
|
||||
}
|
||||
if (Folders == null)
|
||||
{
|
||||
sb.AppendLine($" Folders[] = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($" Folders[] = ({Folders.Length})");
|
||||
foreach (Folder f in Folders)
|
||||
{
|
||||
f.Report(ref sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
public class UnpackedStreamInfo
|
||||
{
|
||||
public ulong UnpackedSize;
|
||||
public uint? Crc;
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
{
|
||||
sb.AppendLine($" Crc = {Crc.ToHex()} , Size = {UnpackedSize}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip
|
||||
{
|
||||
public enum HeaderProperty
|
||||
{
|
||||
kEnd,
|
||||
kHeader,
|
||||
|
||||
kArchiveProperties,
|
||||
|
||||
kAdditionalStreamsInfo,
|
||||
kMainStreamsInfo,
|
||||
kFilesInfo,
|
||||
|
||||
kPackInfo,
|
||||
kUnPackInfo,
|
||||
kSubStreamsInfo,
|
||||
|
||||
kSize,
|
||||
kCRC,
|
||||
|
||||
kFolder,
|
||||
|
||||
kCodersUnPackSize,
|
||||
kNumUnPackStream,
|
||||
|
||||
kEmptyStream,
|
||||
kEmptyFile,
|
||||
kAnti,
|
||||
|
||||
kName,
|
||||
kCreationTime,
|
||||
kLastAccessTime,
|
||||
kLastWriteTime,
|
||||
kWinAttributes,
|
||||
kComment,
|
||||
|
||||
kEncodedHeader,
|
||||
|
||||
kStartPos,
|
||||
kDummy
|
||||
}
|
||||
|
||||
public static class Util
|
||||
{
|
||||
public static readonly Encoding Enc = Encoding.GetEncoding(28591);
|
||||
|
||||
public static void memset(byte[] buffer, int start, byte val, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
buffer[start + i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
public static void memcpyr(byte[] destBuffer, int destPoint, byte[] sourceBuffer, int sourcePoint, int len)
|
||||
{
|
||||
for (int i = len - 1; i >= 0; i--)
|
||||
{
|
||||
destBuffer[destPoint + i] = sourceBuffer[sourcePoint + i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool memcmp(byte[] buffer1, int offset, byte[] buffer2, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (buffer1[offset + i] != buffer2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool Compare(this byte[] b1, byte[] b2)
|
||||
{
|
||||
if ((b1 == null) || (b2 == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (b1.Length != b2.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < b1.Length; i++)
|
||||
{
|
||||
if (b1[i] != b2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static ulong ReadEncodedUInt64(this BinaryReader br)
|
||||
{
|
||||
byte mask = 0x80;
|
||||
int i;
|
||||
byte firstByte = br.ReadByte();
|
||||
ulong value = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if ((firstByte & mask) == 0)
|
||||
{
|
||||
ulong highPart = (ulong)(firstByte & (mask - 1));
|
||||
value += highPart << (8 * i);
|
||||
return value;
|
||||
}
|
||||
byte b = br.ReadByte();
|
||||
value |= (ulong)b << (8 * i);
|
||||
mask >>= 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void WriteEncodedUInt64(this BinaryWriter bw, ulong value)
|
||||
{
|
||||
byte firstByte = 0;
|
||||
byte mask = 0x80;
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (value < (ulong)1 << (7 * (i + 1)))
|
||||
{
|
||||
firstByte |= (byte)(value >> (8 * i));
|
||||
break;
|
||||
}
|
||||
firstByte |= mask;
|
||||
mask >>= 1;
|
||||
}
|
||||
bw.Write(firstByte);
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
bw.Write((byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadName(this BinaryReader br)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (; ; )
|
||||
{
|
||||
char c = (char)br.ReadUInt16();
|
||||
if (c == 0)
|
||||
{
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteName(this BinaryWriter bw, string name)
|
||||
{
|
||||
char[] chars = name.ToCharArray();
|
||||
for (int i = 0; i < chars.Length; i++)
|
||||
{
|
||||
bw.Write((ushort)chars[i]);
|
||||
}
|
||||
bw.Write((ushort)0);
|
||||
}
|
||||
|
||||
|
||||
public static void UnPackCRCs(BinaryReader br, ulong numItems, out uint?[] digests)
|
||||
{
|
||||
bool[] digestsDefined = ReadBoolFlagsDefaultTrue(br, numItems);
|
||||
digests = new uint?[numItems];
|
||||
for (ulong i = 0; i < numItems; i++)
|
||||
{
|
||||
if (digestsDefined[i])
|
||||
{
|
||||
digests[i] = br.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WritePackedCRCs(BinaryWriter bw, uint?[] digests)
|
||||
{
|
||||
bool[] digestsDefined = new bool[digests.Length];
|
||||
for (int i = 0; i < digests.Length; i++)
|
||||
{
|
||||
digestsDefined[i] = digests[i] != null;
|
||||
}
|
||||
WriteBoolFlagsDefaultTrue(bw, digestsDefined);
|
||||
for (int i = 0; i < digests.Length; i++)
|
||||
{
|
||||
if (digestsDefined[i])
|
||||
{
|
||||
bw.Write((uint)digests[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool[] ReadBoolFlagsDefaultTrue(BinaryReader br, ulong numItems)
|
||||
{
|
||||
byte allAreDefined = br.ReadByte();
|
||||
if (allAreDefined == 0)
|
||||
{
|
||||
return ReadBoolFlags(br, numItems);
|
||||
}
|
||||
bool[] flags = new bool[numItems];
|
||||
for (ulong i = 0; i < numItems; i++)
|
||||
{
|
||||
flags[i] = true;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static void WriteBoolFlagsDefaultTrue(BinaryWriter bw, bool[] bArray)
|
||||
{
|
||||
bool allTrue = true;
|
||||
foreach (bool b in bArray)
|
||||
{
|
||||
allTrue &= b;
|
||||
}
|
||||
|
||||
if (allTrue)
|
||||
{
|
||||
bw.Write((byte)1);
|
||||
return;
|
||||
}
|
||||
WriteBoolFlags(bw, bArray);
|
||||
}
|
||||
|
||||
public static bool[] ReadBoolFlags(BinaryReader br, ulong numItems)
|
||||
{
|
||||
byte b = 0;
|
||||
byte mask = 0;
|
||||
|
||||
bool[] flags = new bool[numItems];
|
||||
for (ulong i = 0; i < numItems; i++)
|
||||
{
|
||||
if (mask == 0)
|
||||
{
|
||||
b = br.ReadByte();
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
flags[i] = (b & mask) != 0;
|
||||
|
||||
mask >>= 1;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
public static bool[] ReadBoolFlags2(BinaryReader br, ulong numItems)
|
||||
{
|
||||
byte allAreDefined = br.ReadByte();
|
||||
if (allAreDefined == 0)
|
||||
{
|
||||
return ReadBoolFlags(br, numItems);
|
||||
}
|
||||
|
||||
|
||||
bool[] flags = new bool[numItems];
|
||||
for (ulong i = 0; i < numItems; i++)
|
||||
{
|
||||
flags[i] = true;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
public static void WriteUint32Def(BinaryWriter br, uint[] values)
|
||||
{
|
||||
br.WriteEncodedUInt64((ulong)(values.Length * 4 + 2));
|
||||
br.Write((byte)1);
|
||||
br.Write((byte)0);
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
br.Write(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static uint[] ReadUInt32Def(BinaryReader br, ulong numItems)
|
||||
{
|
||||
uint[] v = new uint[numItems];
|
||||
bool[] defs = ReadBoolFlags2(br, numItems);
|
||||
byte tmp = br.ReadByte();
|
||||
for (ulong i = 0; i < numItems; i++)
|
||||
{
|
||||
v[i] = defs[i] ? br.ReadUInt32() : 0;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static ulong[] ReadUInt64Def(BinaryReader br, ulong numItems)
|
||||
{
|
||||
ulong[] v = new ulong[numItems];
|
||||
bool[] defs = ReadBoolFlags2(br, numItems);
|
||||
byte tmp = br.ReadByte();
|
||||
for (ulong i = 0; i < numItems; i++)
|
||||
{
|
||||
v[i] = defs[i] ? br.ReadUInt64() : 0;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static void WriteBoolFlags(BinaryWriter bw, bool[] bArray)
|
||||
{
|
||||
bw.WriteEncodedUInt64((ulong)((bArray.Length + 7) / 8));
|
||||
byte mask = 0x80;
|
||||
byte tmpOut = 0;
|
||||
for (int i = 0; i < bArray.Length; i++)
|
||||
{
|
||||
if (bArray[i])
|
||||
{
|
||||
tmpOut |= mask;
|
||||
}
|
||||
|
||||
mask >>= 1;
|
||||
if (mask != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bw.Write(tmpOut);
|
||||
mask = 0x80;
|
||||
tmpOut = 0;
|
||||
}
|
||||
if (mask != 0x80)
|
||||
{
|
||||
bw.Write(tmpOut);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] uinttobytes(uint? crc)
|
||||
{
|
||||
if (crc == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
uint c = (uint)crc;
|
||||
|
||||
byte[] b = new byte[4];
|
||||
b[0] = (byte)((c >> 24) & 0xff);
|
||||
b[1] = (byte)((c >> 16) & 0xff);
|
||||
b[2] = (byte)((c >> 8) & 0xff);
|
||||
b[3] = (byte)((c >> 0) & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
public static uint? bytestouint(byte[] crc)
|
||||
{
|
||||
if (crc == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return (uint?)((crc[0] << 24) | (crc[1] << 16) | (crc[2] << 8) | (crc[3] << 0));
|
||||
}
|
||||
|
||||
public static bool ByteArrCompare(byte[] b0, byte[] b1)
|
||||
{
|
||||
if ((b0 == null) || (b1 == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (b0.Length != b1.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < b0.Length; i++)
|
||||
{
|
||||
if (b0[i] != b1[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
{
|
||||
public class ThreadCRC : IDisposable
|
||||
{
|
||||
private Utils.CRC crc;
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
private bool _finished;
|
||||
|
||||
|
||||
public ThreadCRC()
|
||||
{
|
||||
crc = new Utils.CRC();
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public byte[] Hash => crc.Crc32ResultB;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Dispose();
|
||||
_outEvent.Dispose();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
crc.SlurpBlock(_buffer, 0, _size);
|
||||
|
||||
_outEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
{
|
||||
public class ThreadLoadBuffer : IDisposable
|
||||
{
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
private readonly Stream _ds;
|
||||
private bool _finished;
|
||||
public bool errorState;
|
||||
|
||||
public int SizeRead;
|
||||
|
||||
public ThreadLoadBuffer(Stream ds)
|
||||
{
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
_ds = ds;
|
||||
errorState = false;
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Close();
|
||||
_outEvent.Close();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
SizeRead = _ds.Read(_buffer, 0, _size);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorState = true;
|
||||
}
|
||||
_outEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
{
|
||||
public class ThreadMD5 : IDisposable
|
||||
{
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
private readonly MD5 _md5;
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
private bool _finished;
|
||||
|
||||
public ThreadMD5()
|
||||
{
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
_md5 = MD5.Create();
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public byte[] Hash => _md5.Hash;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Close();
|
||||
_outEvent.Close();
|
||||
// _md5.Dispose();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
_md5.TransformBlock(_buffer, 0, _size, null, 0);
|
||||
_outEvent.Set();
|
||||
}
|
||||
|
||||
byte[] tmp = new byte[0];
|
||||
_md5.TransformFinalBlock(tmp, 0, 0);
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
{
|
||||
public class ThreadSHA1 : IDisposable
|
||||
{
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
private readonly SHA1 _sha1;
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
private bool _finished;
|
||||
|
||||
public ThreadSHA1()
|
||||
{
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
_sha1 = SHA1.Create();
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public byte[] Hash => _sha1.Hash;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Close();
|
||||
_outEvent.Close();
|
||||
// _sha1.Dispose();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
_sha1.TransformBlock(_buffer, 0, _size, null, 0);
|
||||
_outEvent.Set();
|
||||
}
|
||||
|
||||
byte[] tmp = new byte[0];
|
||||
_sha1.TransformFinalBlock(tmp, 0, 0);
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
125
SabreTools.Library/External/Compress/Utils/CRC.cs
vendored
125
SabreTools.Library/External/Compress/Utils/CRC.cs
vendored
@@ -1,125 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.Utils
|
||||
{
|
||||
public class CRC
|
||||
{
|
||||
public static readonly uint[] CRC32Lookup;
|
||||
private uint _crc;
|
||||
private long _totalBytesRead;
|
||||
|
||||
static CRC()
|
||||
{
|
||||
const uint polynomial = 0xEDB88320;
|
||||
const int crcNumTables = 8;
|
||||
|
||||
unchecked
|
||||
{
|
||||
CRC32Lookup = new uint[256 * crcNumTables];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
r = (r >> 1) ^ (polynomial & ~((r & 1) - 1));
|
||||
}
|
||||
|
||||
CRC32Lookup[i] = r;
|
||||
}
|
||||
|
||||
for (; i < 256 * crcNumTables; i++)
|
||||
{
|
||||
uint r = CRC32Lookup[i - 256];
|
||||
CRC32Lookup[i] = CRC32Lookup[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public CRC()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_totalBytesRead = 0;
|
||||
_crc = 0xffffffffu;
|
||||
}
|
||||
|
||||
|
||||
internal void UpdateCRC(int inCh)
|
||||
{
|
||||
_crc = (_crc >> 8) ^ CRC32Lookup[(byte)_crc ^ ((byte)inCh)];
|
||||
}
|
||||
|
||||
public void SlurpBlock(byte[] block, int offset, int count)
|
||||
{
|
||||
_totalBytesRead += count;
|
||||
uint crc = _crc;
|
||||
|
||||
for (; (offset & 7) != 0 && count != 0; count--)
|
||||
crc = (crc >> 8) ^ CRC32Lookup[(byte)crc ^ block[offset++]];
|
||||
|
||||
if (count >= 8)
|
||||
{
|
||||
int end = (count - 8) & ~7;
|
||||
count -= end;
|
||||
end += offset;
|
||||
|
||||
while (offset != end)
|
||||
{
|
||||
crc ^= (uint)(block[offset] + (block[offset + 1] << 8) + (block[offset + 2] << 16) + (block[offset + 3] << 24));
|
||||
uint high = (uint)(block[offset + 4] + (block[offset + 5] << 8) + (block[offset + 6] << 16) + (block[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
crc = CRC32Lookup[(byte)crc + 0x700]
|
||||
^ CRC32Lookup[(byte)(crc >>= 8) + 0x600]
|
||||
^ CRC32Lookup[(byte)(crc >>= 8) + 0x500]
|
||||
^ CRC32Lookup[ /*(byte)*/(crc >> 8) + 0x400]
|
||||
^ CRC32Lookup[(byte)high + 0x300]
|
||||
^ CRC32Lookup[(byte)(high >>= 8) + 0x200]
|
||||
^ CRC32Lookup[(byte)(high >>= 8) + 0x100]
|
||||
^ CRC32Lookup[ /*(byte)*/(high >> 8) + 0x000];
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
{
|
||||
crc = (crc >> 8) ^ CRC32Lookup[(byte)crc ^ block[offset++]];
|
||||
}
|
||||
|
||||
_crc = crc;
|
||||
|
||||
}
|
||||
|
||||
public byte[] Crc32ResultB
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] result = BitConverter.GetBytes(~_crc);
|
||||
Array.Reverse(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public Int32 Crc32Result => unchecked((Int32)(~_crc));
|
||||
|
||||
public uint Crc32ResultU => ~_crc;
|
||||
|
||||
public Int64 TotalBytesRead => _totalBytesRead;
|
||||
|
||||
public static uint CalculateDigest(byte[] data, uint offset, uint size)
|
||||
{
|
||||
CRC crc = new CRC();
|
||||
// crc.Init();
|
||||
crc.SlurpBlock(data, (int)offset, (int)size);
|
||||
return crc.Crc32ResultU;
|
||||
}
|
||||
|
||||
public static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
|
||||
{
|
||||
return (CalculateDigest(data, offset, size) == digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.Utils
|
||||
{
|
||||
class CRCStream
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A Stream that calculates a CRC32 (a checksum) on all bytes read,
|
||||
/// or on all bytes written.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class can be used to verify the CRC of a ZipEntry when
|
||||
/// reading from a stream, or to calculate a CRC when writing to a
|
||||
/// stream. The stream should be used to either read, or write, but
|
||||
/// not both. If you intermix reads and writes, the results are not
|
||||
/// defined.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This class is intended primarily for use internally by the
|
||||
/// DotNetZip library.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class CrcCalculatorStream : System.IO.Stream, System.IDisposable
|
||||
{
|
||||
private static readonly Int64 UnsetLengthLimit = -99;
|
||||
|
||||
internal System.IO.Stream _innerStream;
|
||||
private CRC _Crc32;
|
||||
private Int64 _lengthLimit = -99;
|
||||
private bool _leaveOpen;
|
||||
|
||||
/// <summary>
|
||||
/// The default constructor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Instances returned from this constructor will leave the underlying
|
||||
/// stream open upon Close(). The stream uses the default CRC32
|
||||
/// algorithm, which implies a polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream)
|
||||
: this(true, UnsetLengthLimit, stream, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The constructor allows the caller to specify how to handle the
|
||||
/// underlying stream at close.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
|
||||
: this(leaveOpen, UnsetLengthLimit, stream, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Instances returned from this constructor will leave the underlying
|
||||
/// stream open upon Close().
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
|
||||
: this(true, length, stream, null)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read, as well as whether to keep the underlying stream open upon
|
||||
/// Close().
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
|
||||
: this(leaveOpen, length, stream, null)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read, as well as whether to keep the underlying stream open upon
|
||||
/// Close(), and the CRC32 instance to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the specified CRC32 instance, which allows the
|
||||
/// application to specify how the CRC gets calculated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
/// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
|
||||
CRC crc32)
|
||||
: this(leaveOpen, length, stream, crc32)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
|
||||
// This ctor is private - no validation is done here. This is to allow the use
|
||||
// of a (specific) negative value for the _lengthLimit, to indicate that there
|
||||
// is no length set. So we validate the length limit in those ctors that use an
|
||||
// explicit param, otherwise we don't validate, because it could be our special
|
||||
// value.
|
||||
private CrcCalculatorStream
|
||||
(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC crc32)
|
||||
: base()
|
||||
{
|
||||
_innerStream = stream;
|
||||
_Crc32 = crc32 ?? new CRC();
|
||||
_lengthLimit = length;
|
||||
_leaveOpen = leaveOpen;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of bytes run through the CRC32 calculator.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// This is either the total number of bytes read, or the total number of
|
||||
/// bytes written, depending on the direction of this stream.
|
||||
/// </remarks>
|
||||
public Int64 TotalBytesSlurped
|
||||
{
|
||||
get { return _Crc32.TotalBytesRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides the current CRC for all blocks slurped in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The running total of the CRC is kept as data is written or read
|
||||
/// through the stream. read this property after all reads or writes to
|
||||
/// get an accurate CRC for the entire stream.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Int32 Crc
|
||||
{
|
||||
get { return _Crc32.Crc32Result; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the underlying stream will be left open when the
|
||||
/// <c>CrcCalculatorStream</c> is Closed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Set this at any point before calling <see cref="Close()"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool LeaveOpen
|
||||
{
|
||||
get { return _leaveOpen; }
|
||||
set { _leaveOpen = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from the stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">the buffer to read</param>
|
||||
/// <param name="offset">the offset at which to start</param>
|
||||
/// <param name="count">the number of bytes to read</param>
|
||||
/// <returns>the number of bytes actually read</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int bytesToRead = count;
|
||||
|
||||
// Need to limit the # of bytes returned, if the stream is intended to have
|
||||
// a definite length. This is especially useful when returning a stream for
|
||||
// the uncompressed data directly to the application. The app won't
|
||||
// necessarily read only the UncompressedSize number of bytes. For example
|
||||
// wrapping the stream returned from OpenReader() into a StreadReader() and
|
||||
// calling ReadToEnd() on it, We can "over-read" the zip data and get a
|
||||
// corrupt string. The length limits that, prevents that problem.
|
||||
|
||||
if (_lengthLimit != UnsetLengthLimit)
|
||||
{
|
||||
if (_Crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
|
||||
Int64 bytesRemaining = _lengthLimit - _Crc32.TotalBytesRead;
|
||||
if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
|
||||
}
|
||||
int n = _innerStream.Read(buffer, offset, bytesToRead);
|
||||
if (n > 0) _Crc32.SlurpBlock(buffer, offset, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write to the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">the buffer from which to write</param>
|
||||
/// <param name="offset">the offset at which to start writing</param>
|
||||
/// <param name="count">the number of bytes to write</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (count > 0) _Crc32.SlurpBlock(buffer, offset, count);
|
||||
_innerStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return _innerStream.CanRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports seeking.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Always returns false.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return _innerStream.CanWrite; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
_innerStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length of the underlying stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
|
||||
return _innerStream.Length;
|
||||
else return _lengthLimit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The getter for this property returns the total bytes read.
|
||||
/// If you use the setter, it will throw
|
||||
/// <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { return _Crc32.TotalBytesRead; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeking is not supported on this stream. This method always throws
|
||||
/// <see cref="NotSupportedException"/>
|
||||
/// </summary>
|
||||
/// <param name="offset">N/A</param>
|
||||
/// <param name="origin">N/A</param>
|
||||
/// <returns>N/A</returns>
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method always throws
|
||||
/// <see cref="NotSupportedException"/>
|
||||
/// </summary>
|
||||
/// <param name="value">N/A</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the stream.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
if (!_leaveOpen)
|
||||
_innerStream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using RVIO;
|
||||
|
||||
namespace Compress.Utils
|
||||
{
|
||||
public static class DirUtil
|
||||
{
|
||||
public static void CreateDirForFile(string sFilename)
|
||||
{
|
||||
string strTemp = Path.GetDirectoryName(sFilename);
|
||||
|
||||
if (string.IsNullOrEmpty(strTemp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Directory.Exists(strTemp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while ((strTemp.Length > 0) && !Directory.Exists(strTemp))
|
||||
{
|
||||
int pos = strTemp.LastIndexOf(Path.DirectorySeparatorChar);
|
||||
if (pos < 0)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
strTemp = strTemp.Substring(0, pos);
|
||||
}
|
||||
|
||||
while (sFilename.IndexOf(Path.DirectorySeparatorChar, strTemp.Length + 1) > 0)
|
||||
{
|
||||
strTemp = sFilename.Substring(0, sFilename.IndexOf(Path.DirectorySeparatorChar, strTemp.Length + 1));
|
||||
Directory.CreateDirectory(strTemp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
|
||||
namespace Compress.Utils
|
||||
{
|
||||
public static class Reporter
|
||||
{
|
||||
public static string ToArrayString(this ulong[] arr)
|
||||
{
|
||||
if (arr == null)
|
||||
return "NULL";
|
||||
|
||||
string ret = $"({arr.Length}) " + arr[0].ToString();
|
||||
for (int i = 1; i < arr.Length; i++)
|
||||
{
|
||||
ret += "," + arr[i].ToString();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
public static string ToArrayString(this byte[] arr)
|
||||
{
|
||||
if (arr == null)
|
||||
return "NULL";
|
||||
|
||||
string ret = $"({arr.Length}) " + arr[0].ToString("X2");
|
||||
for (int i = 1; i < arr.Length; i++)
|
||||
{
|
||||
ret += "," + arr[i].ToString("X2");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public static string ToHex(this uint? v)
|
||||
{
|
||||
return v == null ? "NULL" : ((uint)v).ToString("X8");
|
||||
}
|
||||
public static string ToHex(this ulong? v)
|
||||
{
|
||||
return v == null ? "NULL" : ((ulong)v).ToString("X8");
|
||||
}
|
||||
}
|
||||
}
|
||||
53
SabreTools.Library/External/Compress/ZipEnums.cs
vendored
53
SabreTools.Library/External/Compress/ZipEnums.cs
vendored
@@ -1,53 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Compress
|
||||
{
|
||||
public enum ZipReturn
|
||||
{
|
||||
ZipGood,
|
||||
ZipFileLocked,
|
||||
ZipFileCountError,
|
||||
ZipSignatureError,
|
||||
ZipExtraDataOnEndOfZip,
|
||||
ZipUnsupportedCompression,
|
||||
ZipLocalFileHeaderError,
|
||||
ZipCentralDirError,
|
||||
ZipEndOfCentralDirectoryError,
|
||||
Zip64EndOfCentralDirError,
|
||||
Zip64EndOfCentralDirectoryLocatorError,
|
||||
ZipReadingFromOutputFile,
|
||||
ZipWritingToInputFile,
|
||||
ZipErrorGettingDataStream,
|
||||
ZipCRCDecodeError,
|
||||
ZipDecodeError,
|
||||
ZipFileNameToLong,
|
||||
ZipFileAlreadyOpen,
|
||||
ZipCannotFastOpen,
|
||||
ZipErrorOpeningFile,
|
||||
ZipErrorFileNotFound,
|
||||
ZipErrorReadingFile,
|
||||
ZipErrorTimeStamp,
|
||||
ZipErrorRollBackFile,
|
||||
ZipTryingToAccessADirectory,
|
||||
ZipErrorWritingToOutputStream,
|
||||
ZipUntested
|
||||
|
||||
}
|
||||
|
||||
public enum ZipOpenType
|
||||
{
|
||||
Closed,
|
||||
OpenRead,
|
||||
OpenWrite,
|
||||
OpenFakeWrite
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ZipStatus
|
||||
{
|
||||
None = 0x0,
|
||||
TrrntZip = 0x1,
|
||||
ExtraData = 0x2,
|
||||
Trrnt7Zip = 0x4
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,436 +0,0 @@
|
||||
// Inftree.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-October-28 12:43:54>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes used in decompression. This code is derived
|
||||
// from the jzlib implementation of zlib. In keeping with the license for jzlib,
|
||||
// the copyright to that code is below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
{
|
||||
|
||||
sealed class InfTree
|
||||
{
|
||||
|
||||
private const int MANY = 1440;
|
||||
|
||||
private const int Z_OK = 0;
|
||||
private const int Z_STREAM_END = 1;
|
||||
private const int Z_NEED_DICT = 2;
|
||||
private const int Z_ERRNO = -1;
|
||||
private const int Z_STREAM_ERROR = -2;
|
||||
private const int Z_DATA_ERROR = -3;
|
||||
private const int Z_MEM_ERROR = -4;
|
||||
private const int Z_BUF_ERROR = -5;
|
||||
private const int Z_VERSION_ERROR = -6;
|
||||
|
||||
internal const int fixed_bl = 9;
|
||||
internal const int fixed_bd = 5;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] fixed_tl = new int[]{96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
|
||||
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
|
||||
14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255};
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] fixed_td = new int[] { 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 };
|
||||
|
||||
// Tables for deflate from PKZIP's appnote.txt.
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cplens = new int[] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 };
|
||||
|
||||
// see note #13 above about 258
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cplext = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 };
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cpdist = new int[] { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cpdext = new int[] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };
|
||||
|
||||
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
|
||||
internal const int BMAX = 15; // maximum bit length of any code
|
||||
|
||||
internal int[] hn = null; // hufts used in space
|
||||
internal int[] v = null; // work area for huft_build
|
||||
internal int[] c = null; // bit length count table
|
||||
internal int[] r = null; // table entry for structure assignment
|
||||
internal int[] u = null; // table stack
|
||||
internal int[] x = null; // bit offsets, then code stack
|
||||
|
||||
private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, int[] v)
|
||||
{
|
||||
// Given a list of code lengths and a maximum table size, make a set of
|
||||
// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
|
||||
// if the given code set is incomplete (the tables are still built in this
|
||||
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
|
||||
// lengths), or Z_MEM_ERROR if not enough memory.
|
||||
|
||||
int a; // counter for codes of length k
|
||||
int f; // i repeats in table every f entries
|
||||
int g; // maximum code length
|
||||
int h; // table level
|
||||
int i; // counter, current code
|
||||
int j; // counter
|
||||
int k; // number of bits in current code
|
||||
int l; // bits per table (returned in m)
|
||||
int mask; // (1 << w) - 1, to avoid cc -O bug on HP
|
||||
int p; // pointer into c[], b[], or v[]
|
||||
int q; // points to current table
|
||||
int w; // bits before this table == (l * h)
|
||||
int xp; // pointer into x
|
||||
int y; // number of dummy codes added
|
||||
int z; // number of entries in current table
|
||||
|
||||
// Generate counts for each bit length
|
||||
|
||||
p = 0; i = n;
|
||||
do
|
||||
{
|
||||
c[b[bindex + p]]++; p++; i--; // assume all entries <= BMAX
|
||||
}
|
||||
while (i != 0);
|
||||
|
||||
if (c[0] == n)
|
||||
{
|
||||
// null input--all zero length codes
|
||||
t[0] = -1;
|
||||
m[0] = 0;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
// Find minimum and maximum length, bound *m by those
|
||||
l = m[0];
|
||||
for (j = 1; j <= BMAX; j++)
|
||||
if (c[j] != 0)
|
||||
break;
|
||||
k = j; // minimum code length
|
||||
if (l < j)
|
||||
{
|
||||
l = j;
|
||||
}
|
||||
for (i = BMAX; i != 0; i--)
|
||||
{
|
||||
if (c[i] != 0)
|
||||
break;
|
||||
}
|
||||
g = i; // maximum code length
|
||||
if (l > i)
|
||||
{
|
||||
l = i;
|
||||
}
|
||||
m[0] = l;
|
||||
|
||||
// Adjust last length count to fill out codes, if needed
|
||||
for (y = 1 << j; j < i; j++, y <<= 1)
|
||||
{
|
||||
if ((y -= c[j]) < 0)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
if ((y -= c[i]) < 0)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
c[i] += y;
|
||||
|
||||
// Generate starting offsets into the value table for each length
|
||||
x[1] = j = 0;
|
||||
p = 1; xp = 2;
|
||||
while (--i != 0)
|
||||
{
|
||||
// note that i == g from above
|
||||
x[xp] = (j += c[p]);
|
||||
xp++;
|
||||
p++;
|
||||
}
|
||||
|
||||
// Make a table of values in order of bit lengths
|
||||
i = 0; p = 0;
|
||||
do
|
||||
{
|
||||
if ((j = b[bindex + p]) != 0)
|
||||
{
|
||||
v[x[j]++] = i;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
while (++i < n);
|
||||
n = x[g]; // set n to length of v
|
||||
|
||||
// Generate the Huffman codes and for each, make the table entries
|
||||
x[0] = i = 0; // first Huffman code is zero
|
||||
p = 0; // grab values in bit order
|
||||
h = -1; // no tables yet--level -1
|
||||
w = -l; // bits decoded == (l * h)
|
||||
u[0] = 0; // just to keep compilers happy
|
||||
q = 0; // ditto
|
||||
z = 0; // ditto
|
||||
|
||||
// go through the bit lengths (k already is bits in shortest code)
|
||||
for (; k <= g; k++)
|
||||
{
|
||||
a = c[k];
|
||||
while (a-- != 0)
|
||||
{
|
||||
// here i is the Huffman code of length k bits for value *p
|
||||
// make tables up to required level
|
||||
while (k > w + l)
|
||||
{
|
||||
h++;
|
||||
w += l; // previous table always l bits
|
||||
// compute minimum size table less than or equal to l bits
|
||||
z = g - w;
|
||||
z = (z > l) ? l : z; // table size upper limit
|
||||
if ((f = 1 << (j = k - w)) > a + 1)
|
||||
{
|
||||
// try a k-w bit table
|
||||
// too few codes for k-w bit table
|
||||
f -= (a + 1); // deduct codes from patterns left
|
||||
xp = k;
|
||||
if (j < z)
|
||||
{
|
||||
while (++j < z)
|
||||
{
|
||||
// try smaller tables up to z bits
|
||||
if ((f <<= 1) <= c[++xp])
|
||||
break; // enough codes to use up j bits
|
||||
f -= c[xp]; // else deduct codes from patterns
|
||||
}
|
||||
}
|
||||
}
|
||||
z = 1 << j; // table entries for j-bit table
|
||||
|
||||
// allocate new table
|
||||
if (hn[0] + z > MANY)
|
||||
{
|
||||
// (note: doesn't matter for fixed)
|
||||
return Z_DATA_ERROR; // overflow of MANY
|
||||
}
|
||||
u[h] = q = hn[0]; // DEBUG
|
||||
hn[0] += z;
|
||||
|
||||
// connect to last table, if there is one
|
||||
if (h != 0)
|
||||
{
|
||||
x[h] = i; // save pattern for backing up
|
||||
r[0] = (sbyte)j; // bits in this table
|
||||
r[1] = (sbyte)l; // bits to dump before this table
|
||||
j = SharedUtils.URShift(i, (w - l));
|
||||
r[2] = (int)(q - u[h - 1] - j); // offset to this table
|
||||
Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table
|
||||
}
|
||||
else
|
||||
{
|
||||
t[0] = q; // first table is returned result
|
||||
}
|
||||
}
|
||||
|
||||
// set up table entry in r
|
||||
r[1] = (sbyte)(k - w);
|
||||
if (p >= n)
|
||||
{
|
||||
r[0] = 128 + 64; // out of values--invalid code
|
||||
}
|
||||
else if (v[p] < s)
|
||||
{
|
||||
r[0] = (sbyte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block
|
||||
r[2] = v[p++]; // simple code is just the value
|
||||
}
|
||||
else
|
||||
{
|
||||
r[0] = (sbyte)(e[v[p] - s] + 16 + 64); // non-simple--look up in lists
|
||||
r[2] = d[v[p++] - s];
|
||||
}
|
||||
|
||||
// fill code-like entries with r
|
||||
f = 1 << (k - w);
|
||||
for (j = SharedUtils.URShift(i, w); j < z; j += f)
|
||||
{
|
||||
Array.Copy(r, 0, hp, (q + j) * 3, 3);
|
||||
}
|
||||
|
||||
// backwards increment the k-bit code i
|
||||
for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1))
|
||||
{
|
||||
i ^= j;
|
||||
}
|
||||
i ^= j;
|
||||
|
||||
// backup over finished tables
|
||||
mask = (1 << w) - 1; // needed on HP, cc -O bug
|
||||
while ((i & mask) != x[h])
|
||||
{
|
||||
h--; // don't need to update q
|
||||
w -= l;
|
||||
mask = (1 << w) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return Z_BUF_ERROR if we were given an incomplete table
|
||||
return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
|
||||
}
|
||||
|
||||
internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z)
|
||||
{
|
||||
int result;
|
||||
initWorkArea(19);
|
||||
hn[0] = 0;
|
||||
result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
|
||||
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed dynamic bit lengths tree";
|
||||
}
|
||||
else if (result == Z_BUF_ERROR || bb[0] == 0)
|
||||
{
|
||||
z.Message = "incomplete dynamic bit lengths tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
|
||||
{
|
||||
int result;
|
||||
|
||||
// build literal/length tree
|
||||
initWorkArea(288);
|
||||
hn[0] = 0;
|
||||
result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
|
||||
if (result != Z_OK || bl[0] == 0)
|
||||
{
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed literal/length tree";
|
||||
}
|
||||
else if (result != Z_MEM_ERROR)
|
||||
{
|
||||
z.Message = "incomplete literal/length tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// build distance tree
|
||||
initWorkArea(288);
|
||||
result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
|
||||
|
||||
if (result != Z_OK || (bd[0] == 0 && nl > 257))
|
||||
{
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed distance tree";
|
||||
}
|
||||
else if (result == Z_BUF_ERROR)
|
||||
{
|
||||
z.Message = "incomplete distance tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
else if (result != Z_MEM_ERROR)
|
||||
{
|
||||
z.Message = "empty distance tree with lengths";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
|
||||
{
|
||||
bl[0] = fixed_bl;
|
||||
bd[0] = fixed_bd;
|
||||
tl[0] = fixed_tl;
|
||||
td[0] = fixed_td;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
private void initWorkArea(int vsize)
|
||||
{
|
||||
if (hn == null)
|
||||
{
|
||||
hn = new int[1];
|
||||
v = new int[vsize];
|
||||
c = new int[BMAX + 1];
|
||||
r = new int[3];
|
||||
u = new int[BMAX];
|
||||
x = new int[BMAX + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.Length < vsize)
|
||||
{
|
||||
v = new int[vsize];
|
||||
}
|
||||
Array.Clear(v, 0, vsize);
|
||||
Array.Clear(c, 0, BMAX + 1);
|
||||
r[0] = 0; r[1] = 0; r[2] = 0;
|
||||
// for(int i=0; i<BMAX; i++){u[i]=0;}
|
||||
//Array.Copy(c, 0, u, 0, BMAX);
|
||||
Array.Clear(u, 0, BMAX);
|
||||
// for(int i=0; i<BMAX+1; i++){x[i]=0;}
|
||||
//Array.Copy(c, 0, x, 0, BMAX + 1);
|
||||
Array.Clear(x, 0, BMAX + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,422 +0,0 @@
|
||||
// Tree.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-October-28 13:29:50>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for zlib compression and
|
||||
// decompression. This code is derived from the jzlib implementation of
|
||||
// zlib. In keeping with the license for jzlib, the copyright to that
|
||||
// code is below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
{
|
||||
sealed class Tree
|
||||
{
|
||||
private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1);
|
||||
|
||||
// extra bits for each length code
|
||||
internal static readonly int[] ExtraLengthBits = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
// extra bits for each distance code
|
||||
internal static readonly int[] ExtraDistanceBits = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
|
||||
};
|
||||
|
||||
// extra bits for each bit length code
|
||||
internal static readonly int[] extra_blbits = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
|
||||
|
||||
internal static readonly sbyte[] bl_order = new sbyte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
|
||||
|
||||
|
||||
// The lengths of the bit length codes are sent in order of decreasing
|
||||
// probability, to avoid transmitting the lengths for unused bit
|
||||
// length codes.
|
||||
|
||||
internal const int Buf_size = 8 * 2;
|
||||
|
||||
// see definition of array dist_code below
|
||||
//internal const int DIST_CODE_LEN = 512;
|
||||
|
||||
private static readonly sbyte[] _dist_code = new sbyte[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
|
||||
};
|
||||
|
||||
internal static readonly sbyte[] LengthCode = new sbyte[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
|
||||
};
|
||||
|
||||
|
||||
internal static readonly int[] LengthBase = new int[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
|
||||
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0
|
||||
};
|
||||
|
||||
|
||||
internal static readonly int[] DistanceBase = new int[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
|
||||
256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Map from a distance to a distance code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// No side effects. _dist_code[256] and _dist_code[257] are never used.
|
||||
/// </remarks>
|
||||
internal static int DistanceCode(int dist)
|
||||
{
|
||||
return (dist < 256)
|
||||
? _dist_code[dist]
|
||||
: _dist_code[256 + SharedUtils.URShift(dist, 7)];
|
||||
}
|
||||
|
||||
internal short[] dyn_tree; // the dynamic tree
|
||||
internal int max_code; // largest code with non zero frequency
|
||||
internal StaticTree staticTree; // the corresponding static tree
|
||||
|
||||
// Compute the optimal bit lengths for a tree and update the total bit length
|
||||
// for the current block.
|
||||
// IN assertion: the fields freq and dad are set, heap[heap_max] and
|
||||
// above are the tree nodes sorted by increasing frequency.
|
||||
// OUT assertions: the field len is set to the optimal bit length, the
|
||||
// array bl_count contains the frequencies for each bit length.
|
||||
// The length opt_len is updated; static_len is also updated if stree is
|
||||
// not null.
|
||||
internal void gen_bitlen(DeflateManager s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = staticTree.treeCodes;
|
||||
int[] extra = staticTree.extraBits;
|
||||
int base_Renamed = staticTree.extraBase;
|
||||
int max_length = staticTree.maxLength;
|
||||
int h; // heap index
|
||||
int n, m; // iterate over the tree elements
|
||||
int bits; // bit length
|
||||
int xbits; // extra bits
|
||||
short f; // frequency
|
||||
int overflow = 0; // number of elements with bit length too large
|
||||
|
||||
for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
s.bl_count[bits] = 0;
|
||||
|
||||
// In a first pass, compute the optimal bit lengths (which may
|
||||
// overflow in the case of the bit length tree).
|
||||
tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
|
||||
|
||||
for (h = s.heap_max + 1; h < HEAP_SIZE; h++)
|
||||
{
|
||||
n = s.heap[h];
|
||||
bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
|
||||
if (bits > max_length)
|
||||
{
|
||||
bits = max_length; overflow++;
|
||||
}
|
||||
tree[n * 2 + 1] = (short)bits;
|
||||
// We overwrite tree[n*2+1] which is no longer needed
|
||||
|
||||
if (n > max_code)
|
||||
continue; // not a leaf node
|
||||
|
||||
s.bl_count[bits]++;
|
||||
xbits = 0;
|
||||
if (n >= base_Renamed)
|
||||
xbits = extra[n - base_Renamed];
|
||||
f = tree[n * 2];
|
||||
s.opt_len += f * (bits + xbits);
|
||||
if (stree != null)
|
||||
s.static_len += f * (stree[n * 2 + 1] + xbits);
|
||||
}
|
||||
if (overflow == 0)
|
||||
return;
|
||||
|
||||
// This happens for example on obj2 and pic of the Calgary corpus
|
||||
// Find the first bit length which could increase:
|
||||
do
|
||||
{
|
||||
bits = max_length - 1;
|
||||
while (s.bl_count[bits] == 0)
|
||||
bits--;
|
||||
s.bl_count[bits]--; // move one leaf down the tree
|
||||
s.bl_count[bits + 1] = (short)(s.bl_count[bits + 1] + 2); // move one overflow item as its brother
|
||||
s.bl_count[max_length]--;
|
||||
// The brother of the overflow item also moves one step up,
|
||||
// but this does not affect bl_count[max_length]
|
||||
overflow -= 2;
|
||||
}
|
||||
while (overflow > 0);
|
||||
|
||||
for (bits = max_length; bits != 0; bits--)
|
||||
{
|
||||
n = s.bl_count[bits];
|
||||
while (n != 0)
|
||||
{
|
||||
m = s.heap[--h];
|
||||
if (m > max_code)
|
||||
continue;
|
||||
if (tree[m * 2 + 1] != bits)
|
||||
{
|
||||
s.opt_len = (int)(s.opt_len + ((long)bits - (long)tree[m * 2 + 1]) * (long)tree[m * 2]);
|
||||
tree[m * 2 + 1] = (short)bits;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct one Huffman tree and assigns the code bit strings and lengths.
|
||||
// Update the total bit length for the current block.
|
||||
// IN assertion: the field freq is set for all tree elements.
|
||||
// OUT assertions: the fields len and code are set to the optimal bit length
|
||||
// and corresponding code. The length opt_len is updated; static_len is
|
||||
// also updated if stree is not null. The field max_code is set.
|
||||
internal void build_tree(DeflateManager s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = staticTree.treeCodes;
|
||||
int elems = staticTree.elems;
|
||||
int n, m; // iterate over heap elements
|
||||
int max_code = -1; // largest code with non zero frequency
|
||||
int node; // new node being created
|
||||
|
||||
// Construct the initial heap, with least frequent element in
|
||||
// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
|
||||
// heap[0] is not used.
|
||||
s.heap_len = 0;
|
||||
s.heap_max = HEAP_SIZE;
|
||||
|
||||
for (n = 0; n < elems; n++)
|
||||
{
|
||||
if (tree[n * 2] != 0)
|
||||
{
|
||||
s.heap[++s.heap_len] = max_code = n;
|
||||
s.depth[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree[n * 2 + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The pkzip format requires that at least one distance code exists,
|
||||
// and that at least one bit should be sent even if there is only one
|
||||
// possible code. So to avoid special checks later on we force at least
|
||||
// two codes of non zero frequency.
|
||||
while (s.heap_len < 2)
|
||||
{
|
||||
node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
|
||||
tree[node * 2] = 1;
|
||||
s.depth[node] = 0;
|
||||
s.opt_len--;
|
||||
if (stree != null)
|
||||
s.static_len -= stree[node * 2 + 1];
|
||||
// node is 0 or 1 so it does not have extra bits
|
||||
}
|
||||
this.max_code = max_code;
|
||||
|
||||
// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
|
||||
// establish sub-heaps of increasing lengths:
|
||||
|
||||
for (n = s.heap_len / 2; n >= 1; n--)
|
||||
s.pqdownheap(tree, n);
|
||||
|
||||
// Construct the Huffman tree by repeatedly combining the least two
|
||||
// frequent nodes.
|
||||
|
||||
node = elems; // next internal node of the tree
|
||||
do
|
||||
{
|
||||
// n = node of least frequency
|
||||
n = s.heap[1];
|
||||
s.heap[1] = s.heap[s.heap_len--];
|
||||
s.pqdownheap(tree, 1);
|
||||
m = s.heap[1]; // m = node of next least frequency
|
||||
|
||||
s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
|
||||
s.heap[--s.heap_max] = m;
|
||||
|
||||
// Create a new node father of n and m
|
||||
tree[node * 2] = unchecked((short)(tree[n * 2] + tree[m * 2]));
|
||||
s.depth[node] = (sbyte)(System.Math.Max((byte)s.depth[n], (byte)s.depth[m]) + 1);
|
||||
tree[n * 2 + 1] = tree[m * 2 + 1] = (short)node;
|
||||
|
||||
// and insert the new node in the heap
|
||||
s.heap[1] = node++;
|
||||
s.pqdownheap(tree, 1);
|
||||
}
|
||||
while (s.heap_len >= 2);
|
||||
|
||||
s.heap[--s.heap_max] = s.heap[1];
|
||||
|
||||
// At this point, the fields freq and dad are set. We can now
|
||||
// generate the bit lengths.
|
||||
|
||||
gen_bitlen(s);
|
||||
|
||||
// The field len is now set, we can generate the bit codes
|
||||
gen_codes(tree, max_code, s.bl_count);
|
||||
}
|
||||
|
||||
// Generate the codes for a given tree and bit counts (which need not be
|
||||
// optimal).
|
||||
// IN assertion: the array bl_count contains the bit length statistics for
|
||||
// the given tree and the field len is set for all tree elements.
|
||||
// OUT assertion: the field code is set for all tree elements of non
|
||||
// zero code length.
|
||||
internal static void gen_codes(short[] tree, int max_code, short[] bl_count)
|
||||
{
|
||||
short[] next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length
|
||||
short code = 0; // running code value
|
||||
int bits; // bit index
|
||||
int n; // code index
|
||||
|
||||
// The distribution counts are first used to generate the code values
|
||||
// without bit reversal.
|
||||
for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
unchecked
|
||||
{
|
||||
next_code[bits] = code = (short)((code + bl_count[bits - 1]) << 1);
|
||||
}
|
||||
|
||||
// Check that the bit counts in bl_count are consistent. The last code
|
||||
// must be all ones.
|
||||
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
|
||||
// "inconsistent bit counts");
|
||||
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
|
||||
|
||||
for (n = 0; n <= max_code; n++)
|
||||
{
|
||||
int len = tree[n * 2 + 1];
|
||||
if (len == 0)
|
||||
continue;
|
||||
// Now reverse the bits
|
||||
tree[n * 2] = unchecked((short)(bi_reverse(next_code[len]++, len)));
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the first len bits of a code, using straightforward code (a faster
|
||||
// method would use a table)
|
||||
// IN assertion: 1 <= len <= 15
|
||||
internal static int bi_reverse(int code, int len)
|
||||
{
|
||||
int res = 0;
|
||||
do
|
||||
{
|
||||
res |= code & 1;
|
||||
code >>= 1; //SharedUtils.URShift(code, 1);
|
||||
res <<= 1;
|
||||
}
|
||||
while (--len > 0);
|
||||
return res >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,480 +0,0 @@
|
||||
// Zlib.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009-2011 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-August-03 19:52:28>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for ZLIB compression and
|
||||
// decompression. This code is derived from the jzlib implementation of
|
||||
// zlib, but significantly modified. The object model is not the same,
|
||||
// and many of the behaviors are new or different. Nonetheless, in
|
||||
// keeping with the license for jzlib, the copyright to that code is
|
||||
// included below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// The following notice applies to jzlib:
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// jzlib is based on zlib-1.1.3.
|
||||
//
|
||||
// The following notice applies to zlib:
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
|
||||
//
|
||||
// The ZLIB software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Jean-loup Gailly jloup@gzip.org
|
||||
// Mark Adler madler@alumni.caltech.edu
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Describes how to flush the current deflate operation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The different FlushType values are useful when using a Deflate in a streaming application.
|
||||
/// </remarks>
|
||||
public enum FlushType
|
||||
{
|
||||
/// <summary>No flush at all.</summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>Closes the current block, but doesn't flush it to
|
||||
/// the output. Used internally only in hypothetical
|
||||
/// scenarios. This was supposed to be removed by Zlib, but it is
|
||||
/// still in use in some edge cases.
|
||||
/// </summary>
|
||||
Partial,
|
||||
|
||||
/// <summary>
|
||||
/// Use this during compression to specify that all pending output should be
|
||||
/// flushed to the output buffer and the output should be aligned on a byte
|
||||
/// boundary. You might use this in a streaming communication scenario, so that
|
||||
/// the decompressor can get all input data available so far. When using this
|
||||
/// with a ZlibCodec, <c>AvailableBytesIn</c> will be zero after the call if
|
||||
/// enough output space has been provided before the call. Flushing will
|
||||
/// degrade compression and so it should be used only when necessary.
|
||||
/// </summary>
|
||||
Sync,
|
||||
|
||||
/// <summary>
|
||||
/// Use this during compression to specify that all output should be flushed, as
|
||||
/// with <c>FlushType.Sync</c>, but also, the compression state should be reset
|
||||
/// so that decompression can restart from this point if previous compressed
|
||||
/// data has been damaged or if random access is desired. Using
|
||||
/// <c>FlushType.Full</c> too often can significantly degrade the compression.
|
||||
/// </summary>
|
||||
Full,
|
||||
|
||||
/// <summary>Signals the end of the compression/decompression stream.</summary>
|
||||
Finish,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress.
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// None means that the data will be simply stored, with no change at all.
|
||||
/// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None
|
||||
/// cannot be opened with the default zip reader. Use a different CompressionLevel.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Same as None.
|
||||
/// </summary>
|
||||
Level0 = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The fastest but least effective compression.
|
||||
/// </summary>
|
||||
BestSpeed = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A synonym for BestSpeed.
|
||||
/// </summary>
|
||||
Level1 = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower, but better, than level 1.
|
||||
/// </summary>
|
||||
Level2 = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower, but better, than level 2.
|
||||
/// </summary>
|
||||
Level3 = 3,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower, but better, than level 3.
|
||||
/// </summary>
|
||||
Level4 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower than level 4, but with better compression.
|
||||
/// </summary>
|
||||
Level5 = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The default compression level, with a good balance of speed and compression efficiency.
|
||||
/// </summary>
|
||||
Default = 6,
|
||||
/// <summary>
|
||||
/// A synonym for Default.
|
||||
/// </summary>
|
||||
Level6 = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Pretty good compression!
|
||||
/// </summary>
|
||||
Level7 = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Better compression than Level7!
|
||||
/// </summary>
|
||||
Level8 = 8,
|
||||
|
||||
/// <summary>
|
||||
/// The "best" compression, where best means greatest reduction in size of the input data stream.
|
||||
/// This is also the slowest compression.
|
||||
/// </summary>
|
||||
BestCompression = 9,
|
||||
|
||||
/// <summary>
|
||||
/// A synonym for BestCompression.
|
||||
/// </summary>
|
||||
Level9 = 9,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes options for how the compression algorithm is executed. Different strategies
|
||||
/// work better on different sorts of data. The strategy parameter can affect the compression
|
||||
/// ratio and the speed of compression but not the correctness of the compresssion.
|
||||
/// </summary>
|
||||
public enum CompressionStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// The default strategy is probably the best for normal data.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The <c>Filtered</c> strategy is intended to be used most effectively with data produced by a
|
||||
/// filter or predictor. By this definition, filtered data consists mostly of small
|
||||
/// values with a somewhat random distribution. In this case, the compression algorithm
|
||||
/// is tuned to compress them better. The effect of <c>Filtered</c> is to force more Huffman
|
||||
/// coding and less string matching; it is a half-step between <c>Default</c> and <c>HuffmanOnly</c>.
|
||||
/// </summary>
|
||||
Filtered = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Using <c>HuffmanOnly</c> will force the compressor to do Huffman encoding only, with no
|
||||
/// string matching.
|
||||
/// </summary>
|
||||
HuffmanOnly = 2,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An enum to specify the direction of transcoding - whether to compress or decompress.
|
||||
/// </summary>
|
||||
public enum CompressionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to specify that the stream should compress the data.
|
||||
/// </summary>
|
||||
Compress = 0,
|
||||
/// <summary>
|
||||
/// Used to specify that the stream should decompress the data.
|
||||
/// </summary>
|
||||
Decompress = 1,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A general purpose exception class for exceptions in the Zlib library.
|
||||
/// </summary>
|
||||
[Guid("ebc25cf6-9120-4283-b972-0e5520d0000E")]
|
||||
public class ZlibException : System.Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// The ZlibException class captures exception information generated
|
||||
/// by the Zlib library.
|
||||
/// </summary>
|
||||
public ZlibException()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This ctor collects a message attached to the exception.
|
||||
/// </summary>
|
||||
/// <param name="s">the message for the exception.</param>
|
||||
public ZlibException(System.String s)
|
||||
: base(s)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class SharedUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static int URShift(int number, int bits)
|
||||
{
|
||||
return (int)((uint)number >> bits);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class InternalConstants
|
||||
{
|
||||
internal static readonly int MAX_BITS = 15;
|
||||
internal static readonly int BL_CODES = 19;
|
||||
internal static readonly int D_CODES = 30;
|
||||
internal static readonly int LITERALS = 256;
|
||||
internal static readonly int LENGTH_CODES = 29;
|
||||
internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
|
||||
|
||||
// Bit length codes must not exceed MAX_BL_BITS bits
|
||||
internal static readonly int MAX_BL_BITS = 7;
|
||||
|
||||
// repeat previous bit length 3-6 times (2 bits of repeat count)
|
||||
internal static readonly int REP_3_6 = 16;
|
||||
|
||||
// repeat a zero length 3-10 times (3 bits of repeat count)
|
||||
internal static readonly int REPZ_3_10 = 17;
|
||||
|
||||
// repeat a zero length 11-138 times (7 bits of repeat count)
|
||||
internal static readonly int REPZ_11_138 = 18;
|
||||
|
||||
}
|
||||
|
||||
internal sealed class StaticTree
|
||||
{
|
||||
internal static readonly short[] lengthAndLiteralsTreeCodes = new short[] {
|
||||
12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8,
|
||||
28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8,
|
||||
2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8,
|
||||
18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8,
|
||||
10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, 8, 106, 8, 234, 8,
|
||||
26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8,
|
||||
6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8,
|
||||
22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8,
|
||||
14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8,
|
||||
30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, 8, 126, 8, 254, 8,
|
||||
1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8,
|
||||
17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, 241, 8,
|
||||
9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8,
|
||||
25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8,
|
||||
5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8,
|
||||
21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8,
|
||||
13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, 237, 8,
|
||||
29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8,
|
||||
19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
|
||||
51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9,
|
||||
11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9,
|
||||
43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, 491, 9,
|
||||
27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9,
|
||||
59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, 251, 9, 507, 9,
|
||||
7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9,
|
||||
39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9,
|
||||
23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9,
|
||||
55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9,
|
||||
15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, 207, 9, 463, 9,
|
||||
47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9,
|
||||
31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9, 223, 9, 479, 9,
|
||||
63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9,
|
||||
0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7,
|
||||
8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7,
|
||||
4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7,
|
||||
3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8
|
||||
};
|
||||
|
||||
internal static readonly short[] distTreeCodes = new short[] {
|
||||
0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5,
|
||||
2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5,
|
||||
1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5,
|
||||
3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 };
|
||||
|
||||
internal static readonly StaticTree Literals;
|
||||
internal static readonly StaticTree Distances;
|
||||
internal static readonly StaticTree BitLengths;
|
||||
|
||||
internal short[] treeCodes; // static tree or null
|
||||
internal int[] extraBits; // extra bits for each code or null
|
||||
internal int extraBase; // base index for extra_bits
|
||||
internal int elems; // max number of elements in the tree
|
||||
internal int maxLength; // max bit length for the codes
|
||||
|
||||
private StaticTree(short[] treeCodes, int[] extraBits, int extraBase, int elems, int maxLength)
|
||||
{
|
||||
this.treeCodes = treeCodes;
|
||||
this.extraBits = extraBits;
|
||||
this.extraBase = extraBase;
|
||||
this.elems = elems;
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
static StaticTree()
|
||||
{
|
||||
Literals = new StaticTree(lengthAndLiteralsTreeCodes, Tree.ExtraLengthBits, InternalConstants.LITERALS + 1, InternalConstants.L_CODES, InternalConstants.MAX_BITS);
|
||||
Distances = new StaticTree(distTreeCodes, Tree.ExtraDistanceBits, 0, InternalConstants.D_CODES, InternalConstants.MAX_BITS);
|
||||
BitLengths = new StaticTree(null, Tree.extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Computes an Adler-32 checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Adler checksum is similar to a CRC checksum, but faster to compute, though less
|
||||
/// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum
|
||||
/// is a required part of the "ZLIB" standard. Applications will almost never need to
|
||||
/// use this class directly.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <exclude/>
|
||||
public sealed class Adler
|
||||
{
|
||||
// largest prime smaller than 65536
|
||||
private static readonly uint BASE = 65521;
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
private static readonly int NMAX = 5552;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is used within ZLIB. You probably don't need to use this directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// To compute an Adler32 checksum on a byte array:
|
||||
/// <code>
|
||||
/// var adler = Adler.Adler32(0, null, 0, 0);
|
||||
/// adler = Adler.Adler32(adler, buffer, index, length);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static uint Adler32(uint adler, byte[] buf, int index, int len)
|
||||
{
|
||||
if (buf == null)
|
||||
return 1;
|
||||
|
||||
uint s1 = (uint)(adler & 0xffff);
|
||||
uint s2 = (uint)((adler >> 16) & 0xffff);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
int k = len < NMAX ? len : NMAX;
|
||||
len -= k;
|
||||
while (k >= 16)
|
||||
{
|
||||
//s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
k -= 16;
|
||||
}
|
||||
if (k != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
s1 += buf[index++];
|
||||
s2 += s1;
|
||||
}
|
||||
while (--k != 0);
|
||||
}
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
return (uint)((s2 << 16) | s1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,556 +0,0 @@
|
||||
// ZlibBaseStream.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2011-August-06 21:22:38>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the ZlibBaseStream class, which is an intnernal
|
||||
// base class for DeflateStream, ZlibStream and GZipStream.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
{
|
||||
|
||||
public enum ZlibStreamFlavor { ZLIB = 1950, DEFLATE = 1951, GZIP = 1952 }
|
||||
|
||||
public class ZlibBaseStream : System.IO.Stream
|
||||
{
|
||||
protected internal ZlibCodec _z = null; // deferred init... new ZlibCodec();
|
||||
|
||||
protected internal StreamMode _streamMode = StreamMode.Undefined;
|
||||
protected internal FlushType _flushMode;
|
||||
protected internal ZlibStreamFlavor _flavor;
|
||||
protected internal CompressionMode _compressionMode;
|
||||
protected internal CompressionLevel _level;
|
||||
protected internal bool _leaveOpen;
|
||||
protected internal byte[] _workingBuffer;
|
||||
protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault;
|
||||
protected internal byte[] _buf1 = new byte[1];
|
||||
|
||||
protected internal System.IO.Stream _stream;
|
||||
protected internal CompressionStrategy Strategy = CompressionStrategy.Default;
|
||||
|
||||
// workitem 7159
|
||||
Compress.Utils.CRC crc;
|
||||
protected internal string _GzipFileName;
|
||||
protected internal string _GzipComment;
|
||||
protected internal DateTime _GzipMtime;
|
||||
protected internal int _gzipHeaderByteCount;
|
||||
|
||||
internal int Crc32 { get { if (crc == null) return 0; return crc.Crc32Result; } }
|
||||
|
||||
public ZlibBaseStream(System.IO.Stream stream,
|
||||
CompressionMode compressionMode,
|
||||
CompressionLevel level,
|
||||
ZlibStreamFlavor flavor,
|
||||
bool leaveOpen)
|
||||
: base()
|
||||
{
|
||||
this._flushMode = FlushType.None;
|
||||
//this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT];
|
||||
this._stream = stream;
|
||||
this._leaveOpen = leaveOpen;
|
||||
this._compressionMode = compressionMode;
|
||||
this._flavor = flavor;
|
||||
this._level = level;
|
||||
// workitem 7159
|
||||
if (flavor == ZlibStreamFlavor.GZIP)
|
||||
{
|
||||
this.crc = new Compress.Utils.CRC();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected internal bool _wantCompress
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this._compressionMode == CompressionMode.Compress);
|
||||
}
|
||||
}
|
||||
|
||||
private ZlibCodec z
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_z == null)
|
||||
{
|
||||
bool wantRfc1950Header = (this._flavor == ZlibStreamFlavor.ZLIB);
|
||||
_z = new ZlibCodec();
|
||||
if (this._compressionMode == CompressionMode.Decompress)
|
||||
{
|
||||
_z.InitializeInflate(wantRfc1950Header);
|
||||
}
|
||||
else
|
||||
{
|
||||
_z.Strategy = Strategy;
|
||||
_z.InitializeDeflate(this._level, wantRfc1950Header);
|
||||
}
|
||||
}
|
||||
return _z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private byte[] workingBuffer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_workingBuffer == null)
|
||||
_workingBuffer = new byte[_bufferSize];
|
||||
return _workingBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void Write(System.Byte[] buffer, int offset, int count)
|
||||
{
|
||||
// workitem 7159
|
||||
// calculate the CRC on the unccompressed data (before writing)
|
||||
if (crc != null)
|
||||
crc.SlurpBlock(buffer, offset, count);
|
||||
|
||||
if (_streamMode == StreamMode.Undefined)
|
||||
_streamMode = StreamMode.Writer;
|
||||
else if (_streamMode != StreamMode.Writer)
|
||||
throw new ZlibException("Cannot Write after Reading.");
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
// first reference of z property will initialize the private var _z
|
||||
z.InputBuffer = buffer;
|
||||
_z.NextIn = offset;
|
||||
_z.AvailableBytesIn = count;
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
_z.OutputBuffer = workingBuffer;
|
||||
_z.NextOut = 0;
|
||||
_z.AvailableBytesOut = _workingBuffer.Length;
|
||||
int rc = (_wantCompress)
|
||||
? _z.Deflate(_flushMode)
|
||||
: _z.Inflate(_flushMode);
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message);
|
||||
|
||||
//if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
|
||||
_stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
|
||||
|
||||
done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
|
||||
|
||||
// If GZIP and de-compress, we're done when 8 bytes remain.
|
||||
if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
|
||||
done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
|
||||
|
||||
}
|
||||
while (!done);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void finish()
|
||||
{
|
||||
if (_z == null) return;
|
||||
|
||||
if (_streamMode == StreamMode.Writer)
|
||||
{
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
_z.OutputBuffer = workingBuffer;
|
||||
_z.NextOut = 0;
|
||||
_z.AvailableBytesOut = _workingBuffer.Length;
|
||||
int rc = (_wantCompress)
|
||||
? _z.Deflate(FlushType.Finish)
|
||||
: _z.Inflate(FlushType.Finish);
|
||||
|
||||
if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
|
||||
{
|
||||
string verb = (_wantCompress ? "de" : "in") + "flating";
|
||||
if (_z.Message == null)
|
||||
throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc));
|
||||
else
|
||||
throw new ZlibException(verb + ": " + _z.Message);
|
||||
}
|
||||
|
||||
if (_workingBuffer.Length - _z.AvailableBytesOut > 0)
|
||||
{
|
||||
_stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut);
|
||||
}
|
||||
|
||||
done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0;
|
||||
// If GZIP and de-compress, we're done when 8 bytes remain.
|
||||
if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress)
|
||||
done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0);
|
||||
|
||||
}
|
||||
while (!done);
|
||||
|
||||
Flush();
|
||||
|
||||
// workitem 7159
|
||||
if (_flavor == ZlibStreamFlavor.GZIP)
|
||||
{
|
||||
if (_wantCompress)
|
||||
{
|
||||
// Emit the GZIP trailer: CRC32 and size mod 2^32
|
||||
int c1 = crc.Crc32Result;
|
||||
_stream.Write(BitConverter.GetBytes(c1), 0, 4);
|
||||
int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF);
|
||||
_stream.Write(BitConverter.GetBytes(c2), 0, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ZlibException("Writing with decompression is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
// workitem 7159
|
||||
else if (_streamMode == StreamMode.Reader)
|
||||
{
|
||||
if (_flavor == ZlibStreamFlavor.GZIP)
|
||||
{
|
||||
if (!_wantCompress)
|
||||
{
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (_z.TotalBytesOut == 0L)
|
||||
return;
|
||||
|
||||
// Read and potentially verify the GZIP trailer:
|
||||
// CRC32 and size mod 2^32
|
||||
byte[] trailer = new byte[8];
|
||||
|
||||
// workitems 8679 & 12554
|
||||
if (_z.AvailableBytesIn < 8)
|
||||
{
|
||||
// Make sure we have read to the end of the stream
|
||||
Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, _z.AvailableBytesIn);
|
||||
int bytesNeeded = 8 - _z.AvailableBytesIn;
|
||||
int bytesRead = _stream.Read(trailer,
|
||||
_z.AvailableBytesIn,
|
||||
bytesNeeded);
|
||||
if (bytesNeeded != bytesRead)
|
||||
{
|
||||
throw new ZlibException(String.Format("Missing or incomplete GZIP trailer. Expected 8 bytes, got {0}.",
|
||||
_z.AvailableBytesIn + bytesRead));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(_z.InputBuffer, _z.NextIn, trailer, 0, trailer.Length);
|
||||
}
|
||||
|
||||
Int32 crc32_expected = BitConverter.ToInt32(trailer, 0);
|
||||
Int32 crc32_actual = crc.Crc32Result;
|
||||
Int32 isize_expected = BitConverter.ToInt32(trailer, 4);
|
||||
Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF);
|
||||
|
||||
if (crc32_actual != crc32_expected)
|
||||
throw new ZlibException(String.Format("Bad CRC32 in GZIP trailer. (actual({0:X8})!=expected({1:X8}))", crc32_actual, crc32_expected));
|
||||
|
||||
if (isize_actual != isize_expected)
|
||||
throw new ZlibException(String.Format("Bad size in GZIP trailer. (actual({0})!=expected({1}))", isize_actual, isize_expected));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ZlibException("Reading with compression is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void end()
|
||||
{
|
||||
if (z == null)
|
||||
return;
|
||||
if (_wantCompress)
|
||||
{
|
||||
_z.EndDeflate();
|
||||
}
|
||||
else
|
||||
{
|
||||
_z.EndInflate();
|
||||
}
|
||||
_z = null;
|
||||
}
|
||||
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (_stream == null) return;
|
||||
try
|
||||
{
|
||||
finish();
|
||||
}
|
||||
finally
|
||||
{
|
||||
end();
|
||||
if (!_leaveOpen) _stream.Close();
|
||||
_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
_stream.Flush();
|
||||
}
|
||||
|
||||
public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return _stream.Seek(offset, origin);
|
||||
}
|
||||
public override void SetLength(System.Int64 value)
|
||||
{
|
||||
_stream.SetLength(value);
|
||||
}
|
||||
|
||||
private bool nomoreinput = false;
|
||||
|
||||
|
||||
|
||||
private string ReadZeroTerminatedString()
|
||||
{
|
||||
var list = new System.Collections.Generic.List<byte>();
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
// workitem 7740
|
||||
int n = _stream.Read(_buf1, 0, 1);
|
||||
if (n != 1)
|
||||
throw new ZlibException("Unexpected EOF reading GZIP header.");
|
||||
else
|
||||
{
|
||||
if (_buf1[0] == 0)
|
||||
done = true;
|
||||
else
|
||||
list.Add(_buf1[0]);
|
||||
}
|
||||
} while (!done);
|
||||
byte[] a = list.ToArray();
|
||||
return iso8859dash1.GetString(a, 0, a.Length);
|
||||
}
|
||||
internal static readonly System.Text.Encoding iso8859dash1 = System.Text.Encoding.GetEncoding("iso-8859-1");
|
||||
internal static readonly System.DateTime _unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
|
||||
private int _ReadAndValidateGzipHeader()
|
||||
{
|
||||
int totalBytesRead = 0;
|
||||
// read the header on the first read
|
||||
byte[] header = new byte[10];
|
||||
int n = _stream.Read(header, 0, header.Length);
|
||||
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
if (n != 10)
|
||||
throw new ZlibException("Not a valid GZIP stream.");
|
||||
|
||||
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
|
||||
throw new ZlibException("Bad GZIP header.");
|
||||
|
||||
Int32 timet = BitConverter.ToInt32(header, 4);
|
||||
_GzipMtime = _unixEpoch.AddSeconds(timet);
|
||||
totalBytesRead += n;
|
||||
if ((header[3] & 0x04) == 0x04)
|
||||
{
|
||||
// read and discard extra field
|
||||
n = _stream.Read(header, 0, 2); // 2-byte length field
|
||||
totalBytesRead += n;
|
||||
|
||||
Int16 extraLength = (Int16)(header[0] + header[1] * 256);
|
||||
byte[] extra = new byte[extraLength];
|
||||
n = _stream.Read(extra, 0, extra.Length);
|
||||
if (n != extraLength)
|
||||
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
|
||||
totalBytesRead += n;
|
||||
}
|
||||
if ((header[3] & 0x08) == 0x08)
|
||||
_GzipFileName = ReadZeroTerminatedString();
|
||||
if ((header[3] & 0x10) == 0x010)
|
||||
_GzipComment = ReadZeroTerminatedString();
|
||||
if ((header[3] & 0x02) == 0x02)
|
||||
Read(_buf1, 0, 1); // CRC16, ignore
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count)
|
||||
{
|
||||
// According to MS documentation, any implementation of the IO.Stream.Read function must:
|
||||
// (a) throw an exception if offset & count reference an invalid part of the buffer,
|
||||
// or if count < 0, or if buffer is null
|
||||
// (b) return 0 only upon EOF, or if count = 0
|
||||
// (c) if not EOF, then return at least 1 byte, up to <count> bytes
|
||||
|
||||
if (_streamMode == StreamMode.Undefined)
|
||||
{
|
||||
if (!this._stream.CanRead) throw new ZlibException("The stream is not readable.");
|
||||
// for the first read, set up some controls.
|
||||
_streamMode = StreamMode.Reader;
|
||||
// (The first reference to _z goes through the private accessor which
|
||||
// may initialize it.)
|
||||
z.AvailableBytesIn = 0;
|
||||
if (_flavor == ZlibStreamFlavor.GZIP)
|
||||
{
|
||||
_gzipHeaderByteCount = _ReadAndValidateGzipHeader();
|
||||
// workitem 8501: handle edge case (decompress empty stream)
|
||||
if (_gzipHeaderByteCount == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_streamMode != StreamMode.Reader)
|
||||
throw new ZlibException("Cannot Read after Writing.");
|
||||
|
||||
if (count == 0) return 0;
|
||||
if (nomoreinput && _wantCompress) return 0; // workitem 8557
|
||||
if (buffer == null) throw new ArgumentNullException("buffer");
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("count");
|
||||
if (offset < buffer.GetLowerBound(0)) throw new ArgumentOutOfRangeException("offset");
|
||||
if ((offset + count) > buffer.GetLength(0)) throw new ArgumentOutOfRangeException("count");
|
||||
|
||||
int rc = 0;
|
||||
|
||||
// set up the output of the deflate/inflate codec:
|
||||
_z.OutputBuffer = buffer;
|
||||
_z.NextOut = offset;
|
||||
_z.AvailableBytesOut = count;
|
||||
|
||||
// This is necessary in case _workingBuffer has been resized. (new byte[])
|
||||
// (The first reference to _workingBuffer goes through the private accessor which
|
||||
// may initialize it.)
|
||||
_z.InputBuffer = workingBuffer;
|
||||
|
||||
do
|
||||
{
|
||||
// need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any.
|
||||
if ((_z.AvailableBytesIn == 0) && (!nomoreinput))
|
||||
{
|
||||
// No data available, so try to Read data from the captive stream.
|
||||
_z.NextIn = 0;
|
||||
_z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length);
|
||||
if (_z.AvailableBytesIn == 0)
|
||||
nomoreinput = true;
|
||||
|
||||
}
|
||||
// we have data in InputBuffer; now compress or decompress as appropriate
|
||||
rc = (_wantCompress)
|
||||
? _z.Deflate(_flushMode)
|
||||
: _z.Inflate(_flushMode);
|
||||
|
||||
if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR))
|
||||
return 0;
|
||||
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
throw new ZlibException(String.Format("{0}flating: rc={1} msg={2}", (_wantCompress ? "de" : "in"), rc, _z.Message));
|
||||
|
||||
if ((nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count))
|
||||
break; // nothing more to read
|
||||
}
|
||||
//while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK);
|
||||
while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK);
|
||||
|
||||
|
||||
// workitem 8557
|
||||
// is there more room in output?
|
||||
if (_z.AvailableBytesOut > 0)
|
||||
{
|
||||
if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0)
|
||||
{
|
||||
// deferred
|
||||
}
|
||||
|
||||
// are we completely done reading?
|
||||
if (nomoreinput)
|
||||
{
|
||||
// and in compression?
|
||||
if (_wantCompress)
|
||||
{
|
||||
// no more input data available; therefore we flush to
|
||||
// try to complete the read
|
||||
rc = _z.Deflate(FlushType.Finish);
|
||||
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rc = (count - _z.AvailableBytesOut);
|
||||
|
||||
// calculate CRC after reading
|
||||
if (crc != null)
|
||||
crc.SlurpBlock(buffer, offset, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override System.Boolean CanRead
|
||||
{
|
||||
get { return this._stream.CanRead; }
|
||||
}
|
||||
|
||||
public override System.Boolean CanSeek
|
||||
{
|
||||
get { return this._stream.CanSeek; }
|
||||
}
|
||||
|
||||
public override System.Boolean CanWrite
|
||||
{
|
||||
get { return this._stream.CanWrite; }
|
||||
}
|
||||
|
||||
public override System.Int64 Length
|
||||
{
|
||||
get { return _stream.Length; }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public enum StreamMode
|
||||
{
|
||||
Writer,
|
||||
Reader,
|
||||
Undefined,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,718 +0,0 @@
|
||||
// ZlibCodec.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-November-03 15:40:51>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines a Codec for ZLIB compression and
|
||||
// decompression. This code extends code that was based the jzlib
|
||||
// implementation of zlib, but this code is completely novel. The codec
|
||||
// class is new, and encapsulates some behaviors that are new, and some
|
||||
// that were present in other classes in the jzlib code base. In
|
||||
// keeping with the license for jzlib, the copyright to the jzlib code
|
||||
// is included below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Interop = System.Runtime.InteropServices;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951).
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// This class compresses and decompresses data according to the Deflate algorithm
|
||||
/// and optionally, the ZLIB format, as documented in <see
|
||||
/// href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950 - ZLIB</see> and <see
|
||||
/// href="http://www.ietf.org/rfc/rfc1951.txt">RFC 1951 - DEFLATE</see>.
|
||||
/// </remarks>
|
||||
[Guid("ebc25cf6-9120-4283-b972-0e5520d0000D")]
|
||||
[Interop.ComVisible(true)]
|
||||
#if !NETCF
|
||||
[Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
|
||||
#endif
|
||||
sealed public class ZlibCodec
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer from which data is taken.
|
||||
/// </summary>
|
||||
public byte[] InputBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// An index into the InputBuffer array, indicating where to start reading.
|
||||
/// </summary>
|
||||
public int NextIn;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes available in the InputBuffer, starting at NextIn.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call.
|
||||
/// The class will update this number as calls to Inflate/Deflate are made.
|
||||
/// </remarks>
|
||||
public int AvailableBytesIn;
|
||||
|
||||
/// <summary>
|
||||
/// Total number of bytes read so far, through all calls to Inflate()/Deflate().
|
||||
/// </summary>
|
||||
public long TotalBytesIn;
|
||||
|
||||
/// <summary>
|
||||
/// Buffer to store output data.
|
||||
/// </summary>
|
||||
public byte[] OutputBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// An index into the OutputBuffer array, indicating where to start writing.
|
||||
/// </summary>
|
||||
public int NextOut;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes available in the OutputBuffer, starting at NextOut.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call.
|
||||
/// The class will update this number as calls to Inflate/Deflate are made.
|
||||
/// </remarks>
|
||||
public int AvailableBytesOut;
|
||||
|
||||
/// <summary>
|
||||
/// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate().
|
||||
/// </summary>
|
||||
public long TotalBytesOut;
|
||||
|
||||
/// <summary>
|
||||
/// used for diagnostics, when something goes wrong!
|
||||
/// </summary>
|
||||
public System.String Message;
|
||||
|
||||
internal DeflateManager dstate;
|
||||
internal InflateManager istate;
|
||||
|
||||
internal uint _Adler32;
|
||||
|
||||
/// <summary>
|
||||
/// The compression level to use in this codec. Useful only in compression mode.
|
||||
/// </summary>
|
||||
public CompressionLevel CompressLevel = CompressionLevel.Default;
|
||||
|
||||
/// <summary>
|
||||
/// The number of Window Bits to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This gauges the size of the sliding window, and hence the
|
||||
/// compression effectiveness as well as memory consumption. It's best to just leave this
|
||||
/// setting alone if you don't know what it is. The maximum value is 15 bits, which implies
|
||||
/// a 32k window.
|
||||
/// </remarks>
|
||||
public int WindowBits = ZlibConstants.WindowBitsDefault;
|
||||
|
||||
/// <summary>
|
||||
/// The compression strategy to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only effective in compression. The theory offered by ZLIB is that different
|
||||
/// strategies could potentially produce significant differences in compression behavior
|
||||
/// for different data sets. Unfortunately I don't have any good recommendations for how
|
||||
/// to set it differently. When I tested changing the strategy I got minimally different
|
||||
/// compression performance. It's best to leave this property alone if you don't have a
|
||||
/// good feel for it. Or, you may want to produce a test harness that runs through the
|
||||
/// different strategy options and evaluates them on different file types. If you do that,
|
||||
/// let me know your results.
|
||||
/// </remarks>
|
||||
public CompressionStrategy Strategy = CompressionStrategy.Default;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this.
|
||||
/// </summary>
|
||||
public int Adler32 { get { return (int)_Adler32; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a ZlibCodec.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you use this default constructor, you will later have to explicitly call
|
||||
/// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress
|
||||
/// or decompress.
|
||||
/// </remarks>
|
||||
public ZlibCodec() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a ZlibCodec that either compresses or decompresses.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// Indicates whether the codec should compress (deflate) or decompress (inflate).
|
||||
/// </param>
|
||||
public ZlibCodec(CompressionMode mode)
|
||||
{
|
||||
if (mode == CompressionMode.Compress)
|
||||
{
|
||||
int rc = InitializeDeflate();
|
||||
if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for deflate.");
|
||||
}
|
||||
else if (mode == CompressionMode.Decompress)
|
||||
{
|
||||
int rc = InitializeInflate();
|
||||
if (rc != ZlibConstants.Z_OK) throw new ZlibException("Cannot initialize for inflate.");
|
||||
}
|
||||
else throw new ZlibException("Invalid ZlibStreamFlavor.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the inflation state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is not necessary to call this before using the ZlibCodec to inflate data;
|
||||
/// It is implicitly called when you call the constructor.
|
||||
/// </remarks>
|
||||
/// <returns>Z_OK if everything goes well.</returns>
|
||||
public int InitializeInflate()
|
||||
{
|
||||
return InitializeInflate(this.WindowBits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the inflation state with an explicit flag to
|
||||
/// govern the handling of RFC1950 header bytes.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// By default, the ZLIB header defined in <see
|
||||
/// href="http://www.ietf.org/rfc/rfc1950.txt">RFC 1950</see> is expected. If
|
||||
/// you want to read a zlib stream you should specify true for
|
||||
/// expectRfc1950Header. If you have a deflate stream, you will want to specify
|
||||
/// false. It is only necessary to invoke this initializer explicitly if you
|
||||
/// want to specify false.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="expectRfc1950Header">whether to expect an RFC1950 header byte
|
||||
/// pair when reading the stream of data to be inflated.</param>
|
||||
///
|
||||
/// <returns>Z_OK if everything goes well.</returns>
|
||||
public int InitializeInflate(bool expectRfc1950Header)
|
||||
{
|
||||
return InitializeInflate(this.WindowBits, expectRfc1950Header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the ZlibCodec for inflation, with the specified number of window bits.
|
||||
/// </summary>
|
||||
/// <param name="windowBits">The number of window bits to use. If you need to ask what that is,
|
||||
/// then you shouldn't be calling this initializer.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int InitializeInflate(int windowBits)
|
||||
{
|
||||
this.WindowBits = windowBits;
|
||||
return InitializeInflate(windowBits, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the inflation state with an explicit flag to govern the handling of
|
||||
/// RFC1950 header bytes.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// If you want to read a zlib stream you should specify true for
|
||||
/// expectRfc1950Header. In this case, the library will expect to find a ZLIB
|
||||
/// header, as defined in <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
|
||||
/// 1950</see>, in the compressed stream. If you will be reading a DEFLATE or
|
||||
/// GZIP stream, which does not have such a header, you will want to specify
|
||||
/// false.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="expectRfc1950Header">whether to expect an RFC1950 header byte pair when reading
|
||||
/// the stream of data to be inflated.</param>
|
||||
/// <param name="windowBits">The number of window bits to use. If you need to ask what that is,
|
||||
/// then you shouldn't be calling this initializer.</param>
|
||||
/// <returns>Z_OK if everything goes well.</returns>
|
||||
public int InitializeInflate(int windowBits, bool expectRfc1950Header)
|
||||
{
|
||||
this.WindowBits = windowBits;
|
||||
if (dstate != null) throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate().");
|
||||
istate = new InflateManager(expectRfc1950Header);
|
||||
return istate.Initialize(this, windowBits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inflate the data in the InputBuffer, placing the result in the OutputBuffer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and
|
||||
/// AvailableBytesOut before calling this method.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// private void InflateBuffer()
|
||||
/// {
|
||||
/// int bufferSize = 1024;
|
||||
/// byte[] buffer = new byte[bufferSize];
|
||||
/// ZlibCodec decompressor = new ZlibCodec();
|
||||
///
|
||||
/// Console.WriteLine("\n============================================");
|
||||
/// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length);
|
||||
/// MemoryStream ms = new MemoryStream(DecompressedBytes);
|
||||
///
|
||||
/// int rc = decompressor.InitializeInflate();
|
||||
///
|
||||
/// decompressor.InputBuffer = CompressedBytes;
|
||||
/// decompressor.NextIn = 0;
|
||||
/// decompressor.AvailableBytesIn = CompressedBytes.Length;
|
||||
///
|
||||
/// decompressor.OutputBuffer = buffer;
|
||||
///
|
||||
/// // pass 1: inflate
|
||||
/// do
|
||||
/// {
|
||||
/// decompressor.NextOut = 0;
|
||||
/// decompressor.AvailableBytesOut = buffer.Length;
|
||||
/// rc = decompressor.Inflate(FlushType.None);
|
||||
///
|
||||
/// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
/// throw new Exception("inflating: " + decompressor.Message);
|
||||
///
|
||||
/// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut);
|
||||
/// }
|
||||
/// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0);
|
||||
///
|
||||
/// // pass 2: finish and flush
|
||||
/// do
|
||||
/// {
|
||||
/// decompressor.NextOut = 0;
|
||||
/// decompressor.AvailableBytesOut = buffer.Length;
|
||||
/// rc = decompressor.Inflate(FlushType.Finish);
|
||||
///
|
||||
/// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
|
||||
/// throw new Exception("inflating: " + decompressor.Message);
|
||||
///
|
||||
/// if (buffer.Length - decompressor.AvailableBytesOut > 0)
|
||||
/// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut);
|
||||
/// }
|
||||
/// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0);
|
||||
///
|
||||
/// decompressor.EndInflate();
|
||||
/// }
|
||||
///
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="flush">The flush to use when inflating.</param>
|
||||
/// <returns>Z_OK if everything goes well.</returns>
|
||||
public int Inflate(FlushType flush)
|
||||
{
|
||||
if (istate == null)
|
||||
throw new ZlibException("No Inflate State!");
|
||||
return istate.Inflate(flush);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ends an inflation session.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Call this after successively calling Inflate(). This will cause all buffers to be flushed.
|
||||
/// After calling this you cannot call Inflate() without a intervening call to one of the
|
||||
/// InitializeInflate() overloads.
|
||||
/// </remarks>
|
||||
/// <returns>Z_OK if everything goes well.</returns>
|
||||
public int EndInflate()
|
||||
{
|
||||
if (istate == null)
|
||||
throw new ZlibException("No Inflate State!");
|
||||
int ret = istate.End();
|
||||
istate = null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// I don't know what this does!
|
||||
/// </summary>
|
||||
/// <returns>Z_OK if everything goes well.</returns>
|
||||
public int SyncInflate()
|
||||
{
|
||||
if (istate == null)
|
||||
throw new ZlibException("No Inflate State!");
|
||||
return istate.Sync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the ZlibCodec for deflation operation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The codec will use the MAX window bits and the default level of compression.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// int bufferSize = 40000;
|
||||
/// byte[] CompressedBytes = new byte[bufferSize];
|
||||
/// byte[] DecompressedBytes = new byte[bufferSize];
|
||||
///
|
||||
/// ZlibCodec compressor = new ZlibCodec();
|
||||
///
|
||||
/// compressor.InitializeDeflate(CompressionLevel.Default);
|
||||
///
|
||||
/// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress);
|
||||
/// compressor.NextIn = 0;
|
||||
/// compressor.AvailableBytesIn = compressor.InputBuffer.Length;
|
||||
///
|
||||
/// compressor.OutputBuffer = CompressedBytes;
|
||||
/// compressor.NextOut = 0;
|
||||
/// compressor.AvailableBytesOut = CompressedBytes.Length;
|
||||
///
|
||||
/// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize)
|
||||
/// {
|
||||
/// compressor.Deflate(FlushType.None);
|
||||
/// }
|
||||
///
|
||||
/// while (true)
|
||||
/// {
|
||||
/// int rc= compressor.Deflate(FlushType.Finish);
|
||||
/// if (rc == ZlibConstants.Z_STREAM_END) break;
|
||||
/// }
|
||||
///
|
||||
/// compressor.EndDeflate();
|
||||
///
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <returns>Z_OK if all goes well. You generally don't need to check the return code.</returns>
|
||||
public int InitializeDeflate()
|
||||
{
|
||||
return _InternalInitializeDeflate(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The codec will use the maximum window bits (15) and the specified
|
||||
/// CompressionLevel. It will emit a ZLIB stream as it compresses.
|
||||
/// </remarks>
|
||||
/// <param name="level">The compression level for the codec.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int InitializeDeflate(CompressionLevel level)
|
||||
{
|
||||
this.CompressLevel = level;
|
||||
return _InternalInitializeDeflate(true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel,
|
||||
/// and the explicit flag governing whether to emit an RFC1950 header byte pair.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The codec will use the maximum window bits (15) and the specified CompressionLevel.
|
||||
/// If you want to generate a zlib stream, you should specify true for
|
||||
/// wantRfc1950Header. In this case, the library will emit a ZLIB
|
||||
/// header, as defined in <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
|
||||
/// 1950</see>, in the compressed stream.
|
||||
/// </remarks>
|
||||
/// <param name="level">The compression level for the codec.</param>
|
||||
/// <param name="wantRfc1950Header">whether to emit an initial RFC1950 byte pair in the compressed stream.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header)
|
||||
{
|
||||
this.CompressLevel = level;
|
||||
return _InternalInitializeDeflate(wantRfc1950Header);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel,
|
||||
/// and the specified number of window bits.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The codec will use the specified number of window bits and the specified CompressionLevel.
|
||||
/// </remarks>
|
||||
/// <param name="level">The compression level for the codec.</param>
|
||||
/// <param name="bits">the number of window bits to use. If you don't know what this means, don't use this method.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int InitializeDeflate(CompressionLevel level, int bits)
|
||||
{
|
||||
this.CompressLevel = level;
|
||||
this.WindowBits = bits;
|
||||
return _InternalInitializeDeflate(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the ZlibCodec for deflation operation, using the specified
|
||||
/// CompressionLevel, the specified number of window bits, and the explicit flag
|
||||
/// governing whether to emit an RFC1950 header byte pair.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="level">The compression level for the codec.</param>
|
||||
/// <param name="wantRfc1950Header">whether to emit an initial RFC1950 byte pair in the compressed stream.</param>
|
||||
/// <param name="bits">the number of window bits to use. If you don't know what this means, don't use this method.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header)
|
||||
{
|
||||
this.CompressLevel = level;
|
||||
this.WindowBits = bits;
|
||||
return _InternalInitializeDeflate(wantRfc1950Header);
|
||||
}
|
||||
|
||||
private int _InternalInitializeDeflate(bool wantRfc1950Header)
|
||||
{
|
||||
if (istate != null) throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate().");
|
||||
dstate = new DeflateManager();
|
||||
dstate.WantRfc1950HeaderBytes = wantRfc1950Header;
|
||||
|
||||
return dstate.Initialize(this, this.CompressLevel, this.WindowBits, this.Strategy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deflate one batch of data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You must have set InputBuffer and OutputBuffer before calling this method.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// private void DeflateBuffer(CompressionLevel level)
|
||||
/// {
|
||||
/// int bufferSize = 1024;
|
||||
/// byte[] buffer = new byte[bufferSize];
|
||||
/// ZlibCodec compressor = new ZlibCodec();
|
||||
///
|
||||
/// Console.WriteLine("\n============================================");
|
||||
/// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length);
|
||||
/// MemoryStream ms = new MemoryStream();
|
||||
///
|
||||
/// int rc = compressor.InitializeDeflate(level);
|
||||
///
|
||||
/// compressor.InputBuffer = UncompressedBytes;
|
||||
/// compressor.NextIn = 0;
|
||||
/// compressor.AvailableBytesIn = UncompressedBytes.Length;
|
||||
///
|
||||
/// compressor.OutputBuffer = buffer;
|
||||
///
|
||||
/// // pass 1: deflate
|
||||
/// do
|
||||
/// {
|
||||
/// compressor.NextOut = 0;
|
||||
/// compressor.AvailableBytesOut = buffer.Length;
|
||||
/// rc = compressor.Deflate(FlushType.None);
|
||||
///
|
||||
/// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
/// throw new Exception("deflating: " + compressor.Message);
|
||||
///
|
||||
/// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut);
|
||||
/// }
|
||||
/// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0);
|
||||
///
|
||||
/// // pass 2: finish and flush
|
||||
/// do
|
||||
/// {
|
||||
/// compressor.NextOut = 0;
|
||||
/// compressor.AvailableBytesOut = buffer.Length;
|
||||
/// rc = compressor.Deflate(FlushType.Finish);
|
||||
///
|
||||
/// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK)
|
||||
/// throw new Exception("deflating: " + compressor.Message);
|
||||
///
|
||||
/// if (buffer.Length - compressor.AvailableBytesOut > 0)
|
||||
/// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut);
|
||||
/// }
|
||||
/// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0);
|
||||
///
|
||||
/// compressor.EndDeflate();
|
||||
///
|
||||
/// ms.Seek(0, SeekOrigin.Begin);
|
||||
/// CompressedBytes = new byte[compressor.TotalBytesOut];
|
||||
/// ms.Read(CompressedBytes, 0, CompressedBytes.Length);
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="flush">whether to flush all data as you deflate. Generally you will want to
|
||||
/// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to
|
||||
/// flush everything.
|
||||
/// </param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int Deflate(FlushType flush)
|
||||
{
|
||||
if (dstate == null)
|
||||
throw new ZlibException("No Deflate State!");
|
||||
return dstate.Deflate(flush);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End a deflation session.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Call this after making a series of one or more calls to Deflate(). All buffers are flushed.
|
||||
/// </remarks>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int EndDeflate()
|
||||
{
|
||||
if (dstate == null)
|
||||
throw new ZlibException("No Deflate State!");
|
||||
// TODO: dinoch Tue, 03 Nov 2009 15:39 (test this)
|
||||
//int ret = dstate.End();
|
||||
dstate = null;
|
||||
return ZlibConstants.Z_OK; //ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset a codec for another deflation session.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Call this to reset the deflation state. For example if a thread is deflating
|
||||
/// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first
|
||||
/// block and before the next Deflate(None) of the second block.
|
||||
/// </remarks>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public void ResetDeflate()
|
||||
{
|
||||
if (dstate == null)
|
||||
throw new ZlibException("No Deflate State!");
|
||||
dstate.Reset();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set the CompressionStrategy and CompressionLevel for a deflation session.
|
||||
/// </summary>
|
||||
/// <param name="level">the level of compression to use.</param>
|
||||
/// <param name="strategy">the strategy to use for compression.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy)
|
||||
{
|
||||
if (dstate == null)
|
||||
throw new ZlibException("No Deflate State!");
|
||||
return dstate.SetParams(level, strategy);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set the dictionary to be used for either Inflation or Deflation.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary bytes to use.</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int SetDictionary(byte[] dictionary)
|
||||
{
|
||||
if (istate != null)
|
||||
return istate.SetDictionary(dictionary);
|
||||
|
||||
if (dstate != null)
|
||||
return dstate.SetDictionary(dictionary);
|
||||
|
||||
throw new ZlibException("No Inflate or Deflate state!");
|
||||
}
|
||||
|
||||
// Flush as much pending output as possible. All deflate() output goes
|
||||
// through this function so some applications may wish to modify it
|
||||
// to avoid allocating a large strm->next_out buffer and copying into it.
|
||||
// (See also read_buf()).
|
||||
internal void flush_pending()
|
||||
{
|
||||
int len = dstate.pendingCount;
|
||||
|
||||
if (len > AvailableBytesOut)
|
||||
len = AvailableBytesOut;
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
if (dstate.pending.Length <= dstate.nextPending ||
|
||||
OutputBuffer.Length <= NextOut ||
|
||||
dstate.pending.Length < (dstate.nextPending + len) ||
|
||||
OutputBuffer.Length < (NextOut + len))
|
||||
{
|
||||
throw new ZlibException(String.Format("Invalid State. (pending.Length={0}, pendingCount={1})",
|
||||
dstate.pending.Length, dstate.pendingCount));
|
||||
}
|
||||
|
||||
Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len);
|
||||
|
||||
NextOut += len;
|
||||
dstate.nextPending += len;
|
||||
TotalBytesOut += len;
|
||||
AvailableBytesOut -= len;
|
||||
dstate.pendingCount -= len;
|
||||
if (dstate.pendingCount == 0)
|
||||
{
|
||||
dstate.nextPending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read a new buffer from the current input stream, update the adler32
|
||||
// and total number of bytes read. All deflate() input goes through
|
||||
// this function so some applications may wish to modify it to avoid
|
||||
// allocating a large strm->next_in buffer and copying from it.
|
||||
// (See also flush_pending()).
|
||||
internal int read_buf(byte[] buf, int start, int size)
|
||||
{
|
||||
int len = AvailableBytesIn;
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
AvailableBytesIn -= len;
|
||||
|
||||
if (dstate.WantRfc1950HeaderBytes)
|
||||
{
|
||||
_Adler32 = Adler.Adler32(_Adler32, InputBuffer, NextIn, len);
|
||||
}
|
||||
Array.Copy(InputBuffer, NextIn, buf, start, len);
|
||||
NextIn += len;
|
||||
TotalBytesIn += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// ZlibConstants.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-November-03 18:50:19>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines constants used by the zlib class library. This
|
||||
// code is derived from the jzlib implementation of zlib, but
|
||||
// significantly modified. In keeping with the license for jzlib, the
|
||||
// copyright to that code is included here.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A bunch of constants used in the Zlib interface.
|
||||
/// </summary>
|
||||
public static class ZlibConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum number of window bits for the Deflate algorithm.
|
||||
/// </summary>
|
||||
public const int WindowBitsMax = 15; // 32K LZ77 window
|
||||
|
||||
/// <summary>
|
||||
/// The default number of window bits for the Deflate algorithm.
|
||||
/// </summary>
|
||||
public const int WindowBitsDefault = WindowBitsMax;
|
||||
|
||||
/// <summary>
|
||||
/// indicates everything is A-OK
|
||||
/// </summary>
|
||||
public const int Z_OK = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the last operation reached the end of the stream.
|
||||
/// </summary>
|
||||
public const int Z_STREAM_END = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The operation ended in need of a dictionary.
|
||||
/// </summary>
|
||||
public const int Z_NEED_DICT = 2;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the stream - not enough data, not open and readable, etc.
|
||||
/// </summary>
|
||||
public const int Z_STREAM_ERROR = -2;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the data - not enough data, bad data, etc.
|
||||
/// </summary>
|
||||
public const int Z_DATA_ERROR = -3;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the working buffer.
|
||||
/// </summary>
|
||||
public const int Z_BUF_ERROR = -5;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes.
|
||||
/// </summary>
|
||||
#if NETCF
|
||||
public const int WorkingBufferSizeDefault = 8192;
|
||||
#else
|
||||
public const int WorkingBufferSizeDefault = 16384;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes.
|
||||
/// </summary>
|
||||
public const int WorkingBufferSizeMin = 1024;
|
||||
}
|
||||
|
||||
}
|
||||
1957
SabreTools.Library/External/Compress/ZipFile/zipFile.cs
vendored
1957
SabreTools.Library/External/Compress/ZipFile/zipFile.cs
vendored
File diff suppressed because it is too large
Load Diff
458
SabreTools.Library/External/Compress/gZip/gZip.cs
vendored
458
SabreTools.Library/External/Compress/gZip/gZip.cs
vendored
@@ -1,458 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.ZipFile.ZLib;
|
||||
using Directory = RVIO.Directory;
|
||||
using FileInfo = RVIO.FileInfo;
|
||||
using FileStream = RVIO.FileStream;
|
||||
using Path = RVIO.Path;
|
||||
|
||||
|
||||
namespace Compress.gZip
|
||||
{
|
||||
public class gZip : ICompress
|
||||
{
|
||||
private FileInfo _zipFileInfo;
|
||||
private Stream _zipFs;
|
||||
private Stream _compressionStream;
|
||||
|
||||
public byte[] CRC { get; private set; }
|
||||
public ulong UnCompressedSize { get; private set; }
|
||||
public ulong CompressedSize { get; private set; }
|
||||
|
||||
private long headerStartPos;
|
||||
private long dataStartPos;
|
||||
|
||||
public int LocalFilesCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public string Filename(int i)
|
||||
{
|
||||
return Path.GetFileName(ZipFilename);
|
||||
}
|
||||
|
||||
public ulong? LocalHeader(int i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ulong UncompressedSize(int i)
|
||||
{
|
||||
return UnCompressedSize;
|
||||
}
|
||||
|
||||
public byte[] CRC32(int i)
|
||||
{
|
||||
return CRC;
|
||||
}
|
||||
|
||||
public bool IsDirectory(int i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public ZipOpenType ZipOpen { get; private set; }
|
||||
|
||||
public ZipReturn ZipFileOpen(string newFilename, long timestamp = -1, bool readHeaders = true)
|
||||
{
|
||||
ZipFileClose();
|
||||
ZipStatus = ZipStatus.None;
|
||||
|
||||
try
|
||||
{
|
||||
if (!RVIO.File.Exists(newFilename))
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorFileNotFound;
|
||||
}
|
||||
_zipFileInfo = new FileInfo(newFilename);
|
||||
if (timestamp != -1 && _zipFileInfo.LastWriteTime != timestamp)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorTimeStamp;
|
||||
}
|
||||
int errorCode = FileStream.OpenFileRead(newFilename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
if (errorCode == 32)
|
||||
{
|
||||
return ZipReturn.ZipFileLocked;
|
||||
}
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipFileNameToLong;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
|
||||
if (!readHeaders)
|
||||
{
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpen(Stream inStream)
|
||||
{
|
||||
ZipFileClose();
|
||||
ZipStatus = ZipStatus.None;
|
||||
_zipFileInfo = null;
|
||||
_zipFs = inStream;
|
||||
|
||||
ZipOpen = ZipOpenType.OpenRead;
|
||||
return ZipFileReadHeaders();
|
||||
}
|
||||
|
||||
private ZipReturn ZipFileReadHeaders()
|
||||
{
|
||||
using (BinaryReader zipBr = new BinaryReader(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
|
||||
byte ID1 = zipBr.ReadByte();
|
||||
byte ID2 = zipBr.ReadByte();
|
||||
|
||||
if ((ID1 != 0x1f) || (ID2 != 0x8b))
|
||||
{
|
||||
_zipFs.Close();
|
||||
return ZipReturn.ZipSignatureError;
|
||||
}
|
||||
|
||||
byte CM = zipBr.ReadByte();
|
||||
if (CM != 8)
|
||||
{
|
||||
_zipFs.Close();
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
byte FLG = zipBr.ReadByte();
|
||||
|
||||
|
||||
uint MTime = zipBr.ReadUInt32();
|
||||
byte XFL = zipBr.ReadByte();
|
||||
byte OS = zipBr.ReadByte();
|
||||
|
||||
ExtraData = null;
|
||||
//if FLG.FEXTRA set
|
||||
if ((FLG & 0x4) == 0x4)
|
||||
{
|
||||
int XLen = zipBr.ReadInt16();
|
||||
ExtraData = zipBr.ReadBytes(XLen);
|
||||
|
||||
switch (XLen)
|
||||
{
|
||||
case 12:
|
||||
CRC = new byte[4];
|
||||
Array.Copy(ExtraData, 0, CRC, 0, 4);
|
||||
UnCompressedSize = BitConverter.ToUInt64(ExtraData, 4);
|
||||
break;
|
||||
case 28:
|
||||
CRC = new byte[4];
|
||||
Array.Copy(ExtraData, 16, CRC, 0, 4);
|
||||
UnCompressedSize = BitConverter.ToUInt64(ExtraData, 20);
|
||||
break;
|
||||
case 77:
|
||||
CRC = new byte[4];
|
||||
Array.Copy(ExtraData, 16, CRC, 0, 4);
|
||||
UnCompressedSize = BitConverter.ToUInt64(ExtraData, 20);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if FLG.FNAME set
|
||||
if ((FLG & 0x8) == 0x8)
|
||||
{
|
||||
int XLen = zipBr.ReadInt16();
|
||||
byte[] bytes = zipBr.ReadBytes(XLen);
|
||||
}
|
||||
|
||||
//if FLG.FComment set
|
||||
if ((FLG & 0x10) == 0x10)
|
||||
{
|
||||
int XLen = zipBr.ReadInt16();
|
||||
byte[] bytes = zipBr.ReadBytes(XLen);
|
||||
}
|
||||
|
||||
//if FLG.FHCRC set
|
||||
if ((FLG & 0x2) == 0x2)
|
||||
{
|
||||
uint crc16 = zipBr.ReadUInt16();
|
||||
}
|
||||
|
||||
CompressedSize = (ulong)(_zipFs.Length - _zipFs.Position) - 8;
|
||||
|
||||
dataStartPos = _zipFs.Position;
|
||||
|
||||
_zipFs.Position = _zipFs.Length - 8;
|
||||
byte[] gzcrc = zipBr.ReadBytes(4);
|
||||
uint gzLength = zipBr.ReadUInt32();
|
||||
|
||||
if (CRC != null)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (gzcrc[3 - i] == CRC[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_zipFs.Close();
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CRC = new[] { gzcrc[3], gzcrc[2], gzcrc[1], gzcrc[0] };
|
||||
}
|
||||
|
||||
if (UnCompressedSize != 0)
|
||||
{
|
||||
if (gzLength != (UnCompressedSize & 0xffffffff))
|
||||
{
|
||||
_zipFs.Close();
|
||||
return ZipReturn.ZipDecodeError;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
}
|
||||
|
||||
public void ZipFileClose()
|
||||
{
|
||||
if (ZipOpen == ZipOpenType.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZipOpen == ZipOpenType.OpenRead)
|
||||
{
|
||||
if (_zipFs != null)
|
||||
{
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong streamSize)
|
||||
{
|
||||
ZipFileCloseReadStream();
|
||||
|
||||
_zipFs.Position = dataStartPos;
|
||||
|
||||
_compressionStream = new ZlibBaseStream(_zipFs, CompressionMode.Decompress, CompressionLevel.Default, ZlibStreamFlavor.DEFLATE, true);
|
||||
stream = _compressionStream;
|
||||
streamSize = UnCompressedSize;
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public bool hasAltFileHeader;
|
||||
|
||||
|
||||
public byte[] ExtraData;
|
||||
|
||||
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong unCompressedSize, ushort compressionMethod, uint? datetime, out Stream stream)
|
||||
{
|
||||
using (BinaryWriter zipBw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
UnCompressedSize = unCompressedSize;
|
||||
|
||||
zipBw.Write((byte)0x1f); // ID1 = 0x1f
|
||||
zipBw.Write((byte)0x8b); // ID2 = 0x8b
|
||||
zipBw.Write((byte)0x08); // CM = 0x08
|
||||
zipBw.Write((byte)0x04); // FLG = 0x04
|
||||
zipBw.Write((uint)0); // MTime = 0
|
||||
zipBw.Write((byte)0x00); // XFL = 0x00
|
||||
zipBw.Write((byte)0xff); // OS = 0x00
|
||||
|
||||
if (ExtraData == null)
|
||||
{
|
||||
zipBw.Write((short)12);
|
||||
headerStartPos = zipBw.BaseStream.Position;
|
||||
zipBw.Write(new byte[12]);
|
||||
}
|
||||
else
|
||||
{
|
||||
zipBw.Write((short)ExtraData.Length); // XLEN 16+4+8+1+16+20+4+8
|
||||
headerStartPos = zipBw.BaseStream.Position;
|
||||
zipBw.Write(ExtraData);
|
||||
}
|
||||
|
||||
|
||||
dataStartPos = zipBw.BaseStream.Position;
|
||||
stream = raw
|
||||
? _zipFs
|
||||
: new ZlibBaseStream(_zipFs, CompressionMode.Compress, CompressionLevel.BestCompression, ZlibStreamFlavor.DEFLATE, true);
|
||||
|
||||
zipBw.Flush();
|
||||
zipBw.Close();
|
||||
}
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCloseReadStream()
|
||||
{
|
||||
|
||||
if (_compressionStream == null)
|
||||
return ZipReturn.ZipGood;
|
||||
if (_compressionStream is ZlibBaseStream dfStream)
|
||||
{
|
||||
dfStream.Close();
|
||||
dfStream.Dispose();
|
||||
}
|
||||
_compressionStream = null;
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public ZipStatus ZipStatus { get; private set; }
|
||||
|
||||
public string ZipFilename => _zipFileInfo != null ? _zipFileInfo.FullName : string.Empty;
|
||||
|
||||
public long TimeStamp => _zipFileInfo?.LastWriteTime ?? 0;
|
||||
|
||||
public void ZipFileAddZeroLengthFile()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileCreate(string newFilename)
|
||||
{
|
||||
if (ZipOpen != ZipOpenType.Closed)
|
||||
{
|
||||
return ZipReturn.ZipFileAlreadyOpen;
|
||||
}
|
||||
|
||||
CreateDirForFile(newFilename);
|
||||
_zipFileInfo = new FileInfo(newFilename);
|
||||
|
||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
ZipFileClose();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenWrite;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
|
||||
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
||||
{
|
||||
using (BinaryWriter zipBw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
||||
{
|
||||
CompressedSize = (ulong)(zipBw.BaseStream.Position - dataStartPos);
|
||||
|
||||
zipBw.Write(CRC[3]);
|
||||
zipBw.Write(CRC[2]);
|
||||
zipBw.Write(CRC[1]);
|
||||
zipBw.Write(CRC[0]);
|
||||
zipBw.Write((uint)UnCompressedSize);
|
||||
|
||||
long endpos = _zipFs.Position;
|
||||
|
||||
_zipFs.Position = headerStartPos;
|
||||
|
||||
if (ExtraData == null)
|
||||
{
|
||||
zipBw.Write(CRC); // 4 bytes
|
||||
zipBw.Write(UnCompressedSize); // 8 bytes
|
||||
}
|
||||
else
|
||||
{
|
||||
zipBw.Write(ExtraData);
|
||||
}
|
||||
|
||||
_zipFs.Position = endpos;
|
||||
|
||||
zipBw.Flush();
|
||||
zipBw.Close();
|
||||
}
|
||||
|
||||
_zipFs.Close();
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public ZipReturn ZipFileRollBack()
|
||||
{
|
||||
_zipFs.Position = dataStartPos;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
public void ZipFileCloseFailed()
|
||||
{
|
||||
if (ZipOpen == ZipOpenType.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZipOpen == ZipOpenType.OpenRead)
|
||||
{
|
||||
if (_zipFs != null)
|
||||
{
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
}
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
return;
|
||||
}
|
||||
|
||||
_zipFs.Flush();
|
||||
_zipFs.Close();
|
||||
_zipFs.Dispose();
|
||||
RVIO.File.Delete(_zipFileInfo.FullName);
|
||||
_zipFileInfo = null;
|
||||
ZipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
|
||||
private static void CreateDirForFile(string sFilename)
|
||||
{
|
||||
string strTemp = Path.GetDirectoryName(sFilename);
|
||||
|
||||
if (string.IsNullOrEmpty(strTemp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Directory.Exists(strTemp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while (strTemp.Length > 0 && !Directory.Exists(strTemp))
|
||||
{
|
||||
int pos = strTemp.LastIndexOf(Path.DirectorySeparatorChar);
|
||||
if (pos < 0)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
strTemp = strTemp.Substring(0, pos);
|
||||
}
|
||||
|
||||
while (sFilename.IndexOf(Path.DirectorySeparatorChar, strTemp.Length + 1) > 0)
|
||||
{
|
||||
strTemp = sFilename.Substring(0, sFilename.IndexOf(Path.DirectorySeparatorChar, strTemp.Length + 1));
|
||||
Directory.CreateDirectory(strTemp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Links for info and original source code:
|
||||
*
|
||||
* https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
* http://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
|
||||
*
|
||||
* Exact code implementation used with permission, originally by motoschifo
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NaturalSort
|
||||
{
|
||||
public class NaturalComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private Dictionary<string, string[]> table;
|
||||
|
||||
public NaturalComparer()
|
||||
{
|
||||
table = new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
table.Clear();
|
||||
table = null;
|
||||
}
|
||||
|
||||
public override int Compare(string x, string y)
|
||||
{
|
||||
if (x.ToLowerInvariant() == y.ToLowerInvariant())
|
||||
{
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
if (!table.TryGetValue(x, out string[] x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
table.Add(x, x1);
|
||||
}
|
||||
if (!table.TryGetValue(y, out string[] y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
table.Add(y, y1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x1.Length && i < y1.Length; i++)
|
||||
{
|
||||
if (x1[i] != y1[i])
|
||||
{
|
||||
return PartCompare(x1[i], y1[i]);
|
||||
}
|
||||
}
|
||||
if (y1.Length > x1.Length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (x1.Length > y1.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
}
|
||||
|
||||
private static int PartCompare(string left, string right)
|
||||
{
|
||||
if (!long.TryParse(left, out long x))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(left, right);
|
||||
}
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(left, right);
|
||||
}
|
||||
|
||||
// If we have an equal part, then make sure that "longer" ones are taken into account
|
||||
if (x.CompareTo(y) == 0)
|
||||
{
|
||||
return left.Length - right.Length;
|
||||
}
|
||||
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace NaturalSort
|
||||
{
|
||||
public static class NaturalComparerUtil
|
||||
{
|
||||
public static int CompareNumeric(string s1, string s2)
|
||||
{
|
||||
// Save the orginal strings, for later comparison
|
||||
string s1orig = s1;
|
||||
string s2orig = s2;
|
||||
|
||||
// We want to normalize the strings, so we set both to lower case
|
||||
s1 = s1.ToLowerInvariant();
|
||||
s2 = s2.ToLowerInvariant();
|
||||
|
||||
// If the strings are the same exactly, return
|
||||
if (s1 == s2)
|
||||
return s1orig.CompareTo(s2orig);
|
||||
|
||||
// If one is null, then say that's less than
|
||||
if (s1 == null)
|
||||
return -1;
|
||||
if (s2 == null)
|
||||
return 1;
|
||||
|
||||
// Now split into path parts after converting AltDirSeparator to DirSeparator
|
||||
s1 = s1.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
s2 = s2.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
string[] s1parts = s1.Split(Path.DirectorySeparatorChar);
|
||||
string[] s2parts = s2.Split(Path.DirectorySeparatorChar);
|
||||
|
||||
// Then compare each part in turn
|
||||
for (int j = 0; j < s1parts.Length && j < s2parts.Length; j++)
|
||||
{
|
||||
int compared = CompareNumericPart(s1parts[j], s2parts[j]);
|
||||
if (compared != 0)
|
||||
return compared;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (s1parts.Length > s2parts.Length)
|
||||
return 1;
|
||||
if (s1parts.Length < s2parts.Length)
|
||||
return -1;
|
||||
|
||||
return s1orig.CompareTo(s2orig);
|
||||
}
|
||||
|
||||
private static int CompareNumericPart(string s1, string s2)
|
||||
{
|
||||
// Otherwise, loop through until we have an answer
|
||||
for (int i = 0; i < s1.Length && i < s2.Length; i++)
|
||||
{
|
||||
int s1c = s1[i];
|
||||
int s2c = s2[i];
|
||||
|
||||
// If the characters are the same, continue
|
||||
if (s1c == s2c)
|
||||
continue;
|
||||
|
||||
// If they're different, check which one was larger
|
||||
if (s1c > s2c)
|
||||
return 1;
|
||||
if (s1c < s2c)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (s1.Length > s2.Length)
|
||||
return 1;
|
||||
if (s1.Length < s2.Length)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Links for info and original source code:
|
||||
*
|
||||
* https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
* http://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
|
||||
*
|
||||
* Exact code implementation used with permission, originally by motoschifo
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NaturalSort
|
||||
{
|
||||
public class NaturalReversedComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private Dictionary<string, string[]> table;
|
||||
|
||||
public NaturalReversedComparer()
|
||||
{
|
||||
table = new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
table.Clear();
|
||||
table = null;
|
||||
}
|
||||
|
||||
public override int Compare(string x, string y)
|
||||
{
|
||||
if (y.ToLowerInvariant() == x.ToLowerInvariant())
|
||||
{
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
if (!table.TryGetValue(x, out string[] x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
table.Add(x, x1);
|
||||
}
|
||||
if (!table.TryGetValue(y, out string[] y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
table.Add(y, y1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x1.Length && i < y1.Length; i++)
|
||||
{
|
||||
if (x1[i] != y1[i])
|
||||
{
|
||||
return PartCompare(x1[i], y1[i]);
|
||||
}
|
||||
}
|
||||
if (y1.Length > x1.Length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (x1.Length > y1.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
}
|
||||
|
||||
private static int PartCompare(string left, string right)
|
||||
{
|
||||
if (!long.TryParse(left, out long x))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(right, left);
|
||||
}
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(right, left);
|
||||
}
|
||||
|
||||
// If we have an equal part, then make sure that "longer" ones are taken into account
|
||||
if (y.CompareTo(x) == 0)
|
||||
{
|
||||
return right.Length - left.Length;
|
||||
}
|
||||
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
786
SabreTools.Library/External/RVIO/RVIO.cs
vendored
786
SabreTools.Library/External/RVIO/RVIO.cs
vendored
@@ -1,786 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace RVIO
|
||||
{
|
||||
[Flags]
|
||||
[ComVisible(true)]
|
||||
[Serializable]
|
||||
public enum FileAttributes
|
||||
{
|
||||
ReadOnly = 1,
|
||||
Hidden = 2,
|
||||
System = 4,
|
||||
Directory = 16,
|
||||
Archive = 32,
|
||||
Device = 64,
|
||||
Normal = 128,
|
||||
Temporary = 256,
|
||||
SparseFile = 512,
|
||||
ReparsePoint = 1024,
|
||||
Compressed = 2048,
|
||||
Offline = 4096,
|
||||
NotContentIndexed = 8192,
|
||||
Encrypted = 16384,
|
||||
}
|
||||
public static class Error
|
||||
{
|
||||
public static int GetLastError()
|
||||
{
|
||||
return Marshal.GetLastWin32Error();
|
||||
}
|
||||
}
|
||||
|
||||
public static class unix
|
||||
{
|
||||
public static bool IsUnix
|
||||
{
|
||||
get
|
||||
{
|
||||
int p = (int)Environment.OSVersion.Platform;
|
||||
return ((p == 4) || (p == 6) || (p == 128));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FileInfo
|
||||
{
|
||||
|
||||
public string Name;
|
||||
public string FullName;
|
||||
public long LastWriteTime;
|
||||
public long Length;
|
||||
|
||||
public FileInfo()
|
||||
{ }
|
||||
|
||||
public FileInfo(string path)
|
||||
{
|
||||
FullName = path;
|
||||
Name = Path.GetFileName(path);
|
||||
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.FileInfo fi = new System.IO.FileInfo(path);
|
||||
|
||||
if (!fi.Exists) return;
|
||||
|
||||
Length = fi.Length;
|
||||
LastWriteTime = fi.LastWriteTimeUtc.Ticks;
|
||||
return;
|
||||
}
|
||||
|
||||
string fileName = NameFix.AddLongPathPrefix(path);
|
||||
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
|
||||
|
||||
bool b = Win32Native.GetFileAttributesEx(fileName, 0, ref wIn32FileAttributeData);
|
||||
|
||||
if (!b || (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0) return;
|
||||
|
||||
Length = Convert.Length(wIn32FileAttributeData.fileSizeHigh, wIn32FileAttributeData.fileSizeLow);
|
||||
LastWriteTime = Convert.Time(wIn32FileAttributeData.ftLastWriteTimeHigh, wIn32FileAttributeData.ftLastWriteTimeLow);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class DirectoryInfo
|
||||
{
|
||||
public string Name;
|
||||
public string FullName;
|
||||
public long LastWriteTime;
|
||||
|
||||
public DirectoryInfo()
|
||||
{ }
|
||||
public DirectoryInfo(string path)
|
||||
{
|
||||
FullName = path;
|
||||
Name = Path.GetFileName(path);
|
||||
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.DirectoryInfo fi = new System.IO.DirectoryInfo(path);
|
||||
|
||||
if (!fi.Exists) return;
|
||||
|
||||
LastWriteTime = fi.LastWriteTimeUtc.Ticks;
|
||||
return;
|
||||
}
|
||||
|
||||
string fileName = NameFix.AddLongPathPrefix(path);
|
||||
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
|
||||
|
||||
bool b = Win32Native.GetFileAttributesEx(fileName, 0, ref wIn32FileAttributeData);
|
||||
|
||||
if (!b || (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) == 0) return;
|
||||
LastWriteTime = Convert.Time(wIn32FileAttributeData.ftLastWriteTimeHigh, wIn32FileAttributeData.ftLastWriteTimeLow);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public DirectoryInfo[] GetDirectories(bool includeHidden = true)
|
||||
{
|
||||
return GetDirectories("*", includeHidden);
|
||||
}
|
||||
public DirectoryInfo[] GetDirectories(string SearchPattern, bool includeHidden = true)
|
||||
{
|
||||
List<DirectoryInfo> dirs = new List<DirectoryInfo>();
|
||||
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(FullName);
|
||||
System.IO.DirectoryInfo[] arrDi = di.GetDirectories(SearchPattern);
|
||||
foreach (System.IO.DirectoryInfo tDi in arrDi)
|
||||
{
|
||||
DirectoryInfo lDi = new DirectoryInfo
|
||||
{
|
||||
Name = tDi.Name,
|
||||
FullName = Path.Combine(FullName, tDi.Name),
|
||||
LastWriteTime = tDi.LastWriteTimeUtc.Ticks
|
||||
};
|
||||
dirs.Add(lDi);
|
||||
}
|
||||
return dirs.ToArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
string dirName = NameFix.AddLongPathPrefix(FullName);
|
||||
|
||||
Win32Native.WIN32_FIND_DATA findData = new Win32Native.WIN32_FIND_DATA();
|
||||
SafeFindHandle findHandle = Win32Native.FindFirstFile(dirName + @"\" + SearchPattern, findData);
|
||||
|
||||
if (!findHandle.IsInvalid)
|
||||
{
|
||||
do
|
||||
{
|
||||
string currentFileName = findData.cFileName;
|
||||
|
||||
// if this is a directory, find its contents
|
||||
if ((findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) == 0) continue;
|
||||
if (currentFileName == "." || currentFileName == "..") continue;
|
||||
if (!includeHidden && (findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_HIDDEN) != 0) continue;
|
||||
|
||||
DirectoryInfo di = new DirectoryInfo
|
||||
{
|
||||
Name = currentFileName,
|
||||
FullName = Path.Combine(FullName, currentFileName),
|
||||
LastWriteTime = Convert.Time(findData.ftLastWriteTimeHigh, findData.ftLastWriteTimeLow)
|
||||
};
|
||||
dirs.Add(di);
|
||||
}
|
||||
while (Win32Native.FindNextFile(findHandle, findData));
|
||||
}
|
||||
|
||||
// close the find handle
|
||||
findHandle.Dispose();
|
||||
|
||||
return dirs.ToArray();
|
||||
}
|
||||
|
||||
public FileInfo[] GetFiles()
|
||||
{
|
||||
return GetFiles("*");
|
||||
}
|
||||
public FileInfo[] GetFiles(string SearchPattern, bool includeHidden = true)
|
||||
{
|
||||
List<FileInfo> files = new List<FileInfo>();
|
||||
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(FullName);
|
||||
System.IO.FileInfo[] arrDi = di.GetFiles(SearchPattern);
|
||||
foreach (System.IO.FileInfo tDi in arrDi)
|
||||
{
|
||||
FileInfo lDi = new FileInfo
|
||||
{
|
||||
Name = tDi.Name,
|
||||
FullName = Path.Combine(FullName, tDi.Name),
|
||||
Length = tDi.Length,
|
||||
LastWriteTime = tDi.LastWriteTimeUtc.Ticks
|
||||
};
|
||||
files.Add(lDi);
|
||||
}
|
||||
return files.ToArray();
|
||||
}
|
||||
|
||||
string dirName = NameFix.AddLongPathPrefix(FullName);
|
||||
|
||||
Win32Native.WIN32_FIND_DATA findData = new Win32Native.WIN32_FIND_DATA();
|
||||
SafeFindHandle findHandle = Win32Native.FindFirstFile(dirName + @"\" + SearchPattern, findData);
|
||||
|
||||
if (!findHandle.IsInvalid)
|
||||
{
|
||||
do
|
||||
{
|
||||
string currentFileName = findData.cFileName;
|
||||
|
||||
// if this is a directory, find its contents
|
||||
if ((findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0) continue;
|
||||
if (!includeHidden && (findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_HIDDEN) != 0) continue;
|
||||
|
||||
FileInfo fi = new FileInfo
|
||||
{
|
||||
Name = currentFileName,
|
||||
FullName = Path.Combine(FullName, currentFileName),
|
||||
Length = Convert.Length(findData.nFileSizeHigh, findData.nFileSizeLow),
|
||||
LastWriteTime = Convert.Time(findData.ftLastWriteTimeHigh, findData.ftLastWriteTimeLow)
|
||||
};
|
||||
files.Add(fi);
|
||||
}
|
||||
while (Win32Native.FindNextFile(findHandle, findData));
|
||||
}
|
||||
|
||||
// close the find handle
|
||||
findHandle.Dispose();
|
||||
|
||||
return files.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Directory
|
||||
{
|
||||
public static bool Exists(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
return System.IO.Directory.Exists(path);
|
||||
|
||||
|
||||
string fixPath = NameFix.AddLongPathPrefix(path);
|
||||
|
||||
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
|
||||
|
||||
bool b = Win32Native.GetFileAttributesEx(fixPath, 0, ref wIn32FileAttributeData);
|
||||
return b && (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
public static void Move(string sourceDirName, string destDirName)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.Directory.Move(sourceDirName, destDirName);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (sourceDirName == null)
|
||||
throw new ArgumentNullException("sourceDirName");
|
||||
if (sourceDirName.Length == 0)
|
||||
throw new ArgumentException("Argument_EmptyFileName", "sourceDirName");
|
||||
|
||||
if (destDirName == null)
|
||||
throw new ArgumentNullException("destDirName");
|
||||
if (destDirName.Length == 0)
|
||||
throw new ArgumentException("Argument_EmptyFileName", "destDirName");
|
||||
|
||||
string fullsourceDirName = NameFix.AddLongPathPrefix(sourceDirName);
|
||||
|
||||
string fulldestDirName = NameFix.AddLongPathPrefix(destDirName);
|
||||
|
||||
if (!Win32Native.MoveFile(fullsourceDirName, fulldestDirName))
|
||||
{
|
||||
int hr = Marshal.GetLastWin32Error();
|
||||
if (hr == Win32Native.ERROR_FILE_NOT_FOUND) // Source dir not found
|
||||
{
|
||||
throw new Exception("ERROR_PATH_NOT_FOUND " + fullsourceDirName);
|
||||
}
|
||||
if (hr == Win32Native.ERROR_ACCESS_DENIED) // WinNT throws IOException. This check is for Win9x. We can't change it for backcomp.
|
||||
{
|
||||
throw new Exception("UnauthorizedAccess_IODenied_Path" + sourceDirName);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void Delete(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.Directory.Delete(path);
|
||||
return;
|
||||
}
|
||||
|
||||
string fullPath = NameFix.AddLongPathPrefix(path);
|
||||
|
||||
Win32Native.RemoveDirectory(fullPath);
|
||||
}
|
||||
|
||||
public static void CreateDirectory(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (path == null)
|
||||
throw new ArgumentNullException("path");
|
||||
if (path.Length == 0)
|
||||
throw new ArgumentException("Argument_PathEmpty");
|
||||
|
||||
string fullPath = NameFix.AddLongPathPrefix(path);
|
||||
|
||||
Win32Native.CreateDirectory(fullPath, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
public static class File
|
||||
{
|
||||
public static bool Exists(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
return System.IO.File.Exists(path);
|
||||
|
||||
|
||||
string fixPath = NameFix.AddLongPathPrefix(path);
|
||||
|
||||
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
|
||||
|
||||
bool b = Win32Native.GetFileAttributesEx(fixPath, 0, ref wIn32FileAttributeData);
|
||||
return b && (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
public static void Copy(string sourceFileName, string destfileName)
|
||||
{
|
||||
Copy(sourceFileName, destfileName, true);
|
||||
}
|
||||
public static void Copy(string sourceFileName, string destFileName, bool overwrite)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.File.Copy(sourceFileName, destFileName, overwrite);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceFileName == null || destFileName == null)
|
||||
throw new ArgumentNullException((sourceFileName == null ? "sourceFileName" : "destFileName"), "ArgumentNull_FileName");
|
||||
if (sourceFileName.Length == 0 || destFileName.Length == 0)
|
||||
throw new ArgumentException("Argument_EmptyFileName", (sourceFileName.Length == 0 ? "sourceFileName" : "destFileName"));
|
||||
|
||||
string fullSourceFileName = NameFix.AddLongPathPrefix(sourceFileName);
|
||||
string fullDestFileName = NameFix.AddLongPathPrefix(destFileName);
|
||||
|
||||
bool r = Win32Native.CopyFile(fullSourceFileName, fullDestFileName, !overwrite);
|
||||
if (!r)
|
||||
{
|
||||
// Save Win32 error because subsequent checks will overwrite this HRESULT.
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
string fileName = destFileName;
|
||||
|
||||
/*
|
||||
if (errorCode != Win32Native.ERROR_FILE_EXISTS)
|
||||
{
|
||||
// For a number of error codes (sharing violation, path
|
||||
// not found, etc) we don't know if the problem was with
|
||||
// the source or dest file. Try reading the source file.
|
||||
using (SafeFileHandle handle = Win32Native.UnsafeCreateFile(fullSourceFileName, FileStream.GENERIC_READ, FileShare.Read, null, FileMode.Open, 0, IntPtr.Zero))
|
||||
{
|
||||
if (handle.IsInvalid)
|
||||
fileName = sourceFileName;
|
||||
}
|
||||
|
||||
if (errorCode == Win32Native.ERROR_ACCESS_DENIED)
|
||||
{
|
||||
if (Directory.InternalExists(fullDestFileName))
|
||||
throw new IOException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_FileIsDirectory_Name"), destFileName), Win32Native.ERROR_ACCESS_DENIED, fullDestFileName);
|
||||
}
|
||||
}
|
||||
|
||||
__Error.WinIOError(errorCode, fileName);
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
public static void Move(string sourceFileName, string destFileName)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.File.Move(sourceFileName, destFileName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceFileName == null || destFileName == null)
|
||||
throw new ArgumentNullException((sourceFileName == null ? "sourceFileName" : "destFileName"), "ArgumentNull_FileName");
|
||||
if (sourceFileName.Length == 0 || destFileName.Length == 0)
|
||||
throw new ArgumentException("Argument_EmptyFileName", (sourceFileName.Length == 0 ? "sourceFileName" : "destFileName"));
|
||||
|
||||
string fullSourceFileName = NameFix.AddLongPathPrefix(sourceFileName);
|
||||
string fullDestFileName = NameFix.AddLongPathPrefix(destFileName);
|
||||
|
||||
if (!Exists(fullSourceFileName))
|
||||
throw new Exception("ERROR_FILE_NOT_FOUND" + fullSourceFileName);
|
||||
|
||||
if (!Win32Native.MoveFile(fullSourceFileName, fullDestFileName))
|
||||
{
|
||||
int hr = Marshal.GetLastWin32Error();
|
||||
throw new Exception(GetErrorCode(hr), new Exception("ERROR_MOVING_FILE. (" + fullSourceFileName + " to " + fullDestFileName + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Delete(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
System.IO.File.Delete(path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string fixPath = NameFix.AddLongPathPrefix(path);
|
||||
|
||||
if (!Win32Native.DeleteFile(fixPath))
|
||||
{
|
||||
int hr = Marshal.GetLastWin32Error();
|
||||
if (hr != Win32Native.ERROR_FILE_NOT_FOUND)
|
||||
throw new Exception(GetErrorCode(hr), new Exception("ERROR_DELETING_FILE. (" + path + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string GetErrorCode(int hr)
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case 5: return "ERROR_ACCESS_DENIED: Access is denied.";
|
||||
case 32: return "ERROR_FILE_IN_USE: The file is in use by another process.";
|
||||
case 39: return "ERROR_HANDLE_DISK_FULL: The disk is full.";
|
||||
case 112: return "ERROR_DISK_FULL: There is not enough space on the disk.";
|
||||
case 123: return "ERROR_INVALID_NAME: The filename, directory name, or volume label syntax is incorrect.";
|
||||
case 183: return "ERROR_ALREADY_EXISTS: Cannot create a file when that file already exists.";
|
||||
}
|
||||
|
||||
return hr.ToString();
|
||||
}
|
||||
|
||||
public static bool SetAttributes(string path, FileAttributes fileAttributes)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.IO.File.SetAttributes(path, (System.IO.FileAttributes)fileAttributes);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string fullPath = NameFix.AddLongPathPrefix(path);
|
||||
return Win32Native.SetFileAttributes(fullPath, (int)fileAttributes);
|
||||
}
|
||||
public static StreamWriter CreateText(string filename)
|
||||
{
|
||||
int errorCode = FileStream.OpenFileWrite(filename, out Stream fStream);
|
||||
return errorCode != 0 ? null : new StreamWriter(fStream);
|
||||
}
|
||||
public static StreamReader OpenText(string filename, Encoding Enc)
|
||||
{
|
||||
int errorCode = FileStream.OpenFileRead(filename, out Stream fStream);
|
||||
return errorCode != 0 ? null : new StreamReader(fStream, Enc);
|
||||
}
|
||||
|
||||
private const int ERROR_INVALID_PARAMETER = 87;
|
||||
private const int ERROR_ACCESS_DENIED = 0x5;
|
||||
}
|
||||
|
||||
public static class Path
|
||||
{
|
||||
public static readonly char DirectorySeparatorChar = '\\';
|
||||
public static readonly char AltDirectorySeparatorChar = '/';
|
||||
public static readonly char VolumeSeparatorChar = ':';
|
||||
|
||||
public static string GetExtension(string path)
|
||||
{
|
||||
return System.IO.Path.GetExtension(path);
|
||||
}
|
||||
public static string Combine(string path1, string path2)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
return System.IO.Path.Combine(path1, path2);
|
||||
|
||||
if (path1 == null || path2 == null)
|
||||
throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
|
||||
//CheckInvalidPathChars(path1);
|
||||
//CheckInvalidPathChars(path2);
|
||||
|
||||
if (path2.Length == 0)
|
||||
return path1;
|
||||
|
||||
if (path1.Length == 0)
|
||||
return path2;
|
||||
|
||||
if (IsPathRooted(path2))
|
||||
return path2;
|
||||
|
||||
char ch = path1[path1.Length - 1];
|
||||
if (ch != DirectorySeparatorChar && ch != AltDirectorySeparatorChar && ch != VolumeSeparatorChar)
|
||||
return path1 + DirectorySeparatorChar + path2;
|
||||
return path1 + path2;
|
||||
}
|
||||
private static bool IsPathRooted(string path)
|
||||
{
|
||||
if (path != null)
|
||||
{
|
||||
//CheckInvalidPathChars(path);
|
||||
|
||||
int length = path.Length;
|
||||
if (
|
||||
(length >= 1 && (path[0] == DirectorySeparatorChar ||
|
||||
path[0] == AltDirectorySeparatorChar)) ||
|
||||
(length >= 2 && path[1] == VolumeSeparatorChar)
|
||||
) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
private static void CheckInvalidPathChars(string path)
|
||||
{
|
||||
for (int index = 0; index < path.Length; ++index)
|
||||
{
|
||||
int num = path[index];
|
||||
switch (num)
|
||||
{
|
||||
case 34:
|
||||
case 60:
|
||||
case 62:
|
||||
case 124:
|
||||
ReportError.SendErrorMessage("Invalid Character " + num + " in filename " + path);
|
||||
continue;
|
||||
default:
|
||||
if (num >= 32)
|
||||
continue;
|
||||
|
||||
goto case 34;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public static string GetFileNameWithoutExtension(string path)
|
||||
{
|
||||
return System.IO.Path.GetFileNameWithoutExtension(path);
|
||||
}
|
||||
|
||||
public static string GetFileName(string path)
|
||||
{
|
||||
return System.IO.Path.GetFileName(path);
|
||||
}
|
||||
public static string GetDirectoryName(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
return System.IO.Path.GetDirectoryName(path);
|
||||
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
int root = GetRootLength(path);
|
||||
int i = path.Length;
|
||||
if (i > root)
|
||||
{
|
||||
i = path.Length;
|
||||
if (i == root) return null;
|
||||
while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar) ;
|
||||
return path.Substring(0, i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int GetRootLength(string path)
|
||||
{
|
||||
int i = 0;
|
||||
int length = path.Length;
|
||||
|
||||
if (length >= 1 && (IsDirectorySeparator(path[0])))
|
||||
{
|
||||
// handles UNC names and directories off current drive's root.
|
||||
i = 1;
|
||||
if (length >= 2 && (IsDirectorySeparator(path[1])))
|
||||
{
|
||||
i = 2;
|
||||
int n = 2;
|
||||
while (i < length && ((path[i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar) || --n > 0)) i++;
|
||||
}
|
||||
}
|
||||
else if (length >= 2 && path[1] == VolumeSeparatorChar)
|
||||
{
|
||||
// handles A:\foo.
|
||||
i = 2;
|
||||
if (length >= 3 && (IsDirectorySeparator(path[2]))) i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
private static bool IsDirectorySeparator(char c)
|
||||
{
|
||||
return (c == DirectorySeparatorChar || c == AltDirectorySeparatorChar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class FileStream
|
||||
{
|
||||
private const uint GENERIC_READ = 0x80000000;
|
||||
private const uint GENERIC_WRITE = 0x40000000;
|
||||
|
||||
private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
|
||||
|
||||
// errorMessage = new Win32Exception(errorCode).Message;
|
||||
|
||||
public static Stream OpenFileRead(string path, out int result)
|
||||
{
|
||||
result = OpenFileRead(path, out Stream stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static int OpenFileRead(string path, out Stream stream)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream = new System.IO.FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
stream = null;
|
||||
return Marshal.GetLastWin32Error();
|
||||
}
|
||||
}
|
||||
|
||||
string filename = NameFix.AddLongPathPrefix(path);
|
||||
SafeFileHandle hFile = Win32Native.CreateFile(filename,
|
||||
GENERIC_READ,
|
||||
System.IO.FileShare.Read,
|
||||
IntPtr.Zero,
|
||||
FileMode.Open,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (hFile.IsInvalid)
|
||||
{
|
||||
stream = null;
|
||||
return Marshal.GetLastWin32Error();
|
||||
}
|
||||
stream = new System.IO.FileStream(hFile, FileAccess.Read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int OpenFileWrite(string path, out Stream stream)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream = new System.IO.FileStream(path, FileMode.Create, FileAccess.ReadWrite);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
stream = null;
|
||||
return Marshal.GetLastWin32Error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string filename = NameFix.AddLongPathPrefix(path);
|
||||
SafeFileHandle hFile = Win32Native.CreateFile(filename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
System.IO.FileShare.None,
|
||||
IntPtr.Zero,
|
||||
FileMode.Create,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (hFile.IsInvalid)
|
||||
{
|
||||
stream = null;
|
||||
return Marshal.GetLastWin32Error();
|
||||
}
|
||||
|
||||
stream = new System.IO.FileStream(hFile, FileAccess.ReadWrite);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class NameFix
|
||||
{
|
||||
public static string GetShortPath(string path)
|
||||
{
|
||||
if (unix.IsUnix)
|
||||
return path;
|
||||
|
||||
int remove = 0;
|
||||
string retPath;
|
||||
if (path.StartsWith(@"\\"))
|
||||
{
|
||||
retPath = @"\\?\UNC\" + path.Substring(2);
|
||||
remove = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
retPath = path;
|
||||
if (path.Substring(1, 1) != ":")
|
||||
retPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), retPath);
|
||||
|
||||
retPath = cleandots(retPath);
|
||||
retPath = @"\\?\" + retPath;
|
||||
remove = 4;
|
||||
}
|
||||
|
||||
|
||||
const int MAX_PATH = 300;
|
||||
StringBuilder shortPath = new StringBuilder(MAX_PATH);
|
||||
Win32Native.GetShortPathName(retPath, shortPath, MAX_PATH);
|
||||
retPath = shortPath.ToString();
|
||||
|
||||
retPath = retPath.Substring(remove);
|
||||
if (remove == 8) retPath = "\\" + retPath;
|
||||
|
||||
return retPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static string AddLongPathPrefix(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path) || path.StartsWith(@"\\?\"))
|
||||
return path;
|
||||
|
||||
if (path.StartsWith(@"\\"))
|
||||
return @"\\?\UNC\" + path.Substring(2);
|
||||
|
||||
string retPath = path;
|
||||
if (path.Substring(1, 1) != ":")
|
||||
retPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), retPath);
|
||||
|
||||
retPath = cleandots(retPath);
|
||||
|
||||
return @"\\?\" + retPath;
|
||||
|
||||
}
|
||||
|
||||
private static string cleandots(string path)
|
||||
{
|
||||
string retPath = path;
|
||||
while (retPath.Contains(@"\..\"))
|
||||
{
|
||||
int index = retPath.IndexOf(@"\..\");
|
||||
string path1 = retPath.Substring(0, index);
|
||||
string path2 = retPath.Substring(index + 4);
|
||||
|
||||
int path1Back = path1.LastIndexOf(@"\");
|
||||
|
||||
retPath = path1.Substring(0, path1Back + 1) + path2;
|
||||
}
|
||||
return retPath;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
178
SabreTools.Library/External/RVIO/Win32Native.cs
vendored
178
SabreTools.Library/External/RVIO/Win32Native.cs
vendored
@@ -1,178 +0,0 @@
|
||||
/******************************************************
|
||||
* ROMVault3 is written by Gordon J. *
|
||||
* Contact gordon@romvault.com *
|
||||
* Copyright 2019 *
|
||||
******************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace RVIO
|
||||
{
|
||||
internal static class Win32Native
|
||||
{
|
||||
private const string KERNEL32 = "kernel32.dll";
|
||||
|
||||
public const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
public const int FILE_ATTRIBUTE_HIDDEN = 0x00000002;
|
||||
|
||||
|
||||
internal const int ERROR_FILE_NOT_FOUND = 0x2;
|
||||
internal const int ERROR_ACCESS_DENIED = 0x5;
|
||||
internal const int ERROR_FILE_EXISTS = 0x50;
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern bool GetFileAttributesEx(string fileName, int fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern SafeFindHandle FindFirstFile(string fileName, [In] [Out] WIN32_FIND_DATA data);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern bool FindNextFile(SafeFindHandle hndFindFile, [In] [Out] [MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATA lpFindFileData);
|
||||
|
||||
[DllImport(KERNEL32)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
internal static extern bool FindClose(IntPtr handle);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern SafeFileHandle CreateFile(string lpFileName,
|
||||
uint dwDesiredAccess, FileShare dwShareMode,
|
||||
IntPtr securityAttrs, FileMode dwCreationDisposition,
|
||||
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern bool CreateDirectory(string path, IntPtr lpSecurityAttributes);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern bool RemoveDirectory(string path);
|
||||
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern bool CopyFile(string src, string dst, bool failIfExists);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern bool MoveFile(string src, string dst);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern bool DeleteFile(string path);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
internal static extern bool SetFileAttributes(string name, int attr);
|
||||
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
internal static extern int GetShortPathName(
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string path,
|
||||
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath,
|
||||
int shortPathLength
|
||||
);
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[BestFitMapping(false)]
|
||||
internal class WIN32_FIND_DATA
|
||||
{
|
||||
internal int dwFileAttributes = 0;
|
||||
internal uint ftCreationTimeLow;
|
||||
internal uint ftCreationTimeHigh;
|
||||
internal uint ftLastAccessTimeLow;
|
||||
internal uint ftLastAccessTimeHigh;
|
||||
internal uint ftLastWriteTimeLow;
|
||||
internal uint ftLastWriteTimeHigh;
|
||||
internal int nFileSizeHigh = 0;
|
||||
internal int nFileSizeLow = 0;
|
||||
internal int dwReserved0 = 0;
|
||||
internal int dwReserved1 = 0;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] internal string cFileName = null;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] internal string cAlternateFileName = null;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[Serializable]
|
||||
internal struct WIN32_FILE_ATTRIBUTE_DATA
|
||||
{
|
||||
internal int fileAttributes;
|
||||
internal uint ftCreationTimeLow;
|
||||
internal uint ftCreationTimeHigh;
|
||||
internal uint ftLastAccessTimeLow;
|
||||
internal uint ftLastAccessTimeHigh;
|
||||
internal uint ftLastWriteTimeLow;
|
||||
internal uint ftLastWriteTimeHigh;
|
||||
internal int fileSizeHigh;
|
||||
internal int fileSizeLow;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
internal SafeFindHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return Win32Native.FindClose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal static class Convert
|
||||
{
|
||||
private const long TicksPerMillisecond = 10000;
|
||||
private const long TicksPerSecond = TicksPerMillisecond * 1000;
|
||||
private const long TicksPerMinute = TicksPerSecond * 60;
|
||||
private const long TicksPerHour = TicksPerMinute * 60;
|
||||
private const long TicksPerDay = TicksPerHour * 24;
|
||||
|
||||
// Number of days in a non-leap year
|
||||
private const int DaysPerYear = 365;
|
||||
// Number of days in 4 years
|
||||
private const int DaysPer4Years = DaysPerYear * 4 + 1;
|
||||
// Number of days in 100 years
|
||||
private const int DaysPer100Years = DaysPer4Years * 25 - 1;
|
||||
// Number of days in 400 years
|
||||
private const int DaysPer400Years = DaysPer100Years * 4 + 1;
|
||||
|
||||
// Number of days from 1/1/0001 to 12/31/1600
|
||||
private const int DaysTo1601 = DaysPer400Years * 4;
|
||||
public const long FileTimeOffset = DaysTo1601 * TicksPerDay;
|
||||
|
||||
|
||||
// Number of days from 1/1/0001 to 12/31/9999
|
||||
private const int DaysTo10000 = DaysPer400Years * 25 - 366;
|
||||
private const long MinTicks = 0;
|
||||
private const long MaxTicks = DaysTo10000 * TicksPerDay - 1;
|
||||
|
||||
|
||||
public static long Length(int high, int low)
|
||||
{
|
||||
return ((long)high << 32) | (low & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
public static long Time(uint high, uint low)
|
||||
{
|
||||
return ((long)high << 32) | low;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Core;
|
||||
|
||||
namespace SabreTools.Library.FileTypes.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Checksum entry, followed by checksum data itself
|
||||
/// </summary>
|
||||
/// <see cref="https://github.com/aaru-dps/Aaru/blob/master/Aaru.Images/AaruFormat/Structs.cs" />
|
||||
public class ChecksumEntry
|
||||
{
|
||||
/// <summary>Checksum algorithm</summary>
|
||||
public AaruChecksumAlgorithm type;
|
||||
/// <summary>Length in bytes of checksum that follows this structure</summary>
|
||||
public uint length;
|
||||
/// <summary>Checksum that follows this structure</summary>
|
||||
public byte[] checksum;
|
||||
|
||||
/// <summary>
|
||||
/// Read a stream as an v
|
||||
/// </summary>
|
||||
/// <param name="stream">ChecksumEntry as a stream</param>
|
||||
/// <returns>Populated ChecksumEntry, null on failure</returns>
|
||||
public static ChecksumEntry Deserialize(Stream stream)
|
||||
{
|
||||
ChecksumEntry checksumEntry = new ChecksumEntry();
|
||||
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
checksumEntry.type = (AaruChecksumAlgorithm)br.ReadByte();
|
||||
checksumEntry.length = br.ReadUInt32();
|
||||
if (checksumEntry.length == 0)
|
||||
return null;
|
||||
|
||||
checksumEntry.checksum = br.ReadBytes((int)checksumEntry.length);
|
||||
}
|
||||
|
||||
return checksumEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Core;
|
||||
|
||||
namespace SabreTools.Library.FileTypes.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Checksum block, contains a checksum of all user data sectors
|
||||
/// (except for optical discs that is 2352 bytes raw sector if available
|
||||
/// </summary>
|
||||
/// <see cref="https://github.com/aaru-dps/Aaru/blob/master/Aaru.Images/AaruFormat/Structs.cs" />
|
||||
public class ChecksumHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.ChecksumBlock" /></summary>
|
||||
public AaruBlockType identifier;
|
||||
/// <summary>Length in bytes of the block</summary>
|
||||
public uint length;
|
||||
/// <summary>How many checksums follow</summary>
|
||||
public byte entries;
|
||||
|
||||
/// <summary>
|
||||
/// Read a stream as an ChecksumHeader
|
||||
/// </summary>
|
||||
/// <param name="stream">ChecksumHeader as a stream</param>
|
||||
/// <returns>Populated ChecksumHeader, null on failure</returns>
|
||||
public static ChecksumHeader Deserialize(Stream stream)
|
||||
{
|
||||
ChecksumHeader checksumHeader = new ChecksumHeader();
|
||||
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
checksumHeader.identifier = (AaruBlockType)br.ReadUInt32();
|
||||
checksumHeader.length = br.ReadUInt32();
|
||||
checksumHeader.entries = br.ReadByte();
|
||||
}
|
||||
|
||||
return checksumHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Core;
|
||||
|
||||
namespace SabreTools.Library.FileTypes.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Index entry
|
||||
/// </summary>
|
||||
/// <see cref="https://github.com/aaru-dps/Aaru/blob/master/Aaru.Images/AaruFormat/Structs.cs" />
|
||||
public class IndexEntry
|
||||
{
|
||||
/// <summary>Type of item pointed by this entry</summary>
|
||||
public AaruBlockType blockType;
|
||||
/// <summary>Type of data contained by the block pointed by this entry</summary>
|
||||
public AaruDataType dataType;
|
||||
/// <summary>Offset in file where item is stored</summary>
|
||||
public ulong offset;
|
||||
|
||||
/// <summary>
|
||||
/// Read a stream as an IndexHeader
|
||||
/// </summary>
|
||||
/// <param name="stream">IndexHeader as a stream</param>
|
||||
/// <returns>Populated IndexHeader, null on failure</returns>
|
||||
public static IndexEntry Deserialize(Stream stream)
|
||||
{
|
||||
IndexEntry indexEntry = new IndexEntry();
|
||||
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
indexEntry.blockType = (AaruBlockType)br.ReadUInt32();
|
||||
indexEntry.dataType = (AaruDataType)br.ReadUInt16();
|
||||
indexEntry.offset = br.ReadUInt64();
|
||||
}
|
||||
|
||||
return indexEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.Core;
|
||||
|
||||
namespace SabreTools.Library.FileTypes.Aaru
|
||||
{
|
||||
/// <summary>
|
||||
/// Header for the index, followed by entries
|
||||
/// </summary>
|
||||
/// <see cref="https://github.com/aaru-dps/Aaru/blob/master/Aaru.Images/AaruFormat/Structs.cs" />
|
||||
public class IndexHeader
|
||||
{
|
||||
/// <summary>Identifier, <see cref="BlockType.Index" /></summary>
|
||||
public AaruBlockType identifier;
|
||||
/// <summary>How many entries follow this header</summary>
|
||||
public ushort entries;
|
||||
/// <summary>CRC64-ECMA of the index</summary>
|
||||
public ulong crc64;
|
||||
|
||||
/// <summary>
|
||||
/// Read a stream as an IndexHeader
|
||||
/// </summary>
|
||||
/// <param name="stream">IndexHeader as a stream</param>
|
||||
/// <returns>Populated IndexHeader, null on failure</returns>
|
||||
public static IndexHeader Deserialize(Stream stream)
|
||||
{
|
||||
IndexHeader indexHeader = new IndexHeader();
|
||||
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
indexHeader.identifier = (AaruBlockType)br.ReadUInt32();
|
||||
indexHeader.entries = br.ReadUInt16();
|
||||
indexHeader.crc64 = br.ReadUInt64();
|
||||
}
|
||||
|
||||
return indexHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Core;
|
||||
using SabreTools.Library.FileTypes.Aaru;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// AaruFormat code is based on the Aaru project
|
||||
/// See https://github.com/aaru-dps/Aaru/tree/master/Aaru.Images/AaruFormat
|
||||
/// </summary>
|
||||
public class AaruFormat : BaseFile
|
||||
{
|
||||
#region Private instance variables
|
||||
|
||||
#region Header
|
||||
|
||||
protected ulong Identifier; // 'AARUFRMT' (0x544D524655524141)
|
||||
protected string Application; // Name of application that created image
|
||||
protected byte ImageMajorVersion; // Image format major version
|
||||
protected byte ImageMinorVersion; // Image format minor version
|
||||
protected byte ApplicationMajorVersion; // Major version of application that created image
|
||||
protected byte ApplicationMinorVersion; // Minor version of application that created image
|
||||
protected AaruMediaType MediaType; // Media type contained in image
|
||||
protected ulong IndexOffset; // Offset to index
|
||||
protected long CreationTime; // Windows filetime of creation time
|
||||
protected long LastWrittenTime; // Windows filetime of last written time
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Values
|
||||
|
||||
protected IndexHeader IndexHeader;
|
||||
protected IndexEntry[] IndexEntries;
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion // Private instance variables
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a new AaruFormat from an input file
|
||||
/// </summary>
|
||||
/// <param name="filename">Filename respresenting the AaruFormat file</param>
|
||||
public static AaruFormat Create(string filename)
|
||||
{
|
||||
using (FileStream fs = File.OpenRead(filename))
|
||||
{
|
||||
return Create(fs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new AaruFormat from an input stream
|
||||
/// </summary>
|
||||
/// <param name="aarustream">Stream representing the AaruFormat file</param>
|
||||
public static AaruFormat Create(Stream aarustream)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Validate that this is actually a valid AaruFormat (by magic string alone)
|
||||
bool validated = ValidateHeader(aarustream);
|
||||
aarustream.SeekIfPossible(); // Seek back to start
|
||||
if (!validated)
|
||||
return null;
|
||||
|
||||
// Read and retrun the current AaruFormat
|
||||
AaruFormat generated = Deserialize(aarustream);
|
||||
if (generated != null)
|
||||
generated.Type = FileType.AaruFormat;
|
||||
|
||||
return generated;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Header Parsing
|
||||
|
||||
/// <summary>
|
||||
/// Validate we start with the right magic number
|
||||
/// </summary>
|
||||
public static bool ValidateHeader(Stream aarustream)
|
||||
{
|
||||
// Read the magic string
|
||||
byte[] magicBytes = new byte[8];
|
||||
int read = aarustream.Read(magicBytes, 0, 8);
|
||||
|
||||
// If we didn't read the magic fully, we don't have an AaruFormat
|
||||
if (read < 8)
|
||||
return false;
|
||||
|
||||
// If the bytes don't match, we don't have an AaruFormat
|
||||
if (!magicBytes.StartsWith(Constants.AaruFormatSignature))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a stream as an AaruFormat
|
||||
/// </summary>
|
||||
/// <param name="stream">AaruFormat file as a stream</param>
|
||||
/// <returns>Populated AaruFormat file, null on failure</returns>
|
||||
public static AaruFormat Deserialize(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
AaruFormat aif = new AaruFormat();
|
||||
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
aif.Identifier = br.ReadUInt64();
|
||||
aif.Application = Encoding.Unicode.GetString(br.ReadBytes(64), 0, 64);
|
||||
aif.ImageMajorVersion = br.ReadByte();
|
||||
aif.ImageMinorVersion = br.ReadByte();
|
||||
aif.ApplicationMajorVersion = br.ReadByte();
|
||||
aif.ApplicationMinorVersion = br.ReadByte();
|
||||
aif.MediaType = (AaruMediaType)br.ReadUInt32();
|
||||
aif.IndexOffset = br.ReadUInt64();
|
||||
aif.CreationTime = br.ReadInt64();
|
||||
aif.LastWrittenTime = br.ReadInt64();
|
||||
|
||||
// If the offset is bigger than the stream, we can't read it
|
||||
if (aif.IndexOffset > (ulong)stream.Length)
|
||||
return null;
|
||||
|
||||
// Otherwise, we read in the index header
|
||||
stream.Seek((long)aif.IndexOffset, SeekOrigin.Begin);
|
||||
aif.IndexHeader = IndexHeader.Deserialize(stream);
|
||||
if (aif.IndexHeader.entries == 0)
|
||||
return null;
|
||||
|
||||
// Get the list of entries
|
||||
aif.IndexEntries = new IndexEntry[aif.IndexHeader.entries];
|
||||
for (ushort index = 0; index < aif.IndexHeader.entries; index++)
|
||||
{
|
||||
aif.IndexEntries[index] = IndexEntry.Deserialize(stream);
|
||||
switch (aif.IndexEntries[index].blockType)
|
||||
{
|
||||
// We don't do anything with these block types currently
|
||||
case AaruBlockType.DataBlock:
|
||||
case AaruBlockType.DeDuplicationTable:
|
||||
case AaruBlockType.Index:
|
||||
case AaruBlockType.Index2:
|
||||
case AaruBlockType.GeometryBlock:
|
||||
case AaruBlockType.MetadataBlock:
|
||||
case AaruBlockType.TracksBlock:
|
||||
case AaruBlockType.CicmBlock:
|
||||
case AaruBlockType.DataPositionMeasurementBlock:
|
||||
case AaruBlockType.SnapshotBlock:
|
||||
case AaruBlockType.ParentBlock:
|
||||
case AaruBlockType.DumpHardwareBlock:
|
||||
case AaruBlockType.TapeFileBlock:
|
||||
case AaruBlockType.TapePartitionBlock:
|
||||
case AaruBlockType.CompactDiscIndexesBlock:
|
||||
// No-op
|
||||
break;
|
||||
|
||||
// Read in all available hashes
|
||||
case AaruBlockType.ChecksumBlock:
|
||||
// If the offset is bigger than the stream, we can't read it
|
||||
if (aif.IndexEntries[index].offset > (ulong)stream.Length)
|
||||
return null;
|
||||
|
||||
// Otherwise, we read in the block
|
||||
stream.Seek((long)aif.IndexEntries[index].offset, SeekOrigin.Begin);
|
||||
ChecksumHeader checksumHeader = ChecksumHeader.Deserialize(stream);
|
||||
if (checksumHeader.entries == 0)
|
||||
return null;
|
||||
|
||||
// Read through each and pick out the ones we care about
|
||||
for (byte entry = 0; entry < checksumHeader.entries; entry++)
|
||||
{
|
||||
ChecksumEntry checksumEntry = ChecksumEntry.Deserialize(stream);
|
||||
if (checksumEntry == null)
|
||||
continue;
|
||||
|
||||
switch (checksumEntry.type)
|
||||
{
|
||||
case AaruChecksumAlgorithm.Invalid:
|
||||
break;
|
||||
case AaruChecksumAlgorithm.Md5:
|
||||
aif.MD5 = checksumEntry.checksum;
|
||||
break;
|
||||
case AaruChecksumAlgorithm.Sha1:
|
||||
aif.SHA1 = checksumEntry.checksum;
|
||||
break;
|
||||
case AaruChecksumAlgorithm.Sha256:
|
||||
aif.SHA256 = checksumEntry.checksum;
|
||||
break;
|
||||
case AaruChecksumAlgorithm.SpamSum:
|
||||
aif.SpamSum = checksumEntry.checksum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Once we got hashes, we return early
|
||||
return aif;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aif;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We don't care what the error was at this point
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Core;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
public abstract class BaseArchive : Folder
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Determines if dates are read or written
|
||||
/// </summary>
|
||||
public bool UseDates { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected instance variables
|
||||
|
||||
/// <summary>
|
||||
/// Buffer size used by archives
|
||||
/// </summary>
|
||||
protected const int _bufferSize = 4096 * 128;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construtors
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Archive with no base file
|
||||
/// </summary>
|
||||
public BaseArchive()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Archive from the given file
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to use as an archive</param>
|
||||
/// <param name="getHashes">True if hashes for this file should be calculated, false otherwise (default)</param>
|
||||
public BaseArchive(string filename, bool getHashes = false)
|
||||
: base(filename, getHashes)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an archive object from a filename, if possible
|
||||
/// </summary>
|
||||
/// <param name="input">Name of the file to create the archive from</param>
|
||||
/// <returns>Archive object representing the inputs</returns>
|
||||
public static BaseArchive Create(string input)
|
||||
{
|
||||
BaseArchive archive = null;
|
||||
|
||||
// First get the archive type
|
||||
FileType? at = GetFileType(input);
|
||||
|
||||
// If we got back null, then it's not an archive, so we we return
|
||||
if (at == null)
|
||||
return archive;
|
||||
|
||||
// Create the archive based on the type
|
||||
staticLogger.Verbose($"Found archive of type: {at}");
|
||||
switch (at)
|
||||
{
|
||||
case FileType.GZipArchive:
|
||||
archive = new GZipArchive(input);
|
||||
break;
|
||||
|
||||
case FileType.RarArchive:
|
||||
archive = new RarArchive(input);
|
||||
break;
|
||||
|
||||
case FileType.SevenZipArchive:
|
||||
archive = new SevenZipArchive(input);
|
||||
break;
|
||||
|
||||
case FileType.TapeArchive:
|
||||
archive = new TapeArchive(input);
|
||||
break;
|
||||
|
||||
case FileType.ZipArchive:
|
||||
archive = new ZipArchive(input);
|
||||
break;
|
||||
|
||||
default:
|
||||
// We ignore all other types for now
|
||||
break;
|
||||
}
|
||||
|
||||
return archive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an archive object of the specified type, if possible
|
||||
/// </summary>
|
||||
/// <param name="archiveType">SharpCompress.Common.ArchiveType representing the archive to create</param>
|
||||
/// <returns>Archive object representing the inputs</returns>
|
||||
public static BaseArchive Create(FileType archiveType)
|
||||
{
|
||||
switch (archiveType)
|
||||
{
|
||||
case FileType.GZipArchive:
|
||||
return new GZipArchive();
|
||||
|
||||
case FileType.RarArchive:
|
||||
return new RarArchive();
|
||||
|
||||
case FileType.SevenZipArchive:
|
||||
return new SevenZipArchive();
|
||||
|
||||
case FileType.TapeArchive:
|
||||
return new TapeArchive();
|
||||
|
||||
case FileType.ZipArchive:
|
||||
return new ZipArchive();
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extraction
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract bool CopyAll(string outDir);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract string CopyToFile(string entryName, string outDir);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract (MemoryStream, string) CopyToStream(string entryName);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Information
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract List<BaseFile> GetChildren();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract List<string> GetEmptyFolders();
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the input file is a standardized format
|
||||
/// </summary>
|
||||
public abstract bool IsTorrent();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Writing
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract bool Write(string inputFile, string outDir, BaseFile baseFile);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract bool Write(Stream inputStream, string outDir, BaseFile baseFile);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract bool Write(List<string> inputFiles, string outDir, List<BaseFile> baseFiles);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,428 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SabreTools.Core;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Library.IO;
|
||||
using SabreTools.Logging;
|
||||
using Compress.ThreadReaders;
|
||||
|
||||
namespace SabreTools.Library.FileTypes
|
||||
{
|
||||
public class BaseFile
|
||||
{
|
||||
// TODO: Get all of these values automatically so there is no public "set"
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Internal type of the represented file
|
||||
/// </summary>
|
||||
public FileType Type { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filename or path to the file
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Direct parent of the file
|
||||
/// </summary>
|
||||
public string Parent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date stamp of the file
|
||||
/// </summary>
|
||||
public string Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional size of the file
|
||||
/// </summary>
|
||||
public long? Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hashes that are available for the file
|
||||
/// </summary>
|
||||
public Hash AvailableHashes { get; set; } = Hash.Standard;
|
||||
|
||||
/// <summary>
|
||||
/// CRC32 hash of the file
|
||||
/// </summary>
|
||||
public byte[] CRC { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// MD5 hash of the file
|
||||
/// </summary>
|
||||
public byte[] MD5 { get; set; } = null;
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
/// <summary>
|
||||
/// RIPEMD160 hash of the file
|
||||
/// </summary>
|
||||
public byte[] RIPEMD160 { get; set; } = null;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// SHA-1 hash of the file
|
||||
/// </summary>
|
||||
public byte[] SHA1 { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// SHA-256 hash of the file
|
||||
/// </summary>
|
||||
public byte[] SHA256 { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// SHA-384 hash of the file
|
||||
/// </summary>
|
||||
public byte[] SHA384 { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// SHA-512 hash of the file
|
||||
/// </summary>
|
||||
public byte[] SHA512 { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// SpamSum fuzzy hash of the file
|
||||
/// </summary>
|
||||
public byte[] SpamSum { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construtors
|
||||
|
||||
/// <summary>
|
||||
/// Create a new BaseFile with no base file
|
||||
/// </summary>
|
||||
public BaseFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new BaseFile from the given file
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to use</param>
|
||||
/// <param name="getHashes">True if hashes for this file should be calculated (default), false otherwise</param>
|
||||
public BaseFile(string filename, bool getHashes = true)
|
||||
{
|
||||
this.Filename = filename;
|
||||
|
||||
if (getHashes)
|
||||
{
|
||||
BaseFile temp = GetInfo(this.Filename, hashes: this.AvailableHashes);
|
||||
if (temp != null)
|
||||
{
|
||||
this.Parent = temp.Parent;
|
||||
this.Date = temp.Date;
|
||||
this.CRC = temp.CRC;
|
||||
this.MD5 = temp.MD5;
|
||||
#if NET_FRAMEWORK
|
||||
this.RIPEMD160 = temp.RIPEMD160;
|
||||
#endif
|
||||
this.SHA1 = temp.SHA1;
|
||||
this.SHA256 = temp.SHA256;
|
||||
this.SHA384 = temp.SHA384;
|
||||
this.SHA512 = temp.SHA512;
|
||||
this.SpamSum = temp.SpamSum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new BaseFile from the given file
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the file to use</param>
|
||||
/// <param name="stream">Stream to populate information from</param>
|
||||
/// <param name="getHashes">True if hashes for this file should be calculated (default), false otherwise</param>
|
||||
public BaseFile(string filename, Stream stream, bool getHashes = true)
|
||||
{
|
||||
this.Filename = filename;
|
||||
|
||||
if (getHashes)
|
||||
{
|
||||
BaseFile temp = GetInfo(stream, hashes: this.AvailableHashes);
|
||||
if (temp != null)
|
||||
{
|
||||
this.Parent = temp.Parent;
|
||||
this.Date = temp.Date;
|
||||
this.CRC = temp.CRC;
|
||||
this.MD5 = temp.MD5;
|
||||
#if NET_FRAMEWORK
|
||||
this.RIPEMD160 = temp.RIPEMD160;
|
||||
#endif
|
||||
this.SHA1 = temp.SHA1;
|
||||
this.SHA256 = temp.SHA256;
|
||||
this.SHA384 = temp.SHA384;
|
||||
this.SHA512 = temp.SHA512;
|
||||
this.SpamSum = temp.SpamSum;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file type of an input file
|
||||
/// </summary>
|
||||
/// <param name="input">Input file to check</param>
|
||||
/// <returns>FileType of inputted file (null on error)</returns>
|
||||
public static FileType? GetFileType(string input)
|
||||
{
|
||||
FileType? outFileType = null;
|
||||
|
||||
// If the file is null, then we have no archive type
|
||||
if (input == null)
|
||||
return outFileType;
|
||||
|
||||
// First line of defense is going to be the extension, for better or worse
|
||||
if (!PathExtensions.HasValidArchiveExtension(input))
|
||||
return outFileType;
|
||||
|
||||
// Read the first bytes of the file and get the magic number
|
||||
BinaryReader br = new BinaryReader(File.OpenRead(input));
|
||||
byte[] magic = br.ReadBytes(8);
|
||||
br.Dispose();
|
||||
|
||||
// Now try to match it to a known signature
|
||||
if (magic.StartsWith(Constants.SevenZipSignature))
|
||||
{
|
||||
outFileType = FileType.SevenZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.AaruFormatSignature))
|
||||
{
|
||||
outFileType = FileType.AaruFormat;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.CHDSignature))
|
||||
{
|
||||
outFileType = FileType.CHD;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.GzSignature))
|
||||
{
|
||||
outFileType = FileType.GZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.LRZipSignature))
|
||||
{
|
||||
outFileType = FileType.LRZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.LZ4Signature)
|
||||
|| magic.StartsWith(Constants.LZ4SkippableMinSignature)
|
||||
|| magic.StartsWith(Constants.LZ4SkippableMaxSignature))
|
||||
{
|
||||
outFileType = FileType.LZ4Archive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.RarSignature)
|
||||
|| magic.StartsWith(Constants.RarFiveSignature))
|
||||
{
|
||||
outFileType = FileType.RarArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.TarSignature)
|
||||
|| magic.StartsWith(Constants.TarZeroSignature))
|
||||
{
|
||||
outFileType = FileType.TapeArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.XZSignature))
|
||||
{
|
||||
outFileType = FileType.XZArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZipSignature)
|
||||
|| magic.StartsWith(Constants.ZipSignatureEmpty)
|
||||
|| magic.StartsWith(Constants.ZipSignatureSpanned))
|
||||
{
|
||||
outFileType = FileType.ZipArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZPAQSignature))
|
||||
{
|
||||
outFileType = FileType.ZPAQArchive;
|
||||
}
|
||||
else if (magic.StartsWith(Constants.ZstdSignature))
|
||||
{
|
||||
outFileType = FileType.ZstdArchive;
|
||||
}
|
||||
|
||||
return outFileType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve file information for a single file
|
||||
/// </summary>
|
||||
/// <param name="input">Filename to get information from</param>
|
||||
/// <param name="header">Populated string representing the name of the skipper to use, a blank string to use the first available checker, null otherwise</param>
|
||||
/// <param name="hashes">Hashes to include in the information</param>
|
||||
/// <param name="asFiles">TreatAsFiles representing special format scanning</param>
|
||||
/// <returns>Populated BaseFile object if success, empty one on error</returns>
|
||||
public static BaseFile GetInfo(string input, string header = null, Hash hashes = Hash.Standard, TreatAsFile asFiles = 0x00)
|
||||
{
|
||||
// Add safeguard if file doesn't exist
|
||||
if (!File.Exists(input))
|
||||
return null;
|
||||
|
||||
// Get input information
|
||||
var fileType = GetFileType(input);
|
||||
Stream inputStream = File.OpenRead(input);
|
||||
|
||||
// Try to match the supplied header skipper
|
||||
if (header != null)
|
||||
{
|
||||
var rule = Transform.GetMatchingRule(input, Path.GetFileNameWithoutExtension(header));
|
||||
|
||||
// If there's a match, transform the stream before getting info
|
||||
if (rule.Tests != null && rule.Tests.Count != 0)
|
||||
{
|
||||
// Create the output stream
|
||||
MemoryStream outputStream = new MemoryStream();
|
||||
|
||||
// Transform the stream and get the information from it
|
||||
rule.TransformStream(inputStream, outputStream, keepReadOpen: false, keepWriteOpen: true);
|
||||
inputStream = outputStream;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the info in the proper manner
|
||||
BaseFile baseFile;
|
||||
if (fileType == FileType.AaruFormat && !asFiles.HasFlag(TreatAsFile.AaruFormat))
|
||||
baseFile = AaruFormat.Create(inputStream);
|
||||
else if (fileType == FileType.CHD && !asFiles.HasFlag(TreatAsFile.CHD))
|
||||
baseFile = CHDFile.Create(inputStream);
|
||||
else
|
||||
baseFile = GetInfo(inputStream, hashes: hashes, keepReadOpen: false);
|
||||
|
||||
// Dispose of the input stream
|
||||
inputStream?.Dispose();
|
||||
|
||||
// Add unique data from the file
|
||||
baseFile.Filename = Path.GetFileName(input);
|
||||
baseFile.Date = new FileInfo(input).LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss");
|
||||
|
||||
return baseFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve file information for a single file
|
||||
/// </summary>
|
||||
/// <param name="input">Filename to get information from</param>
|
||||
/// <param name="size">Size of the input stream</param>
|
||||
/// <param name="hashes">Hashes to include in the information</param>
|
||||
/// <param name="keepReadOpen">True if the underlying read stream should be kept open, false otherwise</param>
|
||||
/// <returns>Populated BaseFile object if success, empty one on error</returns>
|
||||
public static BaseFile GetInfo(Stream input, long size = -1, Hash hashes = Hash.Standard, bool keepReadOpen = false)
|
||||
{
|
||||
// If we want to automatically set the size
|
||||
if (size == -1)
|
||||
size = input.Length;
|
||||
|
||||
try
|
||||
{
|
||||
// Get a list of hashers to run over the buffer
|
||||
List<Hasher> hashers = new List<Hasher>();
|
||||
|
||||
if (hashes.HasFlag(Hash.CRC))
|
||||
hashers.Add(new Hasher(Hash.CRC));
|
||||
if (hashes.HasFlag(Hash.MD5))
|
||||
hashers.Add(new Hasher(Hash.MD5));
|
||||
#if NET_FRAMEWORK
|
||||
if (hashes.HasFlag(Hash.RIPEMD160))
|
||||
hashers.Add(new Hasher(Hash.RIPEMD160));
|
||||
#endif
|
||||
if (hashes.HasFlag(Hash.SHA1))
|
||||
hashers.Add(new Hasher(Hash.SHA1));
|
||||
if (hashes.HasFlag(Hash.SHA256))
|
||||
hashers.Add(new Hasher(Hash.SHA256));
|
||||
if (hashes.HasFlag(Hash.SHA384))
|
||||
hashers.Add(new Hasher(Hash.SHA384));
|
||||
if (hashes.HasFlag(Hash.SHA512))
|
||||
hashers.Add(new Hasher(Hash.SHA512));
|
||||
if (hashes.HasFlag(Hash.SpamSum))
|
||||
hashers.Add(new Hasher(Hash.SpamSum));
|
||||
|
||||
// Initialize the hashing helpers
|
||||
var loadBuffer = new ThreadLoadBuffer(input);
|
||||
int buffersize = 3 * 1024 * 1024;
|
||||
byte[] buffer0 = new byte[buffersize];
|
||||
byte[] buffer1 = new byte[buffersize];
|
||||
|
||||
/*
|
||||
Please note that some of the following code is adapted from
|
||||
RomVault. This is a modified version of how RomVault does
|
||||
threaded hashing. As such, some of the terminology and code
|
||||
is the same, though variable names and comments may have
|
||||
been tweaked to better fit this code base.
|
||||
*/
|
||||
|
||||
// Pre load the first buffer
|
||||
long refsize = size;
|
||||
int next = refsize > buffersize ? buffersize : (int)refsize;
|
||||
input.Read(buffer0, 0, next);
|
||||
int current = next;
|
||||
refsize -= next;
|
||||
bool bufferSelect = true;
|
||||
|
||||
while (current > 0)
|
||||
{
|
||||
// Trigger the buffer load on the second buffer
|
||||
next = refsize > buffersize ? buffersize : (int)refsize;
|
||||
if (next > 0)
|
||||
loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next);
|
||||
|
||||
byte[] buffer = bufferSelect ? buffer0 : buffer1;
|
||||
|
||||
// Run hashes in parallel
|
||||
Parallel.ForEach(hashers, Globals.ParallelOptions, h => h.Process(buffer, current));
|
||||
|
||||
// Wait for the load buffer worker, if needed
|
||||
if (next > 0)
|
||||
loadBuffer.Wait();
|
||||
|
||||
// Setup for the next hashing step
|
||||
current = next;
|
||||
refsize -= next;
|
||||
bufferSelect = !bufferSelect;
|
||||
}
|
||||
|
||||
// Finalize all hashing helpers
|
||||
loadBuffer.Finish();
|
||||
Parallel.ForEach(hashers, Globals.ParallelOptions, h => h.Finalize());
|
||||
|
||||
// Get the results
|
||||
BaseFile baseFile = new BaseFile()
|
||||
{
|
||||
Size = size,
|
||||
CRC = hashes.HasFlag(Hash.CRC) ? hashers.First(h => h.HashType == Hash.CRC).GetHash() : null,
|
||||
MD5 = hashes.HasFlag(Hash.MD5) ? hashers.First(h => h.HashType == Hash.MD5).GetHash() : null,
|
||||
#if NET_FRAMEWORK
|
||||
RIPEMD160 = hashes.HasFlag(Hash.RIPEMD160) ? hashers.First(h => h.HashType == Hash.RIPEMD160).GetHash() : null,
|
||||
#endif
|
||||
SHA1 = hashes.HasFlag(Hash.SHA1) ? hashers.First(h => h.HashType == Hash.SHA1).GetHash() : null,
|
||||
SHA256 = hashes.HasFlag(Hash.SHA256) ? hashers.First(h => h.HashType == Hash.SHA256).GetHash() : null,
|
||||
SHA384 = hashes.HasFlag(Hash.SHA384) ? hashers.First(h => h.HashType == Hash.SHA384).GetHash() : null,
|
||||
SHA512 = hashes.HasFlag(Hash.SHA512) ? hashers.First(h => h.HashType == Hash.SHA512).GetHash() : null,
|
||||
SpamSum = hashes.HasFlag(Hash.SpamSum) ? hashers.First(h => h.HashType == Hash.SpamSum).GetHash() : null,
|
||||
};
|
||||
|
||||
// Dispose of the hashers
|
||||
loadBuffer.Dispose();
|
||||
hashers.ForEach(h => h.Dispose());
|
||||
|
||||
return baseFile;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
LoggerImpl.Warning(ex, "An exception occurred during hashing.");
|
||||
return new BaseFile();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!keepReadOpen)
|
||||
input.Dispose();
|
||||
else
|
||||
input.SeekIfPossible();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user