001/* 002Copyright (c) 2011+, HL7, Inc 003All rights reserved. 004 005Redistribution and use in source and binary forms, with or without modification, 006are permitted provided that the following conditions are met: 007 008 * Redistributions of source code must retain the above copyright notice, this 009 list of conditions and the following disclaimer. 010 * Redistributions in binary form must reproduce the above copyright notice, 011 this list of conditions and the following disclaimer in the documentation 012 and/or other materials provided with the distribution. 013 * Neither the name of HL7 nor the names of its contributors may be used to 014 endorse or promote products derived from this software without specific 015 prior written permission. 016 017THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 018ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 019WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 020IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 021INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 023PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 024WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026POSSIBILITY OF SUCH DAMAGE. 027 028*/ 029package org.hl7.fhir.utilities; 030 031import java.io.IOException; 032import java.io.InputStream; 033import java.io.InputStreamReader; 034import java.io.UnsupportedEncodingException; 035import java.util.ArrayList; 036import java.util.List; 037 038import org.hl7.fhir.exceptions.FHIRException; 039 040/** 041 * Baseclass for readers that read data from files in comma separated file format 042 * @author Ewout 043 * 044 */ 045public class CSVReader extends InputStreamReader { 046 047 public CSVReader(InputStream in) throws UnsupportedEncodingException { 048 super(in, "UTF-8"); 049 } 050 051 private String[] cols; 052 private String[] cells; 053 054 public void readHeaders() throws IOException, FHIRException { 055 cols = parseLine(); 056 } 057 058 059 public boolean line() throws IOException, FHIRException { 060 if (ready()) { 061 cells = parseLine(); 062 return true; 063 } else 064 return false; 065 } 066 067 public boolean has(String name) { 068 return cell(name) != null; 069 } 070 071 public String cell(String name) { 072 int index = -1; 073 for (int i = 0; i < cols.length; i++) { 074 if (name.equals(cols[i])) 075 index = i; 076 } 077 if (index == -1) 078 throw new Error("no cell "+name); 079 String s = cells.length >= index ? cells[index] : null; 080 if (Utilities.noString(s)) 081 return null; 082 return s; 083 } 084 085 protected boolean parseBoolean(String column) { 086 if (column == null) 087 return false; 088 else if (column.equalsIgnoreCase("y") || column.equalsIgnoreCase("yes") || column.equalsIgnoreCase("true") || column.equalsIgnoreCase("1")) 089 return true; 090 else 091 return false; 092 } 093 094 protected static String getColumn(String[] titles, String[] values, String column) { 095 int c = -1; 096 // String s = ""; 097 for (int i = 0; i < titles.length; i++) { 098 // s = s + ","+titles[i]; 099 if (titles[i].equalsIgnoreCase(column)) 100 c = i; 101 } 102 if (c == -1) 103 return ""; // throw new Exception("unable to find column "+column+" in "+s.substring(1)); 104 else if (values.length <= c) 105 return ""; 106 else 107 return values[c]; 108 } 109 110 111 /** 112 * Split one line in a CSV file into its rows. Comma's appearing in double quoted strings will 113 * not be seen as a separator. 114 * @return 115 * @throws IOException 116 * @throws FHIRException 117 * @ 118 */ 119 public String[] parseLine() throws IOException, FHIRException { 120 List<String> res = new ArrayList<String>(); 121 StringBuilder b = new StringBuilder(); 122 boolean inQuote = false; 123 124 while (inQuote || (peek() != '\r' && peek() != '\n')) { 125 char c = peek(); 126 next(); 127 if (c == '"') 128 inQuote = !inQuote; 129 else if (!inQuote && c == ',') { 130 res.add(b.toString().trim()); 131 b = new StringBuilder(); 132 } 133 else 134 b.append(c); 135 } 136 res.add(b.toString().trim()); 137 while (ready() && (peek() == '\r' || peek() == '\n')) { 138 next(); 139 } 140 141 String[] r = new String[] {}; 142 r = res.toArray(r); 143 return r; 144 145 } 146 147 private int state = 0; 148 private char pc; 149 150 private char peek() throws FHIRException, IOException 151 { 152 if (state == 0) 153 next(); 154 if (state == 1) 155 return pc; 156 else 157 throw new FHIRException("read past end of source"); 158 } 159 160 private void next() throws FHIRException, IOException 161 { 162 if (state == 2) 163 throw new FHIRException("read past end of source"); 164 state = 1; 165 int i = read(); 166 if (i == -1) 167 state = 2; 168 else 169 pc = (char) i; 170 } 171 172 173}