docs: public static String decodeComponent(final String s, final Charset charset) {
      if (s == null) {
        return "";
      }
      final int size = s.length();
      boolean modified = false;
      for (int i = 0; i < size; i++) {
        final char c = s.charAt(i);
        if (c == '%' || c == '+') {
          modified = true;
          break;
        }
      }
      if (!modified) {
        return s;
      }
      final byte[] buf = new byte[size];
      int pos = 0;  // position in `buf'.
      for (int i = 0; i < size; i++) {
        char c = s.charAt(i);
        switch (c) {
          case '+':
            buf[pos++] = ' ';  // "+" -> " "
            break;
          case '%':
            if (i == size - 1) {
              throw new IllegalArgumentException("unterminated escape"
                                                 + " sequence at end of string: " + s);
            }
            c = s.charAt(++i);
            if (c == '%') {
              buf[pos++] = '%';  // "%%" -> "%"
              break;
            }
            if (i == size - 1) {
              throw new IllegalArgumentException("partial escape"
                                                 + " sequence at end of string: " + s);
            }
            c = decodeHexNibble(c);
            final char c2 = decodeHexNibble(s.charAt(++i));
            if (c == Character.MAX_VALUE || c2 == Character.MAX_VALUE) {
              throw new IllegalArgumentException(
                  "invalid escape sequence `%" + s.charAt(i - 1)
                  + s.charAt(i) + "' at index " + (i - 2)
                  + " of: " + s);
            }
            c = (char) (c * 16 + c2);
            // Fall through.
          default:
            buf[pos++] = (byte) c;
            break;
        }
      }
      return new String(buf, 0, pos, charset);
    }