unpack_hpp.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. #if !Rar2017_64bit
  2. using nint = System.Int32;
  3. using nuint = System.UInt32;
  4. using size_t = System.UInt32;
  5. #else
  6. using nint = System.Int64;
  7. using nuint = System.UInt64;
  8. using size_t = System.UInt64;
  9. #endif
  10. using int64 = System.Int64;
  11. using System.Collections.Generic;
  12. using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
  13. using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
  14. // TODO: REMOVE THIS... WIP
  15. #pragma warning disable 169
  16. #pragma warning disable 414
  17. namespace SharpCompress.Compressors.Rar.UnpackV2017
  18. {
  19. internal static class UnpackGlobal
  20. {
  21. // Maximum allowed number of compressed bits processed in quick mode.
  22. public const int MAX_QUICK_DECODE_BITS =10;
  23. // Maximum number of filters per entire data block. Must be at least
  24. // twice more than MAX_PACK_FILTERS to store filters from two data blocks.
  25. public const int MAX_UNPACK_FILTERS =8192;
  26. // Maximum number of filters per entire data block for RAR3 unpack.
  27. // Must be at least twice more than v3_MAX_PACK_FILTERS to store filters
  28. // from two data blocks.
  29. public const int MAX3_UNPACK_FILTERS =8192;
  30. // Limit maximum number of channels in RAR3 delta filter to some reasonable
  31. // value to prevent too slow processing of corrupt archives with invalid
  32. // channels number. Must be equal or larger than v3_MAX_FILTER_CHANNELS.
  33. // No need to provide it for RAR5, which uses only 5 bits to store channels.
  34. private const int MAX3_UNPACK_CHANNELS =1024;
  35. // Maximum size of single filter block. We restrict it to limit memory
  36. // allocation. Must be equal or larger than MAX_ANALYZE_SIZE.
  37. public const int MAX_FILTER_BLOCK_SIZE =0x400000;
  38. // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE,
  39. // so we keep number of buffered filter in unpacker reasonable.
  40. public const int UNPACK_MAX_WRITE =0x400000;
  41. }
  42. // Decode compressed bit fields to alphabet numbers.
  43. internal sealed class DecodeTable
  44. {
  45. // Real size of DecodeNum table.
  46. public uint MaxNum;
  47. // Left aligned start and upper limit codes defining code space
  48. // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of
  49. // range for bit length and DecodeLen[BitLength] defines next code
  50. // after the end of range or in other words the upper limit code
  51. // for specified bit length.
  52. public readonly uint[] DecodeLen = new uint[16];
  53. // Every item of this array contains the sum of all preceding items.
  54. // So it contains the start position in code list for every bit length.
  55. public readonly uint[] DecodePos = new uint[16];
  56. // Number of compressed bits processed in quick mode.
  57. // Must not exceed MAX_QUICK_DECODE_BITS.
  58. public uint QuickBits;
  59. // Translates compressed bits (up to QuickBits length)
  60. // to bit length in quick mode.
  61. public readonly byte[] QuickLen = new byte[1<<MAX_QUICK_DECODE_BITS];
  62. // Translates compressed bits (up to QuickBits length)
  63. // to position in alphabet in quick mode.
  64. // 'ushort' saves some memory and even provides a little speed gain
  65. // comparting to 'uint' here.
  66. public readonly ushort[] QuickNum = new ushort[1<<MAX_QUICK_DECODE_BITS];
  67. // Translate the position in code list to position in alphabet.
  68. // We do not allocate it dynamically to avoid performance overhead
  69. // introduced by pointer, so we use the largest possible table size
  70. // as array dimension. Real size of this array is defined in MaxNum.
  71. // We use this array if compressed bit field is too lengthy
  72. // for QuickLen based translation.
  73. // 'ushort' saves some memory and even provides a little speed gain
  74. // comparting to 'uint' here.
  75. public readonly ushort[] DecodeNum = new ushort[LARGEST_TABLE_SIZE];
  76. };
  77. internal struct UnpackBlockHeader
  78. {
  79. public int BlockSize;
  80. public int BlockBitSize;
  81. public int BlockStart;
  82. public int HeaderSize;
  83. public bool LastBlockInFile;
  84. public bool TablePresent;
  85. };
  86. internal struct UnpackBlockTables
  87. {
  88. public DecodeTable LD; // Decode literals.
  89. public DecodeTable DD; // Decode distances.
  90. public DecodeTable LDD; // Decode lower bits of distances.
  91. public DecodeTable RD; // Decode repeating distances.
  92. public DecodeTable BD; // Decode bit lengths in Huffman table.
  93. public void Init() {
  94. LD = new DecodeTable();
  95. DD = new DecodeTable();
  96. LDD = new DecodeTable();
  97. RD = new DecodeTable();
  98. BD = new DecodeTable();
  99. }
  100. };
  101. #if RarV2017_RAR_SMP
  102. enum UNP_DEC_TYPE {
  103. UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
  104. };
  105. struct UnpackDecodedItem
  106. {
  107. UNP_DEC_TYPE Type;
  108. ushort Length;
  109. union
  110. {
  111. uint Distance;
  112. byte Literal[4];
  113. };
  114. };
  115. struct UnpackThreadData
  116. {
  117. Unpack *UnpackPtr;
  118. BitInput Inp;
  119. bool HeaderRead;
  120. UnpackBlockHeader BlockHeader;
  121. bool TableRead;
  122. UnpackBlockTables BlockTables;
  123. int DataSize; // Data left in buffer. Can be less than block size.
  124. bool DamagedData;
  125. bool LargeBlock;
  126. bool NoDataLeft; // 'true' if file is read completely.
  127. bool Incomplete; // Not entire block was processed, need to read more data.
  128. UnpackDecodedItem *Decoded;
  129. uint DecodedSize;
  130. uint DecodedAllocated;
  131. uint ThreadNumber; // For debugging.
  132. UnpackThreadData()
  133. :Inp(false)
  134. {
  135. Decoded=NULL;
  136. }
  137. ~UnpackThreadData()
  138. {
  139. if (Decoded!=NULL)
  140. free(Decoded);
  141. }
  142. };
  143. #endif
  144. //struct UnpackFilter
  145. internal class UnpackFilter
  146. {
  147. public byte Type;
  148. public uint BlockStart;
  149. public uint BlockLength;
  150. public byte Channels;
  151. // uint Width;
  152. // byte PosR;
  153. public bool NextWindow;
  154. };
  155. //struct UnpackFilter30
  156. internal class UnpackFilter30
  157. {
  158. public uint BlockStart;
  159. public uint BlockLength;
  160. public bool NextWindow;
  161. // Position of parent filter in Filters array used as prototype for filter
  162. // in PrgStack array. Not defined for filters in Filters array.
  163. public uint ParentFilter;
  164. /*#if !RarV2017_RAR5ONLY
  165. public VM_PreparedProgram Prg;
  166. #endif*/
  167. };
  168. internal class AudioVariables // For RAR 2.0 archives only.
  169. {
  170. public int K1,K2,K3,K4,K5;
  171. public int D1,D2,D3,D4;
  172. public int LastDelta;
  173. public readonly uint[] Dif = new uint[11];
  174. public uint ByteCount;
  175. public int LastChar;
  176. };
  177. // We can use the fragmented dictionary in case heap does not have the single
  178. // large enough memory block. It is slower than normal dictionary.
  179. internal partial class FragmentedWindow
  180. {
  181. private const int MAX_MEM_BLOCKS=32;
  182. //void Reset();
  183. private readonly byte[][] Mem = new byte[MAX_MEM_BLOCKS][];
  184. private readonly size_t[] MemSize = new size_t[MAX_MEM_BLOCKS];
  185. //FragmentedWindow();
  186. //~FragmentedWindow();
  187. //void Init(size_t WinSize);
  188. //byte& operator [](size_t Item);
  189. //void CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask);
  190. //void CopyData(byte *Dest,size_t WinPos,size_t Size);
  191. //size_t GetBlockSize(size_t StartPos,size_t RequiredSize);
  192. };
  193. internal partial class Unpack
  194. {
  195. //void Unpack5(bool Solid);
  196. //void Unpack5MT(bool Solid);
  197. //bool UnpReadBuf();
  198. //void UnpWriteBuf();
  199. //byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt);
  200. //void UnpWriteArea(size_t StartPtr,size_t EndPtr);
  201. //void UnpWriteData(byte *Data,size_t Size);
  202. //_forceinline uint SlotToLength(BitInput &Inp,uint Slot);
  203. //void UnpInitData50(bool Solid);
  204. //bool ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header);
  205. //bool ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables);
  206. //void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size);
  207. //_forceinline uint DecodeNumber(BitInput &Inp,DecodeTable *Dec);
  208. //void CopyString();
  209. //inline void InsertOldDist(uint Distance);
  210. //void UnpInitData(bool Solid);
  211. //_forceinline void CopyString(uint Length,uint Distance);
  212. //uint ReadFilterData(BitInput &Inp);
  213. //bool ReadFilter(BitInput &Inp,UnpackFilter &Filter);
  214. //bool AddFilter(UnpackFilter &Filter);
  215. //bool AddFilter();
  216. //void InitFilters();
  217. //ComprDataIO *UnpIO;
  218. //BitInput Inp;
  219. private BitInput Inp { get { return this; } } // hopefully this gets inlined
  220. #if RarV2017_RAR_SMP
  221. void InitMT();
  222. bool UnpackLargeBlock(UnpackThreadData &D);
  223. bool ProcessDecoded(UnpackThreadData &D);
  224. ThreadPool *UnpThreadPool;
  225. UnpackThreadData *UnpThreadData;
  226. uint MaxUserThreads;
  227. byte *ReadBufMT;
  228. #endif
  229. private byte[] FilterSrcMemory = new byte[0];
  230. private byte[] FilterDstMemory = new byte[0];
  231. // Filters code, one entry per filter.
  232. private readonly List<UnpackFilter> Filters = new List<UnpackFilter>();
  233. private readonly uint[] OldDist = new uint[4];
  234. private uint OldDistPtr;
  235. private uint LastLength;
  236. // LastDist is necessary only for RAR2 and older with circular OldDist
  237. // array. In RAR3 last distance is always stored in OldDist[0].
  238. private uint LastDist;
  239. private size_t UnpPtr,WrPtr;
  240. // Top border of read packed data.
  241. private int ReadTop;
  242. // Border to call UnpReadBuf. We use it instead of (ReadTop-C)
  243. // for optimization reasons. Ensures that we have C bytes in buffer
  244. // unless we are at the end of file.
  245. private int ReadBorder;
  246. private UnpackBlockHeader BlockHeader;
  247. private UnpackBlockTables BlockTables;
  248. private size_t WriteBorder;
  249. private byte[] Window;
  250. private readonly FragmentedWindow FragWindow = new FragmentedWindow();
  251. private bool Fragmented;
  252. private int64 DestUnpSize;
  253. //bool Suspended;
  254. private bool UnpAllBuf;
  255. private bool UnpSomeRead;
  256. private int64 WrittenFileSize;
  257. private bool FileExtracted;
  258. /***************************** Unpack v 1.5 *********************************/
  259. //void Unpack15(bool Solid);
  260. //void ShortLZ();
  261. //void LongLZ();
  262. //void HuffDecode();
  263. //void GetFlagsBuf();
  264. //void UnpInitData15(int Solid);
  265. //void InitHuff();
  266. //void CorrHuff(ushort *CharSet,byte *NumToPlace);
  267. //void CopyString15(uint Distance,uint Length);
  268. //uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab);
  269. private readonly ushort[] ChSet = new ushort[256],ChSetA = new ushort[256],ChSetB = new ushort[256],ChSetC = new ushort[256];
  270. private readonly byte[] NToPl = new byte[256],NToPlB = new byte[256],NToPlC = new byte[256];
  271. private uint FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
  272. private int Buf60,NumHuf,StMode,LCount,FlagsCnt;
  273. private uint Nhfb,Nlzb,MaxDist3;
  274. /***************************** Unpack v 1.5 *********************************/
  275. /***************************** Unpack v 2.0 *********************************/
  276. //void Unpack20(bool Solid);
  277. private DecodeTable[] MD = new DecodeTable[4]; // Decode multimedia data, up to 4 channels.
  278. private readonly byte[] UnpOldTable20 = new byte[MC20*4];
  279. private bool UnpAudioBlock;
  280. private uint UnpChannels,UnpCurChannel;
  281. private int UnpChannelDelta;
  282. //void CopyString20(uint Length,uint Distance);
  283. //bool ReadTables20();
  284. //void UnpWriteBuf20();
  285. //void UnpInitData20(int Solid);
  286. //void ReadLastTables();
  287. //byte DecodeAudio(int Delta);
  288. private AudioVariables[] AudV = new AudioVariables[4];
  289. /***************************** Unpack v 2.0 *********************************/
  290. /***************************** Unpack v 3.0 *********************************/
  291. public const int BLOCK_LZ = 0;
  292. public const int BLOCK_PPM = 1;
  293. //void UnpInitData30(bool Solid);
  294. //void Unpack29(bool Solid);
  295. //void InitFilters30(bool Solid);
  296. //bool ReadEndOfBlock();
  297. //bool ReadVMCode();
  298. //bool ReadVMCodePPM();
  299. //bool AddVMCode(uint FirstByte,byte *Code,int CodeSize);
  300. //int SafePPMDecodeChar();
  301. //bool ReadTables30();
  302. //bool UnpReadBuf30();
  303. //void UnpWriteBuf30();
  304. //void ExecuteCode(VM_PreparedProgram *Prg);
  305. private int PrevLowDist,LowDistRepCount;
  306. /*#if !RarV2017_RAR5ONLY
  307. ModelPPM PPM;
  308. #endif*/
  309. private int PPMEscChar;
  310. private readonly byte [] UnpOldTable = new byte[HUFF_TABLE_SIZE30];
  311. private int UnpBlockType;
  312. // If we already read decoding tables for Unpack v2,v3,v5.
  313. // We should not use a single variable for all algorithm versions,
  314. // because we can have a corrupt archive with one algorithm file
  315. // followed by another algorithm file with "solid" flag and we do not
  316. // want to reuse tables from one algorithm in another.
  317. private bool TablesRead2,TablesRead3,TablesRead5;
  318. // Virtual machine to execute filters code.
  319. /*#if !RarV2017_RAR5ONLY
  320. RarVM VM;
  321. #endif*/
  322. // Buffer to read VM filters code. We moved it here from AddVMCode
  323. // function to reduce time spent in BitInput constructor.
  324. private readonly BitInput VMCodeInp = new BitInput(true);
  325. // Filters code, one entry per filter.
  326. private readonly List<UnpackFilter30> Filters30 = new List<UnpackFilter30>();
  327. // Filters stack, several entrances of same filter are possible.
  328. private readonly List<UnpackFilter30> PrgStack = new List<UnpackFilter30>();
  329. // Lengths of preceding data blocks, one length of one last block
  330. // for every filter. Used to reduce the size required to write
  331. // the data block length if lengths are repeating.
  332. private readonly List<int> OldFilterLengths = new List<int>();
  333. private int LastFilter;
  334. /***************************** Unpack v 3.0 *********************************/
  335. //Unpack(ComprDataIO *DataIO);
  336. //~Unpack();
  337. //void Init(size_t WinSize,bool Solid);
  338. //void DoUnpack(uint Method,bool Solid);
  339. private bool IsFileExtracted() {return(FileExtracted);}
  340. private void SetDestSize(int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
  341. private void SetSuspended(bool Suspended) {this.Suspended=Suspended;}
  342. #if RarV2017_RAR_SMP
  343. // More than 8 threads are unlikely to provide a noticeable gain
  344. // for unpacking, but would use the additional memory.
  345. void SetThreads(uint Threads) {MaxUserThreads=Min(Threads,8);}
  346. void UnpackDecode(UnpackThreadData &D);
  347. #endif
  348. private size_t MaxWinSize;
  349. private size_t MaxWinMask;
  350. private uint GetChar()
  351. {
  352. if (Inp.InAddr>MAX_SIZE-30)
  353. UnpReadBuf();
  354. return(Inp.InBuf[Inp.InAddr++]);
  355. }
  356. }
  357. }