/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.diff; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Vector; import org.openflexo.toolbox.FileUtils; import org.openflexo.toolbox.StringUtils; public class DiffSource { private MergeSourceType type; private String sourceString; private File sourceFile; private int ignoredCols = -1; private MergeToken[] textTokens; private String text; private int maxCols = 0; private DelimitingMethod _delimitingMethod = DelimitingMethod.LINES; public class MergeToken { private final int beginDelimStartIndex; private final int beginDelimEndIndex; private final int endDelimStartIndex; private final int endDelimEndIndex; protected MergeToken(int beginDelimStartIndex, int beginDelimEndIndex, int endDelimStartIndex, int endDelimEndIndex) { this.beginDelimStartIndex = beginDelimStartIndex; this.beginDelimEndIndex = beginDelimEndIndex; this.endDelimStartIndex = endDelimStartIndex; this.endDelimEndIndex = endDelimEndIndex; } public String getBeginDelim() { return text.substring(beginDelimStartIndex, beginDelimEndIndex); } public String getEndDelim() { return text.substring(endDelimStartIndex, endDelimEndIndex); } public String getToken() { return text.substring(beginDelimEndIndex, endDelimStartIndex); } public String getFullString() { return text.substring(beginDelimStartIndex, endDelimEndIndex); } @Override public String toString() { return getFullString(); } public int getTokenStartIndex() { return beginDelimEndIndex; } public int getTokenEndIndex() { return endDelimStartIndex; } } public enum MergeSourceType { File, String } public DiffSource(String aString) { this(aString, DelimitingMethod.LINES); } public DiffSource(String aString, DelimitingMethod method) { this(aString, method, -1); } public DiffSource(String aString, int ignoredCols) { this(aString, DelimitingMethod.LINES, ignoredCols); } public DiffSource(String aString, DelimitingMethod method, int ignoredCols) { type = MergeSourceType.String; sourceString = aString; sourceFile = null; this.ignoredCols = ignoredCols; _delimitingMethod = method; if (aString == null) { textTokens = slurpString("", ignoredCols, method); } else { textTokens = slurpString(aString, ignoredCols, method); } } public DiffSource(File aFile) throws IOException { this(aFile, DelimitingMethod.LINES); } public DiffSource(File aFile, DelimitingMethod method) throws IOException { this(aFile, method, -1); } public DiffSource(File aFile, int ignoredCols) throws IOException { this(aFile, DelimitingMethod.LINES, ignoredCols); } public DiffSource(File aFile, DelimitingMethod method, int ignoredCols) throws IOException { type = MergeSourceType.File; sourceString = null; sourceFile = aFile; this.ignoredCols = ignoredCols; _delimitingMethod = method; textTokens = slurpFile(aFile, ignoredCols, method); } public void updateWith(String aString) { sourceString = aString; sourceFile = null; textTokens = slurpString(aString, 0, _delimitingMethod); } public void updateSourceString() { StringBuffer sb = new StringBuffer(); for (int i = 0; i < tokensCount(); i++) { sb.append(tokenValueAt(i) + StringUtils.LINE_SEPARATOR); } sourceString = sb.toString(); } /** * Read a text file into an array of String. This provides basic diff functionality. A more advanced diff utility will use specialized * objects to represent the text lines, with options to, for example, convert sequences of whitespace to a single space for comparison * purposes. */ /*private String[] slurpFile(File file) throws IOException { BufferedReader rdr = new BufferedReader(new FileReader(file)); Vector<String> s = new Vector<String>(); StringBuffer sb = new StringBuffer(); for (;;) { String line = rdr.readLine(); if (line == null) break; s.addElement(line); //System.out.println("File: add line "+line); sb.append(line+"\n"); } text = sb.toString(); textLines = new String[s.size()]; s.copyInto(textLines); return textLines; }*/ /** * Same as above, but ignore first ignoredCols cols */ /*private String[] slurpFile(File file, int ignoredCols) throws IOException { BufferedReader rdr = new BufferedReader(new FileReader(file)); Vector<String> s = new Vector<String>(); StringBuffer sb = new StringBuffer(); for (;;) { String line = rdr.readLine(); if (line == null) break; s.addElement(line.substring(ignoredCols)); //System.out.println("File: add line "+line); sb.append(line.substring(ignoredCols)+"\n"); } text = sb.toString(); textLines = new String[s.size()]; s.copyInto(textLines); return textLines; }*/ /** * Convert a String to an array of String (use \n) */ /*private String[] slurpString(String aString) { if (_delimitingMethod == DelimitingMethod.Lines) { BufferedReader rdr = new BufferedReader(new StringReader(aString)); Vector<String> s = new Vector<String>(); StringBuffer sb = new StringBuffer(); for (;;) { String line = null; try { line = rdr.readLine(); } catch (IOException e) { e.printStackTrace(); } if (line == null) break; s.addElement(line); //System.out.println("String: add line "+line); sb.append(line+"\n"); } text = sb.toString(); textLines = new String[s.size()]; s.copyInto(textLines); return textLines; } else { //String delims = "\t\n\r\f=<>?/"+'"'; String delims = "\t\n\r\f= "; StringTokenizer st = new StringTokenizer(aString,delims,true); Vector<String> s = new Vector<String>(); StringBuffer sb = new StringBuffer(); while (st.hasMoreTokens()) { String token = st.nextToken(); s.addElement(token); System.out.println("String: add token "+token); sb.append(token+"\n"); } text = sb.toString(); textLines = new String[s.size()]; s.copyInto(textLines); return textLines; } }*/ /** * Delete first columns */ private static String deleteFirstColumns(String aString, int ignoredCols) { BufferedReader rdr = new BufferedReader(new StringReader(aString)); Vector<String> s = new Vector<String>(); StringBuffer sb = new StringBuffer(); for (;;) { String line = null; try { line = rdr.readLine(); } catch (IOException e) { e.printStackTrace(); } if (line == null) { break; } s.addElement(line); // System.out.println("String: add line "+line); sb.append(line + StringUtils.LINE_SEPARATOR); } return sb.toString(); } /** * Internally tokenize a File given some ignored cols and a delimiting method * * @throws IOException */ private MergeToken[] slurpFile(File aFile, int ignoredCols, DelimitingMethod delimitingMethod) throws IOException { return slurpString(FileUtils.fileContents(aFile), ignoredCols, delimitingMethod); } private static enum TokenLocation { BEGIN, TOKEN, END; } /** * Internally tokenize a String given some ignored cols and a delimiting method */ private MergeToken[] slurpString(String aString, int ignoredCols, DelimitingMethod delimitingMethod) { if (ignoredCols > 0) { aString = deleteFirstColumns(aString, ignoredCols); } aString = aString.replace("\r", ""); text = aString; _significativeTokens = null; maxCols = 0; String delims = delimitingMethod.getDelimiters(); List<MergeToken> tokens = new ArrayList<MergeToken>(); int index = 0; int beginDelimStartIndex = 0; int beginDelimEndIndex = 0; int endDelimStartIndex = 0; int endDelimEndIndex = 0; TokenLocation location = TokenLocation.BEGIN; while (index < aString.length()) { char c = aString.charAt(index); boolean isDelim = delims.indexOf(c) > -1; boolean isNewLine = c == '\n'; if (isNewLine) { if (location == TokenLocation.BEGIN) { beginDelimEndIndex = index; } if (location == TokenLocation.BEGIN || location == TokenLocation.TOKEN) { endDelimStartIndex = index; } location = TokenLocation.END; } switch (location) { case BEGIN: if (!isDelim) { beginDelimEndIndex = index; location = TokenLocation.TOKEN; } break; case END: if (!isDelim || isNewLine) { endDelimEndIndex = isNewLine ? index + 1 : index; if (beginDelimStartIndex < endDelimEndIndex) { tokens.add(new MergeToken(beginDelimStartIndex, beginDelimEndIndex, endDelimStartIndex, endDelimEndIndex)); } beginDelimStartIndex = endDelimEndIndex; if (isNewLine) { location = TokenLocation.BEGIN; } else { location = TokenLocation.TOKEN; } } break; case TOKEN: if (isDelim) { endDelimStartIndex = index; location = TokenLocation.END; } break; } index++; } switch (location) { case BEGIN: beginDelimEndIndex = index; case TOKEN: endDelimStartIndex = index; case END: endDelimEndIndex = index; } if (beginDelimStartIndex < endDelimEndIndex) { tokens.add(new MergeToken(beginDelimStartIndex, beginDelimEndIndex, endDelimStartIndex, endDelimEndIndex)); } return textTokens = tokens.toArray(new MergeToken[tokens.size()]); } /** * Same as above, but ignore first ignoredCols cols */ /*private String[] slurpString(String aString, int ignoredCols) { BufferedReader rdr = new BufferedReader(new StringReader(aString)); Vector<String> s = new Vector<String>(); StringBuffer sb = new StringBuffer(); for (;;) { String line = null; try { line = rdr.readLine(); } catch (IOException e) { e.printStackTrace(); } if (line == null) break; s.addElement(line.substring(ignoredCols)); sb.append(line.substring(ignoredCols)+"\n"); } text = sb.toString(); textLines = new String[s.size()]; s.copyInto(textLines); return textLines; }*/ public int getIgnoredCols() { return ignoredCols; } public File getSourceFile() { return sourceFile; } public String getSourceString() { return sourceString; } public MergeToken[] getTextTokens() { return textTokens; } private String[] _significativeTokens; public String[] getSignificativeTokens() { if (_significativeTokens == null) { _significativeTokens = new String[textTokens.length]; } for (int i = 0; i < textTokens.length; i++) { _significativeTokens[i] = textTokens[i].getToken(); } return _significativeTokens; } public MergeToken tokenAt(int index) { if (index < textTokens.length) { return textTokens[index]; } else { return null; } } public String tokenValueAt(int index) { if (index < textTokens.length) { return textTokens[index].getToken(); } else { return "???"; } } public int tokensCount() { return textTokens.length; } public String getText() { return text; } public MergeSourceType getType() { return type; } public String extractText(int beginIndex, int endIndex) { StringBuffer returned = new StringBuffer(); for (int i = beginIndex; i <= endIndex; i++) { if (i >= 0 && i < textTokens.length) { returned.append(textTokens[i].getFullString()); } } return returned.toString(); } public DelimitingMethod getDelimitingMethod() { return _delimitingMethod; } public int getMaxCols() { return maxCols; } }