protected void init(URL url) throws IOException, MalformedURLException {
        if (!url.scheme().equals("data")) {
            throw new IllegalArgumentException("The input did not start with data:.");
        }

        if (url.fragment() != null) {
            throw new MalformedURLException(
                    "Fragment is not allowed for data: URIs according to RFC 2397.");
        }

        is = new PercentDecodingReaderInputStream(new StringReader(url.schemeData()));
        StringBuilder sb = new StringBuilder();
        State state = State.AT_START;
        int i = 0; // string counter
        for (;;i++) {
            int b = is.read();
            if (b == -1) {
                is.close();
                throw new MalformedURLException("Premature end of URI.");
            }
            if (b >= 0x80) {
                is.close();
                throw new MalformedURLException(
                        "Non-ASCII character in MIME type part of the data URI.");
            }
            char c = (char) b;
            sb.append(c);
            switch (state) {
                case AT_START:
                    if (isTokenChar(c)) {
                        state = State.IN_SUPERTYPE;
                        continue;
                    } else if (c == ';') {
                        sb.setLength(0);
                        sb.append("text/plain;");
                        state = State.SEMICOLON_SEEN;
                        continue;
                    } else if (c == ',') {
                        contentType = "text/plain;charset=US-ASCII";
                        inputStream = is;
                        return;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a token character or a semicolon but saw ",
                                        c, " instead.");
                    }
                case IN_SUPERTYPE:
                    if (isTokenChar(c)) {
                        continue;
                    } else if (c == '/') {
                        state = State.AT_SUBTYPE_START;
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a token character or \u201C/\u201D but saw ",
                                        c, " instead.");
                    }
                case AT_SUBTYPE_START:
                    if (isTokenChar(c)) {
                        state = State.IN_SUBTYPE;
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a token character but saw ",
                                        c, " instead.");
                    }
                case IN_SUBTYPE:
                    if (isTokenChar(c)) {
                        continue;
                    } else if (c == ';') {
                        state = State.SEMICOLON_SEEN;
                        continue;
                    } else if (isWhitespace(c)) {
                        state = State.WS_BEFORE_SEMICOLON;
                        continue;
                    } else if (c == ',') {
                        contentType = sb.substring(0, sb.length() - 1);
                        inputStream = is;
                        return;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a token character, whitespace, a semicolon or a comma but saw ",
                                        c, " instead.");
                    }
                case WS_BEFORE_SEMICOLON:
                    if (isWhitespace(c)) {
                        continue;
                    } else if (c == ';') {
                        state = State.SEMICOLON_SEEN;
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected whitespace or a semicolon but saw ",
                                        c, " instead.");
                    }
                case SEMICOLON_SEEN:
                    if (isWhitespace(c)) {
                        continue;
                    } else if (isTokenChar(c)) {
                        state = State.IN_PARAM_NAME;
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected whitespace or a token character but saw ",
                                        c, " instead.");
                    }
                case IN_PARAM_NAME:
                    if (isTokenChar(c)) {
                        continue;
                    } else if (c == '=') {
                        state = State.EQUALS_SEEN;
                        continue;
                    } else if (c == ',') {
                        // let's see if we had ;base64,
                        int baseFirst = sb.length() - 8;
                        if (baseFirst >= 0 && ";base64,".equals(sb.substring(baseFirst, sb.length()))) {
                            contentType = sb.substring(0, baseFirst);
                            inputStream = new Base64InputStream(is);
                            return;
                        }
                    } else {
                        throw newDatatypeException(i, 
                                "Expected an equals sign, a comma or a token character but saw ",
                                        c, " instead.");
                    }
                case EQUALS_SEEN:
                    if (c == '\"') {
                        state = State.IN_QUOTED_STRING;
                        continue;
                    } else if (isTokenChar(c)) {
                        state = State.IN_UNQUOTED_STRING;
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a double quote or a token character but saw ",
                                        c, " instead.");
                    }
                case IN_QUOTED_STRING:
                    if (c == '\\') {
                        state = State.IN_QUOTED_PAIR;
                        continue;
                    } else if (c == '\"') {
                        state = State.CLOSE_QUOTE_SEEN;
                        continue;
                    } else if (isQDTextChar(c)) {
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a non-control ASCII character but saw ",
                                        c, " instead.");
                    }
                case IN_QUOTED_PAIR:
                    if (c <= 127) {
                        state = State.IN_QUOTED_STRING;
                        continue;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected an ASCII character but saw ",
                                        c, " instead.");
                    }
                case CLOSE_QUOTE_SEEN:
                    if (c == ';') {
                        state = State.SEMICOLON_SEEN;
                        continue;
                    } else if (isWhitespace(c)) {
                        state = State.WS_BEFORE_SEMICOLON;
                        continue;
                    } else if (c == ',') {
                        contentType = sb.substring(0, sb.length() - 1);
                        inputStream = is;
                        return;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected an ASCII character but saw ",
                                        c, " instead.");
                    }
                case IN_UNQUOTED_STRING:
                    if (isTokenChar(c)) {
                        continue;
                    } else if (c == ';') {
                        state = State.SEMICOLON_SEEN;
                        continue;
                    } else if (isWhitespace(c)) {
                        state = State.WS_BEFORE_SEMICOLON;
                        continue;
                    } else if (c == ',') {
                        contentType = sb.substring(0, sb.length() - 1);
                        inputStream = is;
                        return;
                    } else {
                        throw newDatatypeException(i, 
                                "Expected a token character, whitespace, a semicolon, or a comma but saw ",
                                        c, " instead.");
                    }
            }
        }

    }
@param url
@throws MalformedURLException
@throws IOException
src/nu/validator/io/DataUri.java