001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.util;
018    
019    import java.util.ArrayList;
020    import java.util.List;
021    
022    /**
023     * Utility class for parsing quoted string which is intended for parameters, separated by comma.
024     */
025    public final class StringQuoteHelper {
026    
027        private StringQuoteHelper() {
028        }
029    
030        /**
031         * Returns the text wrapped double quotes
032         */
033        public static String doubleQuote(String text) {
034            return quote(text, "\"");
035        }
036    
037        /**
038         * Returns the text wrapped single quotes
039         */
040        public static String singleQuote(String text) {
041            return quote(text, "'");
042        }
043    
044        /**
045         * Wraps the text in the given quote text
046         *
047         * @param text the text to wrap in quotes
048         * @param quote the quote text added to the prefix and postfix of the text
049         *
050         * @return the text wrapped in the given quotes
051         */
052        public static String quote(String text, String quote) {
053            return quote + text + quote;
054        }
055    
056    
057        /**
058         * Splits the input safely honoring if values is enclosed in quotes.
059         * <p/>
060         * Though this method does not support double quoting values. A quoted value
061         * must start with the same start and ending quote, which is either a single
062         * quote or double quote value.
063         * <p/>
064         * Will <i>trim</i> each splitted value by default.
065         *
066         * @param input    the input
067         * @param separator the separator char to split the input, for example a comma.
068         * @return the input splitted, or <tt>null</tt> if the input is null.
069         */
070        public static String[] splitSafeQuote(String input, char separator) {
071            return splitSafeQuote(input, separator, true);
072        }
073    
074        /**
075         * Splits the input safely honoring if values is enclosed in quotes.
076         * <p/>
077         * Though this method does not support double quoting values. A quoted value
078         * must start with the same start and ending quote, which is either a single
079         * quote or double quote value.
080         * \
081         * @param input    the input
082         * @param separator the separator char to split the input, for example a comma.
083         * @param trim      whether to trim each splitted value
084         * @return the input splitted, or <tt>null</tt> if the input is null.
085         */
086        public static String[] splitSafeQuote(String input, char separator, boolean trim) {
087            if (input == null) {
088                return null;
089            }
090    
091            if (input.indexOf(separator) == -1) {
092                // no separator in data, so return single string with input as is
093                return new String[]{trim ? input.trim() : input};
094            }
095    
096            List<String> answer = new ArrayList<String>();
097            StringBuilder sb = new StringBuilder();
098    
099            boolean singleQuoted = false;
100            boolean doubleQuoted = false;
101            boolean skipLeadingWhitespace = true;
102    
103            for (int i = 0; i < input.length(); i++) {
104                char ch = input.charAt(i);
105                char prev = i > 0 ? input.charAt(i - 1) : 0;
106                boolean isQuoting = singleQuoted || doubleQuoted;
107    
108                if (!doubleQuoted &&  ch == '\'') {
109                    if (singleQuoted && prev == ch && sb.length() == 0) {
110                        // its an empty quote so add empty text
111                        answer.add("");
112                    }
113                    // special logic needed if this quote is the end
114                    if (i == input.length() - 1) {
115                        if (singleQuoted && sb.length() > 0) {
116                            String text = sb.toString();
117                            // do not trim a quoted string
118                            answer.add(text);
119                            sb.setLength(0);
120                        }
121                    }
122                    singleQuoted = !singleQuoted;
123                    continue;
124                } else if (!singleQuoted && ch == '"') {
125                    if (doubleQuoted && prev == ch && sb.length() == 0) {
126                        // its an empty quote so add empty text
127                        answer.add("");
128                    }
129                    // special logic needed if this quote is the end
130                    if (i == input.length() - 1) {
131                        if (doubleQuoted && sb.length() > 0) {
132                            String text = sb.toString();
133                            // do not trim a quoted string
134                            answer.add(text);
135                            sb.setLength(0);
136                        }
137                    }
138                    doubleQuoted = !doubleQuoted;
139                    continue;
140                } else if (!isQuoting && ch == ' ') {
141                    if (skipLeadingWhitespace) {
142                        continue;
143                    }
144                } else if (!isQuoting && ch == separator) {
145                    // add as answer if we are not in a quote
146                    if (sb.length() > 0) {
147                        String text = sb.toString();
148                        if (trim) {
149                            text = text.trim();
150                        }
151                        answer.add(text);
152                        sb.setLength(0);
153                    }
154                    // we should avoid adding the separator 
155                    continue;
156                }
157    
158                sb.append(ch);
159            }
160    
161            // any leftover
162            if (sb.length() > 0) {
163                String text = sb.toString();
164                if (trim) {
165                    text = text.trim();
166                }
167                answer.add(text);
168            }
169    
170            return answer.toArray(new String[answer.size()]);
171        }
172    
173    }