001: /*
002: * ====================================================================
003: * Copyright (c) 2004 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012:
013: package de.regnis.q.sequence.line.diff;
014:
015: import java.io.*;
016: import java.util.*;
017:
018: import de.regnis.q.sequence.*;
019: import de.regnis.q.sequence.core.*;
020: import de.regnis.q.sequence.line.*;
021: import de.regnis.q.sequence.line.simplifier.*;
022:
023: /**
024: * @author Ian Sullivan
025: * @author TMate Software Ltd.
026: */
027: public abstract class QDiffSequenceGenerator implements QDiffGenerator {
028:
029: // Abstract ===============================================================
030:
031: protected abstract void processBlock(
032: QSequenceDifferenceBlock[] segment,
033: QSequenceLineCache sourceLines,
034: QSequenceLineCache targetLines, String encoding,
035: Writer output) throws IOException;
036:
037: // Fields =================================================================
038:
039: private final String header;
040:
041: private Map myProperties;
042:
043: // Setup ==================================================================
044:
045: protected QDiffSequenceGenerator(Map properties, String header) {
046: this .header = header;
047: myProperties = properties == null ? Collections.EMPTY_MAP
048: : properties;
049: myProperties = Collections.unmodifiableMap(myProperties);
050: }
051:
052: // Implemented ============================================================
053:
054: public void generateBinaryDiff(InputStream left, InputStream right,
055: String encoding, Writer output) throws IOException {
056: println("Binary files are different", output);
057: }
058:
059: public void generateTextDiff(InputStream left, InputStream right,
060: String encoding, Writer output) throws IOException {
061: final QSequenceLineResult result;
062: try {
063: result = QSequenceLineMedia.createBlocks(
064: QSequenceLineRAByteData.create(left),
065: QSequenceLineRAByteData.create(right),
066: getSimplifier());
067: } catch (QSequenceException ex) {
068: throw new IOException(ex.getMessage());
069: }
070:
071: try {
072: final List combinedBlocks = combineBlocks(result
073: .getBlocks(), getGutter());
074:
075: boolean headerWritten = false;
076: for (Iterator it = combinedBlocks.iterator(); it.hasNext();) {
077: List segment = (List) it.next();
078: if (segment.isEmpty()) {
079: continue;
080: }
081:
082: if (!headerWritten && header != null) {
083: headerWritten = true;
084: output.write(header);
085: }
086:
087: QSequenceDifferenceBlock[] segmentBlocks = (QSequenceDifferenceBlock[]) segment
088: .toArray(new QSequenceDifferenceBlock[segment
089: .size()]);
090: processBlock(segmentBlocks, result.getLeftCache(),
091: result.getRightCache(), encoding, output);
092: }
093: } finally {
094: result.close();
095: }
096: }
097:
098: // Accessing ==============================================================
099:
100: protected Map getProperties() {
101: return myProperties;
102: }
103:
104: protected String getEOL() {
105: if (getProperties().get(QDiffGeneratorFactory.EOL_PROPERTY) instanceof String) {
106: return (String) getProperties().get(
107: QDiffGeneratorFactory.EOL_PROPERTY);
108: }
109: return System.getProperty("line.separator", "\n");
110: }
111:
112: protected QSequenceLineSimplifier getSimplifier() {
113: final Object ignore = getProperties().get(
114: QDiffGeneratorFactory.IGNORE_SPACE_PROPERTY);
115: final QSequenceLineSimplifier baseSimplifier;
116: if (QDiffGeneratorFactory.IGNORE_ALL_SPACE.equals(ignore)) {
117: baseSimplifier = new QSequenceLineWhiteSpaceSkippingSimplifier();
118: } else if (QDiffGeneratorFactory.IGNORE_SPACE_CHANGE
119: .equals(ignore)) {
120: baseSimplifier = new QSequenceLineWhiteSpaceReducingSimplifier();
121: } else {
122: baseSimplifier = new QSequenceLineDummySimplifier();
123: }
124:
125: if (getProperties().containsKey(
126: QDiffGeneratorFactory.IGNORE_EOL_PROPERTY)) {
127: return new QSequenceLineTeeSimplifier(baseSimplifier,
128: new QSequenceLineEOLUnifyingSimplifier());
129: }
130:
131: return baseSimplifier;
132: }
133:
134: protected int getGutter() {
135: Object gutterStr = getProperties().get(
136: QDiffGeneratorFactory.GUTTER_PROPERTY);
137: if (gutterStr == null) {
138: return 0;
139: }
140: try {
141: return Integer.parseInt(gutterStr.toString());
142: } catch (NumberFormatException e) {
143: }
144: return 0;
145: }
146:
147: protected String printLine(QSequenceLine line, String encoding)
148: throws IOException {
149: String str = new String(line.getContentBytes(), encoding);
150: return str;
151: }
152:
153: protected void println(Writer output) throws IOException {
154: output.write(getEOL());
155: }
156:
157: protected void println(String str, Writer output)
158: throws IOException {
159: if (str != null) {
160: output.write(str);
161: }
162: output.write(getEOL());
163: }
164:
165: protected void print(String str, Writer output) throws IOException {
166: if (str != null) {
167: output.write(str);
168: }
169: }
170:
171: // Utils ==================================================================
172:
173: private static List combineBlocks(List blocksList, int gutter) {
174: List combinedBlocks = new LinkedList();
175: List currentList = new LinkedList();
176:
177: QSequenceDifferenceBlock lastBlock = null;
178: for (Iterator blocks = blocksList.iterator(); blocks.hasNext();) {
179: QSequenceDifferenceBlock currentBlock = (QSequenceDifferenceBlock) blocks
180: .next();
181: if (lastBlock != null) {
182: if (currentBlock.getLeftFrom() - 1
183: - lastBlock.getLeftTo() > gutter
184: && currentBlock.getRightFrom() - 1
185: - lastBlock.getRightTo() > gutter) {
186: combinedBlocks.add(currentList);
187: currentList = new LinkedList();
188: }
189: }
190: currentList.add(currentBlock);
191: lastBlock = currentBlock;
192: }
193: if (!combinedBlocks.contains(currentList)) {
194: combinedBlocks.add(currentList);
195: }
196: return combinedBlocks;
197: }
198: }
|