content: package com.taobao.tddl.dbsync.binlog;
  
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.math.BigDecimal;
  import java.math.BigInteger;
  import java.nio.charset.Charset;
  import java.nio.charset.StandardCharsets;
  import java.util.Arrays;
  import java.util.BitSet;
  
  import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;
  import org.apache.commons.io.IOUtils;
  
  /**
   * TODO: Document Me!!
   * 
   * @author <a href="mailto:changyuan.lh@taobao.com">Changyuan.lh</a>
   * @version 1.0
   */
  public class LogBuffer {
  
      static final BigDecimal DECIMAL_ZERO_1_SCALE = BigDecimal.valueOf(0, 1);
      static final BigDecimal DECIMAL_ONE_1_SCALE = BigDecimal.valueOf(10, 1);
      protected byte[] buffer;
  
      protected int    origin, limit;
      protected int    position;
      protected int    semival;
  
      protected LogBuffer(){
      }
  
      public LogBuffer(byte[] buffer, final int origin, final int limit){
          if (origin + limit > buffer.length) {
              throw new IllegalArgumentException("capacity excceed: " + (origin + limit));
          }
  
          this.buffer = buffer;
          this.origin = origin;
          this.position = origin;
          this.limit = limit;
      }
  
      /**
       * Return n bytes in this buffer.
       */
      public final LogBuffer duplicate(final int pos, final int len) {
          if (pos + len > limit) {
              throw new IllegalArgumentException("limit excceed: " + (pos + len));
          }
  
          // XXX: Do momery copy avoid buffer modified.
          final int off = origin + pos;
          byte[] buf = Arrays.copyOfRange(buffer, off, off + len);
          return new LogBuffer(buf, 0, len);
      }
  
      /**
       * Return next n bytes in this buffer.
       */
      public final LogBuffer duplicate(final int len) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          // XXX: Do momery copy avoid buffer modified.
          final int end = position + len;
          byte[] buf = Arrays.copyOfRange(buffer, position, end);
          LogBuffer dupBuffer = new LogBuffer(buf, 0, len);
          position = end;
          return dupBuffer;
      }
  
      /**
       * Return next n bytes in this buffer.
       */
      public final LogBuffer duplicate() {
          // XXX: Do momery copy avoid buffer modified.
          byte[] buf = Arrays.copyOfRange(buffer, origin, origin + limit);
          return new LogBuffer(buf, 0, limit);
      }
  
      /**
       * Returns this buffer's capacity. </p>
       * 
       * @return The capacity of this buffer
       */
      public final int capacity() {
          return buffer.length;
      }
  
      /**
       * Returns this buffer's position. </p>
       * 
       * @return The position of this buffer
       */
      public final int position() {
          return position - origin;
      }
  
      /**
       * Sets this buffer's position. If the mark is defined and larger than the
       * new position then it is discarded. </p>
       * 
       * @param newPosition The new position value; must be non-negative and no
       * larger than the current limit
       * @return This buffer
       * @throws IllegalArgumentException If the preconditions on
       * <tt>newPosition</tt> do not hold
       */
      public final LogBuffer position(final int newPosition) {
          if (newPosition > limit || newPosition < 0) {
              throw new IllegalArgumentException("limit excceed: " + newPosition);
          }
  
          this.position = origin + newPosition;
          return this;
      }
  
      /**
       * Forwards this buffer's position.
       * 
       * @param len The forward distance
       * @return This buffer
       */
      public final LogBuffer forward(final int len) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          this.position += len;
          return this;
      }
  
      /**
       * Consume this buffer, moving origin and position.
       * 
       * @param len The consume distance
       * @return This buffer
       */
      public final LogBuffer consume(final int len) {
          if (limit > len) {
              limit -= len;
              origin += len;
              position = origin;
              return this;
          } else if (limit == len) {
              limit = 0;
              origin = 0;
              position = 0;
              return this;
          } else {
              /* Should not happen. */
              throw new IllegalArgumentException("limit excceed: " + len);
          }
      }
  
      /**
       * Rewinds this buffer. The position is set to zero.
       * 
       * @return This buffer
       */
      public final LogBuffer rewind() {
          position = origin;
          return this;
      }
  
      /**
       * Returns this buffer's limit. </p>
       * 
       * @return The limit of this buffer
       */
      public final int limit() {
          return limit;
      }
  
      /**
       * Sets this buffer's limit. If the position is larger than the new limit
       * then it is set to the new limit. If the mark is defined and larger than
       * the new limit then it is discarded. </p>
       * 
       * @param newLimit The new limit value; must be non-negative and no larger
       * than this buffer's capacity
       * @return This buffer
       * @throws IllegalArgumentException If the preconditions on
       * <tt>newLimit</tt> do not hold
       */
      public final LogBuffer limit(int newLimit) {
          if (origin + newLimit > buffer.length || newLimit < 0) {
              throw new IllegalArgumentException("capacity excceed: " + (origin + newLimit));
          }
  
          limit = newLimit;
          return this;
      }
  
      /**
       * Returns the number of elements between the current position and the
       * limit. </p>
       * 
       * @return The number of elements remaining in this buffer
       */
      public final int remaining() {
          return limit + origin - position;
      }
  
      /**
       * Tells whether there are any elements between the current position and the
       * limit. </p>
       * 
       * @return <tt>true</tt> if, and only if, there is at least one element
       * remaining in this buffer
       */
      public final boolean hasRemaining() {
          return position < limit + origin;
      }
  
      /**
       * Return 8-bit signed int from buffer.
       */
      public final int getInt8(final int pos) {
          if (pos >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + pos);
          }
  
          return buffer[origin + pos];
      }
  
      /**
       * Return next 8-bit signed int from buffer.
       */
      public final int getInt8() {
          if (position >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin));
          }
  
          return buffer[position++];
      }
  
      /**
       * Return 8-bit unsigned int from buffer.
       */
      public final int getUint8(final int pos) {
          if (pos >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + pos);
          }
  
          return 0xff & buffer[origin + pos];
      }
  
      /**
       * Return next 8-bit unsigned int from buffer.
       */
      public final int getUint8() {
          if (position >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin));
          }
  
          return 0xff & buffer[position++];
      }
  
      /**
       * Return 16-bit signed int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint2korr
       */
      public final int getInt16(final int pos) {
          final int position = origin + pos;
  
          if (pos + 1 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position]) | ((buf[position + 1]) << 8);
      }
  
      /**
       * Return next 16-bit signed int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint2korr
       */
      public final int getInt16() {
          if (position + 1 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position++]) | ((buf[position++]) << 8);
      }
  
      /**
       * Return 16-bit unsigned int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint2korr
       */
      public final int getUint16(final int pos) {
          final int position = origin + pos;
  
          if (pos + 1 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8);
      }
  
      /**
       * Return next 16-bit unsigned int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint2korr
       */
      public final int getUint16() {
          if (position + 1 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8);
      }
  
      /**
       * Return 16-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint2korr
       */
      public final int getBeInt16(final int pos) {
          final int position = origin + pos;
          if (pos + 1 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position + 1]) | ((buf[position]) << 8);
      }
  
      /**
       * Return next 16-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - mi_sint2korr
       */
      public final int getBeInt16() {
          if (position + 1 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
          }
  
          byte[] buf = buffer;
          return (buf[position++] << 8) | (0xff & buf[position++]);
      }
  
      /**
       * Return 16-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint2korr
       */
      public final int getBeUint16(final int pos) {
          final int position = origin + pos;
          if (pos + 1 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 1)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position + 1]) | ((0xff & buf[position]) << 8);
      }
  
      /**
       * Return next 16-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint2korr
       */
      public final int getBeUint16() {
          if (position + 1 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 1));
          }
  
          byte[] buf = buffer;
          return ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);
      }
  
      /**
       * Return 24-bit signed int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint3korr
       */
      public final int getInt24(final int pos) {
          final int position = origin + pos;
  
          if (pos + 2 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((buf[position + 2]) << 16);
      }
  
      /**
       * Return next 24-bit signed int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint3korr
       */
      public final int getInt24() {
          if (position + 2 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((buf[position++]) << 16);
      }
  
      /**
       * Return 24-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr
       */
      public final int getBeInt24(final int pos) {
          final int position = origin + pos;
  
          if (pos + 2 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position + 2]) | ((0xff & buf[position + 1]) << 8) | ((buf[position]) << 16);
      }
  
      /**
       * Return next 24-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr
       */
      public final int getBeInt24() {
          if (position + 2 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
          }
  
          byte[] buf = buffer;
          return ((buf[position++]) << 16) | ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);
      }
  
      /**
       * Return 24-bit unsigned int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint3korr
       */
      public final int getUint24(final int pos) {
          final int position = origin + pos;
  
          if (pos + 2 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position + 2]) << 16);
      }
  
      /**
       * Return next 24-bit unsigned int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint3korr
       */
      public final int getUint24() {
          if (position + 2 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((0xff & buf[position++]) << 16);
      }
  
      /**
       * Return 24-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr
       */
      public final int getBeUint24(final int pos) {
          final int position = origin + pos;
  
          if (pos + 2 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 2)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position + 2]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position]) << 16);
      }
  
      /**
       * Return next 24-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint3korr
       */
      public final int getBeUint24() {
          if (position + 2 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 2));
          }
  
          byte[] buf = buffer;
          return ((0xff & buf[position++]) << 16) | ((0xff & buf[position++]) << 8) | (0xff & buf[position++]);
      }
  
      /**
       * Return 32-bit signed int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint4korr
       */
      public final int getInt32(final int pos) {
          final int position = origin + pos;
  
          if (pos + 3 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position]) | ((0xff & buf[position + 1]) << 8) | ((0xff & buf[position + 2]) << 16)
                 | ((buf[position + 3]) << 24);
      }
  
      /**
       * Return 32-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint4korr
       */
      public final int getBeInt32(final int pos) {
          final int position = origin + pos;
  
          if (pos + 3 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position + 3]) | ((0xff & buf[position + 2]) << 8) | ((0xff & buf[position + 1]) << 16)
                 | ((buf[position]) << 24);
      }
  
      /**
       * Return next 32-bit signed int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint4korr
       */
      public final int getInt32() {
          if (position + 3 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
          }
  
          byte[] buf = buffer;
          return (0xff & buf[position++]) | ((0xff & buf[position++]) << 8) | ((0xff & buf[position++]) << 16)
                 | ((buf[position++]) << 24);
      }
  
      /**
       * Return next 32-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint4korr
       */
      public final int getBeInt32() {
          if (position + 3 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
          }
  
          byte[] buf = buffer;
          return ((buf[position++]) << 24) | ((0xff & buf[position++]) << 16) | ((0xff & buf[position++]) << 8)
                 | (0xff & buf[position++]);
      }
  
      /**
       * Return 32-bit unsigned int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint4korr
       */
      public final long getUint32(final int pos) {
          final int position = origin + pos;
  
          if (pos + 3 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24);
      }
  
      /**
       * Return 32-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_usint4korr
       */
      public final long getBeUint32(final int pos) {
          final int position = origin + pos;
  
          if (pos + 3 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 3)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position + 3])) | ((long) (0xff & buf[position + 2]) << 8)
                 | ((long) (0xff & buf[position + 1]) << 16) | ((long) (0xff & buf[position]) << 24);
      }
  
      /**
       * Return next 32-bit unsigned int from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint4korr
       */
      public final long getUint32() {
          if (position + 3 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24);
      }
  
      /**
       * Return next 32-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint4korr
       */
      public final long getBeUint32() {
          if (position + 3 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 3));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)
                 | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));
      }
  
      /**
       * Return 40-bit unsigned int from buffer. (little-endian)
       */
      public final long getUlong40(final int pos) {
          final int position = origin + pos;
  
          if (pos + 4 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 4)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)
                 | ((long) (0xff & buf[position + 4]) << 32);
      }
  
      /**
       * Return next 40-bit unsigned int from buffer. (little-endian)
       */
      public final long getUlong40() {
          if (position + 4 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 4));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 32);
      }
  
      /**
       * Return 40-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint5korr
       */
      public final long getBeUlong40(final int pos) {
          final int position = origin + pos;
  
          if (pos + 4 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 4)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position + 4])) | ((long) (0xff & buf[position + 3]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 1]) << 24)
                 | ((long) (0xff & buf[position]) << 32);
      }
  
      /**
       * Return next 40-bit unsigned int from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint5korr
       */
      public final long getBeUlong40() {
          if (position + 4 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 4));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]));
      }
  
      /**
       * Return 48-bit signed long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint6korr
       */
      public final long getLong48(final int pos) {
          final int position = origin + pos;
  
          if (pos + 5 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)
                 | ((long) (0xff & buf[position + 4]) << 32) | ((long) (buf[position + 5]) << 40);
      }
  
      /**
       * Return 48-bit signed long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint6korr
       */
      public final long getBeLong48(final int pos) {
          final int position = origin + pos;
  
          if (pos + 5 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position + 5])) | ((long) (0xff & buf[position + 4]) << 8)
                 | ((long) (0xff & buf[position + 3]) << 16) | ((long) (0xff & buf[position + 2]) << 24)
                 | ((long) (0xff & buf[position + 1]) << 32) | ((long) (buf[position]) << 40);
      }
  
      /**
       * Return next 48-bit signed long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint6korr
       */
      public final long getLong48() {
          if (position + 5 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 32) | ((long) (buf[position++]) << 40);
      }
  
      /**
       * Return next 48-bit signed long from buffer. (Big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint6korr
       */
      public final long getBeLong48() {
          if (position + 5 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
          }
  
          byte[] buf = buffer;
          return ((long) (buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)
                 | ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)
                 | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));
      }
  
      /**
       * Return 48-bit unsigned long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint6korr
       */
      public final long getUlong48(final int pos) {
          final int position = origin + pos;
  
          if (pos + 5 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)
                 | ((long) (0xff & buf[position + 4]) << 32) | ((long) (0xff & buf[position + 5]) << 40);
      }
  
      /**
       * Return 48-bit unsigned long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint6korr
       */
      public final long getBeUlong48(final int pos) {
          final int position = origin + pos;
  
          if (pos + 5 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 5)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position + 5])) | ((long) (0xff & buf[position + 4]) << 8)
                 | ((long) (0xff & buf[position + 3]) << 16) | ((long) (0xff & buf[position + 2]) << 24)
                 | ((long) (0xff & buf[position + 1]) << 32) | ((long) (0xff & buf[position]) << 40);
      }
  
      /**
       * Return next 48-bit unsigned long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint6korr
       */
      public final long getUlong48() {
          if (position + 5 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 40);
      }
  
      /**
       * Return next 48-bit unsigned long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint6korr
       */
      public final long getBeUlong48() {
          if (position + 5 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 5));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)
                 | ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)
                 | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));
      }
  
      /**
       * Return 56-bit unsigned int from buffer. (little-endian)
       */
      public final long getUlong56(final int pos) {
          final int position = origin + pos;
  
          if (pos + 6 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 6)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)
                 | ((long) (0xff & buf[position + 4]) << 32) | ((long) (0xff & buf[position + 5]) << 40)
                 | ((long) (0xff & buf[position + 6]) << 48);
      }
  
      /**
       * Return next 56-bit unsigned int from buffer. (little-endian)
       */
      public final long getUlong56() {
          if (position + 6 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 6));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 40)
                 | ((long) (0xff & buf[position++]) << 48);
      }
  
      /**
       * Return 56-bit unsigned int from buffer. (big-endian)
       */
      public final long getBeUlong56(final int pos) {
          final int position = origin + pos;
  
          if (pos + 6 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 6)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position + 6])) | ((long) (0xff & buf[position + 5]) << 8)
                 | ((long) (0xff & buf[position + 4]) << 16) | ((long) (0xff & buf[position + 3]) << 24)
                 | ((long) (0xff & buf[position + 2]) << 32) | ((long) (0xff & buf[position + 1]) << 40)
                 | ((long) (0xff & buf[position]) << 48);
      }
  
      /**
       * Return next 56-bit unsigned int from buffer. (big-endian)
       */
      public final long getBeUlong56() {
          if (position + 6 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 6));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++]) << 48) | ((long) (0xff & buf[position++]) << 40)
                 | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]));
      }
  
      /**
       * Return 64-bit signed long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint8korr
       */
      public final long getLong64(final int pos) {
          final int position = origin + pos;
  
          if (pos + 7 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 7)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position])) | ((long) (0xff & buf[position + 1]) << 8)
                 | ((long) (0xff & buf[position + 2]) << 16) | ((long) (0xff & buf[position + 3]) << 24)
                 | ((long) (0xff & buf[position + 4]) << 32) | ((long) (0xff & buf[position + 5]) << 40)
                 | ((long) (0xff & buf[position + 6]) << 48) | ((long) (buf[position + 7]) << 56);
      }
  
      /**
       * Return 64-bit signed long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint8korr
       */
      public final long getBeLong64(final int pos) {
          final int position = origin + pos;
  
          if (pos + 7 >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + 7)));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position + 7])) | ((long) (0xff & buf[position + 6]) << 8)
                 | ((long) (0xff & buf[position + 5]) << 16) | ((long) (0xff & buf[position + 4]) << 24)
                 | ((long) (0xff & buf[position + 3]) << 32) | ((long) (0xff & buf[position + 2]) << 40)
                 | ((long) (0xff & buf[position + 1]) << 48) | ((long) (buf[position]) << 56);
      }
  
      /**
       * Return next 64-bit signed long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - sint8korr
       */
      public final long getLong64() {
          if (position + 7 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 7));
          }
  
          byte[] buf = buffer;
          return ((long) (0xff & buf[position++])) | ((long) (0xff & buf[position++]) << 8)
                 | ((long) (0xff & buf[position++]) << 16) | ((long) (0xff & buf[position++]) << 24)
                 | ((long) (0xff & buf[position++]) << 32) | ((long) (0xff & buf[position++]) << 40)
                 | ((long) (0xff & buf[position++]) << 48) | ((long) (buf[position++]) << 56);
      }
  
      /**
       * Return next 64-bit signed long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_sint8korr
       */
      public final long getBeLong64() {
          if (position + 7 >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position - origin + 7));
          }
  
          byte[] buf = buffer;
          return ((long) (buf[position++]) << 56) | ((long) (0xff & buf[position++]) << 48)
                 | ((long) (0xff & buf[position++]) << 40) | ((long) (0xff & buf[position++]) << 32)
                 | ((long) (0xff & buf[position++]) << 24) | ((long) (0xff & buf[position++]) << 16)
                 | ((long) (0xff & buf[position++]) << 8) | ((long) (0xff & buf[position++]));
      }
  
      /* The max ulonglong - 0x ff ff ff ff ff ff ff ff */
      public static final BigInteger BIGINT_MAX_VALUE = new BigInteger("18446744073709551615");
  
      /**
       * Return 64-bit unsigned long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint8korr
       */
      public final BigInteger getUlong64(final int pos) {
          final long long64 = getLong64(pos);
  
          return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
      }
  
      /**
       * Return 64-bit unsigned long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint8korr
       */
      public final BigInteger getBeUlong64(final int pos) {
          final long long64 = getBeLong64(pos);
  
          return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
      }
  
      /**
       * Return next 64-bit unsigned long from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - uint8korr
       */
      public final BigInteger getUlong64() {
          final long long64 = getLong64();
  
          return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
      }
  
      /**
       * Return next 64-bit unsigned long from buffer. (big-endian)
       * 
       * @see mysql-5.6.10/include/myisampack.h - mi_uint8korr
       */
      public final BigInteger getBeUlong64() {
          final long long64 = getBeLong64();
  
          return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
      }
  
      /**
       * Return 32-bit float from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - float4get
       */
      public final float getFloat32(final int pos) {
          return Float.intBitsToFloat(getInt32(pos));
      }
  
      /**
       * Return next 32-bit float from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - float4get
       */
      public final float getFloat32() {
          return Float.intBitsToFloat(getInt32());
      }
  
      /**
       * Return 64-bit double from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - float8get
       */
      public final double getDouble64(final int pos) {
          return Double.longBitsToDouble(getLong64(pos));
      }
  
      /**
       * Return next 64-bit double from buffer. (little-endian)
       * 
       * @see mysql-5.1.60/include/my_global.h - float8get
       */
      public final double getDouble64() {
          return Double.longBitsToDouble(getLong64());
      }
  
      public static final long NULL_LENGTH = ((long) ~0);
  
      /**
       * Return packed number from buffer. (little-endian) A Packed Integer has
       * the capacity of storing up to 8-byte integers, while small integers still
       * can use 1, 3, or 4 bytes. The value of the first byte determines how to
       * read the number, according to the following table.
       * <ul>
       * <li>0-250 The first byte is the number (in the range 0-250). No
       * additional bytes are used.</li>
       * <li>252 Two more bytes are used. The number is in the range 251-0xffff.</li>
       * <li>253 Three more bytes are used. The number is in the range
       * 0xffff-0xffffff.</li>
       * <li>254 Eight more bytes are used. The number is in the range
       * 0xffffff-0xffffffffffffffff.</li>
       * </ul>
       * That representation allows a first byte value of 251 to represent the SQL
       * NULL value.
       */
      public final long getPackedLong(final int pos) {
          final int lead = getUint8(pos);
          if (lead < 251) return lead;
  
          switch (lead) {
              case 251:
                  return NULL_LENGTH;
              case 252:
                  return getUint16(pos + 1);
              case 253:
                  return getUint24(pos + 1);
              default: /* Must be 254 when here */
                  return getUint32(pos + 1);
          }
      }
  
      /**
       * Return next packed number from buffer. (little-endian)
       * 
       * @see LogBuffer#getPackedLong(int)
       */
      public final long getPackedLong() {
          final int lead = getUint8();
          if (lead < 251) return lead;
  
          switch (lead) {
              case 251:
                  return NULL_LENGTH;
              case 252:
                  return getUint16();
              case 253:
                  return getUint24();
              default: /* Must be 254 when here */
                  final long value = getUint32();
                  position += 4; /* ignore other */
                  return value;
          }
      }
  
      /**
       * Return fix length string from buffer.
       */
      public final String getFixString(final int pos, final int len) {
          return getFixString(pos, len, StandardCharsets.ISO_8859_1);
      }
  
      /**
       * Return next fix length string from buffer.
       */
      public final String getFixString(final int len) {
          return getFixString(len, StandardCharsets.ISO_8859_1);
      }
  
      /**
       * Return fix length string from buffer.
       */
      public final String getFixString(final int pos, final int len, Charset charset) {
          if (pos + len > limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + len)));
          }
  
          final int from = origin + pos;
          final int end = from + len;
          byte[] buf = buffer;
          int found = from;
          for (; (found < end) && buf[found] != '\0'; found++)
              /* empty loop */;
  
          return new String(buf, from, found - from, charset);
      }
  
      /**
       * Return next fix length string from buffer.
       */
      public final String getFixString(final int len, Charset charset) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          final int from = position;
          final int end = from + len;
          byte[] buf = buffer;
          int found = from;
          for (; (found < end) && buf[found] != '\0'; found++)
              /* empty loop */;
  
          String string = new String(buf, from, found - from, charset);
          position += len;
          return string;
      }
  
      /**
       * Return next fix length string from buffer.
       * see json_binary.cc read_variable_length
       */
      public final String getFixLengthString(final int len, Charset charset) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          final int from = position;
          byte[] buf = buffer;
  
          String string = new String(buf, from, len, charset);
          position += len;
          return string;
      }
  
      public final String getFixName(final int len, Charset charset) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          final int from = position;
          final int end = from + len;
          byte[] buf = buffer;
          int found = from;
          for (; (found < end) && buf[found] != '\0'; found++)
              /* empty loop */;
  
          int length = found - from;
          String string = null;
          if (length <= 16) {
              string = NameCache.name(buf, from, length, charset);
          }
          if (string == null) {
              string = new String(buf, from, length, charset);
          }
          position += len;
          return string;
      }
  
      public final String getFixName(final int len) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          final int from = position;
          final int end = from + len;
          byte[] buf = buffer;
          int found = from;
          for (; (found < end) && buf[found] != '\0'; found++)
              /* empty loop */;
  
          int length = found - from;
          String string = null;
          if (length <= 16) {
              string = NameCache.name(buf, from, length, StandardCharsets.ISO_8859_1);
          }
          if (string == null) {
              string = new String(buf, from, length, StandardCharsets.ISO_8859_1);
          }
          position += len;
          return string;
      }
  
      /**
       * Return fix-length string from buffer without null-terminate checking.
       * Fix bug #17 {@link https://github.com/AlibabaTech/canal/issues/17 }
       */
      public final String getFullString(final int pos, final int len, Charset charset) {
          if (pos + len > limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + len)));
          }
  
          return new String(buffer, origin + pos, len, charset);
      }
  
      /**
       * Return next fix-length string from buffer without null-terminate
       * checking.
       * Fix bug #17 {@link https://github.com/AlibabaTech/canal/issues/17 }
       */
      public final String getFullString(final int len, Charset charset) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          String string = new String(buffer, position, len, charset);
          position += len;
          return string;
      }
  
  
      /**
       * Return dynamic length string from buffer.
       */
      public final String getString(final int pos) {
          if (pos >= limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + pos);
          }
  
          byte[] buf = buffer;
          final int len = (0xff & buf[origin + pos]);
          if (pos + len + 1 > limit) {
              throw new IllegalArgumentException("limit excceed: " + (pos + len + 1));
          }
  
          return new String(buf, origin + pos + 1, len, StandardCharsets.ISO_8859_1);
      }
  
      /**
       * Return next dynamic length string from buffer.
       */
      public final String getString() {
          if (position >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + position);
          }
  
          byte[] buf = buffer;
          final int len = (0xff & buf[position]);
          if (position + len + 1 > origin + limit) {
              throw new IllegalArgumentException("limit excceed: "
                                                 + (position + len + 1 - origin));
          }
  
          String string = new String(buf, position + 1, len, StandardCharsets.ISO_8859_1);
          position += len + 1;
          return string;
      }
  
      public final String getName() {
          if (position >= origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + position);
          }
  
          byte[] buf = buffer;
          final int len = (0xff & buf[position]);
          if (position + len + 1 > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len + 1 - origin));
          }
  
          String string = NameCache.name(buf, position + 1, len, StandardCharsets.ISO_8859_1);
          if (string == null) {
              string = new String(buf, position + 1, len, StandardCharsets.ISO_8859_1);
          }
          position += len + 1;
          return string;
      }
  
      /**
       * Return 16-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.1.60/include/myisampack.h - mi_sint2korr
       */
      private static final int getInt16BE(byte[] buffer, final int pos) {
          return ((buffer[pos]) << 8) | (0xff & buffer[pos + 1]);
      }
  
      /**
       * Return 24-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.1.60/include/myisampack.h - mi_sint3korr
       */
      private static final int getInt24BE(byte[] buffer, final int pos) {
          return (buffer[pos] << 16) | ((0xff & buffer[pos + 1]) << 8) | (0xff & buffer[pos + 2]);
      }
  
      /**
       * Return 32-bit signed int from buffer. (big-endian)
       * 
       * @see mysql-5.1.60/include/myisampack.h - mi_sint4korr
       */
      private static final int getInt32BE(byte[] buffer, final int pos) {
          return (buffer[pos] << 24) | ((0xff & buffer[pos + 1]) << 16) | ((0xff & buffer[pos + 2]) << 8)
                 | (0xff & buffer[pos + 3]);
      }
  
      /* decimal representation */
      public static final int DIG_PER_DEC1  = 9;
      public static final int DIG_BASE      = 1000000000;
      public static final int DIG_MAX       = DIG_BASE - 1;
      public static final int dig2bytes[]   = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4 };
      public static final int powers10[]    = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
  
      public static final int DIG_PER_INT32 = 9;
      public static final int SIZE_OF_INT32 = 4;
  
      /**
       * Return big decimal from buffer.
       * 
       * @see mysql-5.1.60/strings/decimal.c - bin2decimal()
       */
      public final BigDecimal getDecimal(final int pos, final int precision, final int scale) {
          final int intg = precision - scale;
          final int frac = scale;
          final int intg0 = intg / DIG_PER_INT32;
          final int frac0 = frac / DIG_PER_INT32;
          final int intg0x = intg - intg0 * DIG_PER_INT32;
          final int frac0x = frac - frac0 * DIG_PER_INT32;
  
          final int binSize = intg0 * SIZE_OF_INT32 + dig2bytes[intg0x] + frac0 * SIZE_OF_INT32 + dig2bytes[frac0x];
          if (pos + binSize > limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos < 0 ? pos : (pos + binSize)));
          }
          return getDecimal0(origin + pos, intg, frac, // NL
              intg0,
              frac0,
              intg0x,
              frac0x);
      }
  
      /**
       * Return next big decimal from buffer.
       * 
       * @see mysql-5.1.60/strings/decimal.c - bin2decimal()
       */
      public final BigDecimal getDecimal(final int precision, final int scale) {
          final int intg = precision - scale;
          final int frac = scale;
          final int intg0 = intg / DIG_PER_INT32;
          final int frac0 = frac / DIG_PER_INT32;
          final int intg0x = intg - intg0 * DIG_PER_INT32;
          final int frac0x = frac - frac0 * DIG_PER_INT32;
  
          final int binSize = intg0 * SIZE_OF_INT32 + dig2bytes[intg0x] + frac0 * SIZE_OF_INT32 + dig2bytes[frac0x];
          if (position + binSize > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + binSize - origin));
          }
  
          BigDecimal decimal = getDecimal0(position, intg, frac, // NL
              intg0,
              frac0,
              intg0x,
              frac0x);
          position += binSize;
          return decimal;
      }
  
      /**
       * Return big decimal from buffer.
       * 
       * <pre>
       * Decimal representation in binlog seems to be as follows:
       * 
       * 1st bit - sign such that set == +, unset == -
       * every 4 bytes represent 9 digits in big-endian order, so that
       * if you print the values of these quads as big-endian integers one after
       * another, you get the whole number string representation in decimal. What
       * remains is to put a sign and a decimal dot.
       * 
       * 80 00 00 05 1b 38 b0 60 00 means:
       * 
       *   0x80 - positive 
       *   0x00000005 - 5
       *   0x1b38b060 - 456700000
       *   0x00       - 0
       * 
       * 54567000000 / 10^{10} = 5.4567
       * </pre>
       * 
       * @see mysql-5.1.60/strings/decimal.c - bin2decimal()
       * @see mysql-5.1.60/strings/decimal.c - decimal2string()
       */
      private final BigDecimal getDecimal0(final int begin, final int intg, final int frac, final int intg0,
                                           final int frac0, final int intg0x, final int frac0x) {
          final int mask = ((buffer[begin] & 0x80) == 0x80) ? 0 : -1;
          int from = begin;
  
          /* max string length */
          final int len = ((mask != 0) ? 1 : 0) + ((intg != 0) ? intg : 1) // NL
                          + ((frac != 0) ? 1 : 0) + frac;
          char[] buf = new char[len];
          int pos = 0;
  
          if (mask != 0) /* decimal sign */
          buf[pos++] = ('-');
  
          final byte[] d_copy = buffer;
          d_copy[begin] ^= 0x80; /* clear sign */
          int mark = pos;
  
          if (intg0x != 0) {
              final int i = dig2bytes[intg0x];
              int x = 0;
              switch (i) {
                  case 1:
                      x = d_copy[from] /* one byte */;
                      break;
                  case 2:
                      x = getInt16BE(d_copy, from);
                      break;
                  case 3:
                      x = getInt24BE(d_copy, from);
                      break;
                  case 4:
                      x = getInt32BE(d_copy, from);
                      break;
              }
              from += i;
              x ^= mask;
              if (x < 0 || x >= powers10[intg0x + 1]) {
                  throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + powers10[intg0x + 1]);
              }
              if (x != 0 /* !digit || x != 0 */) {
                  for (int j = intg0x; j > 0; j--) {
                      final int divisor = powers10[j - 1];
                      final int y = x / divisor;
                      if (mark < pos || y != 0) {
                          buf[pos++] = ((char) ('0' + y));
                      }
                      x -= y * divisor;
                  }
              }
          }
  
          for (final int stop = from + intg0 * SIZE_OF_INT32; from < stop; from += SIZE_OF_INT32) {
              int x = getInt32BE(d_copy, from);
              x ^= mask;
              if (x < 0 || x > DIG_MAX) {
                  throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + DIG_MAX);
              }
              if (x != 0) {
                  if (mark < pos) {
                      for (int i = DIG_PER_DEC1; i > 0; i--) {
                          final int divisor = powers10[i - 1];
                          final int y = x / divisor;
                          buf[pos++] = ((char) ('0' + y));
                          x -= y * divisor;
                      }
                  } else {
                      for (int i = DIG_PER_DEC1; i > 0; i--) {
                          final int divisor = powers10[i - 1];
                          final int y = x / divisor;
                          if (mark < pos || y != 0) {
                              buf[pos++] = ((char) ('0' + y));
                          }
                          x -= y * divisor;
                      }
                  }
              } else if (mark < pos) {
                  for (int i = DIG_PER_DEC1; i > 0; i--)
                      buf[pos++] = ('0');
              }
          }
  
          if (mark == pos)
          /* fix 0.0 problem, only '.' may cause BigDecimal parsing exception. */
          buf[pos++] = ('0');
  
          if (frac > 0) {
              buf[pos++] = ('.');
              mark = pos;
  
              for (final int stop = from + frac0 * SIZE_OF_INT32; from < stop; from += SIZE_OF_INT32) {
                  int x = getInt32BE(d_copy, from);
                  x ^= mask;
                  if (x < 0 || x > DIG_MAX) {
                      throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + DIG_MAX);
                  }
                  if (x != 0) {
                      for (int i = DIG_PER_DEC1; i > 0; i--) {
                          final int divisor = powers10[i - 1];
                          final int y = x / divisor;
                          buf[pos++] = ((char) ('0' + y));
                          x -= y * divisor;
                      }
                  } else {
                      for (int i = DIG_PER_DEC1; i > 0; i--)
                          buf[pos++] = ('0');
                  }
              }
  
              if (frac0x != 0) {
                  final int i = dig2bytes[frac0x];
                  int x = 0;
                  switch (i) {
                      case 1:
                          x = d_copy[from] /* one byte */;
                          break;
                      case 2:
                          x = getInt16BE(d_copy, from);
                          break;
                      case 3:
                          x = getInt24BE(d_copy, from);
                          break;
                      case 4:
                          x = getInt32BE(d_copy, from);
                          break;
                  }
                  x ^= mask;
                  if (x != 0) {
                      final int dig = DIG_PER_DEC1 - frac0x;
                      x *= powers10[dig];
                      if (x < 0 || x > DIG_MAX) {
                          throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + DIG_MAX);
                      }
                      for (int j = DIG_PER_DEC1; j > dig; j--) {
                          final int divisor = powers10[j - 1];
                          final int y = x / divisor;
                          buf[pos++] = ((char) ('0' + y));
                          x -= y * divisor;
                      }
                  }
              }
  
              if (mark == pos)
              /* make number more friendly */
              buf[pos++] = ('0');
          }
  
          d_copy[begin] ^= 0x80; /* restore sign */
          // String decimal = String.valueOf(buf, 0, pos);
          // return new BigDecimal(decimal);
          return new BigDecimal(buf, 0, pos);
      }
  
      /**
       * Fill MY_BITMAP structure from buffer.
       * 
       * @param len The length of MY_BITMAP in bits.
       */
      public final void fillBitmap(BitSet bitmap, final int pos, final int len) {
          if (pos + ((len + 7) / 8) > limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos + (len + 7) / 8));
          }
  
          fillBitmap0(bitmap, origin + pos, len);
      }
  
      /**
       * Fill next MY_BITMAP structure from buffer.
       * 
       * @param len The length of MY_BITMAP in bits.
       */
      public final void fillBitmap(BitSet bitmap, final int len) {
          if (position + ((len + 7) / 8) > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + ((len + 7) / 8) - origin));
          }
  
          position = fillBitmap0(bitmap, position, len);
      }
  
      /**
       * Fill MY_BITMAP structure from buffer.
       * 
       * @param len The length of MY_BITMAP in bits.
       */
      private final int fillBitmap0(BitSet bitmap, int pos, final int len) {
          final byte[] buf = buffer;
  
          for (int bit = 0; bit < len; bit += 8) {
              int flag = ((int) buf[pos++]) & 0xff;
              if (flag == 0) {
                  continue;
              }
              if ((flag & 0x01) != 0) bitmap.set(bit);
              if ((flag & 0x02) != 0) bitmap.set(bit + 1);
              if ((flag & 0x04) != 0) bitmap.set(bit + 2);
              if ((flag & 0x08) != 0) bitmap.set(bit + 3);
              if ((flag & 0x10) != 0) bitmap.set(bit + 4);
              if ((flag & 0x20) != 0) bitmap.set(bit + 5);
              if ((flag & 0x40) != 0) bitmap.set(bit + 6);
              if ((flag & 0x80) != 0) bitmap.set(bit + 7);
          }
          return pos;
      }
  
      /**
       * Return MY_BITMAP structure from buffer.
       * 
       * @param len The length of MY_BITMAP in bits.
       */
      public final BitSet getBitmap(final int pos, final int len) {
          BitSet bitmap = new BitSet(len);
          fillBitmap(bitmap, pos, len);
          return bitmap;
      }
  
      /**
       * Return next MY_BITMAP structure from buffer.
       * 
       * @param len The length of MY_BITMAP in bits.
       */
      public final BitSet getBitmap(final int len) {
          BitSet bitmap = new BitSet(len);
          fillBitmap(bitmap, len);
          return bitmap;
      }
  
      /**
       * Fill n bytes into output stream.
       */
      public final void fillOutput(OutputStream out, final int pos, final int len) throws IOException {
          if (pos + len > limit || pos < 0) throw new IllegalArgumentException("limit excceed: " + (pos + len));
  
          out.write(buffer, origin + pos, len);
      }
  
      /**
       * Fill next n bytes into output stream.
       */
      public final void fillOutput(OutputStream out, final int len) throws IOException {
          if (position + len > origin + limit) throw new IllegalArgumentException("limit excceed: "
                                                                                  + (position + len - origin));
  
          out.write(buffer, position, len);
          position += len;
      }
  
      /**
       * Fill n bytes in this buffer.
       */
      public final void fillBytes(final int pos, byte[] dest, final int destPos, final int len) {
          if (pos + len > limit || pos < 0) {
              throw new IllegalArgumentException("limit excceed: " + (pos + len));
          }
  
          System.arraycopy(buffer, origin + pos, dest, destPos, len);
      }
  
      /**
       * Fill next n bytes in this buffer.
       */
      public final void fillBytes(byte[] dest, final int destPos, final int len) {
          if (position + len > origin + limit) {
              throw new IllegalArgumentException("limit excceed: " + (position + len - origin));
          }
  
          System.arraycopy(buffer, position, dest, destPos, len);
          position += len;
      }
  
      /**
       * Return n-byte data from buffer.
       */
      public final byte[] getData(final int pos, final int len) {
          byte[] buf = new byte[len];
          fillBytes(pos, buf, 0, len);
          return buf;
      }
  
      /**
       * Return next n-byte data from buffer.
       */
      public final byte[] getData(final int len) {
          byte[] buf = new byte[len];
          fillBytes(buf, 0, len);
          return buf;
      }
  
      /**
       * Return all remaining data from buffer.
       */
      public final byte[] getData() {
          return getData(0, limit);
      }
  
      /**
       * mariadb compress log event Get the length of uncompress content.
       * 
       * @return 0 means error.
       */
      public final long getUncompressLong(int lenPad) {
          long len = 0;
          switch (lenPad) {
              case 1:
                  len = getInt8();
                  break;
              case 2:
                  len = getBeUint16();
                  break;
              case 3:
                  len = getBeUint24();
                  break;
              case 4:
                  len = getBeUint32();
                  break;
              default:
                  len = 0;
                  break;
          }
  
          return len;
      }
  
      /**
       * uncompress mariadb log event
       * 
       * @return
       */
      public LogBuffer uncompressBuf() {
          int lenPad = getInt8();
          long len = getUncompressLong(lenPad & 0x07);
          int alg = (lenPad & 0x70) >> 4;
          LogBuffer buffer = null;
          try {
              switch (alg) {
                  case 0:
                      buffer = uncompressZlib(limit - position);
                      break;
                  default:
                      // bad algorithm
                      return this;
              }
          } catch (Exception e) {
              throw new IllegalArgumentException("uncompress failed ", e);
          }
  
          if (buffer.limit() != len) {
              throw new IllegalArgumentException(
                  "uncompress lenght not match, expected : " + len + " , but actual : " + buffer.limit());
          }
          return buffer;
      }
  
      private LogBuffer uncompressZlib(int len) throws Exception {
          if (position + len > limit || position < 0) {
              throw new IllegalArgumentException("limit excceed: " + (position + len));
          }
  
          try (DeflateCompressorInputStream in = new DeflateCompressorInputStream(
              new ByteArrayInputStream(buffer, position, position + len))) {
              byte[] decodeBytes = IOUtils.toByteArray(in);
              return new LogBuffer(decodeBytes, 0, decodeBytes.length);
          }
      }
  
      /**
       * Return full hexdump from position.
       */
      public final String hexdump(final int pos) {
          if ((limit - pos) > 0) {
              final int begin = origin + pos;
              final int end = origin + limit;
  
              byte[] buf = buffer;
              StringBuilder dump = new StringBuilder();
              dump.append(Integer.toHexString(buf[begin] >> 4));
              dump.append(Integer.toHexString(buf[begin] & 0xf));
              for (int i = begin + 1; i < end; i++) {
                  dump.append("_");
                  dump.append(Integer.toHexString(buf[i] >> 4));
                  dump.append(Integer.toHexString(buf[i] & 0xf));
              }
  
              return dump.toString();
          }
          return "";
      }
  
      /**
       * Return hexdump from position, for len bytes.
       */
      public final String hexdump(final int pos, final int len) {
          if ((limit - pos) > 0) {
              final int begin = origin + pos;
              final int end = Math.min(begin + len, origin + limit);
  
              byte[] buf = buffer;
              StringBuilder dump = new StringBuilder();
              dump.append(Integer.toHexString(buf[begin] >> 4));
              dump.append(Integer.toHexString(buf[begin] & 0xf));
              for (int i = begin + 1; i < end; i++) {
                  dump.append("_");
                  dump.append(Integer.toHexString(buf[i] >> 4));
                  dump.append(Integer.toHexString(buf[i] & 0xf));
              }
  
              return dump.toString();
          }
          return "";
      }
  
  }
  