/* * Copyright 2010 Hippo. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Taken from https://forge.onehippo.org/svn/jcr-shell/trunk/core/src/main/java/org/onehippo/forge/jcrshell/util/QuotedStringTokenizer.java package com.orgzly.android.util; import java.util.NoSuchElementException; import java.util.StringTokenizer; /** StringTokenizer with Quoting support. * * This class is a copy of the java.util.StringTokenizer API and * the behavior is the same, except that single and double quoted * string values are recognized. * Delimiters within quotes are not considered delimiters. * Quotes can be escaped with '\'. * * @see java.util.StringTokenizer * Based on the tokenizer in org.mortbay.util */ public class QuotedStringTokenizer extends StringTokenizer { private static final int MAX_INIT_CAPACITY = 512; private static final String DEFAULT_DELIMITER = "\t\n\r"; private String str; private String delimiter = DEFAULT_DELIMITER; private boolean returnQuotes = false; private boolean returnTokens = false; private StringBuilder token; private boolean hasToken = false; private int pos = 0; private int lastStart = 0; private enum State { START, TOKEN, SINGLE, DOUBLE } /* ------------------------------------------------------------ */ public QuotedStringTokenizer(String string, String delim, boolean returnTokens, boolean returnQuotes) { super(""); this.str = string; this.returnTokens = returnTokens; this.returnQuotes = returnQuotes; if (delim != null) { delimiter = delim; } if (delimiter.indexOf('\'') >= 0 || delimiter.indexOf('"') >= 0) { throw new IllegalArgumentException("Can't use quotes as delimiters: " + delimiter); } if (str.length() > (2 * MAX_INIT_CAPACITY) ) { token = new StringBuilder(MAX_INIT_CAPACITY); } else { token = new StringBuilder(str.length() / 2); } } /* ------------------------------------------------------------ */ public QuotedStringTokenizer(String str, String delim, boolean returnTokens) { this(str, delim, returnTokens, false); } /* ------------------------------------------------------------ */ public QuotedStringTokenizer(String str, String delim) { this(str, delim, false, false); } /* ------------------------------------------------------------ */ public QuotedStringTokenizer(String str) { this(str, null, false, false); } /* ------------------------------------------------------------ */ public boolean hasMoreTokens() { // Already found a token if (hasToken) { return true; } lastStart = pos; State state = State.START; boolean escape = false; while (pos < str.length()) { char c = str.charAt(pos++); switch (state) { case START: // Start if (delimiter.indexOf(c) >= 0) { if (returnTokens) { token.append(c); hasToken = true; } } else if (c == '\'') { if (returnQuotes) { token.append(c); } state = State.SINGLE; } else if (c == '\"') { if (returnQuotes) { token.append(c); } state = State.DOUBLE; } else { token.append(c); hasToken = true; state = State.TOKEN; } continue; case TOKEN: // Token hasToken = true; if (delimiter.indexOf(c) >= 0) { if (returnTokens) { pos--; } return hasToken; } else if (c == '\'') { if (returnQuotes) { token.append(c); } state = State.SINGLE; } else if (c == '\"') { if (returnQuotes) { token.append(c); } state = State.DOUBLE; } else { token.append(c); } continue; case SINGLE: // Single Quote hasToken = true; if (escape) { escape = false; token.append(c); } else if (c == '\'') { if (returnQuotes) { token.append(c); } state = State.TOKEN; } else if (c == '\\') { if (returnQuotes) { token.append(c); } escape = true; } else { token.append(c); } continue; case DOUBLE: // Double Quote hasToken = true; if (escape) { escape = false; token.append(c); } else if (c == '\"') { if (returnQuotes) { token.append(c); } state = State.TOKEN; } else if (c == '\\') { if (returnQuotes) { token.append(c); } escape = true; } else { token.append(c); } continue; } } return hasToken; } /* ------------------------------------------------------------ */ public String nextToken() { if (!hasMoreTokens() || token == null) { throw new NoSuchElementException(); } String t = token.toString(); token.setLength(0); hasToken = false; return t; } /* ------------------------------------------------------------ */ public String nextToken(String delim) { delimiter = delim; pos = lastStart; token.setLength(0); hasToken = false; return nextToken(); } /* ------------------------------------------------------------ */ public boolean hasMoreElements() { return hasMoreTokens(); } /* ------------------------------------------------------------ */ public Object nextElement() { return nextToken(); } /* ------------------------------------------------------------ */ /** Not implemented. */ public int countTokens() { return -1; } /* ------------------------------------------------------------ */ /** Quote a string. * The string is quoted only if quoting is required due to * embeded delimiters, quote characters or the * empty string. * @param s The string to quote. * @return quoted string */ public static String quote(String s, String delim) { if (s == null) { return null; } if (s.length() == 0) { return "\"\""; } for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '"' || c == '\\' || c == '\'' || delim.indexOf(c) >= 0) { StringBuilder b = new StringBuilder(s.length() + 8); quote(b, s); return b.toString(); } } return s; } /* ------------------------------------------------------------ */ /** Quote a string into a StringBuilder. * @param buf The StringBuilder * @param s The String to quote. */ public static void quote(StringBuilder buf, String s) { synchronized (buf) { buf.append('"'); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '"') { buf.append("\\\""); continue; } if (c == '\\') { buf.append("\\\\"); continue; } buf.append(c); continue; } buf.append('"'); } } /* ------------------------------------------------------------ */ /** Unquote a string. * @param s The string to unquote. * @return quoted string */ public static String unquote(String s) { if (s == null) { return null; } if (s.length() < 2) { return s; } char first = s.charAt(0); char last = s.charAt(s.length() - 1); if (first != last || (first != '"' && first != '\'')) { return s; } StringBuilder b = new StringBuilder(s.length() - 2); synchronized (b) { boolean quote = false; for (int i = 1; i < s.length() - 1; i++) { char c = s.charAt(i); if (c == '\\' && !quote) { quote = true; continue; } quote = false; b.append(c); } return b.toString(); } } }