@Override
 public int readFInt() throws IOException {
   ensureReadAhead(5);
   final byte head = readFByte();
   // -128 = short byte, -127 == 4 byte
   if (head > -127 && head <= 127) {
     return head;
   }
   if (head == -128) {
     int count = input.pos;
     final byte buf[] = input.buf;
     int ch1 = (buf[count++] + 256) & 0xff;
     int ch2 = (buf[count++] + 256) & 0xff;
     input.pos = count;
     return (short) ((ch2 << 8) + (ch1 << 0));
   } else {
     int count = input.pos;
     final byte buf[] = input.buf;
     int ch1 = (buf[count++] + 256) & 0xff;
     int ch2 = (buf[count++] + 256) & 0xff;
     int ch3 = (buf[count++] + 256) & 0xff;
     int ch4 = (buf[count++] + 256) & 0xff;
     input.pos = count;
     int res = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
     return res;
   }
 }
 @Override
 public void resetWith(byte[] bytes, int len) {
   clnames.clear();
   input.reset();
   input.count = len;
   input.buf = bytes;
   input.pos = 0;
 }
 @Override
 public void resetToCopyOf(byte[] bytes, int off, int len) {
   input.reset();
   input.ensureCapacity(len);
   input.count = len;
   System.arraycopy(bytes, off, input.buf, 0, len);
   clnames.clear();
 }
 private short readPlainShort() throws IOException {
   input.ensureReadAhead(2);
   int count = input.pos;
   final byte buf[] = input.buf;
   int ch1 = (buf[count++] + 256) & 0xff;
   int ch2 = (buf[count++] + 256) & 0xff;
   input.pos = count;
   return (short) ((ch2 << 8) + (ch1 << 0));
 }
 /**
  * len < 127 !!!!!
  *
  * @return
  * @throws java.io.IOException
  */
 @Override
 public String readStringAsc() throws IOException {
   int len = readFByte();
   if (ascStringCache == null || ascStringCache.length < len) ascStringCache = new byte[len];
   input.ensureReadAhead(len);
   System.arraycopy(input.buf, input.pos, ascStringCache, 0, len);
   input.pos += len;
   return new String(ascStringCache, 0, 0, len);
 }
 @Override
 public int readPlainInt() throws IOException {
   input.ensureReadAhead(4);
   int count = input.pos;
   final byte buf[] = input.buf;
   int ch1 = (buf[count++] + 256) & 0xff;
   int ch2 = (buf[count++] + 256) & 0xff;
   int ch3 = (buf[count++] + 256) & 0xff;
   int ch4 = (buf[count++] + 256) & 0xff;
   input.pos = count;
   int res = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
   return res;
 }
 @Override
 public long readFLong() throws IOException {
   input.ensureReadAhead(9);
   byte head = readFByte();
   // -128 = short byte, -127 == 4 byte
   if (head > -126 && head <= 127) {
     return head;
   }
   if (head == -128) {
     int count = input.pos;
     final byte buf[] = input.buf;
     int ch1 = (buf[count++] + 256) & 0xff;
     int ch2 = (buf[count++] + 256) & 0xff;
     input.pos = count;
     return (short) ((ch2 << 8) + (ch1 << 0));
   } else if (head == -127) {
     int count = input.pos;
     final byte buf[] = input.buf;
     int ch1 = (buf[count++] + 256) & 0xff;
     int ch2 = (buf[count++] + 256) & 0xff;
     int ch3 = (buf[count++] + 256) & 0xff;
     int ch4 = (buf[count++] + 256) & 0xff;
     input.pos = count;
     int res = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
     return res;
   } else {
     ensureReadAhead(8);
     int count = input.pos;
     final byte buf[] = input.buf;
     long ch8 = (buf[count++] + 256) & 0xff;
     long ch7 = (buf[count++] + 256) & 0xff;
     long ch6 = (buf[count++] + 256) & 0xff;
     long ch5 = (buf[count++] + 256) & 0xff;
     long ch4 = (buf[count++] + 256) & 0xff;
     long ch3 = (buf[count++] + 256) & 0xff;
     long ch2 = (buf[count++] + 256) & 0xff;
     long ch1 = (buf[count++] + 256) & 0xff;
     input.pos = count;
     return ((ch1 << 56)
         + (ch2 << 48)
         + (ch3 << 40)
         + (ch4 << 32)
         + (ch5 << 24)
         + (ch6 << 16)
         + (ch7 << 8)
         + (ch8 << 0));
   }
 }
 public void readFLongArr(int len, long[] arr) throws IOException {
   int bytelen = arr.length * 8;
   ensureReadAhead(bytelen);
   int count = input.pos;
   final byte buf[] = input.buf;
   for (int j = 0; j < len; j++) {
     long ch8 = (buf[count++] + 256) & 0xff;
     long ch7 = (buf[count++] + 256) & 0xff;
     long ch6 = (buf[count++] + 256) & 0xff;
     long ch5 = (buf[count++] + 256) & 0xff;
     long ch4 = (buf[count++] + 256) & 0xff;
     long ch3 = (buf[count++] + 256) & 0xff;
     long ch2 = (buf[count++] + 256) & 0xff;
     long ch1 = (buf[count++] + 256) & 0xff;
     arr[j] =
         ((ch1 << 56)
             + (ch2 << 48)
             + (ch3 << 40)
             + (ch4 << 32)
             + (ch5 << 24)
             + (ch6 << 16)
             + (ch7 << 8)
             + (ch8 << 0));
   }
   input.pos += bytelen;
 }
 /**
  * assumes class header+len already read
  *
  * @param componentType
  * @param len
  * @return
  */
 @Override
 public Object readFPrimitiveArray(Object array, Class componentType, int len) {
   try {
     if (componentType == byte.class) {
       byte[] arr = (byte[]) array;
       ensureReadAhead(arr.length); // fixme: move this stuff to the stream !
       System.arraycopy(input.buf, input.pos, arr, 0, len);
       input.pos += len;
       return arr;
     } else if (componentType == char.class) {
       char[] arr = (char[]) array;
       for (int j = 0; j < len; j++) {
         arr[j] = readFChar();
       }
       return arr;
     } else if (componentType == short.class) {
       short[] arr = (short[]) array;
       ensureReadAhead(arr.length * 2);
       for (int j = 0; j < len; j++) {
         arr[j] = readFShort();
       }
       return arr;
     } else if (componentType == int.class) {
       final int[] arr = (int[]) array;
       readFIntArr(len, arr);
       return arr;
     } else if (componentType == float.class) {
       float[] arr = (float[]) array;
       ensureReadAhead(arr.length * 4);
       for (int j = 0; j < len; j++) {
         arr[j] = readFFloat();
       }
       return arr;
     } else if (componentType == double.class) {
       double[] arr = (double[]) array;
       ensureReadAhead(arr.length * 8);
       for (int j = 0; j < len; j++) {
         arr[j] = readFDouble();
       }
       return arr;
     } else if (componentType == long.class) {
       long[] arr = (long[]) array;
       readFLongArr(len, arr);
       return arr;
     } else if (componentType == boolean.class) {
       boolean[] arr = (boolean[]) array;
       ensureReadAhead(arr.length);
       for (int j = 0; j < len; j++) {
         arr[j] = readFByte() == 0 ? false : true;
       }
       return arr;
     } else {
       throw new RuntimeException("unexpected primitive type " + componentType.getName());
     }
   } catch (IOException e) {
     throw FSTUtil.rethrow(
         e); // To change body of catch statement use File | Settings | File Templates.
   }
 }
 @Override
 public short readFShort() throws IOException {
   input.ensureReadAhead(3);
   int head = readFByte() & 0xff;
   if (head >= 0 && head < 255) {
     return (short) head;
   }
   int ch1 = readFByte() & 0xff;
   int ch2 = readFByte() & 0xff;
   return (short) ((ch1 << 0) + (ch2 << 8));
 }
 public String readStringUTF() throws IOException {
   int len = readFInt();
   char[] charBuf = getCharBuf(len * 3);
   input.ensureReadAhead(len * 3);
   byte buf[] = input.buf;
   int count = input.pos;
   int chcount = 0;
   for (int i = 0; i < len; i++) {
     char head = (char) ((buf[count++] + 256) & 0xff);
     if (head < 255) {
       charBuf[chcount++] = head;
     } else {
       int ch1 = ((buf[count++] + 256) & 0xff);
       int ch2 = ((buf[count++] + 256) & 0xff);
       charBuf[chcount++] = (char) ((ch1 << 0) + (ch2 << 8));
     }
   }
   input.pos = count;
   return new String(charBuf, 0, chcount);
 }
 @Override
 public char readFChar() throws IOException {
   input.ensureReadAhead(3);
   char head = (char) ((readFByte() + 256) & 0xff);
   // -128 = short byte, -127 == 4 byte
   if (head >= 0 && head < 255) {
     return head;
   }
   int ch1 = readFByte() & 0xff;
   int ch2 = readFByte() & 0xff;
   return (char) ((ch1 << 0) + (ch2 << 8));
 }
 private long readPlainLong() throws IOException {
   input.ensureReadAhead(8);
   int count = input.pos;
   final byte buf[] = input.buf;
   long ch8 = (buf[count++] + 256) & 0xff;
   long ch7 = (buf[count++] + 256) & 0xff;
   long ch6 = (buf[count++] + 256) & 0xff;
   long ch5 = (buf[count++] + 256) & 0xff;
   long ch4 = (buf[count++] + 256) & 0xff;
   long ch3 = (buf[count++] + 256) & 0xff;
   long ch2 = (buf[count++] + 256) & 0xff;
   long ch1 = (buf[count++] + 256) & 0xff;
   input.pos = count;
   return ((ch1 << 56)
       + (ch2 << 48)
       + (ch3 << 40)
       + (ch4 << 32)
       + (ch5 << 24)
       + (ch6 << 16)
       + (ch7 << 8)
       + (ch8 << 0));
 }
 @Override
 public void readFIntArr(int len, int[] arr) throws IOException {
   int bytelen = arr.length * 4;
   ensureReadAhead(bytelen);
   int count = input.pos;
   final byte buf[] = input.buf;
   for (int j = 0; j < len; j++) {
     int ch1 = (buf[count++] + 256) & 0xff;
     int ch2 = (buf[count++] + 256) & 0xff;
     int ch3 = (buf[count++] + 256) & 0xff;
     int ch4 = (buf[count++] + 256) & 0xff;
     arr[j] = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
   }
   input.pos += bytelen;
 }
 @Override
 public void readPlainBytes(byte[] b, int off, int len) {
   input.ensureReadAhead(len);
   System.arraycopy(input.buf, input.pos, b, off, len);
 }
 @Override
 public final byte readFByte() throws IOException {
   input.ensureReadAhead(1);
   return input.buf[input.pos++];
 }
 @Override
 public void skip(int n) {
   input.pos += n;
 }
 public void ensureReadAhead(int bytes) {
   input.ensureReadAhead(bytes);
 }
 @Override
 public void moveTo(int position) {
   input.pos = position;
 }
 @Override
 public void reset() {
   input.reset();
   clnames.clear();
 }
 @Override
 public void setInputStream(InputStream in) {
   if (input == null) input = new FSTInputStream(in);
   else input.initFromStream(in);
   clnames.clear();
 }