private void determineOffsets() {
    int at = 10; // offset from the start of the file to the first cst
    int lastCategory;

    for (int i = 1; i < offsets.length; i += lastCategory) {
      offsets[i] = at;
      int tag = bytes.getUnsignedByte(at);
      try {
        switch (tag) {
          case CONSTANT_Integer:
          case CONSTANT_Float:
          case CONSTANT_Fieldref:
          case CONSTANT_Methodref:
          case CONSTANT_InterfaceMethodref:
          case CONSTANT_NameAndType:
            {
              lastCategory = 1;
              at += 5;
              break;
            }
          case CONSTANT_Long:
          case CONSTANT_Double:
            {
              lastCategory = 2;
              at += 9;
              break;
            }
          case CONSTANT_Class:
          case CONSTANT_String:
            {
              lastCategory = 1;
              at += 3;
              break;
            }
          case CONSTANT_Utf8:
            {
              lastCategory = 1;
              at += bytes.getUnsignedShort(at + 1) + 3;
              break;
            }
          case CONSTANT_MethodHandle:
            {
              lastCategory = 1;
              at += 4;
              break;
            }
          case CONSTANT_MethodType:
            {
              lastCategory = 1;
              at += 3;
              break;
            }
          case CONSTANT_InvokeDynamic:
            {
              lastCategory = 1;
              at += 5;
              break;
            }
          default:
            {
              throw new ParseException("unknown tag byte: " + Hex.u1(tag));
            }
        }
      } catch (ParseException ex) {
        ex.addContext("...while preparsing cst " + Hex.u2(i) + " at offset " + Hex.u4(at));
        throw ex;
      }
    }

    endOffset = at;
  }
Populates {@link #offsets} and also completely parse utf8 constants.
android/android_framework/dex-maker/src/main/java/com/android/dx/cf/cst/ConstantPoolParser.java