Unpack.unpack_cpp.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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 System;
  11. using SharpCompress.Common;
  12. using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
  13. using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
  14. namespace SharpCompress.Compressors.Rar.UnpackV2017
  15. {
  16. internal sealed partial class Unpack : BitInput
  17. {
  18. public Unpack(/* ComprDataIO *DataIO */)
  19. //:Inp(true),VMCodeInp(true)
  20. : base(true)
  21. {
  22. _UnpackCtor();
  23. //UnpIO=DataIO;
  24. Window=null;
  25. Fragmented=false;
  26. Suspended=false;
  27. UnpAllBuf=false;
  28. UnpSomeRead=false;
  29. #if RarV2017_RAR_SMP
  30. MaxUserThreads=1;
  31. UnpThreadPool=CreateThreadPool();
  32. ReadBufMT=null;
  33. UnpThreadData=null;
  34. #endif
  35. MaxWinSize=0;
  36. MaxWinMask=0;
  37. // Perform initialization, which should be done only once for all files.
  38. // It prevents crash if first DoUnpack call is later made with wrong
  39. // (true) 'Solid' value.
  40. UnpInitData(false);
  41. #if !RarV2017_SFX_MODULE
  42. // RAR 1.5 decompression initialization
  43. UnpInitData15(false);
  44. InitHuff();
  45. #endif
  46. }
  47. // later: may need Dispose() if we support thread pool
  48. //Unpack::~Unpack()
  49. //{
  50. // InitFilters30(false);
  51. //
  52. // if (Window!=null)
  53. // free(Window);
  54. //#if RarV2017_RAR_SMP
  55. // DestroyThreadPool(UnpThreadPool);
  56. // delete[] ReadBufMT;
  57. // delete[] UnpThreadData;
  58. //#endif
  59. //}
  60. private void Init(size_t WinSize,bool Solid)
  61. {
  62. // If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size
  63. // will be 0 because of size_t overflow. Let's issue the memory error.
  64. if (WinSize==0)
  65. //ErrHandler.MemoryError();
  66. throw new InvalidFormatException("invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)");
  67. // Minimum window size must be at least twice more than maximum possible
  68. // size of filter block, which is 0x10000 in RAR now. If window size is
  69. // smaller, we can have a block with never cleared flt->NextWindow flag
  70. // in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's
  71. // use 0x40000 for extra safety and possible filter area size expansion.
  72. const size_t MinAllocSize=0x40000;
  73. if (WinSize<MinAllocSize)
  74. WinSize=MinAllocSize;
  75. if (WinSize<=MaxWinSize) // Use the already allocated window.
  76. return;
  77. if ((WinSize>>16)>0x10000) // Window size must not exceed 4 GB.
  78. return;
  79. // Archiving code guarantees that window size does not grow in the same
  80. // solid stream. So if we are here, we are either creating a new window
  81. // or increasing the size of non-solid window. So we could safely reject
  82. // current window data without copying them to a new window, though being
  83. // extra cautious, we still handle the solid window grow case below.
  84. bool Grow=Solid && (Window!=null || Fragmented);
  85. // We do not handle growth for existing fragmented window.
  86. if (Grow && Fragmented)
  87. //throw std::bad_alloc();
  88. throw new InvalidFormatException("Grow && Fragmented");
  89. byte[] NewWindow=Fragmented ? null : new byte[WinSize];
  90. if (NewWindow==null)
  91. if (Grow || WinSize<0x1000000)
  92. {
  93. // We do not support growth for new fragmented window.
  94. // Also exclude RAR4 and small dictionaries.
  95. //throw std::bad_alloc();
  96. throw new InvalidFormatException("Grow || WinSize<0x1000000");
  97. }
  98. else
  99. {
  100. if (Window!=null) // If allocated by preceding files.
  101. {
  102. //free(Window);
  103. Window=null;
  104. }
  105. FragWindow.Init(WinSize);
  106. Fragmented=true;
  107. }
  108. if (!Fragmented)
  109. {
  110. // Clean the window to generate the same output when unpacking corrupt
  111. // RAR files, which may access unused areas of sliding dictionary.
  112. // sharpcompress: don't need this, freshly allocated above
  113. //memset(NewWindow,0,WinSize);
  114. // If Window is not NULL, it means that window size has grown.
  115. // In solid streams we need to copy data to a new window in such case.
  116. // RAR archiving code does not allow it in solid streams now,
  117. // but let's implement it anyway just in case we'll change it sometimes.
  118. if (Grow)
  119. for (size_t I=1;I<=MaxWinSize;I++)
  120. NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)];
  121. //if (Window!=null)
  122. // free(Window);
  123. Window=NewWindow;
  124. }
  125. MaxWinSize=WinSize;
  126. MaxWinMask=MaxWinSize-1;
  127. }
  128. private void DoUnpack(uint Method,bool Solid)
  129. {
  130. // Methods <50 will crash in Fragmented mode when accessing NULL Window.
  131. // They cannot be called in such mode now, but we check it below anyway
  132. // just for extra safety.
  133. switch(Method)
  134. {
  135. #if !RarV2017_SFX_MODULE
  136. case 15: // rar 1.5 compression
  137. if (!Fragmented)
  138. Unpack15(Solid);
  139. break;
  140. case 20: // rar 2.x compression
  141. case 26: // files larger than 2GB
  142. if (!Fragmented)
  143. Unpack20(Solid);
  144. break;
  145. #endif
  146. #if !RarV2017_RAR5ONLY
  147. case 29: // rar 3.x compression
  148. if (!Fragmented)
  149. throw new NotImplementedException();
  150. break;
  151. #endif
  152. case 50: // RAR 5.0 compression algorithm.
  153. #if RarV2017_RAR_SMP
  154. if (MaxUserThreads>1)
  155. {
  156. // We do not use the multithreaded unpack routine to repack RAR archives
  157. // in 'suspended' mode, because unlike the single threaded code it can
  158. // write more than one dictionary for same loop pass. So we would need
  159. // larger buffers of unknown size. Also we do not support multithreading
  160. // in fragmented window mode.
  161. if (!Fragmented)
  162. {
  163. Unpack5MT(Solid);
  164. break;
  165. }
  166. }
  167. #endif
  168. Unpack5(Solid);
  169. break;
  170. #if !Rar2017_NOSTRICT
  171. default: throw new InvalidFormatException("unknown compression method " + Method);
  172. #endif
  173. }
  174. }
  175. private void UnpInitData(bool Solid)
  176. {
  177. if (!Solid)
  178. {
  179. Utility.Memset<uint>(OldDist, 0, OldDist.Length);
  180. OldDistPtr=0;
  181. LastDist=LastLength=0;
  182. // memset(Window,0,MaxWinSize);
  183. //memset(&BlockTables,0,sizeof(BlockTables));
  184. BlockTables = new UnpackBlockTables();
  185. // sharpcompress: no default ctor for struct
  186. BlockTables.Init();
  187. UnpPtr=WrPtr=0;
  188. WriteBorder=Math.Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask;
  189. }
  190. // Filters never share several solid files, so we can safely reset them
  191. // even in solid archive.
  192. InitFilters();
  193. Inp.InitBitInput();
  194. WrittenFileSize=0;
  195. ReadTop=0;
  196. ReadBorder=0;
  197. //memset(&BlockHeader,0,sizeof(BlockHeader));
  198. BlockHeader = new UnpackBlockHeader();
  199. BlockHeader.BlockSize=-1; // '-1' means not defined yet.
  200. #if !RarV2017_SFX_MODULE
  201. UnpInitData20(Solid);
  202. #endif
  203. //UnpInitData30(Solid);
  204. UnpInitData50(Solid);
  205. }
  206. // LengthTable contains the length in bits for every element of alphabet.
  207. // Dec is the structure to decode Huffman code/
  208. // Size is size of length table and DecodeNum field in Dec structure,
  209. private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec,uint Size)
  210. {
  211. // Size of alphabet and DecodePos array.
  212. Dec.MaxNum=Size;
  213. // Calculate how many entries for every bit length in LengthTable we have.
  214. uint[] LengthCount = new uint[16];
  215. //memset(LengthCount,0,sizeof(LengthCount));
  216. for (size_t I=0;I<Size;I++)
  217. LengthCount[LengthTable[offset+I] & 0xf]++;
  218. // We must not calculate the number of zero length codes.
  219. LengthCount[0]=0;
  220. // Set the entire DecodeNum to zero.
  221. //memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum));
  222. Utility.FillFast<ushort>(Dec.DecodeNum, 0);
  223. // Initialize not really used entry for zero length code.
  224. Dec.DecodePos[0]=0;
  225. // Start code for bit length 1 is 0.
  226. Dec.DecodeLen[0]=0;
  227. // Right aligned upper limit code for current bit length.
  228. uint UpperLimit=0;
  229. for (int I=1;I<16;I++)
  230. {
  231. // Adjust the upper limit code.
  232. UpperLimit+=LengthCount[I];
  233. // Left aligned upper limit code.
  234. uint LeftAligned=UpperLimit<<(16-I);
  235. // Prepare the upper limit code for next bit length.
  236. UpperLimit*=2;
  237. // Store the left aligned upper limit code.
  238. Dec.DecodeLen[I]=(uint)LeftAligned;
  239. // Every item of this array contains the sum of all preceding items.
  240. // So it contains the start position in code list for every bit length.
  241. Dec.DecodePos[I]=Dec.DecodePos[I-1]+LengthCount[I-1];
  242. }
  243. // Prepare the copy of DecodePos. We'll modify this copy below,
  244. // so we cannot use the original DecodePos.
  245. uint[] CopyDecodePos = new uint[Dec.DecodePos.Length];
  246. //memcpy(CopyDecodePos,Dec->DecodePos,sizeof(CopyDecodePos));
  247. Array.Copy(Dec.DecodePos, 0, CopyDecodePos, 0, CopyDecodePos.Length);
  248. // For every bit length in the bit length table and so for every item
  249. // of alphabet.
  250. for (uint I=0;I<Size;I++)
  251. {
  252. // Get the current bit length.
  253. byte _CurBitLength=(byte)(LengthTable[offset+I] & 0xf);
  254. if (_CurBitLength!=0)
  255. {
  256. // Last position in code list for current bit length.
  257. uint LastPos=CopyDecodePos[_CurBitLength];
  258. // Prepare the decode table, so this position in code list will be
  259. // decoded to current alphabet item number.
  260. Dec.DecodeNum[LastPos]=(ushort)I;
  261. // We'll use next position number for this bit length next time.
  262. // So we pass through the entire range of positions available
  263. // for every bit length.
  264. CopyDecodePos[_CurBitLength]++;
  265. }
  266. }
  267. // Define the number of bits to process in quick mode. We use more bits
  268. // for larger alphabets. More bits means that more codes will be processed
  269. // in quick mode, but also that more time will be spent to preparation
  270. // of tables for quick decode.
  271. switch (Size)
  272. {
  273. case NC:
  274. case NC20:
  275. case NC30:
  276. Dec.QuickBits=MAX_QUICK_DECODE_BITS;
  277. break;
  278. default:
  279. Dec.QuickBits=MAX_QUICK_DECODE_BITS-3;
  280. break;
  281. }
  282. // Size of tables for quick mode.
  283. uint QuickDataSize=1U<<(int)Dec.QuickBits;
  284. // Bit length for current code, start from 1 bit codes. It is important
  285. // to use 1 bit instead of 0 for minimum code length, so we are moving
  286. // forward even when processing a corrupt archive.
  287. //uint CurBitLength=1;
  288. byte CurBitLength=1;
  289. // For every right aligned bit string which supports the quick decoding.
  290. for (uint Code=0;Code<QuickDataSize;Code++)
  291. {
  292. // Left align the current code, so it will be in usual bit field format.
  293. uint BitField=Code<<(int)(16-Dec.QuickBits);
  294. // Prepare the table for quick decoding of bit lengths.
  295. // Find the upper limit for current bit field and adjust the bit length
  296. // accordingly if necessary.
  297. while (CurBitLength<Dec.DecodeLen.Length && BitField>=Dec.DecodeLen[CurBitLength])
  298. CurBitLength++;
  299. // Translation of right aligned bit string to bit length.
  300. Dec.QuickLen[Code]=CurBitLength;
  301. // Prepare the table for quick translation of position in code list
  302. // to position in alphabet.
  303. // Calculate the distance from the start code for current bit length.
  304. uint Dist=BitField-Dec.DecodeLen[CurBitLength-1];
  305. // Right align the distance.
  306. Dist>>=(16-CurBitLength);
  307. // Now we can calculate the position in the code list. It is the sum
  308. // of first position for current bit length and right aligned distance
  309. // between our bit field and start code for current bit length.
  310. uint Pos;
  311. if (CurBitLength<Dec.DecodePos.Length &&
  312. (Pos=Dec.DecodePos[CurBitLength]+Dist)<Size)
  313. {
  314. // Define the code to alphabet number translation.
  315. Dec.QuickNum[Code]=Dec.DecodeNum[Pos];
  316. }
  317. else
  318. {
  319. // Can be here for length table filled with zeroes only (empty).
  320. Dec.QuickNum[Code]=0;
  321. }
  322. }
  323. }
  324. }
  325. }