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

org.eclipse.jetty.util.QuotedStringTokenizer Maven / Gradle / Ivy

// 
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// 
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// 
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// 
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
// 
package org.eclipse.jetty.util;

import java.io.IOException;
import java.util.Arrays;
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 behaviour is the same, except that single and double quoted
 *  string values are recognised.
 *  Delimiters within quotes are not considered delimiters.
 *  Quotes can be escaped with '\'.
 *
 *  @see java.util.StringTokenizer
 *
 * @deprecated The Eclipse Jetty and Apache Felix Http Jetty packages are no longer supported.
 */
@Deprecated(since = "2021-05-27")
public class QuotedStringTokenizer extends StringTokenizer {

    private static final String __delim = "\t\n\r";

    private String _string;

    private String _delim = __delim;

    private boolean _returnQuotes = false;

    private boolean _returnDelimiters = false;

    private StringBuffer _token;

    private boolean _hasToken = false;

    private int _i = 0;

    private int _lastStart = 0;

    private boolean _double = true;

    private boolean _single = true;

    public QuotedStringTokenizer(String str, String delim, boolean returnDelimiters, boolean returnQuotes) {
        super("");
        _string = str;
        if (delim != null)
            _delim = delim;
        _returnDelimiters = returnDelimiters;
        _returnQuotes = returnQuotes;
        if (_delim.indexOf('\'') >= 0 || _delim.indexOf('"') >= 0)
            throw new Error("Can't use quotes as delimiters: " + _delim);
        _token = new StringBuffer(_string.length() > 1024 ? 512 : _string.length() / 2);
    }

    public QuotedStringTokenizer(String str, String delim, boolean returnDelimiters) {
        this(str, delim, returnDelimiters, false);
    }

    public QuotedStringTokenizer(String str, String delim) {
        this(str, delim, false, false);
    }

    public QuotedStringTokenizer(String str) {
        this(str, null, false, false);
    }

    @Override
    public boolean hasMoreTokens() {
        // Already found a token
        if (_hasToken)
            return true;
        _lastStart = _i;
        int state = 0;
        boolean escape = false;
        while (_i < _string.length()) {
            char c = _string.charAt(_i++);
            switch(state) {
                case // Start
                0:
                    if (_delim.indexOf(c) >= 0) {
                        if (_returnDelimiters) {
                            _token.append(c);
                            return _hasToken = true;
                        }
                    } else if (c == '\'' && _single) {
                        if (_returnQuotes)
                            _token.append(c);
                        state = 2;
                    } else if (c == '\"' && _double) {
                        if (_returnQuotes)
                            _token.append(c);
                        state = 3;
                    } else {
                        _token.append(c);
                        _hasToken = true;
                        state = 1;
                    }
                    break;
                case // Token
                1:
                    _hasToken = true;
                    if (_delim.indexOf(c) >= 0) {
                        if (_returnDelimiters)
                            _i--;
                        return _hasToken;
                    } else if (c == '\'' && _single) {
                        if (_returnQuotes)
                            _token.append(c);
                        state = 2;
                    } else if (c == '\"' && _double) {
                        if (_returnQuotes)
                            _token.append(c);
                        state = 3;
                    } else {
                        _token.append(c);
                    }
                    break;
                case // Single Quote
                2:
                    _hasToken = true;
                    if (escape) {
                        escape = false;
                        _token.append(c);
                    } else if (c == '\'') {
                        if (_returnQuotes)
                            _token.append(c);
                        state = 1;
                    } else if (c == '\\') {
                        if (_returnQuotes)
                            _token.append(c);
                        escape = true;
                    } else {
                        _token.append(c);
                    }
                    break;
                case // Double Quote
                3:
                    _hasToken = true;
                    if (escape) {
                        escape = false;
                        _token.append(c);
                    } else if (c == '\"') {
                        if (_returnQuotes)
                            _token.append(c);
                        state = 1;
                    } else if (c == '\\') {
                        if (_returnQuotes)
                            _token.append(c);
                        escape = true;
                    } else {
                        _token.append(c);
                    }
                    break;
            }
        }
        return _hasToken;
    }

    @Override
    public String nextToken() throws NoSuchElementException {
        if (!hasMoreTokens() || _token == null)
            throw new NoSuchElementException();
        String t = _token.toString();
        _token.setLength(0);
        _hasToken = false;
        return t;
    }

    @Override
    public String nextToken(String delim) throws NoSuchElementException {
        _delim = delim;
        _i = _lastStart;
        _token.setLength(0);
        _hasToken = false;
        return nextToken();
    }

    @Override
    public boolean hasMoreElements() {
        return hasMoreTokens();
    }

    @Override
    public Object nextElement() throws NoSuchElementException {
        return nextToken();
    }

    /**
     * Not implemented.
     */
    @Override
    public int countTokens() {
        return -1;
    }

