• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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