public static String utf8BytesToString(ByteArray bytes) {
    int length = bytes.size();
    char[] chars = new char[length]; // This is sized to avoid a realloc.
    int outAt = 0;

    for (int at = 0; length > 0; /*at*/ ) {
      int v0 = bytes.getUnsignedByte(at);
      char out;
      switch (v0 >> 4) {
        case 0x00:
        case 0x01:
        case 0x02:
        case 0x03:
        case 0x04:
        case 0x05:
        case 0x06:
        case 0x07:
          {
            // 0XXXXXXX -- single-byte encoding
            length--;
            if (v0 == 0) {
              // A single zero byte is illegal.
              return throwBadUtf8(v0, at);
            }
            out = (char) v0;
            at++;
            break;
          }
        case 0x0c:
        case 0x0d:
          {
            // 110XXXXX -- two-byte encoding
            length -= 2;
            if (length < 0) {
              return throwBadUtf8(v0, at);
            }
            int v1 = bytes.getUnsignedByte(at + 1);
            if ((v1 & 0xc0) != 0x80) {
              return throwBadUtf8(v1, at + 1);
            }
            int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f);
            if ((value != 0) && (value < 0x80)) {
              /*
               * This should have been represented with
               * one-byte encoding.
               */
              return throwBadUtf8(v1, at + 1);
            }
            out = (char) value;
            at += 2;
            break;
          }
        case 0x0e:
          {
            // 1110XXXX -- three-byte encoding
            length -= 3;
            if (length < 0) {
              return throwBadUtf8(v0, at);
            }
            int v1 = bytes.getUnsignedByte(at + 1);
            if ((v1 & 0xc0) != 0x80) {
              return throwBadUtf8(v1, at + 1);
            }
            int v2 = bytes.getUnsignedByte(at + 2);
            if ((v1 & 0xc0) != 0x80) {
              return throwBadUtf8(v2, at + 2);
            }
            int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) | (v2 & 0x3f);
            if (value < 0x800) {
              /*
               * This should have been represented with one- or
               * two-byte encoding.
               */
              return throwBadUtf8(v2, at + 2);
            }
            out = (char) value;
            at += 3;
            break;
          }
        default:
          {
            // 10XXXXXX, 1111XXXX -- illegal
            return throwBadUtf8(v0, at);
          }
      }
      chars[outAt] = out;
      outAt++;
    }

    return new String(chars, 0, outAt);
  }
Converts an array of UTF-8 bytes into a string.

@param bytes {@code non-null;} the bytes to convert
@return {@code non-null;} the converted string
android/android_framework/dex-maker/src/main/java/com/android/dx/rop/cst/CstString.java