All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.util.text.DataUriSchemeParser Maven / Gradle / Ivy

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.util.text;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;

import org.bouncycastle.util.encoders.Base64;

import brooklyn.util.exceptions.Exceptions;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
//import com.sun.jersey.core.util.Base64;

/** implementation (currently hokey) of RFC-2397 data: URI scheme.
 * see: http://stackoverflow.com/questions/12353552/any-rfc-2397-data-uri-parser-for-java */
public class DataUriSchemeParser {

    public static final String PROTOCOL_PREFIX = "data:";
    public static final String DEFAULT_MIME_TYPE = "text/plain";
    public static final String DEFAULT_CHARSET = "US-ASCII";
    
    private final String url;
    private int parseIndex = 0;
    private boolean isParsed = false;
    private boolean allowMissingComma = false;
    private boolean allowSlashesAfterColon = false;
    
    private String mimeType;
    private byte[] data;
    private Map parameters = new LinkedHashMap();

    public DataUriSchemeParser(String url) {
        this.url = Preconditions.checkNotNull(url, "url");
    }

    // ---- static conveniences -----
    
    public static String toString(String url) {
        return new DataUriSchemeParser(url).lax().parse().getDataAsString();
    }

    public static byte[] toBytes(String url) {
        return new DataUriSchemeParser(url).lax().parse().getData();
    }

    // ---- accessors (once it is parsed) -----------
    
    public String getCharset() {
        String charset = parameters.get("charset");
        if (charset!=null) return charset;
        return DEFAULT_CHARSET;
    }

    public String getMimeType() {
        assertParsed();
        if (mimeType!=null) return mimeType;
        return DEFAULT_MIME_TYPE;
    }
    
    public Map getParameters() {
        return ImmutableMap.copyOf(parameters);
    }

    public byte[] getData() {
        assertParsed();
        return data;
    }
    
    public ByteArrayInputStream getDataAsInputStream() {
        return new ByteArrayInputStream(getData());
    }

    public String getDataAsString() {
        return new String(getData(), Charset.forName(getCharset()));
    }

    // ---- config ------------------
    
    public synchronized DataUriSchemeParser lax() {
        return allowMissingComma(true).allowSlashesAfterColon(true);
    }
        
    public synchronized DataUriSchemeParser allowMissingComma(boolean allowMissingComma) {
        assertNotParsed();
        this.allowMissingComma = allowMissingComma;
        return this;
    }
    
    public synchronized DataUriSchemeParser allowSlashesAfterColon(boolean allowSlashesAfterColon) {
        assertNotParsed();
        this.allowSlashesAfterColon = allowSlashesAfterColon;
        return this;
    }
    
    private void assertNotParsed() {
        if (isParsed) throw new IllegalStateException("Operation not permitted after parsing");
    }

    private void assertParsed() {
        if (!isParsed) throw new IllegalStateException("Operation not permitted before parsing");
    }

    public synchronized DataUriSchemeParser parse() {
        try {
            return parseChecked();
        } catch (Exception e) {
            throw Exceptions.propagate(e);
        }
    }
    
    public synchronized DataUriSchemeParser parseChecked() throws UnsupportedEncodingException, MalformedURLException {
        if (isParsed) return this;
        
        skipOptional(PROTOCOL_PREFIX);
        if (allowSlashesAfterColon)
            while (skipOptional("/")) ;
        
        if (allowMissingComma && remainder().indexOf(',')==-1) {
            mimeType = DEFAULT_MIME_TYPE;
            parameters.put("charset", DEFAULT_CHARSET);
        } else {        
            parseMediaType();
            parseParameterOrParameterValues();
            skipRequired(",");
        }
        
        parseData();
        
        isParsed = true;
        return this;
    }

    private void parseMediaType() throws MalformedURLException {
        if (remainder().startsWith(";") || remainder().startsWith(","))
            return;
        int slash = remainder().indexOf("/");
        if (slash==-1) throw new MalformedURLException("Missing required '/' in MIME type of data: URL");
        String type = read(slash);
        skipRequired("/");
        int next = nextSemiOrComma();
        String subtype = read(next);
        mimeType = type+"/"+subtype;
    }

    private String read(int next) {
        String result = remainder().substring(0, next);
        parseIndex += next;
        return result;
    }

    private int nextSemiOrComma() throws MalformedURLException {
        int semi = remainder().indexOf(';');
        int comma = remainder().indexOf(',');
        if (semi<0 && comma<0) throw new MalformedURLException("Missing required ',' in data: URL");
        if (semi<0) return comma;
        if (comma<0) return semi;
        return Math.min(semi, comma);
    }

    private void parseParameterOrParameterValues() throws MalformedURLException {
        while (true) {
            if (!remainder().startsWith(";")) return;
            parseIndex++;
            int eq = remainder().indexOf('=');
            String word, value;
            int nextSemiOrComma = nextSemiOrComma();
            if (eq==-1 || eq>nextSemiOrComma) {
                word = read(nextSemiOrComma);
                value = null;
            } else {
                word = read(eq);
                if (remainder().startsWith("\"")) {
                    // is quoted
                    parseIndex++;
                    int nextUnescapedQuote = nextUnescapedQuote();
                    value = "\"" + read(nextUnescapedQuote);
                } else {
                    value = read(nextSemiOrComma());
                }
            }
            parameters.put(word, value);
        }
    }

    private int nextUnescapedQuote() throws MalformedURLException {
        int i=0;
        String r = remainder();
        boolean escaped = false;
        while (i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy