001    /* 
002     * Copyright 2008-2009 the original author or authors.
003     * The contents of this file are subject to the Mozilla Public License
004     * Version 1.1 (the "License"); you may not use this file except in
005     * compliance with the License. You may obtain a copy of the License at
006     * http://www.mozilla.org/MPL/
007     *
008     * Software distributed under the License is distributed on an "AS IS"
009     * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
010     * License for the specific language governing rights and limitations
011     * under the License.
012     */
013     
014    package com.mtgi.csv;
015    
016    import java.io.IOException;
017    
018    public class CSVUtil {
019    
020            /**
021             * Calls {@link #quoteCSV(String, Appendable)} to construct a new
022             * escaped string based on <code>str</code>.
023             * @return the escaped string
024             */
025            public static String quoteCSV(Object value) {
026                    if (value == null)
027                            return "";
028                    String str = value.toString();
029                    try {
030                            return quoteCSVInner(str, new StringBuffer(2 + str.length())).toString();
031                    } catch (IOException ioe) {
032                            throw new RuntimeException("Unexpected error; StringBuffer should not raise I/O Exceptions", ioe);
033                    }
034            }
035    
036            /**
037             * Add double quotes around <code>str</code>, stuttering any internal
038             * quotation marks in the manner expected by most CSV parsers.
039             * @param str the input string, to be quoted.
040             * @param escaped destination to which the escaped text is written
041             * @return a reference to <code>escaped</code>, for syntactic convenience
042             * @throws IOException if <code>escaped</code> raises errors while the data is being written.
043             */
044            public static Appendable quoteCSV(Object value, Appendable escaped) throws IOException {
045                    if (value == null)
046                            return escaped;
047                    String str = value.toString();
048                    return quoteCSVInner(str, escaped);
049            }
050            
051            //private implementation, without argument checks performed by public methods.
052            private static Appendable quoteCSVInner(String str, Appendable escaped) throws IOException {
053                    escaped.append('"');
054                    for (int i = 0, len = str.length(); i < len; ++i) {
055                            char c = str.charAt(i);
056                            switch (c) {
057                            case '\n':
058                                    //convert \r\n or \n to single \r.
059                                    if (i == 0 || str.charAt(i - 1) != '\r')
060                                            escaped.append('\r');
061                                    break;
062                            case '"':
063                                    escaped.append('"'); //stutter quotes
064                            default:
065                                    escaped.append(c);
066                                    break;
067                            }
068                    }
069                    escaped.append('"');
070                    return escaped;
071            }
072    }