/* * Copyright 2005-2014, martin isenburg, rapidlasso - fast tools to catch reality * * This is free software; you can redistribute and/or modify it under the * terms of the GNU Lesser General Licence as published by the Free Software * Foundation. See the LICENSE.txt file for more information. * * This software is distributed WITHOUT ANY WARRANTY and without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ package com.revolsys.elevation.cloud.las.zip; import static java.lang.Integer.compareUnsigned; import com.revolsys.io.channels.ChannelWriter; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Fast arithmetic coding implementation - // -> 32-bit variables, 32-bit product, periodic updates, table decoding - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Version 1.00 - April 25, 2004 - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // WARNING - // ========= - // - // The only purpose of this program is to demonstrate the basic principles - // of arithmetic coding. It is provided as is, without any express or - // implied warranty, without even the warranty of fitness for any particular - // purpose, or that the implementations are correct. - // - // Permission to copy and redistribute this code is hereby granted, provided - // that this warning and copyright notices are not removed or altered. - // - // Copyright (c) 2004 by Amir Said (said@ieee.org) & - // William A. Pearlman (pearlw@ecse.rpi.edu) - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // A description of the arithmetic coding method used here is available in - // - // Lossless Compression Handbook, ed. K. Sayood - // Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - // - // A. Said, Introduction to Arithetic Coding Theory and Practice - // HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public class ArithmeticEncoder implements ArithmeticConstants { private static final byte ZERO = 0; private ChannelWriter out; private final byte[] outbuffer = new byte[AC_BUFFER_SIZE]; private final int endbuffer = AC_BUFFER_SIZE; private int outbyte; private int endbyte; private int base; private int value; private int length; public ArithmeticEncoder(final ChannelWriter out) { this.out = out; } public ArithmeticBitModel createBitModel() { return new ArithmeticBitModel(); } ArithmeticModel createSymbolModel(final int symbols) { return new ArithmeticModel(symbols, true); } public void done() { final int init_base = this.base; // done encoding: set final data bytes boolean another_byte = true; if (Integer.compareUnsigned(this.length, 2 * AC_MIN_LENGTH) > 0) { this.base += AC_MIN_LENGTH; // base offset this.length = AC_MIN_LENGTH >>> 1; // set new length for 1 more byte } else { this.base += AC_MIN_LENGTH >>> 1; // base offset this.length = AC_MIN_LENGTH >>> 9; // set new length for 2 more bytes another_byte = false; } if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } renorm_enc_interval(); // renormalization = output last bytes /* * TODO doesn't make sense. is this really needed? if (endbyte != endbuffer) { assert(outbyte < * AC_BUFFER_SIZE); outstream.putBytes(outbuffer + AC_BUFFER_SIZE, AC_BUFFER_SIZE); } */ final int buffer_size = this.outbyte; if (buffer_size > 0) { this.out.putBytes(this.outbuffer, buffer_size); } // write two or three zero bytes to be in sync with the decoder's byte reads this.out.putByte(ZERO); this.out.putByte(ZERO); if (another_byte) { this.out.putByte(ZERO); } this.out = null; } void encodeBit(final ArithmeticBitModel m, final int sym) { assert m != null && sym <= 1; final int x = m.bit0Prob * (this.length >>> BM_LENGTH_SHIFT); // product l x p0 // update interval if (sym == 0) { this.length = x; ++m.bit0Count; } else { final int init_base = this.base; this.base += x; this.length -= x; if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } } if (compareUnsigned(this.length, AC_MIN_LENGTH) < 0) { renorm_enc_interval(); // renormalization } m.updateIfRequired(); } void encodeSymbol(final ArithmeticModel m, final int sym) { assert m != null && compareUnsigned(sym, m.lastSymbol) <= 0; int x; final int init_base = this.base; // compute products if (sym == m.lastSymbol) { x = m.distribution[sym] * (this.length >>> DM_LENGTH_SHIFT); this.base += x; // update interval this.length -= x; // no product needed } else { x = m.distribution[sym] * (this.length >>>= DM_LENGTH_SHIFT); this.base += x; // update interval this.length = m.distribution[sym + 1] * this.length - x; } if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } if (compareUnsigned(this.length, AC_MIN_LENGTH) < 0) { renorm_enc_interval(); // renormalization } m.update(sym); } public boolean init() { this.base = 0; this.length = AC_MAX_LENGTH; this.outbyte = 0; this.endbyte = this.endbuffer; return true; } void initBitModel(final ArithmeticBitModel m) { m.init(); } void initSymbolModel(final ArithmeticModel m) { initSymbolModel(m, null); } void initSymbolModel(final ArithmeticModel m, final int[] table) { m.init(table); } private void manage_outbuffer() { if (this.outbyte == this.endbuffer) { this.outbyte = 0; } this.out.putBytes(this.outbuffer, AC_BUFFER_SIZE); this.endbyte = this.outbyte + AC_BUFFER_SIZE; assert this.endbyte > this.outbyte; assert this.outbyte < this.endbuffer; } private void propagate_carry() { int p; if (this.outbyte == 0) { p = this.endbuffer - 1; } else { p = this.outbyte - 1; } while (this.outbuffer[p] == 0xFF) { this.outbuffer[p] = 0; if (p == 0) { p = this.endbuffer - 1; } else { p--; } assert 0 <= p; assert p < this.endbuffer; assert this.outbyte < this.endbuffer; } ++this.outbuffer[p]; } private void renorm_enc_interval() { do { // output and discard top byte assert 0 <= this.outbyte; assert this.outbyte < this.endbuffer; assert this.outbyte < this.endbyte; this.outbuffer[this.outbyte++] = (byte)(this.base >>> 24); if (this.outbyte == this.endbyte) { manage_outbuffer(); } this.base <<= 8; } while (Integer.compareUnsigned(this.length <<= 8, AC_MIN_LENGTH) < 0); // length multiplied // by 256 } void writeBit(final int sym) { assert sym < 2; final int init_base = this.base; this.base += sym * (this.length >>>= 1); // new interval base and length if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } if (compareUnsigned(this.length, AC_MIN_LENGTH) < 0) { renorm_enc_interval(); // renormalization } } void writeBits(int bits, int sym) { assert bits != 0 && bits <= 32 && sym < 1 << bits; if (bits > 19) { writeShort((short)(sym & 0xFFFF)); sym = sym >>> 16; bits = bits - 16; } final int init_base = this.base; this.base += sym * (this.length >>>= bits); // new interval base and length if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } if (compareUnsigned(this.length, AC_MIN_LENGTH) < 0) { renorm_enc_interval(); // renormalization } } void writeByte(final byte sym) { final int init_base = this.base; this.base += sym * (this.length >>>= 8); // new interval base and length if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } if (compareUnsigned(this.length, AC_MIN_LENGTH) < 0) { renorm_enc_interval(); // renormalization } } void writeDouble(final double sym) /* danger in float reinterpretation */ { writeInt64(Double.doubleToLongBits(sym)); } void writeFloat(final float sym) /* danger in float reinterpretation */ { writeInt(Float.floatToIntBits(sym)); } void writeInt(final int sym) { writeShort((short)(sym & 0xFFFF)); // lower 16 bits writeShort((short)(sym >>> 16)); // UPPER 16 bits } void writeInt64(final long sym) { writeInt((int)(sym & 0xFFFFFFFF)); // lower 32 bits writeInt((int)(sym >>> 32)); // UPPER 32 bits } void writeShort(final short sym) { final int init_base = this.base; this.base += sym * (this.length >>>= 16); // new interval base and length if (compareUnsigned(init_base, this.base) > 0) { propagate_carry(); // overflow = carry } if (compareUnsigned(this.length, AC_MIN_LENGTH) < 0) { renorm_enc_interval(); // renormalization } } }