Blind update of zip code to newest RVWorld version

This commit is contained in:
Matt Nadareski
2019-12-04 15:42:30 -08:00
parent 1f3420a08f
commit 9c393b12c6
97 changed files with 27794 additions and 13760 deletions

View File

@@ -0,0 +1,152 @@
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);
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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

View File

@@ -0,0 +1,138 @@

/*
* 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;
}
}

View File

@@ -0,0 +1,366 @@
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; }
}
}

View File

@@ -0,0 +1,148 @@
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;
}
}
}
}

View File

@@ -0,0 +1,186 @@
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;
}
}
}
}

View File

@@ -0,0 +1,74 @@
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;
}
}

View File

@@ -0,0 +1,404 @@
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

View File

@@ -0,0 +1,57 @@
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
};
}
}
}

View File

@@ -0,0 +1,318 @@
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;
}
}
}
}

View File

@@ -0,0 +1,75 @@
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();
}
}
}

View File

@@ -0,0 +1,945 @@
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);
}
}
}
}

View File

@@ -0,0 +1,563 @@
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);
}
}
}

View File

@@ -0,0 +1,34 @@
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;
}
}
}

View File

@@ -0,0 +1,183 @@
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();
}
}
}

View File

@@ -0,0 +1,125 @@
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);
}
}
}
}

View File

@@ -0,0 +1,53 @@
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();
}
}
}

View File

@@ -0,0 +1,107 @@
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();
}
}
}

View File

@@ -0,0 +1,120 @@
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();
}
}
}

View File

@@ -0,0 +1,90 @@
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();
}
}
}

View File

@@ -0,0 +1,489 @@
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);
}
}
}

View File

@@ -0,0 +1,457 @@
#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
}
}

View File

@@ -0,0 +1,100 @@
#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;
}
}
}

View File

@@ -0,0 +1,246 @@
#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();
}
}
}

View File

@@ -0,0 +1,819 @@
#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
}
}

View File

@@ -0,0 +1,29 @@
#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
}
}

View File

@@ -0,0 +1,319 @@
#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();
}
}
}

View File

@@ -0,0 +1,787 @@
#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;
}
}
}

View File

@@ -0,0 +1,206 @@
#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();
}
}
}

View File

@@ -0,0 +1,55 @@
#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++);
}
}
}
}

View File

@@ -0,0 +1,81 @@
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)));
}
}
}
}

View File

@@ -0,0 +1,154 @@
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);
}
}
}

View File

@@ -0,0 +1,467 @@
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
}
}

View File

@@ -0,0 +1,247 @@
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(); }
}
}

View File

@@ -0,0 +1,119 @@
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;
}
}
}
}

View File

@@ -0,0 +1,157 @@
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;
}
}
}

View File

@@ -0,0 +1,204 @@
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();
}
}
}

View File

@@ -0,0 +1,90 @@
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;
}
}
}

View File

@@ -0,0 +1,100 @@
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();
}
}
}
}

View File

@@ -0,0 +1,171 @@
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);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
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);
}
}
}

View File

@@ -0,0 +1,159 @@
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
}
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;
}
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()}");
}
}
}

View File

@@ -0,0 +1,140 @@
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(" ------");
}
}
}

View File

@@ -0,0 +1,434 @@
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);
}
if (Folders[0].UnpackCRC != null)
{
bw.Write((byte) HeaderProperty.kCRC);
throw new NotImplementedException();
}
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);
}
}
}
}
}

View File

@@ -0,0 +1,133 @@
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());
}
}
}
private void Write(BinaryWriter bw)
{
bw.Write((byte)HeaderProperty.kHeader);
StreamsInfo.Write(bw);
FileInfo.Write(bw);
bw.Write((byte)HeaderProperty.kEnd);
}
public void WriteHeader(BinaryWriter bw)
{
Write(bw);
}
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);
}
}
}
}

View File

@@ -0,0 +1,98 @@
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}");
}
}
}

View File

@@ -0,0 +1,110 @@
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);
}
}
}

View File

@@ -0,0 +1,84 @@
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 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);
}
}
}
}
}

View File

@@ -0,0 +1,16 @@
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}");
}
}
}

View File

@@ -0,0 +1,351 @@
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();
}
}
}
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;
}
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;
}
}
}