1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/******************************************************************************* 2398ee59bebad6835dab57b60157eff16d511709eMarc R. Hoffmann * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors 3e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * All rights reserved. This program and the accompanying materials 4e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * are made available under the terms of the Eclipse Public License v1.0 5e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * which accompanies this distribution, and is available at 6e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * http://www.eclipse.org/legal/epl-v10.html 7e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 8e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Contributors: 9e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Brock Janiczak - initial API and implementation 10e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 11e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *******************************************************************************/ 12e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpackage org.jacoco.report.csv; 13e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 14e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.IOException; 15e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.Writer; 16e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 17e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/** 18e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Helper class for writing out CSV or tab delimited files. 19e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * <p> 20e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * <strong>Example Usage:</strong> 21e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 22e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * <pre> 23e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimitedWriter.writeFields("header1", "header2", ...); 24e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * for each line to be written { 25e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimitedWriter.writeField(value1); 26e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimitedWriter.writeField(value2); 27e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimitedWriter.nextLine(); 28e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * } 29e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimitedWriter.close(); 30e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * </pre> 31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 32e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * </p> 33e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 34e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovclass DelimitedWriter { 35e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private static final String QUOTE = "\""; 36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private static final String ESCAPED_QUOTE = "\"\""; 37e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 38e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private static final char DEFAULT_DELIMITER = ','; 39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private static final String NEW_LINE = System.getProperty("line.separator"); 40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final char delimiter; 41e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final Writer delegate; 42e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private int fieldPosition = 0; 43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Creates a new Delimited writer using the default delimiter 46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param delegate 48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Writer to delegate all writes to 49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public DelimitedWriter(final Writer delegate) { 51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this(delegate, DEFAULT_DELIMITER); 52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Creates a new Delimited writer using the default delimiter 56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param delegate 58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Writer to delegate all writes to 59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param delimiter 60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimiter to use (usually a comma, tab or space) 61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public DelimitedWriter(final Writer delegate, final char delimiter) { 63e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.delegate = delegate; 64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.delimiter = delimiter; 65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Write multiple fields at once. Values will be auto escaped and quoted as 69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * needed. Each value will be separated using the current delimiter 70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param fields 72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Values to write 73e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 74e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Error writing to the underlying writer object 75e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 76e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void write(final String... fields) throws IOException { 77e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov for (final String field : fields) { 78e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov write(field); 79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 80e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 81e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 82e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 83e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Write a single value. Values will be auto escaped and quoted as needed. 84e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * If this is not the first field of the current line the value will be 85e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * prepended with the current delimiter 86e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 87e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param field 88e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Value to write 89e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 90e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Error writing to the underlying writer object 91e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 92e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void write(final String field) throws IOException { 93e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov if (fieldPosition != 0) { 94e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov delegate.write(delimiter); 95e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 96e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov delegate.write(escape(field)); 97e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov fieldPosition++; 98e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 99e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 100e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 101e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Write a single integer value. 102e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 103e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param value 104e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Value to write 105e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 106e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Error writing to the underlying writer object 107e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 108e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void write(final int value) throws IOException { 109e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov write(Integer.toString(value)); 110e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 111e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 112e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 113e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Write muliple integer values 114e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 115e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param values 116e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * values to write 117e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 118e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Error writing to the underlying writer object 119e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 120e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void write(final int... values) throws IOException { 121e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov for (final int value : values) { 122e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov write(Integer.toString(value)); 123e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 124e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 125e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 126e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 127e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Output a new line and advance the writer to the next line. The line 128e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * delimiter is the default for the platform. 129e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 130e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 131e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Error writing to the underlying writer object 132e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 133e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void nextLine() throws IOException { 134e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov delegate.write(NEW_LINE); 135e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov fieldPosition = 0; 136e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 137e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 138e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 139e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Close the underlying writer object. Once closed all write operations will 140e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * fail 141e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 142e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @throws IOException 143e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Error closing the underlying writer object 144e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 145e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public void close() throws IOException { 146e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov delegate.close(); 147e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 148e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 149e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 150e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Escapes any occurrences of the quote character in value by replacing it 151e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * with a double quote. Also Quotes the value if a quote or delimiter value 152e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * is found. 153e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 154e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param value 155e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * String that needs escaping 156e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @return New string with all values escaped 157e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 158e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private String escape(final String value) { 159e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov String escapedValue = value; 160e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 161e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // Escape and quote if the source value contains the delimiter 162e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // or the quote character 163e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov if (value.indexOf(QUOTE) != -1 || value.indexOf(delimiter) != -1) { 164e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov escapedValue = value.replace(QUOTE, ESCAPED_QUOTE); 165e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov escapedValue = QUOTE + escapedValue + QUOTE; 166e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 167e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 168e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return escapedValue; 169e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 170e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov} 171