1 /******************************************************************************* 2 * Copyright (c) 2000, 2018 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Brock Janiczak <brockj@tpg.com.au> - Bug 181919 LineReader creating unneeded garbage 14 *******************************************************************************/ 15 package org.eclipse.compare.internal.core.patch; 16 17 import java.io.BufferedReader; 18 import java.io.IOException; 19 import java.util.*; 20 21 import org.eclipse.compare.internal.core.ComparePlugin; 22 import org.eclipse.compare.patch.ReaderCreator; 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.CoreException; 25 26 public class LineReader { 27 /** 28 * Reads the contents and returns them as a List of lines. 29 */ load(ReaderCreator content, boolean create)30 public static List<String> load(ReaderCreator content, boolean create) { 31 List<String> lines = null; 32 BufferedReader bufferedReader = null; 33 if (!create && content != null && content.canCreateReader()) { 34 // read current contents 35 try { 36 bufferedReader = new BufferedReader(content.createReader()); 37 lines = readLines(bufferedReader); 38 } catch (CoreException ex) { 39 ComparePlugin.log(ex); 40 } finally { 41 if (bufferedReader != null) { 42 try { 43 bufferedReader.close(); 44 } catch (IOException ex) { 45 // silently ignored 46 } 47 } 48 } 49 } 50 51 if (lines == null) 52 lines = new ArrayList<>(); 53 return lines; 54 } 55 readLines(BufferedReader reader)56 public static List<String> readLines(BufferedReader reader) { 57 List<String> lines; 58 LineReader lr= new LineReader(reader); 59 lr.ignoreSingleCR(); // Don't treat single CRs as line feeds to be consistent with command line patch 60 lines= lr.readLines(); 61 return lines; 62 } 63 64 /* 65 * Concatenates all strings found in the given List. 66 */ createString(boolean preserveLineDelimeters, List<String> lines)67 public static String createString(boolean preserveLineDelimeters, List<String> lines) { 68 StringBuilder sb= new StringBuilder(); 69 Iterator<String> iter= lines.iterator(); 70 if (preserveLineDelimeters) { 71 while (iter.hasNext()) 72 sb.append(iter.next()); 73 } else { 74 String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$ 75 while (iter.hasNext()) { 76 String line= iter.next(); 77 int l= length(line); 78 if (l < line.length()) { // line has delimiter 79 sb.append(line.substring(0, l)); 80 sb.append(lineSeparator); 81 } else { 82 sb.append(line); 83 } 84 } 85 } 86 return sb.toString(); 87 } 88 89 /* 90 * Returns the length (excluding a line delimiter CR, LF, CR/LF) 91 * of the given string. 92 */ length(String s)93 static int length(String s) { 94 int l= s.length(); 95 if (l > 0) { 96 char c= s.charAt(l-1); 97 if (c == '\r') 98 return l-1; 99 if (c == '\n') { 100 if (l > 1 && s.charAt(l-2) == '\r') 101 return l-2; 102 return l-1; 103 } 104 } 105 return l; 106 } 107 108 private boolean fHaveChar= false; 109 private int fLastChar; 110 private boolean fSawEOF= false; 111 private BufferedReader fReader; 112 private boolean fIgnoreSingleCR= false; 113 private StringBuilder fBuffer= new StringBuilder(); 114 LineReader(BufferedReader reader)115 public LineReader(BufferedReader reader) { 116 this.fReader= reader; 117 Assert.isNotNull(reader); 118 } 119 ignoreSingleCR()120 public void ignoreSingleCR() { 121 this.fIgnoreSingleCR= true; 122 } 123 124 /** 125 * Reads a line of text. A line is considered to be terminated by any one 126 * of a line feed ('\n'), a carriage return ('\r'), or a carriage return 127 * followed immediately by a line-feed. 128 * @return A string containing the contents of the line including 129 * the line-termination characters, or <code>null</code> if the end of the 130 * stream has been reached 131 * @exception IOException If an I/O error occurs 132 */ readLine()133 String readLine() throws IOException { 134 try { 135 while (!this.fSawEOF) { 136 int c= readChar(); 137 if (c == -1) { 138 this.fSawEOF= true; 139 break; 140 } 141 this.fBuffer.append((char)c); 142 if (c == '\n') 143 break; 144 if (c == '\r') { 145 c= readChar(); 146 if (c == -1) { 147 this.fSawEOF= true; 148 break; // EOF 149 } 150 if (c != '\n') { 151 if (this.fIgnoreSingleCR) { 152 this.fBuffer.append((char)c); 153 continue; 154 } 155 this.fHaveChar= true; 156 this.fLastChar= c; 157 } else 158 this.fBuffer.append((char)c); 159 break; 160 } 161 } 162 163 if (this.fBuffer.length() != 0) { 164 return this.fBuffer.toString(); 165 } 166 return null; 167 } finally { 168 this.fBuffer.setLength(0); 169 } 170 } 171 close()172 void close() { 173 try { 174 this.fReader.close(); 175 } catch (IOException ex) { 176 // silently ignored 177 } 178 } 179 readLines()180 public List<String> readLines() { 181 try { 182 List<String> lines= new ArrayList<>(); 183 String line; 184 while ((line= readLine()) != null) 185 lines.add(line); 186 return lines; 187 } catch (IOException ex) { 188 // NeedWork 189 //System.out.println("error while reading file: " + fileName + "(" + ex + ")"); 190 } finally { 191 close(); 192 } 193 return null; 194 } 195 196 /* 197 * Returns the number of characters in the given string without 198 * counting a trailing line separator. 199 */ lineContentLength(String line)200 int lineContentLength(String line) { 201 if (line == null) 202 return 0; 203 int length= line.length(); 204 for (int i= length-1; i >= 0; i--) { 205 char c= line.charAt(i); 206 if (c =='\n' || c == '\r') 207 length--; 208 else 209 break; 210 } 211 return length; 212 } 213 214 //---- private 215 readChar()216 private int readChar() throws IOException { 217 if (this.fHaveChar) { 218 this.fHaveChar= false; 219 return this.fLastChar; 220 } 221 return this.fReader.read(); 222 } 223 } 224