    /**
     * Quote a string.
     * The string is quoted only if quoting is required due to
     * embedded delimiters, quote characters or the
     * empty string.
     *
     * @param s The string to quote.
     * @param delim the delimiter to use to quote the string
     * @return quoted string
     */
    public static String quoteIfNeeded(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 == '\'' || Character.isWhitespace(c) || delim.indexOf(c) >= 0) {
                StringBuffer b = new StringBuffer(s.length() + 8);
                quote(b, s);
                return b.toString();
            }
        }
        return s;
    }

    /**
     * Quote a string.
     * The string is quoted only if quoting is required due to
     * embedded delimiters, quote characters or the
     * empty string.
     *
     * @param s The string to quote.
     * @return quoted string
     */
    public static String quote(String s) {
        if (s == null)
            return null;
        if (s.length() == 0)
            return "\"\"";
        StringBuffer b = new StringBuffer(s.length() + 8);
        quote(b, s);
        return b.toString();
    }

    private static final char[] escapes = new char[32];

    static {
        Arrays.fill(escapes, (char) 0xFFFF);
        escapes['\b'] = 'b';
        escapes['\t'] = 't';
        escapes['\n'] = 'n';
        escapes['\f'] = 'f';
        escapes['\r'] = 'r';
    }

    /**
     * Quote a string into an Appendable.
     * Only quotes and backslash are escaped.
     *
     * @param buffer The Appendable
     * @param input The String to quote.
     */
    public static void quoteOnly(Appendable buffer, String input) {
        if (input == null)
            return;
        try {
            buffer.append('"');
            for (int i = 0; i < input.length(); ++i) {
                char c = input.charAt(i);
                if (c == '"' || c == '\\')
                    buffer.append('\\');
                buffer.append(c);
            }
            buffer.append('"');
        } catch (IOException x) {
            throw new RuntimeException(x);
        }
    }

    /**
     * Quote a string into an Appendable.
     * The characters ", \, \n, \r, \t, \f and \b are escaped
     *
     * @param buffer The Appendable
     * @param input The String to quote.
     */
    public static void quote(Appendable buffer, String input) {
        if (input == null)
            return;
        try {
            buffer.append('"');
            for (int i = 0; i < input.length(); ++i) {
                char c = input.charAt(i);
                if (c >= 32) {
                    if (c == '"' || c == '\\')
                        buffer.append('\\');
                    buffer.append(c);
                } else {
                    char escape = escapes[c];
                    if (escape == 0xFFFF) {
                        // Unicode escape
                        buffer.append('\\').append('u').append('0').append('0');
                        if (c < 0x10)
                            buffer.append('0');
                        buffer.append(Integer.toString(c, 16));
                    } else {
                        buffer.append('\\').append(escape);
                    }
                }
            }
            buffer.append('"');
        } catch (IOException x) {
            throw new RuntimeException(x);
        }
    }

    public static String unquoteOnly(String s) {
        return unquoteOnly(s, false);
    }

    /**
     * Unquote a string, NOT converting unicode sequences
     *
     * @param s The string to unquote.
     * @param lenient if true, will leave in backslashes that aren't valid escapes
     * @return quoted string
     */
    public static String unquoteOnly(String s, boolean lenient) {
        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);
        boolean escape = false;
        for (int i = 1; i < s.length() - 1; i++) {
            char c = s.charAt(i);
            if (escape) {
                escape = false;
                if (lenient && !isValidEscaping(c)) {
                    b.append('\\');
                }
                b.append(c);
            } else if (c == '\\') {
                escape = true;
            } else {
                b.append(c);
            }
        }
        return b.toString();
    }

    public static String unquote(String s) {
        return unquote(s, false);
    }

    /**
     * Unquote a string.
     *
     * @param s The string to unquote.
     * @param lenient true if unquoting should be lenient to escaped content, leaving some alone, false if string unescaping
     * @return quoted string
     */
    public static String unquote(String s, boolean lenient) {
        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);
        boolean escape = false;
        for (int i = 1; i < s.length() - 1; i++) {
            char c = s.charAt(i);
            if (escape) {
                escape = false;
                switch(c) {
                    case 'n':
                        b.append('\n');
                        break;
                    case 'r':
                        b.append('\r');
                        break;
                    case 't':
                        b.append('\t');
                        break;
                    case 'f':
                        b.append('\f');
                        break;
                    case 'b':
                        b.append('\b');
                        break;
                    case '\\':
                        b.append('\\');
                        break;
                    case '/':
                        b.append('/');
                        break;
                    case '"':
                        b.append('"');
                        break;
                    case 'u':
                        b.append((char) ((TypeUtil.convertHexDigit((byte) s.charAt(i++)) << 24) + (TypeUtil.convertHexDigit((byte) s.charAt(i++)) << 16) + (TypeUtil.convertHexDigit((byte) s.charAt(i++)) << 8) + (TypeUtil.convertHexDigit((byte) s.charAt(i++)))));
                        break;
                    default:
                        if (lenient && !isValidEscaping(c)) {
                            b.append('\\');
                        }
                        b.append(c);
                }
            } else if (c == '\\') {
                escape = true;
            } else {
                b.append(c);
            }
        }
        return b.toString();
    }

    /**
     * Check that char c (which is preceded by a backslash) is a valid
     * escape sequence.
     */
    private static boolean isValidEscaping(char c) {
        return ((c == 'n') || (c == 'r') || (c == 't') || (c == 'f') || (c == 'b') || (c == '\\') || (c == '/') || (c == '"') || (c == 'u'));
    }

    public static boolean isQuoted(String s) {
        return s != null && s.length() > 0 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"';
    }

    /**
     * @return handle double quotes if true
     */
    public boolean getDouble() {
        return _double;
    }

    /**
     * @param d handle double quotes if true
     */
    public void setDouble(boolean d) {
        _double = d;
    }

    /**
     * @return handle single quotes if true
     */
    public boolean getSingle() {
        return _single;
    }

    /**
     * @param single handle single quotes if true
     */
    public void setSingle(boolean single) {
        _single = single;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy