diff --git a/ar/AdaptiveArithmeticCompress.cs b/ar/AdaptiveArithmeticCompress.cs
new file mode 100644
index 0000000..337fe8e
--- /dev/null
+++ b/ar/AdaptiveArithmeticCompress.cs
@@ -0,0 +1,73 @@
+using System;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// Compression application using adaptive arithmetic coding.
+/// Usage: java AdaptiveArithmeticCompress InputFile OutputFile
+/// Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file.
+/// Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1),
+/// and updates it after each byte encoded. The corresponding decompressor program also starts with a flat
+/// frequency table and updates it after each byte decoded. It is by design that the compressor and
+/// decompressor have synchronized states, so that the data can be decompressed properly.
+///
+public class AdaptiveArithmeticCompress
+{
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+ public static void Main(string[] args)
+ {
+ /* @@@@ PORT
+ // Handle command line arguments
+ if (args.Length != 2)
+ {
+ Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile");
+ Environment.Exit(1);
+ return;
+ }
+ File inputFile = new File(args[0]);
+ File outputFile = new File(args[1]);
+
+ // Perform file compression
+ using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
+ {
+ compress(@in, @out);
+ }
+ */
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
+ internal static void compress(Stream @in, BitOutputStream @out)
+ {
+ FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
+ FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
+ ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
+ while (true)
+ {
+ // Read and encode one byte
+ int symbol = @in.ReadByte();
+ if (symbol == -1)
+ {
+ break;
+ }
+ enc.write(freqs, symbol);
+ freqs.increment(symbol);
+ }
+ enc.write(freqs, 256); // EOF
+ enc.finish(); // Flush remaining code bits
+ }
+
+}
diff --git a/ar/AdaptiveArithmeticDecompress.cs b/ar/AdaptiveArithmeticDecompress.cs
new file mode 100644
index 0000000..3bb4208
--- /dev/null
+++ b/ar/AdaptiveArithmeticDecompress.cs
@@ -0,0 +1,67 @@
+using System;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// Decompression application using adaptive arithmetic coding.
+/// Usage: java AdaptiveArithmeticDecompress InputFile OutputFile
+/// This decompresses files generated by the "AdaptiveArithmeticCompress" application.
+///
+public class AdaptiveArithmeticDecompress
+{
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+ public static void Main(string[] args)
+ {
+ /* @@@@ PORT
+ // Handle command line arguments
+ if (args.Length != 2)
+ {
+ Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile");
+ Environment.Exit(1);
+ return;
+ }
+ File inputFile = new File(args[0]);
+ File outputFile = new File(args[1]);
+
+ // Perform file decompression
+ using (BitInputStream @in = new BitInputStream(new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))), Stream @out = new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
+ {
+ decompress(@in, @out);
+ }
+ */
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
+ internal static void decompress(BitInputStream @in, Stream @out)
+ {
+ FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
+ FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
+ ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
+ while (true)
+ {
+ // Decode and write one byte
+ int symbol = dec.read(freqs);
+ if (symbol == 256) // EOF symbol
+ {
+ break;
+ }
+ @out.WriteByte((byte)symbol);
+ freqs.increment(symbol);
+ }
+ }
+
+}
diff --git a/ar/ArithmeticCoderBase.cs b/ar/ArithmeticCoderBase.cs
new file mode 100644
index 0000000..4c30f35
--- /dev/null
+++ b/ar/ArithmeticCoderBase.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Diagnostics;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+///
+/// Provides the state and behaviors that arithmetic coding encoders and decoders share.
+///
+///
+public abstract class ArithmeticCoderBase
+{
+
+ /*---- Configuration fields ----*/
+
+ ///
+ /// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
+ ///
+ /// - For state sizes less than the midpoint of around 32, larger values are generally better -
+ /// they allow a larger maximum frequency total (maximumTotal), and they reduce the approximation
+ /// error inherent in adapting fractions to integers; both effects reduce the data encoding loss
+ /// and asymptotically approach the efficiency of arithmetic coding using exact fractions.
+ /// - But for state sizes greater than the midpoint, because intermediate computations are limited
+ /// to the long integer type's 63-bit unsigned precision, larger state sizes will decrease the
+ /// maximum frequency total, which might constrain the user-supplied probability model.
+ /// - Therefore numStateBits=32 is recommended as the most versatile setting
+ /// because it maximizes maximumTotal (which ends up being slightly over 2^30).
+ /// - Note that numStateBits=62 is legal but useless because it implies maximumTotal=1,
+ /// which means a frequency table can only support one symbol with non-zero frequency.
+ ///
+ ///
+ protected internal readonly int numStateBits;
+
+ ///
+ /// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000.
+ protected internal readonly long fullRange;
+
+ ///
+ /// The top bit at width numStateBits, which is 0100...000.
+ protected internal readonly long halfRange;
+
+ ///
+ /// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1.
+ protected internal readonly long quarterRange;
+
+ ///
+ /// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010.
+ protected internal readonly long minimumRange;
+
+ ///
+ /// Maximum allowed total from a frequency table at all times during coding.
+ protected internal readonly long maximumTotal;
+
+ ///
+ /// Bit mask of numStateBits ones, which is 0111...111.
+ protected internal readonly long stateMask;
+
+
+
+ /*---- State fields ----*/
+
+ ///
+ /// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
+ ///
+ protected internal long low;
+
+ ///
+ /// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
+ ///
+ protected internal long high;
+
+
+
+ /*---- Constructor ----*/
+
+ ///
+ /// Constructs an arithmetic coder, which initializes the code range.
+ /// the number of bits for the arithmetic coding range
+ /// if stateSize is outside the range [1, 62]
+ public ArithmeticCoderBase(int numBits)
+ {
+ if (numBits < 1 || numBits > 62)
+ {
+ throw new System.ArgumentException("State size out of range");
+ }
+ numStateBits = numBits;
+ fullRange = 1L << numStateBits;
+ halfRange = (long)((ulong)fullRange >> 1); // Non-zero
+ quarterRange = (long)((ulong)halfRange >> 1); // Can be zero
+ minimumRange = quarterRange + 2; // At least 2
+ maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange);
+ stateMask = fullRange - 1;
+
+ low = 0;
+ high = stateMask;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Updates the code range (low and high) of this arithmetic coder as a result
+ /// of processing the specified symbol with the specified frequency table.
+ /// Invariants that are true before and after encoding/decoding each symbol
+ /// (letting fullRange = 2numStateBits):
+ ///
+ /// - 0 ≤ low ≤ code ≤ high < fullRange. ('code' exists only in the decoder.)
+ /// Therefore these variables are unsigned integers of numStateBits bits.
+ /// - low < 1/2 × fullRange ≤ high.
+ /// In other words, they are in different halves of the full range.
+ /// - (low < 1/4 × fullRange) || (high ≥ 3/4 × fullRange).
+ /// In other words, they are not both in the middle two quarters.
+ /// - Let range = high − low + 1, then fullRange/4 < minimumRange ≤ range ≤
+ /// fullRange. These invariants for 'range' essentially dictate the maximum total that the
+ /// incoming frequency table can have, such that intermediate calculations don't overflow.
+ ///
+ /// the frequency table to use
+ /// the symbol that was processed
+ /// if the symbol has zero frequency or the frequency table's total is too large
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
+ protected internal virtual void update(CheckedFrequencyTable freqs, int symbol)
+ {
+ // State check
+ Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range");
+
+ long range = high - low + 1;
+ Debug.Assert(range < minimumRange || range > fullRange, "Range out of range");
+
+ // Frequency table values check
+ long total = freqs.Total;
+ long symLow = freqs.getLow(symbol);
+ long symHigh = freqs.getHigh(symbol);
+ Debug.Assert( symLow == symHigh, "Symbol has zero frequency");
+
+ Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large");
+
+ // Update range
+ long newLow = low + symLow * range / total;
+ long newHigh = low + symHigh * range / total - 1;
+ low = newLow;
+ high = newHigh;
+
+ // While low and high have the same top bit value, shift them out
+ while (((low ^ high) & halfRange) == 0)
+ {
+ shift();
+ low = ((low << 1) & stateMask);
+ high = ((high << 1) & stateMask) | 1;
+ }
+ // Now low's top bit must be 0 and high's top bit must be 1
+
+ // While low's top two bits are 01 and high's are 10, delete the second highest bit of both
+ while ((low & ~high & quarterRange) != 0)
+ {
+ underflow();
+ low = (low << 1) ^ halfRange;
+ high = ((high ^ halfRange) << 1) | halfRange | 1;
+ }
+ }
+
+
+ ///
+ /// Called to handle the situation when the top bit of {@code low} and {@code high} are equal.
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
+ protected internal abstract void shift();
+
+
+ ///
+ /// Called to handle the situation when low=01(...) and high=10(...).
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
+ protected internal abstract void underflow();
+
+}
diff --git a/ar/ArithmeticCompress.cs b/ar/ArithmeticCompress.cs
new file mode 100644
index 0000000..34c81d6
--- /dev/null
+++ b/ar/ArithmeticCompress.cs
@@ -0,0 +1,127 @@
+using System;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// Compression application using static arithmetic coding.
+/// Usage: java ArithmeticCompress InputFile OutputFile
+/// Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.
+/// Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte
+/// values and 1 symbol for the EOF marker. The compressed file format starts with a list
+/// of 256 symbol frequencies, and then followed by the arithmetic-coded data.
+///
+public class ArithmeticCompress
+{
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+ public static void Main(string[] args)
+ {
+ /* @@ PORT
+ // Handle command line arguments
+ if (args.Length != 2)
+ {
+ Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile");
+ Environment.Exit(1);
+ return;
+ }
+ File inputFile = new File(args[0]);
+ File outputFile = new File(args[1]);
+
+ // Read input file once to compute symbol frequencies
+ FrequencyTable freqs = getFrequencies(inputFile);
+ freqs.increment(256); // EOF symbol gets a frequency of 1
+
+ // Read input file again, compress with arithmetic coding, and write output file
+ using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
+ {
+ writeFrequencies(@out, freqs);
+ compress(freqs, @in, @out);
+ }
+ */
+ }
+
+
+ // Returns a frequency table based on the bytes in the given file.
+ // Also contains an extra entry for symbol 256, whose frequency is set to 0.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException
+ private static FrequencyTable getFrequencies(string file)
+ {
+
+
+ FrequencyTable freqs = new SimpleFrequencyTable(new int[257]);
+ using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read)))
+ {
+ while (true)
+ {
+ int b = input.ReadByte();
+ if (b == -1)
+ {
+ break;
+ }
+ freqs.increment(b);
+ }
+ }
+ return freqs;
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException
+ internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs)
+ {
+ for (int i = 0; i < 256; i++)
+ {
+ writeInt(@out, 32, freqs.get(i));
+ }
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException
+ internal static void compress(FrequencyTable freqs, Stream @in, BitOutputStream @out)
+ {
+ ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
+ while (true)
+ {
+ int symbol = @in.ReadByte();
+ if (symbol == -1)
+ {
+ break;
+ }
+ enc.write(freqs, symbol);
+ }
+ enc.write(freqs, 256); // EOF
+ enc.finish(); // Flush remaining code bits
+ }
+
+
+ // Writes an unsigned integer of the given bit width to the given stream.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException
+ private static void writeInt(BitOutputStream @out, int numBits, int value)
+ {
+ if (numBits < 0 || numBits > 32)
+ {
+ throw new System.ArgumentException();
+ }
+
+ for (int i = numBits - 1; i >= 0; i--)
+ {
+ @out.write(((int)((uint)value >> i)) & 1); // Big endian
+ }
+ }
+
+}
diff --git a/ar/ArithmeticDecoder.cs b/ar/ArithmeticDecoder.cs
new file mode 100644
index 0000000..506e4f6
--- /dev/null
+++ b/ar/ArithmeticDecoder.cs
@@ -0,0 +1,152 @@
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+using System.Diagnostics;
+///
+/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe.
+///
+public sealed class ArithmeticDecoder : ArithmeticCoderBase
+{
+
+ /*---- Fields ----*/
+
+ // The underlying bit input stream (not null).
+ private BitInputStream input;
+
+ // The current raw code bits being buffered, which is always in the range [low, high].
+ private long code;
+
+
+
+ /*---- Constructor ----*/
+
+ ///
+ /// Constructs an arithmetic coding decoder based on the
+ /// specified bit input stream, and fills the code bits.
+ /// the number of bits for the arithmetic coding range
+ /// the bit input stream to read from
+ /// if the input steam is {@code null}
+ /// if stateSize is outside the range [1, 62]
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException
+ public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits)
+ {
+ input = @in; //Objects.requireNonNull(@in);
+ code = 0;
+ for (int i = 0; i < numStateBits; i++)
+ {
+ code = code << 1 | readCodeBit();
+ }
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Decodes the next symbol based on the specified frequency table and returns it.
+ /// Also updates this arithmetic coder's state and may read in some bits.
+ /// the frequency table to use
+ /// the next symbol
+ /// if the frequency table is {@code null}
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException
+ public int read(FrequencyTable freqs)
+ {
+ return read(new CheckedFrequencyTable(freqs));
+ }
+
+
+ ///
+ /// Decodes the next symbol based on the specified frequency table and returns it.
+ /// Also updates this arithmetic coder's state and may read in some bits.
+ /// the frequency table to use
+ /// the next symbol
+ /// if the frequency table is {@code null}
+ /// if the frequency table's total is too large
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException
+ public int read(CheckedFrequencyTable freqs)
+ {
+ // Translate from coding range scale to frequency table scale
+ long total = freqs.Total;
+ if (total > maximumTotal)
+ {
+ throw new System.ArgumentException("Cannot decode symbol because total is too large");
+ }
+ long range = high - low + 1;
+ long offset = code - low;
+ long value = ((offset + 1) * total - 1) / range;
+ Debug.Assert(value * range / total > offset);
+
+ Debug.Assert(value < 0 || value >= total);
+
+ // A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value.
+ int start = 0;
+ int end = freqs.SymbolLimit;
+ while (end - start > 1)
+ {
+ int middle = (int)((uint)(start + end) >> 1);
+ if (freqs.getLow(middle) > value)
+ {
+ end = middle;
+ }
+ else
+ {
+ start = middle;
+ }
+ }
+ Debug.Assert( start + 1 != end);
+
+
+ int symbol = start;
+ Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset);
+
+ update(freqs, symbol);
+ Debug.Assert(code < low || code > high);
+
+ return symbol;
+ }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: protected void shift() throws java.io.IOException
+ protected internal override void shift()
+ {
+ code = ((code << 1) & stateMask) | readCodeBit();
+ }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: protected void underflow() throws java.io.IOException
+ protected internal override void underflow()
+ {
+ code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit();
+ }
+
+
+ // Returns the next bit (0 or 1) from the input stream. The end
+ // of stream is treated as an infinite number of trailing zeros.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: private int readCodeBit() throws java.io.IOException
+ private int readCodeBit()
+ {
+ int temp = input.read();
+ if (temp == -1)
+ {
+ temp = 0;
+ }
+ return temp;
+ }
+
+}
diff --git a/ar/ArithmeticDecompress.cs b/ar/ArithmeticDecompress.cs
new file mode 100644
index 0000000..f8e45a4
--- /dev/null
+++ b/ar/ArithmeticDecompress.cs
@@ -0,0 +1,99 @@
+using System;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// Decompression application using static arithmetic coding.
+/// Usage: java ArithmeticDecompress InputFile OutputFile
+/// This decompresses files generated by the "ArithmeticCompress" application.
+///
+public class ArithmeticDecompress
+{
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+ public static void Main(string[] args)
+ {
+ // Handle command line arguments
+ if (args.Length != 2)
+ {
+ Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile");
+ Environment.Exit(1);
+ return;
+ }
+ string inputFile = args[0]; // new File(args[0]);
+ string outputFile = args[1]; //new File(args[1]);
+
+ // Perform file decompression
+ using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))))
+ using( Stream @out = new BufferedStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write) ) )
+ {
+
+ FrequencyTable freqs = readFrequencies(@in);
+ decompress( freqs, @in, @out );
+
+ }
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException
+ internal static FrequencyTable readFrequencies(BitInputStream @in)
+ {
+ int[] freqs = new int[257];
+ for (int i = 0; i < 256; i++)
+ {
+ freqs[i] = readInt(@in, 32);
+ }
+ freqs[256] = 1; // EOF symbol
+ return new SimpleFrequencyTable(freqs);
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void decompress(FrequencyTable freqs, BitInputStream in, java.io.OutputStream out) throws java.io.IOException
+ internal static void decompress(FrequencyTable freqs, BitInputStream @in, Stream @out)
+ {
+ ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
+ while (true)
+ {
+ int symbol = dec.read(freqs);
+ if (symbol == 256) // EOF symbol
+ {
+ break;
+ }
+ @out.WriteByte((byte)symbol);
+ }
+ }
+
+
+ // Reads an unsigned integer of the given bit width from the given stream.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException
+ private static int readInt(BitInputStream @in, int numBits)
+ {
+ if (numBits < 0 || numBits > 32)
+ {
+ throw new System.ArgumentException();
+ }
+
+ int result = 0;
+ for (int i = 0; i < numBits; i++)
+ {
+ result = (result << 1) | @in.readNoEof(); // Big endian
+ }
+ return result;
+ }
+
+}
diff --git a/ar/ArithmeticEncoder.cs b/ar/ArithmeticEncoder.cs
new file mode 100644
index 0000000..6403817
--- /dev/null
+++ b/ar/ArithmeticEncoder.cs
@@ -0,0 +1,118 @@
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+using System;
+///
+/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe.
+///
+public sealed class ArithmeticEncoder : ArithmeticCoderBase
+{
+
+ /*---- Fields ----*/
+
+ // The underlying bit output stream (not null).
+ private BitOutputStream output;
+
+ // Number of saved underflow bits. This value can grow without bound,
+ // so a truly correct implementation would use a BigInteger.
+ private int numUnderflow;
+
+
+
+ /*---- Constructor ----*/
+
+ ///
+ /// Constructs an arithmetic coding encoder based on the specified bit output stream.
+ /// the number of bits for the arithmetic coding range
+ /// the bit output stream to write to
+ /// if the output stream is {@code null}
+ /// if stateSize is outside the range [1, 62]
+ public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits)
+ {
+ output = @out; //Objects.requireNonNull(@out);
+ numUnderflow = 0;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Encodes the specified symbol based on the specified frequency table.
+ /// This updates this arithmetic coder's state and may write out some bits.
+ /// the frequency table to use
+ /// the symbol to encode
+ /// if the frequency table is {@code null}
+ /// if the symbol has zero frequency
+ /// or the frequency table's total is too large
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException
+ public void write(FrequencyTable freqs, int symbol)
+ {
+ write(new CheckedFrequencyTable(freqs), symbol);
+ }
+
+
+ ///
+ /// Encodes the specified symbol based on the specified frequency table.
+ /// Also updates this arithmetic coder's state and may write out some bits.
+ /// the frequency table to use
+ /// the symbol to encode
+ /// if the frequency table is {@code null}
+ /// if the symbol has zero frequency
+ /// or the frequency table's total is too large
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
+ public void write(CheckedFrequencyTable freqs, int symbol)
+ {
+ update(freqs, symbol);
+ }
+
+
+ ///
+ /// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly.
+ /// It is important that this method must be called at the end of the each encoding process.
+ /// Note that this method merely writes data to the underlying output stream but does not close it.
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public void finish() throws java.io.IOException
+ public void finish()
+ {
+ output.write(1);
+ }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: protected void shift() throws java.io.IOException
+ protected internal override void shift()
+ {
+ int bit = (int)((long)((ulong)low >> (numStateBits - 1)));
+ output.write(bit);
+
+ // Write out the saved underflow bits
+ for (; numUnderflow > 0; numUnderflow--)
+ {
+ output.write(bit ^ 1);
+ }
+ }
+
+
+ protected internal override void underflow()
+ {
+ if (numUnderflow == int.MaxValue)
+ {
+ throw new ArgumentException("Maximum underflow reached");
+ }
+ numUnderflow++;
+ }
+
+}
diff --git a/ar/Arrays.cs b/ar/Arrays.cs
new file mode 100644
index 0000000..6feabc0
--- /dev/null
+++ b/ar/Arrays.cs
@@ -0,0 +1,41 @@
+//---------------------------------------------------------------------------------------------------------
+// Copyright © 2007 - 2020 Tangible Software Solutions, Inc.
+// This class can be used by anyone provided that the copyright notice remains intact.
+//
+// This class is used to replace some calls to java.util.Arrays methods with the C# equivalent.
+//---------------------------------------------------------------------------------------------------------
+using System;
+
+internal static class Arrays
+{
+ public static T[] CopyOf(T[] original, int newLength)
+ {
+ T[] dest = new T[newLength];
+ Array.Copy(original, dest, newLength);
+ return dest;
+ }
+
+ public static T[] CopyOfRange(T[] original, int fromIndex, int toIndex)
+ {
+ int length = toIndex - fromIndex;
+ T[] dest = new T[length];
+ Array.Copy(original, fromIndex, dest, 0, length);
+ return dest;
+ }
+
+ public static void Fill(T[] array, T value)
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void Fill(T[] array, int fromIndex, int toIndex, T value)
+ {
+ for (int i = fromIndex; i < toIndex; i++)
+ {
+ array[i] = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ar/BitInputStream.cs b/ar/BitInputStream.cs
new file mode 100644
index 0000000..04ceebd
--- /dev/null
+++ b/ar/BitInputStream.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// A stream of bits that can be read. Because they come from an underlying byte stream,
+/// the total number of bits is always a multiple of 8. The bits are read in big endian.
+/// Mutable and not thread-safe.
+///
+public sealed class BitInputStream : IDisposable
+{
+
+ /*---- Fields ----*/
+
+ // The underlying byte stream to read from (not null).
+ private Stream input;
+
+ // Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached.
+ private int currentByte;
+
+ // Number of remaining bits in the current byte, always between 0 and 7 (inclusive).
+ private int numBitsRemaining;
+
+
+
+ /*---- Constructor ----*/
+
+ ///
+ /// Constructs a bit input stream based on the specified byte input stream.
+ /// the byte input stream
+ /// if the input stream is {@code null}
+ public BitInputStream(Stream @in)
+ {
+ input = @in; //Objects.requireNonNull(@in);
+ currentByte = 0;
+ numBitsRemaining = 0;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if
+ /// the end of stream is reached. The end of stream always occurs on a byte boundary.
+ /// the next bit of 0 or 1, or -1 for the end of stream
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public int read() throws java.io.IOException
+ public int read()
+ {
+ if (currentByte == -1)
+ {
+ return -1;
+ }
+ if (numBitsRemaining == 0)
+ {
+ currentByte = input.ReadByte(); // input.Read();
+ if (currentByte == -1)
+ {
+ return -1;
+ }
+ numBitsRemaining = 8;
+ }
+ Debug.Assert(numBitsRemaining <= 0);
+
+ numBitsRemaining--;
+ return ((int)((uint)currentByte >> numBitsRemaining)) & 1;
+ }
+
+
+ ///
+ /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException}
+ /// if the end of stream is reached. The end of stream always occurs on a byte boundary.
+ /// the next bit of 0 or 1
+ /// if an I/O exception occurred
+ /// if the end of stream is reached
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public int readNoEof() throws java.io.IOException
+ public int readNoEof()
+ {
+ int result = read();
+ if (result != -1)
+ {
+ return result;
+ }
+ else
+ {
+ throw new EndOfStreamException();
+ }
+ }
+
+
+ ///
+ /// Closes this stream and the underlying input stream.
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public void close() throws java.io.IOException
+ public void close()
+ {
+ input.Close();
+ currentByte = -1;
+ numBitsRemaining = 0;
+ }
+
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/ar/BitOutputStream.cs b/ar/BitOutputStream.cs
new file mode 100644
index 0000000..8c1c7ce
--- /dev/null
+++ b/ar/BitOutputStream.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// A stream where bits can be written to. Because they are written to an underlying
+/// byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits.
+/// The bits are written in big endian. Mutable and not thread-safe.
+///
+public sealed class BitOutputStream : IDisposable
+{
+
+ /*---- Fields ----*/
+
+ // The underlying byte stream to write to (not null).
+ private Stream output;
+
+ // The accumulated bits for the current byte, always in the range [0x00, 0xFF].
+ private int currentByte;
+
+ // Number of accumulated bits in the current byte, always between 0 and 7 (inclusive).
+ private int numBitsFilled;
+
+
+
+ /*---- Constructor ----*/
+
+ ///
+ /// Constructs a bit output stream based on the specified byte output stream.
+ /// the byte output stream
+ /// if the output stream is {@code null}
+ public BitOutputStream(Stream @out)
+ {
+ output = @out; //Objects.requireNonNull(@out);
+ currentByte = 0;
+ numBitsFilled = 0;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Writes a bit to the stream. The specified bit must be 0 or 1.
+ /// the bit to write, which must be 0 or 1
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public void write(int b) throws java.io.IOException
+ public void write(int b)
+ {
+ if (b != 0 && b != 1)
+ {
+ throw new System.ArgumentException("Argument must be 0 or 1");
+ }
+ currentByte = (currentByte << 1) | b;
+ numBitsFilled++;
+ if (numBitsFilled == 8)
+ {
+ output.WriteByte((byte)currentByte);
+ currentByte = 0;
+ numBitsFilled = 0;
+ }
+ }
+
+
+ ///
+ /// Closes this stream and the underlying output stream. If called when this
+ /// bit stream is not at a byte boundary, then the minimum number of "0" bits
+ /// (between 0 and 7 of them) are written as padding to reach the next byte boundary.
+ /// if an I/O exception occurred
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public void close() throws java.io.IOException
+ public void close()
+ {
+ while (numBitsFilled != 0)
+ {
+ write(0);
+ }
+ output.Close();
+ }
+
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/ar/CheckedFrequencyTable.cs b/ar/CheckedFrequencyTable.cs
new file mode 100644
index 0000000..62504ed
--- /dev/null
+++ b/ar/CheckedFrequencyTable.cs
@@ -0,0 +1,128 @@
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+using System;
+using System.Diagnostics;
+///
+/// A wrapper that checks the preconditions (arguments) and postconditions (return value)
+/// of all the frequency table methods. Useful for finding faults in a frequency table
+/// implementation. However, arithmetic overflow conditions are not checked.
+///
+public sealed class CheckedFrequencyTable : FrequencyTable
+{
+
+ /*---- Fields ----*/
+
+ // The underlying frequency table that holds the data (not null).
+ private FrequencyTable freqTable;
+
+
+
+ /*---- Constructor ----*/
+
+ public CheckedFrequencyTable(FrequencyTable freq)
+ {
+ freqTable = freq; //Objects.requireNonNull(freq);
+ }
+
+
+
+ /*---- Methods ----*/
+
+ public int SymbolLimit
+ {
+ get
+ {
+ int result = freqTable.SymbolLimit;
+ Debug.Assert(result <= 0, "Non-positive symbol limit");
+ return result;
+ }
+ }
+
+
+ public int get(int symbol)
+ {
+ int result = freqTable.get(symbol);
+ Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
+ Debug.Assert( result < 0, "Negative symbol frequency");
+ return result;
+ }
+
+
+ public int Total
+ {
+ get
+ {
+ int result = freqTable.Total;
+ Debug.Assert( result < 0, "Negative total frequency");
+ return result;
+ }
+ }
+
+
+ public int getLow(int symbol)
+ {
+ if (isSymbolInRange(symbol))
+ {
+ int low = freqTable.getLow(symbol);
+ int high = freqTable.getHigh(symbol);
+ Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range");
+ return low;
+ }
+ else
+ {
+ freqTable.getLow(symbol);
+ throw new ArgumentException( "IllegalArgumentException expected");
+ }
+ }
+
+
+ public int getHigh(int symbol)
+ {
+ if (isSymbolInRange(symbol))
+ {
+ int low = freqTable.getLow(symbol);
+ int high = freqTable.getHigh(symbol);
+ Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range");
+ return high;
+ }
+ else
+ {
+ freqTable.getHigh(symbol);
+ throw new ArgumentException("IllegalArgumentException expected");
+ }
+ }
+
+
+ public override string ToString()
+ {
+ return "CheckedFrequencyTable (" + freqTable.ToString() + ")";
+ }
+
+
+ public void set(int symbol, int freq)
+ {
+ freqTable.set(symbol, freq);
+ Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected");
+ }
+
+
+ public void increment(int symbol)
+ {
+ freqTable.increment(symbol);
+ Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
+ }
+
+
+ private bool isSymbolInRange(int symbol)
+ {
+ return 0 <= symbol && symbol < SymbolLimit;
+ }
+
+}
diff --git a/ar/FlatFrequencyTable.cs b/ar/FlatFrequencyTable.cs
new file mode 100644
index 0000000..f46a337
--- /dev/null
+++ b/ar/FlatFrequencyTable.cs
@@ -0,0 +1,145 @@
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+///
+/// An immutable frequency table where every symbol has the same frequency of 1.
+/// Useful as a fallback model when no statistics are available.
+///
+public sealed class FlatFrequencyTable : FrequencyTable
+{
+
+ /*---- Fields ----*/
+
+ // Total number of symbols, which is at least 1.
+ private readonly int numSymbols;
+
+
+
+ /*---- Constructor ----*/
+
+ ///
+ /// Constructs a flat frequency table with the specified number of symbols.
+ /// the number of symbols, which must be at least 1
+ /// if the number of symbols is less than 1
+ public FlatFrequencyTable(int numSyms)
+ {
+ if (numSyms < 1)
+ {
+ throw new System.ArgumentException("Number of symbols must be positive");
+ }
+ numSymbols = numSyms;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Returns the number of symbols in this table, which is at least 1.
+ /// the number of symbols in this table
+ public int SymbolLimit
+ {
+ get
+ {
+ return numSymbols;
+ }
+ }
+
+
+ ///
+ /// Returns the frequency of the specified symbol, which is always 1.
+ /// the symbol to query
+ /// the frequency of the symbol, which is 1
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public int get(int symbol)
+ {
+ checkSymbol(symbol);
+ return 1;
+ }
+
+
+ ///
+ /// Returns the total of all symbol frequencies, which is
+ /// always equal to the number of symbols in this table.
+ /// the total of all symbol frequencies, which is {@code getSymbolLimit()}
+ public int Total
+ {
+ get
+ {
+ return numSymbols;
+ }
+ }
+
+
+ ///
+ /// Returns the sum of the frequencies of all the symbols strictly below
+ /// the specified symbol value. The returned value is equal to {@code symbol}.
+ /// the symbol to query
+ /// the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol}
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public int getLow(int symbol)
+ {
+ checkSymbol(symbol);
+ return symbol;
+ }
+
+
+ ///
+ /// Returns the sum of the frequencies of the specified symbol and all
+ /// the symbols below. The returned value is equal to {@code symbol + 1}.
+ /// the symbol to query
+ /// the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1}
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public int getHigh(int symbol)
+ {
+ checkSymbol(symbol);
+ return symbol + 1;
+ }
+
+
+ // Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception.
+ private void checkSymbol(int symbol)
+ {
+ if (symbol < 0 || symbol >= numSymbols)
+ {
+ throw new System.ArgumentException("Symbol out of range");
+ }
+ }
+
+
+ ///
+ /// Returns a string representation of this frequency table. The format is subject to change.
+ /// a string representation of this frequency table
+ public override string ToString()
+ {
+ return "FlatFrequencyTable=" + numSymbols;
+ }
+
+
+ ///
+ /// Unsupported operation, because this frequency table is immutable.
+ /// ignored
+ /// ignored
+ /// because this frequency table is immutable
+ public void set(int symbol, int freq)
+ {
+ throw new System.NotSupportedException();
+ }
+
+
+ ///
+ /// Unsupported operation, because this frequency table is immutable.
+ /// ignored
+ /// because this frequency table is immutable
+ public void increment(int symbol)
+ {
+ throw new System.NotSupportedException();
+ }
+
+}
diff --git a/ar/FrequencyTable.cs b/ar/FrequencyTable.cs
new file mode 100644
index 0000000..9158ac3
--- /dev/null
+++ b/ar/FrequencyTable.cs
@@ -0,0 +1,76 @@
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+///
+/// A table of symbol frequencies. The table holds data for symbols numbered from 0
+/// to getSymbolLimit()−1. Each symbol has a frequency, which is a non-negative integer.
+/// Frequency table objects are primarily used for getting cumulative symbol
+/// frequencies. These objects can be mutable depending on the implementation.
+/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE.
+///
+public interface FrequencyTable
+{
+
+ ///
+ /// Returns the number of symbols in this frequency table, which is a positive number.
+ /// the number of symbols in this frequency table
+ int SymbolLimit {get;}
+
+
+ ///
+ /// Returns the frequency of the specified symbol. The returned value is at least 0.
+ /// the symbol to query
+ /// the frequency of the symbol
+ /// if the symbol is out of range
+ int get(int symbol);
+
+
+ ///
+ /// Sets the frequency of the specified symbol to the specified value.
+ /// The frequency value must be at least 0.
+ /// the symbol to set
+ /// the frequency value to set
+ /// if the frequency is negative or the symbol is out of range
+ /// if an arithmetic overflow occurs
+ void set(int symbol, int freq);
+
+
+ ///
+ /// Increments the frequency of the specified symbol.
+ /// the symbol whose frequency to increment
+ /// if the symbol is out of range
+ /// if an arithmetic overflow occurs
+ void increment(int symbol);
+
+
+ ///
+ /// Returns the total of all symbol frequencies. The returned value is at
+ /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}.
+ /// the total of all symbol frequencies
+ int Total {get;}
+
+
+ ///
+ /// Returns the sum of the frequencies of all the symbols strictly
+ /// below the specified symbol value. The returned value is at least 0.
+ /// the symbol to query
+ /// the sum of the frequencies of all the symbols below {@code symbol}
+ /// if the symbol is out of range
+ int getLow(int symbol);
+
+
+ ///
+ /// Returns the sum of the frequencies of the specified symbol
+ /// and all the symbols below. The returned value is at least 0.
+ /// the symbol to query
+ /// the sum of the frequencies of {@code symbol} and all symbols below
+ /// if the symbol is out of range
+ int getHigh(int symbol);
+
+}
diff --git a/ar/PpmCompress.cs b/ar/PpmCompress.cs
new file mode 100644
index 0000000..d54929a
--- /dev/null
+++ b/ar/PpmCompress.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// Compression application using prediction by partial matching (PPM) with arithmetic coding.
+/// Usage: java PpmCompress InputFile OutputFile
+/// Then use the corresponding "PpmDecompress" application to recreate the original input file.
+/// Note that both the compressor and decompressor need to use the same PPM context modeling logic.
+/// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding.
+///
+public sealed class PpmCompress
+{
+
+ // Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n).
+ private const int MODEL_ORDER = 3;
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+ public static void Main(string[] args)
+ {
+ /* @@@@ PORT
+ // Handle command line arguments
+ if (args.Length != 2)
+ {
+ Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile");
+ Environment.Exit(1);
+ return;
+ }
+ File inputFile = new File(args[0]);
+ File outputFile = new File(args[1]);
+
+ // Perform file compression
+ using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
+ {
+ compress(@in, @out);
+ }
+ */
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
+ internal static void compress(Stream @in, BitOutputStream @out)
+ {
+ // Set up encoder and model. In this PPM model, symbol 256 represents EOF;
+ // its frequency is 1 in the order -1 context but its frequency
+ // is 0 in all other contexts (which have non-negative order).
+ ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
+ PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
+ int[] history = new int[0];
+
+ while (true)
+ {
+ // Read and encode one byte
+ int symbol = @in.ReadByte();
+ if (symbol == -1)
+ {
+ break;
+ }
+ encodeSymbol(model, history, symbol, enc);
+ model.incrementContexts(history, symbol);
+
+ if (model.modelOrder >= 1)
+ {
+ // Prepend current symbol, dropping oldest symbol if necessary
+ if (history.Length < model.modelOrder)
+ {
+ history = Arrays.CopyOf(history, history.Length + 1);
+ }
+ Array.Copy(history, 0, history, 1, history.Length - 1);
+ history[0] = symbol;
+ }
+ }
+
+ encodeSymbol(model, history, 256, enc); // EOF
+ enc.finish(); // Flush remaining code bits
+ }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) throws java.io.IOException
+ private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc)
+ {
+ // Try to use highest order context that exists based on the history suffix, such
+ // that the next symbol has non-zero frequency. When symbol 256 is produced at a context
+ // at any non-negative order, it means "escape to the next lower order with non-empty
+ // context". When symbol 256 is produced at the order -1 context, it means "EOF".
+ for (int order = history.Length; order >= 0; order--)
+ {
+ PpmModel.Context ctx = model.rootContext;
+ for (int i = 0; i < order; i++)
+ {
+ Debug.Assert(ctx.subcontexts == null);
+
+ ctx = ctx.subcontexts[history[i]];
+ if (ctx == null)
+ {
+ goto outerContinue;
+ }
+ }
+ if (symbol != 256 && ctx.frequencies.get(symbol) > 0)
+ {
+ enc.write(ctx.frequencies, symbol);
+ return;
+ }
+ // Else write context escape symbol and continue decrementing the order
+ enc.write(ctx.frequencies, 256);
+ outerContinue:;
+ }
+ outerBreak:
+ // Logic for order = -1
+ enc.write(model.orderMinus1Freqs, symbol);
+ }
+
+}
diff --git a/ar/PpmDecompress.cs b/ar/PpmDecompress.cs
new file mode 100644
index 0000000..68f4034
--- /dev/null
+++ b/ar/PpmDecompress.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+
+///
+/// Decompression application using prediction by partial matching (PPM) with arithmetic coding.
+/// Usage: java PpmDecompress InputFile OutputFile
+/// This decompresses files generated by the "PpmCompress" application.
+///
+public sealed class PpmDecompress
+{
+
+ // Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n).
+ private const int MODEL_ORDER = 3;
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+ public static void Main(string[] args)
+ {
+ // Handle command line arguments
+ if (args.Length != 2)
+ {
+ Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile");
+ Environment.Exit(1);
+ return;
+ }
+
+ string inputFile = args[0]; //new File(args[0]);
+ string outputFile =args[1]; //new File(args[1]);
+
+ // Perform file decompression
+ using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))))
+ using( Stream @out = new BufferedStream( new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
+ {
+ decompress(@in, @out);
+ }
+ }
+
+
+ // To allow unit testing, this method is package-private instead of private.
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
+ internal static void decompress(BitInputStream @in, Stream @out)
+ {
+ // Set up decoder and model. In this PPM model, symbol 256 represents EOF;
+ // its frequency is 1 in the order -1 context but its frequency
+ // is 0 in all other contexts (which have non-negative order).
+ ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
+ PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
+ int[] history = new int[0];
+
+ while (true)
+ {
+ // Decode and write one byte
+ int symbol = decodeSymbol(dec, model, history);
+ if (symbol == 256) // EOF symbol
+ {
+ break;
+ }
+ @out.WriteByte((byte)symbol);
+ model.incrementContexts(history, symbol);
+
+ if (model.modelOrder >= 1)
+ {
+ // Prepend current symbol, dropping oldest symbol if necessary
+ if (history.Length < model.modelOrder)
+ {
+ history = Arrays.CopyOf(history, history.Length + 1);
+ }
+ Array.Copy(history, 0, history, 1, history.Length - 1);
+ history[0] = symbol;
+ }
+ }
+ }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
+//ORIGINAL LINE: private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) throws java.io.IOException
+ private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history)
+ {
+ // Try to use highest order context that exists based on the history suffix. When symbol 256
+ // is consumed at a context at any non-negative order, it means "escape to the next lower order
+ // with non-empty context". When symbol 256 is consumed at the order -1 context, it means "EOF".
+ for (int order = history.Length; order >= 0; order--)
+ {
+ PpmModel.Context ctx = model.rootContext;
+ for (int i = 0; i < order; i++)
+ {
+ Debug.Assert(ctx.subcontexts == null);
+
+ ctx = ctx.subcontexts[history[i]];
+ if (ctx == null)
+ {
+ goto outerContinue;
+ }
+ }
+ int symbol = dec.read(ctx.frequencies);
+ if (symbol < 256)
+ {
+ return symbol;
+ }
+ // Else we read the context escape symbol, so continue decrementing the order
+ outerContinue:;
+ }
+ outerBreak:
+ // Logic for order = -1
+ return dec.read(model.orderMinus1Freqs);
+ }
+
+}
diff --git a/ar/PpmModel.cs b/ar/PpmModel.cs
new file mode 100644
index 0000000..2a9ae3a
--- /dev/null
+++ b/ar/PpmModel.cs
@@ -0,0 +1,113 @@
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+using System.Diagnostics;
+
+internal sealed class PpmModel
+{
+
+ /*---- Fields ----*/
+
+ public readonly int modelOrder;
+
+ private readonly int symbolLimit;
+ private readonly int escapeSymbol;
+
+ public readonly Context rootContext;
+ public readonly FrequencyTable orderMinus1Freqs;
+
+
+
+ /*---- Constructors ----*/
+
+ public PpmModel(int order, int symbolLimit, int escapeSymbol)
+ {
+ if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit)
+ {
+ throw new System.ArgumentException();
+ }
+ this.modelOrder = order;
+ this.symbolLimit = symbolLimit;
+ this.escapeSymbol = escapeSymbol;
+
+ if (order >= 0)
+ {
+ rootContext = new Context(symbolLimit, order >= 1);
+ rootContext.frequencies.increment(escapeSymbol);
+ }
+ else
+ {
+ rootContext = null;
+ }
+ orderMinus1Freqs = new FlatFrequencyTable(symbolLimit);
+ }
+
+
+
+ /*---- Methods ----*/
+
+ public void incrementContexts(int[] history, int symbol)
+ {
+ if (modelOrder == -1)
+ {
+ return;
+ }
+ if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit)
+ {
+ throw new System.ArgumentException();
+ }
+
+ Context ctx = rootContext;
+ ctx.frequencies.increment(symbol);
+ int i = 0;
+ foreach (int sym in history)
+ {
+ Context[] subctxs = ctx.subcontexts;
+ Debug.Assert(subctxs == null);
+
+
+ if (subctxs[sym] == null)
+ {
+ subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder);
+ subctxs[sym].frequencies.increment(escapeSymbol);
+ }
+ ctx = subctxs[sym];
+ ctx.frequencies.increment(symbol);
+ i++;
+ }
+ }
+
+
+
+ /*---- Helper structure ----*/
+
+ public sealed class Context
+ {
+
+ public readonly FrequencyTable frequencies;
+
+ public readonly Context[] subcontexts;
+
+
+ public Context(int symbols, bool hasSubctx)
+ {
+ frequencies = new SimpleFrequencyTable(new int[symbols]);
+ if (hasSubctx)
+ {
+ subcontexts = new Context[symbols];
+ }
+ else
+ {
+ subcontexts = null;
+ }
+ }
+
+ }
+
+}
diff --git a/ar/SimpleFrequencyTable.cs b/ar/SimpleFrequencyTable.cs
new file mode 100644
index 0000000..81b5f42
--- /dev/null
+++ b/ar/SimpleFrequencyTable.cs
@@ -0,0 +1,260 @@
+using System.Diagnostics;
+using System.Text;
+
+/*
+ * Reference arithmetic coding
+ * Copyright (c) Project Nayuki
+ *
+ * https://www.nayuki.io/page/reference-arithmetic-coding
+ * https://github.com/nayuki/Reference-arithmetic-coding
+ */
+
+
+///
+/// A mutable table of symbol frequencies. The number of symbols cannot be changed
+/// after construction. The current algorithm for calculating cumulative frequencies
+/// takes linear time, but there exist faster algorithms such as Fenwick trees.
+///
+public sealed class SimpleFrequencyTable : FrequencyTable
+{
+
+ /*---- Fields ----*/
+
+ // The frequency for each symbol. Its length is at least 1, and each element is non-negative.
+ private int[] frequencies;
+
+ // cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive).
+ // Initialized lazily. When this is not null, the data is valid.
+ private int[] cumulative;
+
+ // Always equal to the sum of 'frequencies'.
+ private int total;
+
+
+
+ /*---- Constructors ----*/
+
+ ///
+ /// Constructs a frequency table from the specified array of symbol frequencies. There must be at least
+ /// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}.
+ /// the array of symbol frequencies
+ /// if the array is {@code null}
+ /// if {@code freqs.length} < 1,
+ /// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} < 0
+ /// if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE}
+ public SimpleFrequencyTable(int[] freqs)
+ {
+ //Objects.requireNonNull(freqs);
+ if (freqs.Length < 1)
+ {
+ throw new System.ArgumentException("At least 1 symbol needed");
+ }
+ if (freqs.Length > int.MaxValue - 1)
+ {
+ throw new System.ArgumentException("Too many symbols");
+ }
+
+ frequencies = (int[])freqs.Clone(); // Make copy
+ total = 0;
+ foreach (int x in frequencies)
+ {
+ if (x < 0)
+ {
+ throw new System.ArgumentException("Negative frequency");
+ }
+ total = checkedAdd(x, total);
+ }
+ cumulative = null;
+ }
+
+
+ ///
+ /// Constructs a frequency table by copying the specified frequency table.
+ /// the frequency table to copy
+ /// if {@code freqs} is {@code null}
+ /// if {@code freqs.getSymbolLimit()} < 1
+ /// or any element {@code freqs.get(i)} < 0
+ /// if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE}
+ public SimpleFrequencyTable(FrequencyTable freqs)
+ {
+ //Objects.requireNonNull(freqs);
+ int numSym = freqs.SymbolLimit;
+ Debug.Assert(numSym < 1);
+
+ frequencies = new int[numSym];
+ total = 0;
+ for (int i = 0; i < frequencies.Length; i++)
+ {
+ int x = freqs.get(i);
+ Debug.Assert(x < 0);
+
+ frequencies[i] = x;
+ total = checkedAdd(x, total);
+ }
+ cumulative = null;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ ///
+ /// Returns the number of symbols in this frequency table, which is at least 1.
+ /// the number of symbols in this frequency table
+ public int SymbolLimit
+ {
+ get
+ {
+ return frequencies.Length;
+ }
+ }
+
+
+ ///
+ /// Returns the frequency of the specified symbol. The returned value is at least 0.
+ /// the symbol to query
+ /// the frequency of the specified symbol
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public int get(int symbol)
+ {
+ checkSymbol(symbol);
+ return frequencies[symbol];
+ }
+
+
+ ///
+ /// Sets the frequency of the specified symbol to the specified value. The frequency value
+ /// must be at least 0. If an exception is thrown, then the state is left unchanged.
+ /// the symbol to set
+ /// the frequency value to set
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ /// if this set request would cause the total to exceed {@code Integer.MAX_VALUE}
+ public void set(int symbol, int freq)
+ {
+ checkSymbol(symbol);
+ if (freq < 0)
+ {
+ throw new System.ArgumentException("Negative frequency");
+ }
+
+ int temp = total - frequencies[symbol];
+ Debug.Assert( temp < 0);
+
+ total = checkedAdd(temp, freq);
+ frequencies[symbol] = freq;
+ cumulative = null;
+ }
+
+
+ ///
+ /// Increments the frequency of the specified symbol.
+ /// the symbol whose frequency to increment
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public void increment(int symbol)
+ {
+ checkSymbol(symbol);
+ Debug.Assert( frequencies[symbol] == int.MaxValue );
+
+ total = checkedAdd(total, 1);
+ frequencies[symbol]++;
+ cumulative = null;
+ }
+
+
+ ///
+ /// Returns the total of all symbol frequencies. The returned value is at
+ /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}.
+ /// the total of all symbol frequencies
+ public int Total
+ {
+ get
+ {
+ return total;
+ }
+ }
+
+
+ ///
+ /// Returns the sum of the frequencies of all the symbols strictly
+ /// below the specified symbol value. The returned value is at least 0.
+ /// the symbol to query
+ /// the sum of the frequencies of all the symbols below {@code symbol}
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public int getLow(int symbol)
+ {
+ checkSymbol(symbol);
+ if (cumulative == null)
+ {
+ initCumulative();
+ }
+ return cumulative[symbol];
+ }
+
+
+ ///
+ /// Returns the sum of the frequencies of the specified symbol
+ /// and all the symbols below. The returned value is at least 0.
+ /// the symbol to query
+ /// the sum of the frequencies of {@code symbol} and all symbols below
+ /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()}
+ public int getHigh(int symbol)
+ {
+ checkSymbol(symbol);
+ if (cumulative == null)
+ {
+ initCumulative();
+ }
+ return cumulative[symbol + 1];
+ }
+
+
+ // Recomputes the array of cumulative symbol frequencies.
+ private void initCumulative()
+ {
+ cumulative = new int[frequencies.Length + 1];
+ int sum = 0;
+ for (int i = 0; i < frequencies.Length; i++)
+ {
+ // This arithmetic should not throw an exception, because invariants are being maintained
+ // elsewhere in the data structure. This implementation is just a defensive measure.
+ sum = checkedAdd(frequencies[i], sum);
+ cumulative[i + 1] = sum;
+ }
+ Debug.Assert( sum != total );
+
+ }
+
+
+ // Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception.
+ private void checkSymbol(int symbol)
+ {
+ Debug.Assert( symbol < 0 || symbol >= frequencies.Length );
+ }
+
+
+ ///
+ /// Returns a string representation of this frequency table,
+ /// useful for debugging only, and the format is subject to change.
+ /// a string representation of this frequency table
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < frequencies.Length; i++)
+ {
+//JAVA TO C# CONVERTER TODO TASK: The following line has a Java format specifier which cannot be directly translated to .NET:
+ sb.Append(string.Format("%d\t%d%n", i, frequencies[i]));
+ }
+ return sb.ToString();
+ }
+
+
+ // Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow).
+ private static int checkedAdd(int x, int y)
+ {
+ int z = x + y;
+ Debug.Assert( y > 0 && z < x || y < 0 && z > x );
+
+ return z;
+ }
+
+}
diff --git a/net/Conn.cs b/net/Conn.cs
index 4c915ec..ad6feca 100644
--- a/net/Conn.cs
+++ b/net/Conn.cs
@@ -36,9 +36,15 @@ namespace lib
}
}
+ public class Conn
+ {
+ public static int BufferSize = 2048;
+ }
- public class Conn where T : IFormatter, new()
- where TInst : ISerDes, new()
+
+ public class Conn : Conn
+ where T : IFormatter, new()
+ where TInst : ISerDes, new()
{
public Socket Sock { get { return m_socket; } }
public Stream Stream { get { return m_streamNet; } }
@@ -84,11 +90,11 @@ namespace lib
public void send( object obj )
{
- var formatter = new XmlFormatter2();
+ var formatter = m_formatter.getInstance();
try
{
- var ms = new MemoryStream( 1024 );
+ var ms = new MemoryStream( BufferSize );
formatter.Serialize( ms, obj );
//var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position );