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