@Override
  public ContentType readValue() throws IOException {
    ContentType result = null;

    boolean readingMediaType = true;
    boolean readingParamName = false;
    boolean readingParamValue = false;

    StringBuilder mediaTypeBuffer = new StringBuilder();
    StringBuilder paramNameBuffer = null;
    StringBuilder paramValueBuffer = null;

    Series<Parameter> parameters = null;
    String nextValue = readRawValue();
    int nextIndex = 0;

    if (nextValue != null) {
      int nextChar = nextValue.charAt(nextIndex++);

      while (result == null) {
        if (readingMediaType) {
          if (nextChar == -1) {
            if (mediaTypeBuffer.length() > 0) {
              // End of metadata section
              // No parameters detected
              result = createContentType(mediaTypeBuffer, null);
              paramNameBuffer = new StringBuilder();
            } else {
              // Ignore empty metadata name
            }
          } else if (nextChar == ';') {
            if (mediaTypeBuffer.length() > 0) {
              // End of mediaType section
              // Parameters detected
              readingMediaType = false;
              readingParamName = true;
              paramNameBuffer = new StringBuilder();
              // [ifndef gwt] instruction
              parameters = new Series<Parameter>(Parameter.class);
              // [ifdef gwt] instruction uncomment
              // parameters = new
              // org.restlet.engine.util.ParameterSeries();
            } else {
              throw new IOException("Empty mediaType name detected.");
            }
          } else if (HeaderUtils.isSpace(nextChar)) {
            // Ignore spaces
          } else if (HeaderUtils.isText(nextChar)) {
            mediaTypeBuffer.append((char) nextChar);
          } else {
            throw new IOException(
                "The " + (char) nextChar + " character isn't allowed in a media type name.");
          }
        } else if (readingParamName) {
          if (nextChar == '=') {
            if (paramNameBuffer.length() > 0) {
              // End of parameter name section
              readingParamName = false;
              readingParamValue = true;
              paramValueBuffer = new StringBuilder();
            } else {
              throw new IOException("Empty parameter name detected.");
            }
          } else if (nextChar == -1) {
            if (paramNameBuffer.length() > 0) {
              // End of parameters section
              parameters.add(Parameter.create(paramNameBuffer, null));
              result = createContentType(mediaTypeBuffer, parameters);
            } else if (paramNameBuffer.length() == 0) {
              result = createContentType(mediaTypeBuffer, parameters);
            } else {
              throw new IOException("Empty parameter name detected.");
            }
          } else if (nextChar == ';') {
            // End of parameter
            parameters.add(Parameter.create(paramNameBuffer, null));
            paramNameBuffer = new StringBuilder();
            readingParamName = true;
            readingParamValue = false;
          } else if (HeaderUtils.isSpace(nextChar) && (paramNameBuffer.length() == 0)) {
            // Ignore white spaces
          } else if (HeaderUtils.isTokenChar(nextChar)) {
            paramNameBuffer.append((char) nextChar);
          } else {
            throw new IOException(
                "The \""
                    + (char) nextChar
                    + "\" character isn't allowed in a media type parameter name.");
          }
        } else if (readingParamValue) {
          if (nextChar == -1) {
            if (paramValueBuffer.length() > 0) {
              // End of parameters section
              parameters.add(Parameter.create(paramNameBuffer, paramValueBuffer));
              result = createContentType(mediaTypeBuffer, parameters);
            } else {
              throw new IOException("Empty parameter value detected");
            }
          } else if (nextChar == ';') {
            // End of parameter
            parameters.add(Parameter.create(paramNameBuffer, paramValueBuffer));
            paramNameBuffer = new StringBuilder();
            readingParamName = true;
            readingParamValue = false;
          } else if ((nextChar == '"') && (paramValueBuffer.length() == 0)) {
            // Parse the quoted string
            boolean done = false;
            boolean quotedPair = false;

            while ((!done) && (nextChar != -1)) {
              nextChar = (nextIndex < nextValue.length()) ? nextValue.charAt(nextIndex++) : -1;

              if (quotedPair) {
                // End of quoted pair (escape sequence)
                if (HeaderUtils.isText(nextChar)) {
                  paramValueBuffer.append((char) nextChar);
                  quotedPair = false;
                } else {
                  throw new IOException(
                      "Invalid character \""
                          + (char) nextChar
                          + "\" detected in quoted string. Please check your value");
                }
              } else if (HeaderUtils.isDoubleQuote(nextChar)) {
                // End of quoted string
                done = true;
              } else if (nextChar == '\\') {
                // Begin of quoted pair (escape sequence)
                quotedPair = true;
              } else if (HeaderUtils.isText(nextChar)) {
                paramValueBuffer.append((char) nextChar);
              } else {
                throw new IOException(
                    "Invalid character \""
                        + (char) nextChar
                        + "\" detected in quoted string. Please check your value");
              }
            }
          } else if (HeaderUtils.isTokenChar(nextChar)) {
            paramValueBuffer.append((char) nextChar);
          } else {
            throw new IOException(
                "The \""
                    + (char) nextChar
                    + "\" character isn't allowed in a media type parameter value.");
          }
        }

        nextChar = (nextIndex < nextValue.length()) ? nextValue.charAt(nextIndex++) : -1;
      }
    }

    return result;
  }