Decode.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. namespace System.Net.ApiService.Compression.Brotli {
  2. /// <summary>API for Brotli decompression.</summary>
  3. internal sealed class Decode {
  4. private const int DefaultCodeLength = 8;
  5. private const int CodeLengthRepeatCode = 16;
  6. private const int NumLiteralCodes = 256;
  7. private const int NumInsertAndCopyCodes = 704;
  8. private const int NumBlockLengthCodes = 26;
  9. private const int LiteralContextBits = 6;
  10. private const int DistanceContextBits = 2;
  11. private const int HuffmanTableBits = 8;
  12. private const int HuffmanTableMask = unchecked((int)(0xFF));
  13. private const int CodeLengthCodes = 18;
  14. private static readonly int[] CodeLengthCodeOrder = new int[] { 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
  15. private const int NumDistanceShortCodes = 16;
  16. private static readonly int[] DistanceShortCodeIndexOffset = new int[] { 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
  17. private static readonly int[] DistanceShortCodeValueOffset = new int[] { 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 };
  18. /// <summary>Static Huffman code for the code length code lengths.</summary>
  19. private static readonly int[] FixedTable = new int[] { unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003
  20. )), unchecked((int)(0x040001)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int
  21. )(0x040005)) };
  22. /// <summary>Decodes a number in the range [0..255], by reading 1 - 11 bits.</summary>
  23. private static int DecodeVarLenUnsignedByte(System.Net.ApiService.Compression.Brotli.BitReader br) {
  24. if (System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) != 0) {
  25. int n = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 3);
  26. if (n == 0) {
  27. return 1;
  28. } else {
  29. return System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, n) + (1 << n);
  30. }
  31. }
  32. return 0;
  33. }
  34. private static void DecodeMetaBlockLength(System.Net.ApiService.Compression.Brotli.BitReader br, System.Net.ApiService.Compression.Brotli.State state) {
  35. state.inputEnd = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) == 1;
  36. state.metaBlockLength = 0;
  37. state.isUncompressed = false;
  38. state.isMetadata = false;
  39. if (state.inputEnd && System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) != 0) {
  40. return;
  41. }
  42. int sizeNibbles = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 2) + 4;
  43. if (sizeNibbles == 7) {
  44. state.isMetadata = true;
  45. if (System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) != 0) {
  46. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Corrupted reserved bit");
  47. }
  48. int sizeBytes = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 2);
  49. if (sizeBytes == 0) {
  50. return;
  51. }
  52. for (int i = 0; i < sizeBytes; i++) {
  53. int bits = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 8);
  54. if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1) {
  55. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Exuberant nibble");
  56. }
  57. state.metaBlockLength |= bits << (i * 8);
  58. }
  59. } else {
  60. for (int i = 0; i < sizeNibbles; i++) {
  61. int bits = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 4);
  62. if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4) {
  63. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Exuberant nibble");
  64. }
  65. state.metaBlockLength |= bits << (i * 4);
  66. }
  67. }
  68. state.metaBlockLength++;
  69. if (!state.inputEnd) {
  70. state.isUncompressed = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) == 1;
  71. }
  72. }
  73. /// <summary>Decodes the next Huffman code from bit-stream.</summary>
  74. private static int ReadSymbol(int[] table, int offset, System.Net.ApiService.Compression.Brotli.BitReader br) {
  75. int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset));
  76. offset += val & HuffmanTableMask;
  77. int bits = table[offset] >> 16;
  78. int sym = table[offset] & unchecked((int)(0xFFFF));
  79. if (bits <= HuffmanTableBits) {
  80. br.bitOffset += bits;
  81. return sym;
  82. }
  83. offset += sym;
  84. int mask = (1 << bits) - 1;
  85. offset += (int)(((uint)(val & mask)) >> HuffmanTableBits);
  86. br.bitOffset += ((table[offset] >> 16) + HuffmanTableBits);
  87. return table[offset] & unchecked((int)(0xFFFF));
  88. }
  89. private static int ReadBlockLength(int[] table, int offset, System.Net.ApiService.Compression.Brotli.BitReader br) {
  90. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  91. int code = ReadSymbol(table, offset, br);
  92. int n = System.Net.ApiService.Compression.Brotli.Prefix.BlockLengthNBits[code];
  93. return System.Net.ApiService.Compression.Brotli.Prefix.BlockLengthOffset[code] + System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, n);
  94. }
  95. private static int TranslateShortCodes(int code, int[] ringBuffer, int index) {
  96. if (code < NumDistanceShortCodes) {
  97. index += DistanceShortCodeIndexOffset[code];
  98. index &= 3;
  99. return ringBuffer[index] + DistanceShortCodeValueOffset[code];
  100. }
  101. return code - NumDistanceShortCodes + 1;
  102. }
  103. private static void MoveToFront(int[] v, int index) {
  104. int value = v[index];
  105. for (; index > 0; index--) {
  106. v[index] = v[index - 1];
  107. }
  108. v[0] = value;
  109. }
  110. private static void InverseMoveToFrontTransform(byte[] v, int vLen) {
  111. int[] mtf = new int[256];
  112. for (int i = 0; i < 256; i++) {
  113. mtf[i] = i;
  114. }
  115. for (int i = 0; i < vLen; i++) {
  116. int index = v[i] & unchecked((int)(0xFF));
  117. v[i] = unchecked((byte)mtf[index]);
  118. if (index != 0) {
  119. MoveToFront(mtf, index);
  120. }
  121. }
  122. }
  123. private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, System.Net.ApiService.Compression.Brotli.BitReader br) {
  124. int symbol = 0;
  125. int prevCodeLen = DefaultCodeLength;
  126. int repeat = 0;
  127. int repeatCodeLen = 0;
  128. int space = 32768;
  129. int[] table = new int[32];
  130. System.Net.ApiService.Compression.Brotli.Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes);
  131. while (symbol < numSymbols && space > 0) {
  132. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  133. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  134. int p = (int)(((long)(((ulong)br.accumulator) >> br.bitOffset))) & 31;
  135. br.bitOffset += table[p] >> 16;
  136. int codeLen = table[p] & unchecked((int)(0xFFFF));
  137. if (codeLen < CodeLengthRepeatCode) {
  138. repeat = 0;
  139. codeLengths[symbol++] = codeLen;
  140. if (codeLen != 0) {
  141. prevCodeLen = codeLen;
  142. space -= 32768 >> codeLen;
  143. }
  144. } else {
  145. int extraBits = codeLen - 14;
  146. int newLen = 0;
  147. if (codeLen == CodeLengthRepeatCode) {
  148. newLen = prevCodeLen;
  149. }
  150. if (repeatCodeLen != newLen) {
  151. repeat = 0;
  152. repeatCodeLen = newLen;
  153. }
  154. int oldRepeat = repeat;
  155. if (repeat > 0) {
  156. repeat -= 2;
  157. repeat <<= extraBits;
  158. }
  159. repeat += System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, extraBits) + 3;
  160. int repeatDelta = repeat - oldRepeat;
  161. if (symbol + repeatDelta > numSymbols) {
  162. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("symbol + repeatDelta > numSymbols");
  163. }
  164. // COV_NF_LINE
  165. for (int i = 0; i < repeatDelta; i++) {
  166. codeLengths[symbol++] = repeatCodeLen;
  167. }
  168. if (repeatCodeLen != 0) {
  169. space -= repeatDelta << (15 - repeatCodeLen);
  170. }
  171. }
  172. }
  173. if (space != 0) {
  174. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Unused space");
  175. }
  176. // COV_NF_LINE
  177. // TODO: Pass max_symbol to Huffman table builder instead?
  178. System.Net.ApiService.Compression.Brotli.Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol);
  179. }
  180. // TODO: Use specialized versions for smaller tables.
  181. internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, System.Net.ApiService.Compression.Brotli.BitReader br) {
  182. bool ok = true;
  183. int simpleCodeOrSkip;
  184. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  185. // TODO: Avoid allocation.
  186. int[] codeLengths = new int[alphabetSize];
  187. simpleCodeOrSkip = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 2);
  188. if (simpleCodeOrSkip == 1) {
  189. // Read symbols, codes & code lengths directly.
  190. int maxBitsCounter = alphabetSize - 1;
  191. int maxBits = 0;
  192. int[] symbols = new int[4];
  193. int numSymbols = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 2) + 1;
  194. while (maxBitsCounter != 0) {
  195. maxBitsCounter >>= 1;
  196. maxBits++;
  197. }
  198. // TODO: uncomment when codeLengths is reused.
  199. // Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
  200. for (int i = 0; i < numSymbols; i++) {
  201. symbols[i] = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, maxBits) % alphabetSize;
  202. codeLengths[symbols[i]] = 2;
  203. }
  204. codeLengths[symbols[0]] = 1;
  205. switch (numSymbols) {
  206. case 1: {
  207. break;
  208. }
  209. case 2: {
  210. ok = symbols[0] != symbols[1];
  211. codeLengths[symbols[1]] = 1;
  212. break;
  213. }
  214. case 3: {
  215. ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[1] != symbols[2];
  216. break;
  217. }
  218. case 4:
  219. default: {
  220. ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[0] != symbols[3] && symbols[1] != symbols[2] && symbols[1] != symbols[3] && symbols[2] != symbols[3];
  221. if (System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) == 1) {
  222. codeLengths[symbols[2]] = 3;
  223. codeLengths[symbols[3]] = 3;
  224. } else {
  225. codeLengths[symbols[0]] = 2;
  226. }
  227. break;
  228. }
  229. }
  230. } else {
  231. // Decode Huffman-coded code lengths.
  232. int[] codeLengthCodeLengths = new int[CodeLengthCodes];
  233. int space = 32;
  234. int numCodes = 0;
  235. for (int i = simpleCodeOrSkip; i < CodeLengthCodes && space > 0; i++) {
  236. int codeLenIdx = CodeLengthCodeOrder[i];
  237. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  238. int p = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & 15;
  239. // TODO: Demultiplex FIXED_TABLE.
  240. br.bitOffset += FixedTable[p] >> 16;
  241. int v = FixedTable[p] & unchecked((int)(0xFFFF));
  242. codeLengthCodeLengths[codeLenIdx] = v;
  243. if (v != 0) {
  244. space -= (32 >> v);
  245. numCodes++;
  246. }
  247. }
  248. ok = (numCodes == 1 || space == 0);
  249. ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, br);
  250. }
  251. if (!ok) {
  252. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Can't readHuffmanCode");
  253. }
  254. // COV_NF_LINE
  255. System.Net.ApiService.Compression.Brotli.Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize);
  256. }
  257. private static int DecodeContextMap(int contextMapSize, byte[] contextMap, System.Net.ApiService.Compression.Brotli.BitReader br) {
  258. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  259. int numTrees = DecodeVarLenUnsignedByte(br) + 1;
  260. if (numTrees == 1) {
  261. System.Net.ApiService.Compression.Brotli.Utils.FillWithZeroes(contextMap, 0, contextMapSize);
  262. return numTrees;
  263. }
  264. bool useRleForZeros = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) == 1;
  265. int maxRunLengthPrefix = 0;
  266. if (useRleForZeros) {
  267. maxRunLengthPrefix = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 4) + 1;
  268. }
  269. int[] table = new int[System.Net.ApiService.Compression.Brotli.Huffman.HuffmanMaxTableSize];
  270. ReadHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, br);
  271. for (int i = 0; i < contextMapSize;) {
  272. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  273. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  274. int code = ReadSymbol(table, 0, br);
  275. if (code == 0) {
  276. contextMap[i] = 0;
  277. i++;
  278. } else if (code <= maxRunLengthPrefix) {
  279. int reps = (1 << code) + System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, code);
  280. while (reps != 0) {
  281. if (i >= contextMapSize) {
  282. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Corrupted context map");
  283. }
  284. // COV_NF_LINE
  285. contextMap[i] = 0;
  286. i++;
  287. reps--;
  288. }
  289. } else {
  290. contextMap[i] = unchecked((byte)(code - maxRunLengthPrefix));
  291. i++;
  292. }
  293. }
  294. if (System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 1) == 1) {
  295. InverseMoveToFrontTransform(contextMap, contextMapSize);
  296. }
  297. return numTrees;
  298. }
  299. private static void DecodeBlockTypeAndLength(System.Net.ApiService.Compression.Brotli.State state, int treeType) {
  300. System.Net.ApiService.Compression.Brotli.BitReader br = state.br;
  301. int[] ringBuffers = state.blockTypeRb;
  302. int offset = treeType * 2;
  303. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  304. int blockType = ReadSymbol(state.blockTypeTrees, treeType * System.Net.ApiService.Compression.Brotli.Huffman.HuffmanMaxTableSize, br);
  305. state.blockLength[treeType] = ReadBlockLength(state.blockLenTrees, treeType * System.Net.ApiService.Compression.Brotli.Huffman.HuffmanMaxTableSize, br);
  306. if (blockType == 1) {
  307. blockType = ringBuffers[offset + 1] + 1;
  308. } else if (blockType == 0) {
  309. blockType = ringBuffers[offset];
  310. } else {
  311. blockType -= 2;
  312. }
  313. if (blockType >= state.numBlockTypes[treeType]) {
  314. blockType -= state.numBlockTypes[treeType];
  315. }
  316. ringBuffers[offset] = ringBuffers[offset + 1];
  317. ringBuffers[offset + 1] = blockType;
  318. }
  319. private static void DecodeLiteralBlockSwitch(System.Net.ApiService.Compression.Brotli.State state) {
  320. DecodeBlockTypeAndLength(state, 0);
  321. int literalBlockType = state.blockTypeRb[1];
  322. state.contextMapSlice = literalBlockType << LiteralContextBits;
  323. state.literalTreeIndex = state.contextMap[state.contextMapSlice] & unchecked((int)(0xFF));
  324. state.literalTree = state.hGroup0.trees[state.literalTreeIndex];
  325. int contextMode = state.contextModes[literalBlockType];
  326. state.contextLookupOffset1 = System.Net.ApiService.Compression.Brotli.Context.LookupOffsets[contextMode];
  327. state.contextLookupOffset2 = System.Net.ApiService.Compression.Brotli.Context.LookupOffsets[contextMode + 1];
  328. }
  329. private static void DecodeCommandBlockSwitch(System.Net.ApiService.Compression.Brotli.State state) {
  330. DecodeBlockTypeAndLength(state, 1);
  331. state.treeCommandOffset = state.hGroup1.trees[state.blockTypeRb[3]];
  332. }
  333. private static void DecodeDistanceBlockSwitch(System.Net.ApiService.Compression.Brotli.State state) {
  334. DecodeBlockTypeAndLength(state, 2);
  335. state.distContextMapSlice = state.blockTypeRb[5] << DistanceContextBits;
  336. }
  337. private static void MaybeReallocateRingBuffer(System.Net.ApiService.Compression.Brotli.State state) {
  338. int newSize = state.maxRingBufferSize;
  339. if ((long)newSize > state.expectedTotalSize) {
  340. /* TODO: Handle 2GB+ cases more gracefully. */
  341. int minimalNewSize = (int)state.expectedTotalSize + state.customDictionary.Length;
  342. while ((newSize >> 1) > minimalNewSize) {
  343. newSize >>= 1;
  344. }
  345. if (!state.inputEnd && newSize < 16384 && state.maxRingBufferSize >= 16384) {
  346. newSize = 16384;
  347. }
  348. }
  349. if (newSize <= state.ringBufferSize) {
  350. return;
  351. }
  352. int ringBufferSizeWithSlack = newSize + System.Net.ApiService.Compression.Brotli.Dictionary.MaxTransformedWordLength;
  353. byte[] newBuffer = new byte[ringBufferSizeWithSlack];
  354. if (state.ringBuffer != null) {
  355. System.Array.Copy(state.ringBuffer, 0, newBuffer, 0, state.ringBufferSize);
  356. } else if (state.customDictionary.Length != 0) {
  357. /* Prepend custom dictionary, if any. */
  358. int length = state.customDictionary.Length;
  359. int offset = 0;
  360. if (length > state.maxBackwardDistance) {
  361. offset = length - state.maxBackwardDistance;
  362. length = state.maxBackwardDistance;
  363. }
  364. System.Array.Copy(state.customDictionary, offset, newBuffer, 0, length);
  365. state.pos = length;
  366. state.bytesToIgnore = length;
  367. }
  368. state.ringBuffer = newBuffer;
  369. state.ringBufferSize = newSize;
  370. }
  371. /// <summary>Reads next metablock header.</summary>
  372. /// <param name="state">decoding state</param>
  373. private static void ReadMetablockInfo(System.Net.ApiService.Compression.Brotli.State state) {
  374. System.Net.ApiService.Compression.Brotli.BitReader br = state.br;
  375. if (state.inputEnd) {
  376. state.nextRunningState = System.Net.ApiService.Compression.Brotli.RunningState.Finished;
  377. state.bytesToWrite = state.pos;
  378. state.bytesWritten = 0;
  379. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Write;
  380. return;
  381. }
  382. // TODO: Reset? Do we need this?
  383. state.hGroup0.codes = null;
  384. state.hGroup0.trees = null;
  385. state.hGroup1.codes = null;
  386. state.hGroup1.trees = null;
  387. state.hGroup2.codes = null;
  388. state.hGroup2.trees = null;
  389. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  390. DecodeMetaBlockLength(br, state);
  391. if (state.metaBlockLength == 0 && !state.isMetadata) {
  392. return;
  393. }
  394. if (state.isUncompressed || state.isMetadata) {
  395. System.Net.ApiService.Compression.Brotli.BitReader.JumpToByteBoundary(br);
  396. state.runningState = state.isMetadata ? System.Net.ApiService.Compression.Brotli.RunningState.ReadMetadata : System.Net.ApiService.Compression.Brotli.RunningState.CopyUncompressed;
  397. } else {
  398. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.CompressedBlockStart;
  399. }
  400. if (state.isMetadata) {
  401. return;
  402. }
  403. state.expectedTotalSize += state.metaBlockLength;
  404. if (state.ringBufferSize < state.maxRingBufferSize) {
  405. MaybeReallocateRingBuffer(state);
  406. }
  407. }
  408. private static void ReadMetablockHuffmanCodesAndContextMaps(System.Net.ApiService.Compression.Brotli.State state) {
  409. System.Net.ApiService.Compression.Brotli.BitReader br = state.br;
  410. for (int i = 0; i < 3; i++) {
  411. state.numBlockTypes[i] = DecodeVarLenUnsignedByte(br) + 1;
  412. state.blockLength[i] = 1 << 28;
  413. if (state.numBlockTypes[i] > 1) {
  414. ReadHuffmanCode(state.numBlockTypes[i] + 2, state.blockTypeTrees, i * System.Net.ApiService.Compression.Brotli.Huffman.HuffmanMaxTableSize, br);
  415. ReadHuffmanCode(NumBlockLengthCodes, state.blockLenTrees, i * System.Net.ApiService.Compression.Brotli.Huffman.HuffmanMaxTableSize, br);
  416. state.blockLength[i] = ReadBlockLength(state.blockLenTrees, i * System.Net.ApiService.Compression.Brotli.Huffman.HuffmanMaxTableSize, br);
  417. }
  418. }
  419. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  420. state.distancePostfixBits = System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 2);
  421. state.numDirectDistanceCodes = NumDistanceShortCodes + (System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 4) << state.distancePostfixBits);
  422. state.distancePostfixMask = (1 << state.distancePostfixBits) - 1;
  423. int numDistanceCodes = state.numDirectDistanceCodes + (48 << state.distancePostfixBits);
  424. // TODO: Reuse?
  425. state.contextModes = new byte[state.numBlockTypes[0]];
  426. for (int i = 0; i < state.numBlockTypes[0];) {
  427. /* Ensure that less than 256 bits read between readMoreInput. */
  428. int limit = System.Math.Min(i + 96, state.numBlockTypes[0]);
  429. for (; i < limit; ++i) {
  430. state.contextModes[i] = unchecked((byte)(System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 2) << 1));
  431. }
  432. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  433. }
  434. // TODO: Reuse?
  435. state.contextMap = new byte[state.numBlockTypes[0] << LiteralContextBits];
  436. int numLiteralTrees = DecodeContextMap(state.numBlockTypes[0] << LiteralContextBits, state.contextMap, br);
  437. state.trivialLiteralContext = true;
  438. for (int j = 0; j < state.numBlockTypes[0] << LiteralContextBits; j++) {
  439. if (state.contextMap[j] != j >> LiteralContextBits) {
  440. state.trivialLiteralContext = false;
  441. break;
  442. }
  443. }
  444. // TODO: Reuse?
  445. state.distContextMap = new byte[state.numBlockTypes[2] << DistanceContextBits];
  446. int numDistTrees = DecodeContextMap(state.numBlockTypes[2] << DistanceContextBits, state.distContextMap, br);
  447. System.Net.ApiService.Compression.Brotli.HuffmanTreeGroup.Init(state.hGroup0, NumLiteralCodes, numLiteralTrees);
  448. System.Net.ApiService.Compression.Brotli.HuffmanTreeGroup.Init(state.hGroup1, NumInsertAndCopyCodes, state.numBlockTypes[1]);
  449. System.Net.ApiService.Compression.Brotli.HuffmanTreeGroup.Init(state.hGroup2, numDistanceCodes, numDistTrees);
  450. System.Net.ApiService.Compression.Brotli.HuffmanTreeGroup.Decode(state.hGroup0, br);
  451. System.Net.ApiService.Compression.Brotli.HuffmanTreeGroup.Decode(state.hGroup1, br);
  452. System.Net.ApiService.Compression.Brotli.HuffmanTreeGroup.Decode(state.hGroup2, br);
  453. state.contextMapSlice = 0;
  454. state.distContextMapSlice = 0;
  455. state.contextLookupOffset1 = System.Net.ApiService.Compression.Brotli.Context.LookupOffsets[state.contextModes[0]];
  456. state.contextLookupOffset2 = System.Net.ApiService.Compression.Brotli.Context.LookupOffsets[state.contextModes[0] + 1];
  457. state.literalTreeIndex = 0;
  458. state.literalTree = state.hGroup0.trees[0];
  459. state.treeCommandOffset = state.hGroup1.trees[0];
  460. // TODO: == 0?
  461. state.blockTypeRb[0] = state.blockTypeRb[2] = state.blockTypeRb[4] = 1;
  462. state.blockTypeRb[1] = state.blockTypeRb[3] = state.blockTypeRb[5] = 0;
  463. }
  464. private static void CopyUncompressedData(System.Net.ApiService.Compression.Brotli.State state) {
  465. System.Net.ApiService.Compression.Brotli.BitReader br = state.br;
  466. byte[] ringBuffer = state.ringBuffer;
  467. // Could happen if block ends at ring buffer end.
  468. if (state.metaBlockLength <= 0) {
  469. System.Net.ApiService.Compression.Brotli.BitReader.Reload(br);
  470. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.BlockStart;
  471. return;
  472. }
  473. int chunkLength = System.Math.Min(state.ringBufferSize - state.pos, state.metaBlockLength);
  474. System.Net.ApiService.Compression.Brotli.BitReader.CopyBytes(br, ringBuffer, state.pos, chunkLength);
  475. state.metaBlockLength -= chunkLength;
  476. state.pos += chunkLength;
  477. if (state.pos == state.ringBufferSize) {
  478. state.nextRunningState = System.Net.ApiService.Compression.Brotli.RunningState.CopyUncompressed;
  479. state.bytesToWrite = state.ringBufferSize;
  480. state.bytesWritten = 0;
  481. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Write;
  482. return;
  483. }
  484. System.Net.ApiService.Compression.Brotli.BitReader.Reload(br);
  485. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.BlockStart;
  486. }
  487. private static bool WriteRingBuffer(System.Net.ApiService.Compression.Brotli.State state) {
  488. /* Ignore custom dictionary bytes. */
  489. if (state.bytesToIgnore != 0) {
  490. state.bytesWritten += state.bytesToIgnore;
  491. state.bytesToIgnore = 0;
  492. }
  493. int toWrite = System.Math.Min(state.outputLength - state.outputUsed, state.bytesToWrite - state.bytesWritten);
  494. if (toWrite != 0) {
  495. System.Array.Copy(state.ringBuffer, state.bytesWritten, state.output, state.outputOffset + state.outputUsed, toWrite);
  496. state.outputUsed += toWrite;
  497. state.bytesWritten += toWrite;
  498. }
  499. return state.outputUsed < state.outputLength;
  500. }
  501. internal static void SetCustomDictionary(System.Net.ApiService.Compression.Brotli.State state, byte[] data) {
  502. state.customDictionary = (data == null) ? new byte[0] : data;
  503. }
  504. /// <summary>Actual decompress implementation.</summary>
  505. internal static void Decompress(System.Net.ApiService.Compression.Brotli.State state) {
  506. if (state.runningState == System.Net.ApiService.Compression.Brotli.RunningState.Uninitialized) {
  507. throw new System.InvalidOperationException("Can't decompress until initialized");
  508. }
  509. if (state.runningState == System.Net.ApiService.Compression.Brotli.RunningState.Closed) {
  510. throw new System.InvalidOperationException("Can't decompress after close");
  511. }
  512. System.Net.ApiService.Compression.Brotli.BitReader br = state.br;
  513. int ringBufferMask = state.ringBufferSize - 1;
  514. byte[] ringBuffer = state.ringBuffer;
  515. while (state.runningState != System.Net.ApiService.Compression.Brotli.RunningState.Finished) {
  516. switch (state.runningState) {
  517. case System.Net.ApiService.Compression.Brotli.RunningState.BlockStart: {
  518. // TODO: extract cases to methods for the better readability.
  519. if (state.metaBlockLength < 0) {
  520. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Invalid metablock length");
  521. }
  522. ReadMetablockInfo(state);
  523. /* Ring-buffer would be reallocated here. */
  524. ringBufferMask = state.ringBufferSize - 1;
  525. ringBuffer = state.ringBuffer;
  526. continue;
  527. }
  528. case System.Net.ApiService.Compression.Brotli.RunningState.CompressedBlockStart: {
  529. ReadMetablockHuffmanCodesAndContextMaps(state);
  530. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.MainLoop;
  531. goto case System.Net.ApiService.Compression.Brotli.RunningState.MainLoop;
  532. }
  533. case System.Net.ApiService.Compression.Brotli.RunningState.MainLoop: {
  534. // Fall through
  535. if (state.metaBlockLength <= 0) {
  536. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.BlockStart;
  537. continue;
  538. }
  539. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  540. if (state.blockLength[1] == 0) {
  541. DecodeCommandBlockSwitch(state);
  542. }
  543. state.blockLength[1]--;
  544. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  545. int cmdCode = ReadSymbol(state.hGroup1.codes, state.treeCommandOffset, br);
  546. int rangeIdx = (int)(((uint)cmdCode) >> 6);
  547. state.distanceCode = 0;
  548. if (rangeIdx >= 2) {
  549. rangeIdx -= 2;
  550. state.distanceCode = -1;
  551. }
  552. int insertCode = System.Net.ApiService.Compression.Brotli.Prefix.InsertRangeLut[rangeIdx] + (((int)(((uint)cmdCode) >> 3)) & 7);
  553. int copyCode = System.Net.ApiService.Compression.Brotli.Prefix.CopyRangeLut[rangeIdx] + (cmdCode & 7);
  554. state.insertLength = System.Net.ApiService.Compression.Brotli.Prefix.InsertLengthOffset[insertCode] + System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, System.Net.ApiService.Compression.Brotli.Prefix.InsertLengthNBits[insertCode]);
  555. state.copyLength = System.Net.ApiService.Compression.Brotli.Prefix.CopyLengthOffset[copyCode] + System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, System.Net.ApiService.Compression.Brotli.Prefix.CopyLengthNBits[copyCode]);
  556. state.j = 0;
  557. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.InsertLoop;
  558. goto case System.Net.ApiService.Compression.Brotli.RunningState.InsertLoop;
  559. }
  560. case System.Net.ApiService.Compression.Brotli.RunningState.InsertLoop: {
  561. // Fall through
  562. if (state.trivialLiteralContext) {
  563. while (state.j < state.insertLength) {
  564. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  565. if (state.blockLength[0] == 0) {
  566. DecodeLiteralBlockSwitch(state);
  567. }
  568. state.blockLength[0]--;
  569. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  570. ringBuffer[state.pos] = unchecked((byte)ReadSymbol(state.hGroup0.codes, state.literalTree, br));
  571. state.j++;
  572. if (state.pos++ == ringBufferMask) {
  573. state.nextRunningState = System.Net.ApiService.Compression.Brotli.RunningState.InsertLoop;
  574. state.bytesToWrite = state.ringBufferSize;
  575. state.bytesWritten = 0;
  576. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Write;
  577. break;
  578. }
  579. }
  580. } else {
  581. int prevByte1 = ringBuffer[(state.pos - 1) & ringBufferMask] & unchecked((int)(0xFF));
  582. int prevByte2 = ringBuffer[(state.pos - 2) & ringBufferMask] & unchecked((int)(0xFF));
  583. while (state.j < state.insertLength) {
  584. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  585. if (state.blockLength[0] == 0) {
  586. DecodeLiteralBlockSwitch(state);
  587. }
  588. int literalTreeIndex = state.contextMap[state.contextMapSlice + (System.Net.ApiService.Compression.Brotli.Context.Lookup[state.contextLookupOffset1 + prevByte1] | System.Net.ApiService.Compression.Brotli.Context.Lookup[state.contextLookupOffset2 + prevByte2])] & unchecked((int)(0xFF));
  589. state.blockLength[0]--;
  590. prevByte2 = prevByte1;
  591. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  592. prevByte1 = ReadSymbol(state.hGroup0.codes, state.hGroup0.trees[literalTreeIndex], br);
  593. ringBuffer[state.pos] = unchecked((byte)prevByte1);
  594. state.j++;
  595. if (state.pos++ == ringBufferMask) {
  596. state.nextRunningState = System.Net.ApiService.Compression.Brotli.RunningState.InsertLoop;
  597. state.bytesToWrite = state.ringBufferSize;
  598. state.bytesWritten = 0;
  599. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Write;
  600. break;
  601. }
  602. }
  603. }
  604. if (state.runningState != System.Net.ApiService.Compression.Brotli.RunningState.InsertLoop) {
  605. continue;
  606. }
  607. state.metaBlockLength -= state.insertLength;
  608. if (state.metaBlockLength <= 0) {
  609. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.MainLoop;
  610. continue;
  611. }
  612. if (state.distanceCode < 0) {
  613. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  614. if (state.blockLength[2] == 0) {
  615. DecodeDistanceBlockSwitch(state);
  616. }
  617. state.blockLength[2]--;
  618. System.Net.ApiService.Compression.Brotli.BitReader.FillBitWindow(br);
  619. state.distanceCode = ReadSymbol(state.hGroup2.codes, state.hGroup2.trees[state.distContextMap[state.distContextMapSlice + (state.copyLength > 4 ? 3 : state.copyLength - 2)] & unchecked((int)(0xFF))], br);
  620. if (state.distanceCode >= state.numDirectDistanceCodes) {
  621. state.distanceCode -= state.numDirectDistanceCodes;
  622. int postfix = state.distanceCode & state.distancePostfixMask;
  623. state.distanceCode = (int)(((uint)state.distanceCode) >> state.distancePostfixBits);
  624. int n = ((int)(((uint)state.distanceCode) >> 1)) + 1;
  625. int offset = ((2 + (state.distanceCode & 1)) << n) - 4;
  626. state.distanceCode = state.numDirectDistanceCodes + postfix + ((offset + System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, n)) << state.distancePostfixBits);
  627. }
  628. }
  629. // Convert the distance code to the actual distance by possibly looking up past distances
  630. // from the ringBuffer.
  631. state.distance = TranslateShortCodes(state.distanceCode, state.distRb, state.distRbIdx);
  632. if (state.distance < 0) {
  633. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Negative distance");
  634. }
  635. // COV_NF_LINE
  636. if (state.maxDistance != state.maxBackwardDistance && state.pos < state.maxBackwardDistance) {
  637. state.maxDistance = state.pos;
  638. } else {
  639. state.maxDistance = state.maxBackwardDistance;
  640. }
  641. state.copyDst = state.pos;
  642. if (state.distance > state.maxDistance) {
  643. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Transform;
  644. continue;
  645. }
  646. if (state.distanceCode > 0) {
  647. state.distRb[state.distRbIdx & 3] = state.distance;
  648. state.distRbIdx++;
  649. }
  650. if (state.copyLength > state.metaBlockLength) {
  651. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Invalid backward reference");
  652. }
  653. // COV_NF_LINE
  654. state.j = 0;
  655. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.CopyLoop;
  656. goto case System.Net.ApiService.Compression.Brotli.RunningState.CopyLoop;
  657. }
  658. case System.Net.ApiService.Compression.Brotli.RunningState.CopyLoop: {
  659. // fall through
  660. int src = (state.pos - state.distance) & ringBufferMask;
  661. int dst = state.pos;
  662. int copyLength = state.copyLength - state.j;
  663. if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask)) {
  664. for (int k = 0; k < copyLength; ++k) {
  665. ringBuffer[dst++] = ringBuffer[src++];
  666. }
  667. state.j += copyLength;
  668. state.metaBlockLength -= copyLength;
  669. state.pos += copyLength;
  670. } else {
  671. for (; state.j < state.copyLength;) {
  672. ringBuffer[state.pos] = ringBuffer[(state.pos - state.distance) & ringBufferMask];
  673. state.metaBlockLength--;
  674. state.j++;
  675. if (state.pos++ == ringBufferMask) {
  676. state.nextRunningState = System.Net.ApiService.Compression.Brotli.RunningState.CopyLoop;
  677. state.bytesToWrite = state.ringBufferSize;
  678. state.bytesWritten = 0;
  679. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Write;
  680. break;
  681. }
  682. }
  683. }
  684. if (state.runningState == System.Net.ApiService.Compression.Brotli.RunningState.CopyLoop) {
  685. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.MainLoop;
  686. }
  687. continue;
  688. }
  689. case System.Net.ApiService.Compression.Brotli.RunningState.Transform: {
  690. if (state.copyLength >= System.Net.ApiService.Compression.Brotli.Dictionary.MinWordLength && state.copyLength <= System.Net.ApiService.Compression.Brotli.Dictionary.MaxWordLength) {
  691. int offset = System.Net.ApiService.Compression.Brotli.Dictionary.OffsetsByLength[state.copyLength];
  692. int wordId = state.distance - state.maxDistance - 1;
  693. int shift = System.Net.ApiService.Compression.Brotli.Dictionary.SizeBitsByLength[state.copyLength];
  694. int mask = (1 << shift) - 1;
  695. int wordIdx = wordId & mask;
  696. int transformIdx = (int)(((uint)wordId) >> shift);
  697. offset += wordIdx * state.copyLength;
  698. if (transformIdx < System.Net.ApiService.Compression.Brotli.Transform.Transforms.Length) {
  699. int len = System.Net.ApiService.Compression.Brotli.Transform.TransformDictionaryWord(ringBuffer, state.copyDst, System.Net.ApiService.Compression.Brotli.Dictionary.GetData(), offset, state.copyLength, System.Net.ApiService.Compression.Brotli.Transform.Transforms[transformIdx]);
  700. state.copyDst += len;
  701. state.pos += len;
  702. state.metaBlockLength -= len;
  703. if (state.copyDst >= state.ringBufferSize) {
  704. state.nextRunningState = System.Net.ApiService.Compression.Brotli.RunningState.CopyWrapBuffer;
  705. state.bytesToWrite = state.ringBufferSize;
  706. state.bytesWritten = 0;
  707. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.Write;
  708. continue;
  709. }
  710. } else {
  711. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Invalid backward reference");
  712. }
  713. } else {
  714. // COV_NF_LINE
  715. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Invalid backward reference");
  716. }
  717. // COV_NF_LINE
  718. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.MainLoop;
  719. continue;
  720. }
  721. case System.Net.ApiService.Compression.Brotli.RunningState.CopyWrapBuffer: {
  722. System.Array.Copy(ringBuffer, state.ringBufferSize, ringBuffer, 0, state.copyDst - state.ringBufferSize);
  723. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.MainLoop;
  724. continue;
  725. }
  726. case System.Net.ApiService.Compression.Brotli.RunningState.ReadMetadata: {
  727. while (state.metaBlockLength > 0) {
  728. System.Net.ApiService.Compression.Brotli.BitReader.ReadMoreInput(br);
  729. // Optimize
  730. System.Net.ApiService.Compression.Brotli.BitReader.ReadBits(br, 8);
  731. state.metaBlockLength--;
  732. }
  733. state.runningState = System.Net.ApiService.Compression.Brotli.RunningState.BlockStart;
  734. continue;
  735. }
  736. case System.Net.ApiService.Compression.Brotli.RunningState.CopyUncompressed: {
  737. CopyUncompressedData(state);
  738. continue;
  739. }
  740. case System.Net.ApiService.Compression.Brotli.RunningState.Write: {
  741. if (!WriteRingBuffer(state)) {
  742. // Output buffer is full.
  743. return;
  744. }
  745. if (state.pos >= state.maxBackwardDistance) {
  746. state.maxDistance = state.maxBackwardDistance;
  747. }
  748. state.pos &= ringBufferMask;
  749. state.runningState = state.nextRunningState;
  750. continue;
  751. }
  752. default: {
  753. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Unexpected state " + state.runningState);
  754. }
  755. }
  756. }
  757. if (state.runningState == System.Net.ApiService.Compression.Brotli.RunningState.Finished) {
  758. if (state.metaBlockLength < 0) {
  759. throw new System.Net.ApiService.Compression.Brotli.BrotliRuntimeException("Invalid metablock length");
  760. }
  761. System.Net.ApiService.Compression.Brotli.BitReader.JumpToByteBoundary(br);
  762. System.Net.ApiService.Compression.Brotli.BitReader.CheckHealth(state.br, true);
  763. }
  764. }
  765. }
  766. }