BrotliInputStream.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. namespace System.Net.ApiService.Compression.Brotli {
  2. /// <summary>
  3. /// <see cref="System.IO.Stream"/>
  4. /// decorator that decompresses brotli data.
  5. /// <p> Not thread-safe.
  6. /// </summary>
  7. public class BrotliInputStream : System.IO.Stream {
  8. public const int DefaultInternalBufferSize = 16384;
  9. /// <summary>Internal buffer used for efficient byte-by-byte reading.</summary>
  10. private byte[] buffer;
  11. /// <summary>Number of decoded but still unused bytes in internal buffer.</summary>
  12. private int remainingBufferBytes;
  13. /// <summary>Next unused byte offset.</summary>
  14. private int bufferOffset;
  15. /// <summary>Decoder state.</summary>
  16. private readonly System.Net.ApiService.Compression.Brotli.State state = new System.Net.ApiService.Compression.Brotli.State();
  17. /// <summary>
  18. /// Creates a
  19. /// <see cref="System.IO.Stream"/>
  20. /// wrapper that decompresses brotli data.
  21. /// <p> For byte-by-byte reading (
  22. /// <see cref="ReadByte()"/>
  23. /// ) internal buffer with
  24. /// <see cref="DefaultInternalBufferSize"/>
  25. /// size is allocated and used.
  26. /// <p> Will block the thread until first kilobyte of data of source is available.
  27. /// </summary>
  28. /// <param name="source">underlying data source</param>
  29. /// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
  30. public BrotliInputStream(System.IO.Stream source)
  31. : this(source, DefaultInternalBufferSize, null) {
  32. }
  33. /// <summary>
  34. /// Creates a
  35. /// <see cref="System.IO.Stream"/>
  36. /// wrapper that decompresses brotli data.
  37. /// <p> For byte-by-byte reading (
  38. /// <see cref="ReadByte()"/>
  39. /// ) internal buffer of specified size is
  40. /// allocated and used.
  41. /// <p> Will block the thread until first kilobyte of data of source is available.
  42. /// </summary>
  43. /// <param name="source">compressed data source</param>
  44. /// <param name="byteReadBufferSize">
  45. /// size of internal buffer used in case of
  46. /// byte-by-byte reading
  47. /// </param>
  48. /// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
  49. public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize)
  50. : this(source, byteReadBufferSize, null) {
  51. }
  52. /// <summary>
  53. /// Creates a
  54. /// <see cref="System.IO.Stream"/>
  55. /// wrapper that decompresses brotli data.
  56. /// <p> For byte-by-byte reading (
  57. /// <see cref="ReadByte()"/>
  58. /// ) internal buffer of specified size is
  59. /// allocated and used.
  60. /// <p> Will block the thread until first kilobyte of data of source is available.
  61. /// </summary>
  62. /// <param name="source">compressed data source</param>
  63. /// <param name="byteReadBufferSize">
  64. /// size of internal buffer used in case of
  65. /// byte-by-byte reading
  66. /// </param>
  67. /// <param name="customDictionary">
  68. /// custom dictionary data;
  69. /// <see langword="null"/>
  70. /// if not used
  71. /// </param>
  72. /// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
  73. public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize, byte[] customDictionary) {
  74. if (byteReadBufferSize <= 0) {
  75. throw new System.ArgumentException("Bad buffer size:" + byteReadBufferSize);
  76. } else if (source == null) {
  77. throw new System.ArgumentException("source is null");
  78. }
  79. this.buffer = new byte[byteReadBufferSize];
  80. this.remainingBufferBytes = 0;
  81. this.bufferOffset = 0;
  82. try {
  83. System.Net.ApiService.Compression.Brotli.State.SetInput(state, source);
  84. } catch (System.Net.ApiService.Compression.Brotli.BrotliRuntimeException ex) {
  85. throw new System.IO.IOException("Brotli decoder initialization failed", ex);
  86. }
  87. if (customDictionary != null) {
  88. System.Net.ApiService.Compression.Brotli.Decode.SetCustomDictionary(state, customDictionary);
  89. }
  90. }
  91. /// <summary><inheritDoc/></summary>
  92. /// <exception cref="System.IO.IOException"/>
  93. public override void Close() {
  94. System.Net.ApiService.Compression.Brotli.State.Close(state);
  95. }
  96. /// <summary><inheritDoc/></summary>
  97. /// <exception cref="System.IO.IOException"/>
  98. public override int ReadByte() {
  99. if (bufferOffset >= remainingBufferBytes) {
  100. remainingBufferBytes = Read(buffer, 0, buffer.Length);
  101. bufferOffset = 0;
  102. if (remainingBufferBytes == -1) {
  103. return -1;
  104. }
  105. }
  106. return buffer[bufferOffset++] & unchecked((int)(0xFF));
  107. }
  108. /// <summary><inheritDoc/></summary>
  109. /// <exception cref="System.IO.IOException"/>
  110. public override int Read(byte[] destBuffer, int destOffset, int destLen) {
  111. if (destOffset < 0) {
  112. throw new System.ArgumentException("Bad offset: " + destOffset);
  113. } else if (destLen < 0) {
  114. throw new System.ArgumentException("Bad length: " + destLen);
  115. } else if (destOffset + destLen > destBuffer.Length) {
  116. throw new System.ArgumentException("Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.Length);
  117. } else if (destLen == 0) {
  118. return 0;
  119. }
  120. int copyLen = System.Math.Max(remainingBufferBytes - bufferOffset, 0);
  121. if (copyLen != 0) {
  122. copyLen = System.Math.Min(copyLen, destLen);
  123. System.Array.Copy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
  124. bufferOffset += copyLen;
  125. destOffset += copyLen;
  126. destLen -= copyLen;
  127. if (destLen == 0) {
  128. return copyLen;
  129. }
  130. }
  131. try {
  132. state.output = destBuffer;
  133. state.outputOffset = destOffset;
  134. state.outputLength = destLen;
  135. state.outputUsed = 0;
  136. System.Net.ApiService.Compression.Brotli.Decode.Decompress(state);
  137. if (state.outputUsed == 0) {
  138. return -1;
  139. }
  140. return state.outputUsed + copyLen;
  141. } catch (System.Net.ApiService.Compression.Brotli.BrotliRuntimeException ex) {
  142. throw new System.IO.IOException("Brotli stream decoding failed", ex);
  143. }
  144. }
  145. // <{[INJECTED CODE]}>
  146. public override bool CanRead {
  147. get {
  148. return true;
  149. }
  150. }
  151. public override bool CanSeek {
  152. get {
  153. return false;
  154. }
  155. }
  156. public override long Length {
  157. get {
  158. throw new System.NotSupportedException();
  159. }
  160. }
  161. public override long Position {
  162. get {
  163. throw new System.NotSupportedException();
  164. }
  165. set {
  166. throw new System.NotSupportedException();
  167. }
  168. }
  169. public override long Seek(long offset, System.IO.SeekOrigin origin) {
  170. throw new System.NotSupportedException();
  171. }
  172. public override void SetLength(long value) {
  173. throw new System.NotSupportedException();
  174. }
  175. public override bool CanWrite {
  176. get {
  177. return false;
  178. }
  179. }
  180. public override System.IAsyncResult BeginWrite(byte[] buffer, int offset,
  181. int count, System.AsyncCallback callback, object state) {
  182. throw new System.NotSupportedException();
  183. }
  184. public override void Write(byte[] buffer, int offset, int count) {
  185. throw new System.NotSupportedException();
  186. }
  187. public override void Flush() {
  188. }
  189. }
  190. }