static CMap createCMap(Buffer buffer, int offset) {
    /* First do a sanity check that this cmap subtable is contained
     * within the cmap table.
     */
    int subtableFormat = buffer.getChar(offset);

    switch (subtableFormat) {
      case 0:
        return new CMapFormat0(buffer, offset);
      case 2:
        return new CMapFormat2(buffer, offset);
      case 4:
        return new CMapFormat4(buffer, offset);
      case 6:
        return new CMapFormat6(buffer, offset);
      case 8:
        return new CMapFormat8(buffer, offset);
      case 10:
        return new CMapFormat10(buffer, offset);
      case 12:
        return new CMapFormat12(buffer, offset);
      default:
        throw new RuntimeException("Cmap format unimplemented: " + (int) buffer.getChar(offset));
    }
  }
    CMapFormat6(Buffer buffer, int offset) {

      buffer.position(offset + 6);
      firstCode = buffer.getChar();
      entryCount = buffer.getChar();
      glyphIdArray = new char[entryCount];
      for (int i = 0; i < entryCount; i++) {
        glyphIdArray[i] = buffer.getChar();
      }
    }
    CMapFormat0(Buffer buffer, int offset) {

      /* skip 6 bytes of format, length, and version */
      int len = buffer.getChar(offset + 2);
      cmap = new byte[len - 6];
      buffer.get(offset + 6, cmap, 0, len - 6);
    }
    CMapFormat2(Buffer buffer, int offset) {

      int tableLen = buffer.getChar(offset + 2);
      buffer.position(offset + 6);
      char maxSubHeader = 0;
      for (int i = 0; i < 256; i++) {
        subHeaderKey[i] = buffer.getChar();
        if (subHeaderKey[i] > maxSubHeader) {
          maxSubHeader = subHeaderKey[i];
        }
      }
      /* The value of the subHeaderKey is 8 * the subHeader index,
       * so the number of subHeaders can be obtained by dividing
       * this value bv 8 and adding 1.
       */
      int numSubHeaders = (maxSubHeader >> 3) + 1;
      firstCodeArray = new char[numSubHeaders];
      entryCountArray = new char[numSubHeaders];
      idDeltaArray = new short[numSubHeaders];
      idRangeOffSetArray = new char[numSubHeaders];
      for (int i = 0; i < numSubHeaders; i++) {
        firstCodeArray[i] = buffer.getChar();
        entryCountArray[i] = buffer.getChar();
        idDeltaArray[i] = (short) buffer.getChar();
        idRangeOffSetArray[i] = buffer.getChar();
      }

      int glyphIndexArrSize = (tableLen - 518 - numSubHeaders * 8) / 2;
      glyphIndexArray = new char[glyphIndexArrSize];
      for (int i = 0; i < glyphIndexArrSize; i++) {
        glyphIndexArray[i] = buffer.getChar();
      }
    }
    CMapFormat10(Buffer buffer, int offset) {

      buffer.position(offset + 12);
      startCharCode = buffer.getInt() & INTMASK;
      numChars = buffer.getInt() & INTMASK;
      glyphIdArray = new char[numChars];
      for (int i = 0; i < numChars; i++) {
        glyphIdArray[i] = buffer.getChar();
      }
    }
    CMapFormat4(Buffer buffer, int offset) {

      buffer.position(offset);
      buffer.getChar(); // skip, we already know format=4
      int subtableLength = buffer.getChar();
      /* Try to recover from some bad fonts which specify a subtable
       * length that would overflow the byte buffer holding the whole
       * cmap table. If this isn't a recoverable situation an exception
       * may be thrown which is caught higher up the call stack.
       * Whilst this may seem lenient, in practice, unless the "bad"
       * subtable we are using is the last one in the cmap table we
       * would have no way of knowing about this problem anyway.
       */
      if (offset + subtableLength > buffer.capacity()) {
        subtableLength = buffer.capacity() - offset;
      }
      buffer.getChar(); // skip language
      segCount = buffer.getChar() / 2;
      buffer.getChar(); // skip searchRange
      entrySelector = buffer.getChar();
      rangeShift = buffer.getChar() / 2;
      startCount = new char[segCount];
      endCount = new char[segCount];
      idDelta = new short[segCount];
      idRangeOffset = new char[segCount];

      for (int i = 0; i < segCount; i++) {
        endCount[i] = buffer.getChar();
      }
      buffer.getChar(); // 2 bytes for reserved pad
      for (int i = 0; i < segCount; i++) {
        startCount[i] = buffer.getChar();
      }

      for (int i = 0; i < segCount; i++) {
        idDelta[i] = (short) buffer.getChar();
      }

      for (int i = 0; i < segCount; i++) {
        char ctmp = buffer.getChar();
        idRangeOffset[i] = (char) ((ctmp >> 1) & 0xffff);
      }
      /* Can calculate the number of glyph IDs by subtracting
       * "pos" from the length of the cmap
       */
      int pos = (segCount * 8 + 16) / 2;
      buffer.position(pos * 2 + offset); // * 2 for chars
      int numGlyphIds = (subtableLength / 2 - pos);
      glyphIds = new char[numGlyphIds];
      for (int i = 0; i < numGlyphIds; i++) {
        glyphIds[i] = buffer.getChar();
      }
    }