// protected int[] readExtIndexes(int skip) throws IOException
 protected ByteBuffer readExtIndexes(int skip) throws IOException, InvalidFormatException {
   ICUBinary.skipBytes(byteBuffer, skip);
   ByteBuffer b = ICUBinary.sliceWithOrder(byteBuffer);
   int lengthOfIndexes = b.getInt(0);
   if (lengthOfIndexes < 32) {
     throw new InvalidFormatException();
   }
   int numBytesExtensionStructure = b.getInt(31 * 4);
   b.limit(numBytesExtensionStructure);
   ICUBinary.skipBytes(byteBuffer, numBytesExtensionStructure);
   return b;
 }
  /**
   * Protected constructor.
   *
   * @param bytes ICU conversion data file
   * @exception IOException throw if data file fails authentication
   */
  protected UConverterDataReader(ByteBuffer bytes) throws IOException {
    // if(debug) System.out.println("Bytes in buffer " + bytes.remaining());

    byteBuffer = bytes;
    /*unicodeVersion = */ ICUBinary.readHeader(byteBuffer, DATA_FORMAT_ID, IS_ACCEPTABLE);

    // if(debug) System.out.println("Bytes left in byteBuffer " + byteBuffer.remaining());
  }
  protected void readMBCSTable(MBCSHeader header, UConverterMBCSTable mbcsTable)
      throws IOException {
    IntBuffer intBuffer = byteBuffer.asIntBuffer();
    mbcsTable.countStates = (byte) header.countStates;
    mbcsTable.stateTable = new int[header.countStates][256];
    int i;
    for (i = 0; i < header.countStates; ++i) {
      intBuffer.get(mbcsTable.stateTable[i]);
    }

    mbcsTable.countToUFallbacks = header.countToUFallbacks;
    mbcsTable.toUFallbacks = new MBCSToUFallback[header.countToUFallbacks];
    for (i = 0; i < header.countToUFallbacks; ++i) {
      int offset = intBuffer.get();
      int codePoint = intBuffer.get();
      mbcsTable.toUFallbacks[i] = new MBCSToUFallback(offset, codePoint);
    }
    // Skip as many bytes as we have read from the IntBuffer.
    int length = intBuffer.position() * 4;
    ICUBinary.skipBytes(byteBuffer, length);

    // Consider leaving some large arrays as CharBuffer/IntBuffer rather than
    // reading them into Java arrays, to reduce initialization time and memory usage,
    // at the cost of some performance.
    // For example: unicodeCodeUnits, fromUnicodeTable, fromUnicodeInts.
    // Take care not to modify the buffer contents for swaplfnl.
    CharBuffer charBuffer = byteBuffer.asCharBuffer();
    length = header.offsetFromUTable - header.offsetToUCodeUnits;
    assert (length & 1) == 0;
    mbcsTable.unicodeCodeUnits = new char[length / 2];
    charBuffer.get(mbcsTable.unicodeCodeUnits);
    // Skip as many bytes as we have read from the CharBuffer.
    ICUBinary.skipBytes(byteBuffer, length);

    length = header.offsetFromUBytes - header.offsetFromUTable;
    assert (length & 1) == 0;
    int fromUTableCharsLength;
    if (mbcsTable.outputType == CharsetMBCS.MBCS_OUTPUT_1) {
      // single-byte table stage1 + stage2
      fromUTableCharsLength = length / 2;
    } else if (mbcsTable.hasSupplementary()) {
      // stage1 for Unicode limit 0x110000 >> 10
      fromUTableCharsLength = 0x440;
    } else {
      // stage1 for BMP limit 0x10000 >> 10
      fromUTableCharsLength = 0x40;
    }
    mbcsTable.fromUnicodeTable = new char[fromUTableCharsLength];
    charBuffer.get(mbcsTable.fromUnicodeTable);
    if (mbcsTable.outputType != CharsetMBCS.MBCS_OUTPUT_1) {
      // Read both stage1 and stage2 together into an int[] array.
      // Keeping the short stage1 in the array avoids offsetting at runtime.
      // The stage1 part of this array will not be used.
      assert (length & 3) == 0;
      mbcsTable.fromUnicodeTableInts = new int[length / 4];
      byteBuffer.asIntBuffer().get(mbcsTable.fromUnicodeTableInts);
    }
    // Skip as many bytes as are in stage1 + stage2.
    ICUBinary.skipBytes(byteBuffer, length);

    mbcsTable.fromUBytesLength = header.fromUBytesLength;
    boolean noFromU = ((header.options & CharsetMBCS.MBCS_OPT_NO_FROM_U) != 0);
    if (!noFromU) {
      switch (mbcsTable.outputType) {
        case CharsetMBCS.MBCS_OUTPUT_1:
        case CharsetMBCS.MBCS_OUTPUT_2:
        case CharsetMBCS.MBCS_OUTPUT_2_SISO:
        case CharsetMBCS.MBCS_OUTPUT_3_EUC:
          mbcsTable.fromUnicodeChars =
              ICUBinary.getChars(byteBuffer, header.fromUBytesLength / 2, 0);
          break;
        case CharsetMBCS.MBCS_OUTPUT_3:
        case CharsetMBCS.MBCS_OUTPUT_4_EUC:
          mbcsTable.fromUnicodeBytes = new byte[header.fromUBytesLength];
          byteBuffer.get(mbcsTable.fromUnicodeBytes);
          break;
        case CharsetMBCS.MBCS_OUTPUT_4:
          mbcsTable.fromUnicodeInts = ICUBinary.getInts(byteBuffer, header.fromUBytesLength / 4, 0);
          break;
        default:
          // Cannot occur, caller checked already.
          assert false;
      }
    } else {
      // Optional utf8Friendly mbcsIndex -- _MBCSHeader.version 4.3 (ICU 3.8) and higher.
      // Needed for reconstituting omitted data.
      mbcsTable.mbcsIndex = byteBuffer.asCharBuffer();
    }
  }