aboutsummaryrefslogtreecommitdiff
path: root/csharp/org/brotli/dec/BitReader.cs
diff options
context:
space:
mode:
authorEugene Kliuchnikov <eustas@google.com>2017-04-10 21:16:08 +0200
committerGitHub <noreply@github.com>2017-04-10 21:16:08 +0200
commitf2aa4d1e8cd8fed9c4d9b3123b7c709fe429c8da (patch)
tree8cc25fb04bac7b7cdfec19bfc8379edf9402d1ae /csharp/org/brotli/dec/BitReader.cs
parent66e798d46ae95af5fcd569b5b2ec71001688ced4 (diff)
downloadbrotli-f2aa4d1e8cd8fed9c4d9b3123b7c709fe429c8da.zip
brotli-f2aa4d1e8cd8fed9c4d9b3123b7c709fe429c8da.tar.gz
brotli-f2aa4d1e8cd8fed9c4d9b3123b7c709fe429c8da.tar.bz2
Add C# transpilation script. (#538)
Diffstat (limited to 'csharp/org/brotli/dec/BitReader.cs')
-rw-r--r--csharp/org/brotli/dec/BitReader.cs271
1 files changed, 271 insertions, 0 deletions
diff --git a/csharp/org/brotli/dec/BitReader.cs b/csharp/org/brotli/dec/BitReader.cs
new file mode 100644
index 0000000..d3f1a3f
--- /dev/null
+++ b/csharp/org/brotli/dec/BitReader.cs
@@ -0,0 +1,271 @@
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+Distributed under MIT license.
+See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+namespace Org.Brotli.Dec
+{
+ /// <summary>Bit reading helpers.</summary>
+ internal sealed class BitReader
+ {
+ /// <summary>
+ /// Input byte buffer, consist of a ring-buffer and a "slack" region where bytes from the start of
+ /// the ring-buffer are copied.
+ /// </summary>
+ private const int Capacity = 1024;
+
+ private const int Slack = 16;
+
+ private const int IntBufferSize = Capacity + Slack;
+
+ private const int ByteReadSize = Capacity << 2;
+
+ private const int ByteBufferSize = IntBufferSize << 2;
+
+ private readonly byte[] byteBuffer = new byte[ByteBufferSize];
+
+ private readonly int[] intBuffer = new int[IntBufferSize];
+
+ private readonly Org.Brotli.Dec.IntReader intReader = new Org.Brotli.Dec.IntReader();
+
+ private System.IO.Stream input;
+
+ /// <summary>Input stream is finished.</summary>
+ private bool endOfStreamReached;
+
+ /// <summary>Pre-fetched bits.</summary>
+ internal long accumulator;
+
+ /// <summary>Current bit-reading position in accumulator.</summary>
+ internal int bitOffset;
+
+ /// <summary>Offset of next item in intBuffer.</summary>
+ private int intOffset;
+
+ private int tailBytes = 0;
+
+ /* Number of bytes in unfinished "int" item. */
+ /// <summary>Fills up the input buffer.</summary>
+ /// <remarks>
+ /// Fills up the input buffer.
+ /// <p> No-op if there are at least 36 bytes present after current position.
+ /// <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
+ /// buffer.
+ /// </remarks>
+ internal static void ReadMoreInput(Org.Brotli.Dec.BitReader br)
+ {
+ // TODO: Split to check and read; move read outside of decoding loop.
+ if (br.intOffset <= Capacity - 9)
+ {
+ return;
+ }
+ if (br.endOfStreamReached)
+ {
+ if (IntAvailable(br) >= -2)
+ {
+ return;
+ }
+ throw new Org.Brotli.Dec.BrotliRuntimeException("No more input");
+ }
+ int readOffset = br.intOffset << 2;
+ int bytesRead = ByteReadSize - readOffset;
+ System.Array.Copy(br.byteBuffer, readOffset, br.byteBuffer, 0, bytesRead);
+ br.intOffset = 0;
+ try
+ {
+ while (bytesRead < ByteReadSize)
+ {
+ int len = br.input.Read(br.byteBuffer, bytesRead, ByteReadSize - bytesRead);
+ // EOF is -1 in Java, but 0 in C#.
+ if (len <= 0)
+ {
+ br.endOfStreamReached = true;
+ br.tailBytes = bytesRead;
+ bytesRead += 3;
+ break;
+ }
+ bytesRead += len;
+ }
+ }
+ catch (System.IO.IOException e)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
+ }
+ Org.Brotli.Dec.IntReader.Convert(br.intReader, bytesRead >> 2);
+ }
+
+ internal static void CheckHealth(Org.Brotli.Dec.BitReader br, bool endOfStream)
+ {
+ if (!br.endOfStreamReached)
+ {
+ return;
+ }
+ int byteOffset = (br.intOffset << 2) + ((br.bitOffset + 7) >> 3) - 8;
+ if (byteOffset > br.tailBytes)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Read after end");
+ }
+ if (endOfStream && (byteOffset != br.tailBytes))
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unused bytes after end");
+ }
+ }
+
+ /// <summary>Advances the Read buffer by 5 bytes to make room for reading next 24 bits.</summary>
+ internal static void FillBitWindow(Org.Brotli.Dec.BitReader br)
+ {
+ if (br.bitOffset >= 32)
+ {
+ br.accumulator = ((long)br.intBuffer[br.intOffset++] << 32) | ((long)(((ulong)br.accumulator) >> 32));
+ br.bitOffset -= 32;
+ }
+ }
+
+ /// <summary>Reads the specified number of bits from Read Buffer.</summary>
+ internal static int ReadBits(Org.Brotli.Dec.BitReader br, int n)
+ {
+ FillBitWindow(br);
+ int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & ((1 << n) - 1);
+ br.bitOffset += n;
+ return val;
+ }
+
+ /// <summary>Initialize bit reader.</summary>
+ /// <remarks>
+ /// Initialize bit reader.
+ /// <p> Initialisation turns bit reader to a ready state. Also a number of bytes is prefetched to
+ /// accumulator. Because of that this method may block until enough data could be read from input.
+ /// </remarks>
+ /// <param name="br">BitReader POJO</param>
+ /// <param name="input">data source</param>
+ internal static void Init(Org.Brotli.Dec.BitReader br, System.IO.Stream input)
+ {
+ if (br.input != null)
+ {
+ throw new System.InvalidOperationException("Bit reader already has associated input stream");
+ }
+ Org.Brotli.Dec.IntReader.Init(br.intReader, br.byteBuffer, br.intBuffer);
+ br.input = input;
+ br.accumulator = 0;
+ br.bitOffset = 64;
+ br.intOffset = Capacity;
+ br.endOfStreamReached = false;
+ Prepare(br);
+ }
+
+ private static void Prepare(Org.Brotli.Dec.BitReader br)
+ {
+ ReadMoreInput(br);
+ CheckHealth(br, false);
+ FillBitWindow(br);
+ FillBitWindow(br);
+ }
+
+ internal static void Reload(Org.Brotli.Dec.BitReader br)
+ {
+ if (br.bitOffset == 64)
+ {
+ Prepare(br);
+ }
+ }
+
+ /// <exception cref="System.IO.IOException"/>
+ internal static void Close(Org.Brotli.Dec.BitReader br)
+ {
+ System.IO.Stream @is = br.input;
+ br.input = null;
+ if (@is != null)
+ {
+ @is.Close();
+ }
+ }
+
+ internal static void JumpToByteBoundary(Org.Brotli.Dec.BitReader br)
+ {
+ int padding = (64 - br.bitOffset) & 7;
+ if (padding != 0)
+ {
+ int paddingBits = Org.Brotli.Dec.BitReader.ReadBits(br, padding);
+ if (paddingBits != 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted padding bits");
+ }
+ }
+ }
+
+ internal static int IntAvailable(Org.Brotli.Dec.BitReader br)
+ {
+ int limit = Capacity;
+ if (br.endOfStreamReached)
+ {
+ limit = (br.tailBytes + 3) >> 2;
+ }
+ return limit - br.intOffset;
+ }
+
+ internal static void CopyBytes(Org.Brotli.Dec.BitReader br, byte[] data, int offset, int length)
+ {
+ if ((br.bitOffset & 7) != 0)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unaligned copyBytes");
+ }
+ // Drain accumulator.
+ while ((br.bitOffset != 64) && (length != 0))
+ {
+ data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
+ br.bitOffset += 8;
+ length--;
+ }
+ if (length == 0)
+ {
+ return;
+ }
+ // Get data from shadow buffer with "sizeof(int)" granularity.
+ int copyInts = System.Math.Min(IntAvailable(br), length >> 2);
+ if (copyInts > 0)
+ {
+ int readOffset = br.intOffset << 2;
+ System.Array.Copy(br.byteBuffer, readOffset, data, offset, copyInts << 2);
+ offset += copyInts << 2;
+ length -= copyInts << 2;
+ br.intOffset += copyInts;
+ }
+ if (length == 0)
+ {
+ return;
+ }
+ // Read tail bytes.
+ if (IntAvailable(br) > 0)
+ {
+ // length = 1..3
+ FillBitWindow(br);
+ while (length != 0)
+ {
+ data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
+ br.bitOffset += 8;
+ length--;
+ }
+ CheckHealth(br, false);
+ return;
+ }
+ // Now it is possible to copy bytes directly.
+ try
+ {
+ while (length > 0)
+ {
+ int len = br.input.Read(data, offset, length);
+ if (len == -1)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected end of input");
+ }
+ offset += len;
+ length -= len;
+ }
+ }
+ catch (System.IO.IOException e)
+ {
+ throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
+ }
+ }
+ }
+}