diff --git a/source/org/apache/commons/jrcs/diff/AddDelta.java b/source/org/apache/commons/jrcs/diff/AddDelta.java new file mode 100644 index 0000000..f116392 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/AddDelta.java @@ -0,0 +1,131 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.List; + +/** + * Holds an add-delta between to revisions of a text. + * + * @version $Id: AddDelta.java,v 1.1 2003/07/14 12:22:29 dchandler Exp $ + * @author Juanco Anez + * @see Delta + * @see Diff + * @see Chunk + */ +public class AddDelta + extends Delta +{ + + AddDelta() + { + super(); + } + + public AddDelta(int origpos, Chunk rev) + { + init(new Chunk(origpos, 0), rev); + } + + public void verify(List target) throws PatchFailedException + { + if (original.first() > target.size()) + { + throw new PatchFailedException("original.first() > target.size()"); + } + } + + public void applyTo(List target) + { + revised.applyAdd(original.first(), target); + } + + public void toString(StringBuffer s) + { + s.append(original.anchor()); + s.append("a"); + s.append(revised.rangeString()); + s.append(Diff.NL); + revised.toString(s, "> ", Diff.NL); + } + + public void toRCSString(StringBuffer s, String EOL) + { + s.append("a"); + s.append(original.anchor()); + s.append(" "); + s.append(revised.size()); + s.append(EOL); + revised.toString(s, "", EOL); + } + + public void Accept(RevisionVisitor visitor) + { + visitor.visit(this); + } + + public void accept(RevisionVisitor visitor) + { + visitor.visit(this); + } +} + + + + + diff --git a/source/org/apache/commons/jrcs/diff/ChangeDelta.java b/source/org/apache/commons/jrcs/diff/ChangeDelta.java new file mode 100644 index 0000000..d3194f5 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/ChangeDelta.java @@ -0,0 +1,134 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.List; + +/** + * Holds an change-delta between to revisions of a text. + * + * @version $Id: ChangeDelta.java,v 1.1 2003/07/14 12:22:29 dchandler Exp $ + * @author Juanco Anez + * @see Delta + * @see Diff + * @see Chunk + */ +public class ChangeDelta extends Delta +{ + + ChangeDelta() + { + super(); + } + + public ChangeDelta(Chunk orig, Chunk rev) + { + init(orig, rev); + } + + public void verify(List target) throws PatchFailedException + { + if (!original.verify(target)) + { + throw new PatchFailedException(); + } + if (original.first() > target.size()) + { + throw new PatchFailedException("original.first() > target.size()"); + } + } + + public void applyTo(List target) + { + original.applyDelete(target); + revised.applyAdd(original.first(), target); + } + + public void toString(StringBuffer s) + { + original.rangeString(s); + s.append("c"); + revised.rangeString(s); + s.append(Diff.NL); + original.toString(s, "< ", "\n"); + s.append("---"); + s.append(Diff.NL); + revised.toString(s, "> ", "\n"); + } + + public void toRCSString(StringBuffer s, String EOL) + { + s.append("d"); + s.append(original.rcsfrom()); + s.append(" "); + s.append(original.size()); + s.append(EOL); + s.append("a"); + s.append(original.rcsto()); + s.append(" "); + s.append(revised.size()); + s.append(EOL); + revised.toString(s, "", EOL); + } + + public void accept(RevisionVisitor visitor) + { + visitor.visit(this); + } +} + diff --git a/source/org/apache/commons/jrcs/diff/Chunk.java b/source/org/apache/commons/jrcs/diff/Chunk.java new file mode 100644 index 0000000..250f478 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/Chunk.java @@ -0,0 +1,357 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * Holds a information about a parrt of the text involved in + * a differencing or patching operation. + * + * @version $Id: Chunk.java,v 1.1 2003/07/14 12:22:29 dchandler Exp $ + * @author Juanco Anez + * @see Diff + * @see Delta + */ +public class Chunk + extends org.apache.commons.jrcs.util.ToString +{ + + protected int anchor; + + protected int count; + + protected List chunk; + + /** + * Creates a chunk that doesn't copy the original text. + * @param pos the start position in the text. + * @param count the size of the chunk. + */ + public Chunk(int pos, int count) + { + this.anchor = pos; + this.count = (count >= 0 ? count : 0); + } + + /** + * Creates a chunk and saves a copy the original chunk's text. + * @param iseq the original text. + * @param pos the start position in the text. + * @param count the size of the chunk. + */ + public Chunk(Object[] iseq, int pos, int count) + { + this(pos, count); + chunk = slice(iseq, pos, count); + } + + /** + * Creates a chunk that will be displaced in the resulting text, + * and saves a copy the original chunk's text. + * @param iseq the original text. + * @param pos the start position in the text. + * @param count the size of the chunk. + * @param offset the position the chunk should have in the resulting text. + */ + public Chunk(Object[] iseq, int pos, int count, int offset) + { + this(offset, count); + chunk = slice(iseq, pos, count); + } + + /** + * Creates a chunk and saves a copy the original chunk's text. + * @param iseq the original text. + * @param pos the start position in the text. + * @param count the size of the chunk. + */ + public Chunk(List iseq, int pos, int count) + { + this(pos, count); + chunk = slice(iseq, pos, count); + } + + /** + * Creates a chunk that will be displaced in the resulting text, + * and saves a copy the original chunk's text. + * @param iseq the original text. + * @param pos the start position in the text. + * @param count the size of the chunk. + * @param offset the position the chunk should have in the resulting text. + */ + public Chunk(List iseq, int pos, int count, int offset) + { + this(offset, count); + chunk = slice(iseq, pos, count); + } + + /** + * Returns the anchor position of the chunk. + * @return the anchor position. + */ + public int anchor() + { + return anchor; + } + + /** + * Returns the size of the chunk. + * @return the size. + */ + public int size() + { + return count; + } + + /** + * Returns the index of the first line of the chunk. + */ + public int first() + { + return anchor(); + } + + /** + * Returns the index of the last line of the chunk. + */ + public int last() + { + return anchor() + size() - 1; + } + + /** + * Returns the from index of the chunk in RCS terms. + */ + public int rcsfrom() + { + return anchor + 1; + } + + /** + * Returns the to index of the chunk in RCS terms. + */ + public int rcsto() + { + return anchor + count; + } + + /** + * Returns the text saved for this chunk. + * @return the text. + */ + public List chunk() + { + return chunk; + } + + /** + * Verifies that this chunk's saved text matches the corresponding + * text in the given sequence. + * @param target the sequence to verify against. + * @return true if the texts match. + */ + public boolean verify(List target) + { + if (chunk == null) + { + return true; + } + if (last() > target.size()) + { + return false; + } + for (int i = 0; i < count; i++) + { + if (!target.get(anchor + i).equals(chunk.get(i))) + { + return false; + } + } + return true; + } + + /** + * Delete this chunk from he given text. + * @param target the text to delete from. + */ + public void applyDelete(List target) + { + for (int i = last(); i >= first(); i--) + { + target.remove(i); + } + } + + /** + * Add the text of this chunk to the target at the given position. + * @param start where to add the text. + * @param target the text to add to. + */ + public void applyAdd(int start, List target) + { + Iterator i = chunk.iterator(); + while (i.hasNext()) + { + target.add(start++, i.next()); + } + } + + /** + * Provide a string image of the chunk using the an empty prefix and + * postfix. + */ + public void toString(StringBuffer s) + { + toString(s, "", ""); + } + + /** + * Provide a string image of the chunk using the given prefix and + * postfix. + * @param s where the string image should be appended. + * @param prefix the text thatshould prefix each line. + * @param postfix the text that should end each line. + */ + public StringBuffer toString(StringBuffer s, String prefix, String postfix) + { + if (chunk != null) + { + Iterator i = chunk.iterator(); + while (i.hasNext()) + { + s.append(prefix); + s.append(i.next()); + s.append(postfix); + } + } + return s; + } + + /** + * Retreives the specified part from a {@link List List}. + * @param seq the list to retreive a slice from. + * @param pos the start position. + * @param count the number of items in the slice. + * @return a {@link List List} containing the specified items. + */ + public static List slice(List seq, int pos, int count) + { + if (count <= 0) + { + return new ArrayList(seq.subList(pos, pos)); + } + else + { + return new ArrayList(seq.subList(pos, pos + count)); + } + } + + /** + * Retrieves a slice from an {@link Object Object} array. + * @param seq the list to retreive a slice from. + * @param pos the start position. + * @param count the number of items in the slice. + * @return a {@link List List} containing the specified items. + */ + public static List slice(Object[] seq, int pos, int count) + { + return slice(Arrays.asList(seq), pos, count); + } + + /** + * Provide a string representation of the numeric range of this chunk. + */ + public String rangeString() + { + StringBuffer result = new StringBuffer(); + rangeString(result); + return result.toString(); + } + + /** + * Provide a string representation of the numeric range of this chunk. + * @param s where the string representation should be appended. + */ + public void rangeString(StringBuffer s) + { + rangeString(s, ","); + } + + /** + * Provide a string representation of the numeric range of this chunk. + * @param s where the string representation should be appended. + * @param separ what to use as line separator. + */ + public void rangeString(StringBuffer s, String separ) + { + if (size() <= 1) + { + s.append(Integer.toString(rcsfrom())); + } + else + { + s.append(Integer.toString(rcsfrom())); + s.append(separ); + s.append(Integer.toString(rcsto())); + } + } +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/DeleteDelta.java b/source/org/apache/commons/jrcs/diff/DeleteDelta.java new file mode 100644 index 0000000..bafaa94 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/DeleteDelta.java @@ -0,0 +1,121 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.List; + +/** + * Holds a delete-delta between to revisions of a text. + * + * @version $Id: DeleteDelta.java,v 1.1 2003/07/14 12:22:29 dchandler Exp $ + * @author Juanco Anez + * @see Delta + * @see Diff + * @see Chunk + */ +public class DeleteDelta + extends Delta +{ + + DeleteDelta() + { + super(); + } + + public DeleteDelta(Chunk orig) + { + init(orig, null); + } + + public void verify(List target) + throws PatchFailedException + { + if (!original.verify(target)) + { + throw new PatchFailedException(); + } + } + + public void applyTo(List target) + { + original.applyDelete(target); + } + + public void toString(StringBuffer s) + { + s.append(original.rangeString()); + s.append("d"); + s.append(revised.rcsto()); + s.append(Diff.NL); + original.toString(s, "< ", Diff.NL); + } + + public void toRCSString(StringBuffer s, String EOL) + { + s.append("d"); + s.append(original.rcsfrom()); + s.append(" "); + s.append(original.size()); + s.append(EOL); + } + + public void accept(RevisionVisitor visitor) + { + visitor.visit(this); + } +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/Delta.java b/source/org/apache/commons/jrcs/diff/Delta.java new file mode 100644 index 0000000..5f7243b --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/Delta.java @@ -0,0 +1,255 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.List; + +/** + * Holds a "delta" difference between to revisions of a text. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * + * @author Juanco Anez + * @author Brian McBride + * @see Diff + * @see Chunk + * @see Revision + * + * modifications + * + * 27 Apr 2003 bwm + * + * Added getOriginal() and getRevised() accessor methods + * Added visitor pattern accept() method + */ + +public abstract class Delta + extends org.apache.commons.jrcs.util.ToString +{ + + protected Chunk original; + + protected Chunk revised; + + static Class[][] DeltaClass; + + static + { + DeltaClass = new Class[2][2]; + try + { + DeltaClass[0][0] = org.apache.commons.jrcs.diff.ChangeDelta.class; + DeltaClass[0][1] = org.apache.commons.jrcs.diff.AddDelta.class; + DeltaClass[1][0] = org.apache.commons.jrcs.diff.DeleteDelta.class; + DeltaClass[1][1] = org.apache.commons.jrcs.diff.ChangeDelta.class; + } + catch (Throwable o) + { + + } + } + + /** + * Returns a Delta that corresponds to the given chunks in the + * original and revised text respectively. + * @param orig the chunk in the original text. + * @param rev the chunk in the revised text. + */ + public static Delta newDelta(Chunk orig, Chunk rev) + { + Class c = DeltaClass[orig.size() > 0 ? 1 : 0] + [rev.size() > 0 ? 1 : 0]; + Delta result; + try + { + result = (Delta) c.newInstance(); + } + catch (Throwable e) + { + return null; + } + result.init(orig, rev); + return result; + } + + /** + * Creates an uninitialized delta. + */ + protected Delta() + { + } + + /** + * Creates a delta object with the given chunks from the original + * and revised texts. + */ + protected Delta(Chunk orig, Chunk rev) + { + init(orig, rev); + } + + /** + * Initializaes the delta with the given chunks from the original + * and revised texts. + */ + protected void init(Chunk orig, Chunk rev) + { + original = orig; + revised = rev; + } + + /** + * Verifies that this delta can be used to patch the given text. + * @param target the text to patch. + * @throws PatchFailedException if the patch cannot be applied. + */ + public abstract void verify(List target) + throws PatchFailedException; + + /** + * Applies this delta as a patch to the given text. + * @param target the text to patch. + * @throws PatchFailedException if the patch cannot be applied. + */ + public final void patch(List target) + throws PatchFailedException + { + verify(target); + try + { + applyTo(target); + } + catch (Exception e) + { + throw new PatchFailedException(e.getMessage()); + } + } + + /** + * Applies this delta as a patch to the given text. + * @param target the text to patch. + * @throws PatchFailedException if the patch cannot be applied. + */ + public abstract void applyTo(List target); + + /** + * Converts this delta into its Unix diff style string representation. + * @param s a {@link StringBuffer StringBuffer} to which the string + * representation will be appended. + */ + public void toString(StringBuffer s) + { + original.rangeString(s); + s.append("x"); + revised.rangeString(s); + s.append(Diff.NL); + original.toString(s, "> ", "\n"); + s.append("---"); + s.append(Diff.NL); + revised.toString(s, "< ", "\n"); + } + + /** + * Converts this delta into its RCS style string representation. + * @param s a {@link StringBuffer StringBuffer} to which the string + * representation will be appended. + * @param EOL the string to use as line separator. + */ + public abstract void toRCSString(StringBuffer s, String EOL); + + /** + * Converts this delta into its RCS style string representation. + * @param EOL the string to use as line separator. + */ + public String toRCSString(String EOL) + { + StringBuffer s = new StringBuffer(); + toRCSString(s, EOL); + return s.toString(); + } + + /** + * Accessor method to return the chunk representing the original + * sequence of items + * + * @return the original sequence + */ + public Chunk getOriginal() + { + return original; + } + + /** + * Accessor method to return the chunk representing the updated + * sequence of items. + * + * @return the updated sequence + */ + public Chunk getRevised() + { + return revised; + } + + /** + * Accepts a visitor. + *

+ * See the Visitor pattern in "Design Patterns" by the GOF4. + * @param visitor The visitor. + */ + public abstract void accept(RevisionVisitor visitor); +} diff --git a/source/org/apache/commons/jrcs/diff/Diff.java b/source/org/apache/commons/jrcs/diff/Diff.java new file mode 100644 index 0000000..0353d26 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/Diff.java @@ -0,0 +1,344 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.*; + +import org.apache.commons.jrcs.diff.myers.MyersDiff; +import org.apache.commons.jrcs.util.ToString; + +/** + * Implements a differencing engine that works on arrays of {@link Object Object}. + * + *

Within this library, the word text means a unit of information + * subject to version control. + * + *

Text is represented as Object[] because + * the diff engine is capable of handling more than plain ascci. In fact, + * arrays of any type that implements + * {@link java.lang.Object#hashCode hashCode()} and + * {@link java.lang.Object#equals equals()} + * correctly can be subject to differencing using this + * library.

+ * + *

This library provides a framework in which different differencing + * algorithms may be used. If no algorithm is specififed, a default + * algorithm is used.

+ * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * @author Juanco Anez + * @see Delta + * @see DiffAlgorithm + * + * modifications: + * + * 27 Apr 2003 bwm + * + * Added some comments whilst trying to figure out the algorithm + * + * 03 May 2003 bwm + * + * Factored out the algorithm implementation into a separate difference + * algorithm class to allow pluggable algorithms. + */ + +public class Diff + extends ToString +{ + /** The standard line separator. */ + public static final String NL = System.getProperty("line.separator"); + + /** The line separator to use in RCS format output. */ + public static final String RCS_EOL = "\n"; + + /** The original sequence. */ + protected final Object[] orig; + + /** The differencing algorithm to use. */ + protected DiffAlgorithm algorithm; + + /** + * Create a differencing object using the default algorithm + * + * @param the original text that will be compared + */ + public Diff(Object[] original) + { + this(original, null); + } + + /** + * Create a differencing object using the given algorithm + * + * @param o the original text which will be compared against + * @param algorithm the difference algorithm to use. + */ + public Diff(Object[] original, DiffAlgorithm algorithm) + { + if (original == null) + { + throw new IllegalArgumentException(); + } + + this.orig = original; + if (algorithm != null) + this.algorithm = algorithm; + else + this.algorithm = defaultAlgorithm(); + } + + protected DiffAlgorithm defaultAlgorithm() + { + return new MyersDiff(); + } + + /** + * compute the difference between an original and a revision. + * + * @param orig the original + * @param rev the revision to compare with the original. + * @return a Revision describing the differences + */ + public static Revision diff(Object[] orig, Object[] rev) + throws DifferentiationFailedException + { + if (orig == null || rev == null) + { + throw new IllegalArgumentException(); + } + + return diff(orig, rev, null); + } + + /** + * compute the difference between an original and a revision. + * + * @param orig the original + * @param rev the revision to compare with the original. + * @param algorithm the difference algorithm to use + * @return a Revision describing the differences + */ + public static Revision diff(Object[] orig, Object[] rev, + DiffAlgorithm algorithm) + throws DifferentiationFailedException + { + if (orig == null || rev == null) + { + throw new IllegalArgumentException(); + } + + return new Diff(orig, algorithm).diff(rev); + } + + /** + * compute the difference between the original and a revision. + * + * @param rev the revision to compare with the original. + * @return a Revision describing the differences + */ + public Revision diff(Object[] rev) + throws DifferentiationFailedException + { + return algorithm.diff(orig, rev); + } + + /** + * Compares the two input sequences. + * @param orig The original sequence. + * @param rev The revised sequence. + * @return true if the sequences are identical. False otherwise. + */ + public static boolean compare(Object[] orig, Object[] rev) + { + if (orig.length != rev.length) + { + return false; + } + else + { + for (int i = 0; i < orig.length; i++) + { + if (!orig[i].equals(rev[i])) + { + return false; + } + } + return true; + } + } + + /** + * Converts an array of {@link Object Object} to a string + * using {@link Diff#NL Diff.NL} + * as the line separator. + * @param o the array of objects. + */ + public static String arrayToString(Object[] o) + { + return arrayToString(o, Diff.NL); + } + + /** + * Edits all of the items in the input sequence. + * @param text The input sequence. + * @return A sequence of the same length with all the lines + * differing from the corresponding ones in the input. + */ + public static Object[] editAll(Object[] text) + { + Object[] result = new String[text.length]; + + for(int i = 0; i < text.length; i++) + result[i] = text[i] + " "; + + return result; + } + + /** + * Performs random edits on the input sequence. Useful for testing. + * @param text The input sequence. + * @return The sequence with random edits performed. + */ + public static Object[] randomEdit(Object[] text) + { + return randomEdit(text, text.length); + } + + /** + * Performs random edits on the input sequence. Useful for testing. + * @param text The input sequence. + * @param seed A seed value for the randomizer. + * @return The sequence with random edits performed. + */ + public static Object[] randomEdit(Object[] text, long seed) + { + List result = new ArrayList(Arrays.asList(text)); + Random r = new Random(seed); + int nops = r.nextInt(10); + for (int i = 0; i < nops; i++) + { + boolean del = r.nextBoolean(); + int pos = r.nextInt(result.size() + 1); + int len = Math.min(result.size() - pos, 1 + r.nextInt(4)); + if (del && result.size() > 0) + { // delete + result.subList(pos, pos + len).clear(); + } + else + { + for (int k = 0; k < len; k++, pos++) + { + result.add(pos, + "[" + i + "] random edit[" + i + "][" + i + "]"); + } + } + } + return result.toArray(); + } + + /** + * Shuffles around the items in the input sequence. + * @param text The input sequence. + * @return The shuffled sequence. + */ + public static Object[] shuffle(Object[] text) + { + return shuffle(text, text.length); + } + + /** + * Shuffles around the items in the input sequence. + * @param text The input sequence. + * @param seed A seed value for randomizing the suffle. + * @return The shuffled sequence. + */ + public static Object[] shuffle(Object[] text, long seed) + { + List result = new ArrayList(Arrays.asList(text)); + Collections.shuffle(result); + return result.toArray(); + } + + /** + * Generate a random sequence of the given size. + * @param The size of the sequence to generate. + * @return The generated sequence. + */ + public static Object[] randomSequence(int size) + { + return randomSequence(size, size); + } + + /** + * Generate a random sequence of the given size. + * @param The size of the sequence to generate. + * @param seed A seed value for randomizing the generation. + * @return The generated sequence. + */ + public static Object[] randomSequence(int size, long seed) + { + Integer[] result = new Integer[size]; + Random r = new Random(seed); + for(int i = 0; i < result.length; i++) + { + result[i] = new Integer(r.nextInt(size)); + } + return result; + } + +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/DiffAlgorithm.java b/source/org/apache/commons/jrcs/diff/DiffAlgorithm.java new file mode 100644 index 0000000..bedd52c --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/DiffAlgorithm.java @@ -0,0 +1,84 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +/** + * A simple interface for implementations of differencing algorithms. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * + * @author Brian McBride + */ +public interface DiffAlgorithm +{ + /** + * Computes the difference between the original + * sequence and the revised sequence and returns it + * as a {@link org.apache.commons.jrcs.diff.Revision Revision} + * object. + *

+ * The revision can be used to construct the revised sequence + * from the original sequence. + * + * @param rev the revised text + * @return the revision script. + * @throws DifferentiationFailedException if the diff could not be computed. + */ + public abstract Revision diff(Object[] orig, Object[] rev) + throws DifferentiationFailedException; +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/DiffException.java b/source/org/apache/commons/jrcs/diff/DiffException.java new file mode 100644 index 0000000..069ff59 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/DiffException.java @@ -0,0 +1,79 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +/** + * Base class for all exceptions emanating from this package. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * + * @author Juanco Anez + */ +public class DiffException extends Exception +{ + + public DiffException() + { + } + + public DiffException(String msg) + { + super(msg); + } +} + diff --git a/source/org/apache/commons/jrcs/diff/DifferentiationFailedException.java b/source/org/apache/commons/jrcs/diff/DifferentiationFailedException.java new file mode 100644 index 0000000..e3dc004 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/DifferentiationFailedException.java @@ -0,0 +1,82 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +/** + * Thrown whenever the differencing engine cannot produce the differences + * between two revisions of ta text. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * + * @author Juanco Anez + * @see Diff + * @see DiffAlgorithm + */ +public class DifferentiationFailedException extends DiffException +{ + + public DifferentiationFailedException() + { + } + + public DifferentiationFailedException(String msg) + { + super(msg); + } +} + diff --git a/source/org/apache/commons/jrcs/diff/PatchFailedException.java b/source/org/apache/commons/jrcs/diff/PatchFailedException.java new file mode 100644 index 0000000..3314794 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/PatchFailedException.java @@ -0,0 +1,82 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +/** + * Thrown whenever a delta cannot be applied as a patch to a given text. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * @author Juanco Anez + * @see Delta + * @see Diff + */ +public class PatchFailedException extends DiffException +{ + + public PatchFailedException() + { + } + + public PatchFailedException(String msg) + { + super(msg); + } +} + + + diff --git a/source/org/apache/commons/jrcs/diff/Revision.java b/source/org/apache/commons/jrcs/diff/Revision.java new file mode 100644 index 0000000..d5c9a02 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/Revision.java @@ -0,0 +1,253 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.jrcs.util.ToString; + + +/** + * A Revision holds the series of deltas that describe the differences + * between two sequences. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * + * @author Juanco Anez + * @author Brian McBride + * + * @see Delta + * @see Diff + * @see Chunk + * @see Revision + * + * modifications + * 27 Apr 2003 bwm + * + * Added visitor pattern Visitor interface and accept() method. + */ + +public class Revision + extends ToString +{ + + List deltas_ = new LinkedList(); + + + /** + * Creates an empty Revision. + */ + public Revision() + { + } + + + /** + * Adds a delta to this revision. + * @param delta the {@link Delta Delta} to add. + */ + public synchronized void addDelta(Delta delta) + { + if (delta == null) + { + throw new IllegalArgumentException("new delta is null"); + } + deltas_.add(delta); + } + + + /** + * Adds a delta to the start of this revision. + * @param delta the {@link Delta Delta} to add. + */ + public synchronized void insertDelta(Delta delta) + { + if (delta == null) + { + throw new IllegalArgumentException("new delta is null"); + } + deltas_.add(0, delta); + } + + + /** + * Retrieves a delta from this revision by position. + * @param i the position of the delta to retrieve. + * @return the specified delta + */ + public Delta getDelta(int i) + { + return (Delta) deltas_.get(i); + } + + /** + * Returns the number of deltas in this revision. + * @return the number of deltas. + */ + public int size() + { + return deltas_.size(); + } + + /** + * Applies the series of deltas in this revision as patches to + * the given text. + * @param src the text to patch, which the method doesn't change. + * @return the resulting text after the patches have been applied. + * @throws PatchFailedException if any of the patches cannot be applied. + */ + public Object[] patch(Object[] src) throws PatchFailedException + { + List target = new ArrayList(Arrays.asList(src)); + applyTo(target); + return target.toArray(); + } + + /** + * Applies the series of deltas in this revision as patches to + * the given text. + * @param target the text to patch. + * @throws PatchFailedException if any of the patches cannot be applied. + */ + public synchronized void applyTo(List target) throws PatchFailedException + { + ListIterator i = deltas_.listIterator(deltas_.size()); + while (i.hasPrevious()) + { + Delta delta = (Delta) i.previous(); + delta.patch(target); + } + } + + /** + * Converts this revision into its Unix diff style string representation. + * @param s a {@link StringBuffer StringBuffer} to which the string + * representation will be appended. + */ + public synchronized void toString(StringBuffer s) + { + Iterator i = deltas_.iterator(); + while (i.hasNext()) + { + ((Delta) i.next()).toString(s); + } + } + + /** + * Converts this revision into its RCS style string representation. + * @param s a {@link StringBuffer StringBuffer} to which the string + * representation will be appended. + * @param EOL the string to use as line separator. + */ + public synchronized void toRCSString(StringBuffer s, String EOL) + { + Iterator i = deltas_.iterator(); + while (i.hasNext()) + { + ((Delta) i.next()).toRCSString(s, EOL); + } + } + + /** + * Converts this revision into its RCS style string representation. + * @param s a {@link StringBuffer StringBuffer} to which the string + * representation will be appended. + */ + public void toRCSString(StringBuffer s) + { + toRCSString(s, Diff.NL); + } + + /** + * Converts this delta into its RCS style string representation. + * @param EOL the string to use as line separator. + */ + public String toRCSString(String EOL) + { + StringBuffer s = new StringBuffer(); + toRCSString(s, EOL); + return s.toString(); + } + + /** + * Converts this delta into its RCS style string representation + * using the default line separator. + */ + public String toRCSString() + { + return toRCSString(Diff.NL); + } + + /** + * Accepts a visitor. + * @param visitor the {@link Visitor} visiting this instance + */ + public void accept(RevisionVisitor visitor) { + visitor.visit(this); + Iterator iter = deltas_.iterator(); + while (iter.hasNext()) { + ((Delta) iter.next()).accept(visitor); + } + } + +} diff --git a/source/org/apache/commons/jrcs/diff/RevisionVisitor.java b/source/org/apache/commons/jrcs/diff/RevisionVisitor.java new file mode 100644 index 0000000..d7bd7ad --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/RevisionVisitor.java @@ -0,0 +1,73 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +/** + * Definition of a Visitor interface for {@link Revision Revisions} + * See "Design Patterns" by the Gang of Four + */ +public interface RevisionVisitor +{ + public void visit(Revision revision); + + public void visit(DeleteDelta delta); + + public void visit(ChangeDelta delta); + + public void visit(AddDelta delta); +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/SimpleDiff.java b/source/org/apache/commons/jrcs/diff/SimpleDiff.java new file mode 100644 index 0000000..2ae0608 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/SimpleDiff.java @@ -0,0 +1,315 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff; + +import java.util.*; + +/** + * Implements a simple differencing algortithm.

+ * + * @date $Date: 2003/07/14 12:22:29 $ + * @version $Revision: 1.1 $ + * @author Juanco Anez + * + *

Overview of Algorithm

+ * + *

by bwm + *

+ * + *

The algorithm is optimised for situations where the input sequences + * have few repeated objects. If it is given input with many repeated + * objects it will report sub-optimal changes. However, given appropriate + * input, it is fast, and linear in memory usage.

+ * + *

The algorithm consists of the following steps:

+ *
    + *
  • compute an equivalence set for the input data
  • + *
  • translate each element of the orginal + * and revised input sequences to a member of the equivalence set + *
  • + *
  • match the the input sequences to determine the deltas, i.e. + * the differences between the original and revised sequences.
  • + *
+ * + *

The first step is to compute a an equivalence set for the input data. + * The equivalence set is computed from objects that are in the original + * input sequence

+ *
+ *   eq(x) = the index of the first occurence of x in the original sequence.
+ * 
+ * + *

With this equivalence function, the algorithm can compare integers rather + * than strings, which is considerably more efficient.

+ * + *

The second step is to compute the datastructure on which the + * algorithm will operate. Having computed the equivalence function + * in the previous step, we can compute two arrays where + * indx[i] = eqs(orig[i]) and jndx[i] = eqs(rev[i]). The algorithm can + * now operate on indx and jndx instead of orig and rev. Thus, comparisons + * are then on O(int == int) instead of O(Object.equals(Object)). + *

+ * + *

The algorithm now matches indx and jndx. Whilst indx[i] == jndx[i] + * it skips matching objects in the sequence. In seeking to match objects + * in the input sequence it assumes that each object is likely to be unique. + * It uses the known characteristics of the unique equivalence function. It can + * tell from the eq value if this object appeared in the other sequence + * at all. If it did not, there is no point in searching for a match.

+ * + *

Recall that the eq function value is the index earliest occurrence in + * the orig sequence. This information is used to search efficiently for + * the next match. The algorithm is perfect when all input objects are + * unique, but degrades when input objects are not unique. When input + * objects are not unique an optimal match may not be found, but a + * correct match will be.

+ * + *

Having identified common matching objects in the orig and revised + * sequences, the differences between them are easily computed. + *

+ * + * @see Delta + * @see Revision + * Modifications: + * + * 27/Apr/2003 bwm + * Added some comments whilst trying to figure out the algorithm + * + * 03 May 2003 bwm + * Created this implementation class by refactoring it out of the Diff + * class to enable plug in difference algorithms + * + */ +public class SimpleDiff + implements DiffAlgorithm +{ + + static final int NOT_FOUND_i = -2; + static final int NOT_FOUND_j = -1; + static final int EOS = Integer.MAX_VALUE; + + public SimpleDiff() + { + } + + protected int scan(int[] ndx, int i, int target) + { + while (ndx[i] < target) + { + i++; + } + return i; + } + + /** + * Compute the difference between original and revised sequences. + * + * @param orig The original sequence. + * @param rev The revised sequence to be compared with the original. + * @return A Revision object describing the differences. + * @throws DifferenciationFailedException if the diff could not be computed. + */ + public Revision diff(Object[] orig, Object[] rev) + throws DifferentiationFailedException + { + // create map eqs, such that for each item in both orig and rev + // eqs(item) = firstOccurrence(item, orig); + Map eqs = buildEqSet(orig, rev); + + // create an array such that + // indx[i] = NOT_FOUND_i if orig[i] is not in rev + // indx[i] = firstOccurrence(orig[i], orig) + int[] indx = buildIndex(eqs, orig, NOT_FOUND_i); + + // create an array such that + // jndx[j] = NOT_FOUND_j if orig[j] is not in rev + // jndx[j] = firstOccurrence(rev[j], orig) + int[] jndx = buildIndex(eqs, rev, NOT_FOUND_j); + + // what in effect has been done is to build a unique hash + // for each item that is in both orig and rev + // and to label each item in orig and new with that hash value + // or a marker that the item is not common to both. + + eqs = null; // let gc know we're done with this + + Revision deltas = new Revision(); //!!! new Revision() + int i = 0; + int j = 0; + + // skip matching + // skip leading items that are equal + // could be written + // for (i=0; indx[i] != EOS && indx[i] == jndx[i]; i++); + // j = i; + for (; indx[i] != EOS && indx[i] == jndx[j]; i++, j++) + { + /* void */ + } + + while (indx[i] != jndx[j]) + { // only equal if both == EOS + // they are different + int ia = i; + int ja = j; + + // size of this delta + do + { + // look down rev for a match + // stop at a match + // or if the FO(rev[j]) > FO(orig[i]) + // or at the end + while (jndx[j] < 0 || jndx[j] < indx[i]) + { + j++; + } + // look down orig for a match + // stop at a match + // or if the FO(orig[i]) > FO(rev[j]) + // or at the end + while (indx[i] < 0 || indx[i] < jndx[j]) + { + i++; + } + + // this doesn't do a compare each line with each other line + // so it won't find all matching lines + } + while (indx[i] != jndx[j]); + + // on exit we have a match + + // they are equal, reverse any exedent matches + // it is possible to overshoot, so count back matching items + while (i > ia && j > ja && indx[i - 1] == jndx[j - 1]) + { + --i; + --j; + } + + deltas.addDelta(Delta.newDelta(new Chunk(orig, ia, i - ia), + new Chunk(rev, ja, j - ja))); + // skip matching + for (; indx[i] != EOS && indx[i] == jndx[j]; i++, j++) + { + /* void */ + } + } + return deltas; + } + + /** + * create a Map from each common item in orig and rev + * to the index of its first occurrence in orig + * + * @param orig the original sequence of items + * @param rev the revised sequence of items + */ + protected Map buildEqSet(Object[] orig, Object[] rev) + { + // construct a set of the objects that orig and rev have in common + + // first construct a set containing all the elements in orig + Set items = new HashSet(Arrays.asList(orig)); + + // then remove all those not in rev + items.retainAll(Arrays.asList(rev)); + + Map eqs = new HashMap(); + for (int i = 0; i < orig.length; i++) + { + // if its a common item and hasn't been found before + if (items.contains(orig[i])) + { + // add it to the map + eqs.put(orig[i], new Integer(i)); + // and make sure its not considered again + items.remove(orig[i]); + } + } + return eqs; + } + + /** + * build a an array such each a[i] = eqs([i]) or NF if eqs([i]) undefined + * + * @param eqs a mapping from Object to Integer + * @param seq a sequence of objects + * @param NF the not found marker + */ + protected int[] buildIndex(Map eqs, Object[] seq, int NF) + { + int[] result = new int[seq.length + 1]; + for (int i = 0; i < seq.length; i++) + { + Integer value = (Integer) eqs.get(seq[i]); + if (value == null || value.intValue() < 0) + { + result[i] = NF; + } + else + { + result[i] = value.intValue(); + } + } + result[seq.length] = EOS; + return result; + } + +} diff --git a/source/org/apache/commons/jrcs/diff/myers/DiffNode.java b/source/org/apache/commons/jrcs/diff/myers/DiffNode.java new file mode 100644 index 0000000..45fd8f0 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/myers/DiffNode.java @@ -0,0 +1,57 @@ +package org.apache.commons.jrcs.diff.myers; + +/** + *

Title:

+ *

Description:

+ *

Copyright: Copyright (c) 2002

+ *

Company:

+ * @author not attributable + * @version 1.0 + */ + +/** + * A diffnode in a diffpath. + *

+ * A DiffNode and its previous node mark a delta between + * two input sequences, that is, two differing subsequences + * between (possibly zero length) matching sequences. + * + * {@link DiffNode DiffNodes} and {@link Snake Snakes} allow for compression + * of diffpaths, as each snake is represented by a single {@link Snake Snake} + * node and each contiguous series of insertions and deletions is represented + * by a single {@link DiffNode DiffNodes}. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:29 $ + * @author Juanco Anez + * + */ +public final class DiffNode + extends PathNode +{ + /** + * Constructs a DiffNode. + *

+ * DiffNodes are compressed. That means that + * the path pointed to by the prev parameter + * will be followed using {@link PathNode#previousSnake} + * until a non-diff node is found. + * + * @param the position in the original sequence + * @param the position in the revised sequence + * @param prev the previous node in the path. + */ + public DiffNode(int i, int j, PathNode prev) + { + super(i, j, (prev == null ? null : prev.previousSnake()) ); + } + + /** + * {@inheritDoc} + * @return false, always + */ + public boolean isSnake() + { + return false; + } + +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/myers/MyersDiff.java b/source/org/apache/commons/jrcs/diff/myers/MyersDiff.java new file mode 100644 index 0000000..32ebb1f --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/myers/MyersDiff.java @@ -0,0 +1,222 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff.myers; + +import org.apache.commons.jrcs.diff.*; + +/** + * A clean-room implementation of + * + * Eugene Myers differencing algorithm. + *

+ * See the paper at + * + * http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:30 $ + * @author Juanco Anez + * @see Delta + * @see Revision + * @see Diff + */ +public class MyersDiff + implements DiffAlgorithm +{ + /** + * Constructs an instance of the Myers differencing algorithm. + */ + public MyersDiff() + { + } + + /** + * {@inheritDoc} + */ + public Revision diff(Object[] orig, Object[] rev) + throws DifferentiationFailedException + { + PathNode path = buildPath(orig, rev); + return buildRevision(path, orig, rev); + } + + /** + * Computes the minimum diffpath that expresses de differences + * between the original and revised sequences, according + * to Gene Myers differencing algorithm. + * + * @param orig The original sequence. + * @param rev The revised sequence. + * @return A minimum {@link PathNode Path} accross the differences graph. + * @throws DifferentiationFailedException if a diff path could not be found. + */ + public static PathNode buildPath(Object[] orig, Object[] rev) + throws DifferentiationFailedException + { + if (orig == null) + throw new IllegalArgumentException("original sequence is null"); + if (rev == null) + throw new IllegalArgumentException("revised sequence is null"); + + // these are local constants + final int N = orig.length; + final int M = rev.length; + + final int MAX = N + M + 1; + final int size = 1 + 2 * MAX; + final int middle = (size + 1) / 2; + final PathNode diagonal[] = new PathNode[size]; + + PathNode path = null; + + diagonal[middle + 1] = new Snake(0, -1, null); + for (int d = 0; d < MAX; d++) + { + for (int k = -d; k <= d; k += 2) + { + final int kmiddle = middle + k; + final int kplus = kmiddle + 1; + final int kminus = kmiddle - 1; + PathNode prev = null; + + int i; + if ( (k == -d) || + (k != d && diagonal[kminus].i < diagonal[kplus].i)) + { + i = diagonal[kplus].i; + prev = diagonal[kplus]; + } + else + { + i = diagonal[kminus].i + 1; + prev = diagonal[kminus]; + } + + diagonal[kminus] = null; // no longer used + + int j = i - k; + + PathNode node = new DiffNode(i, j, prev); + + // orig and rev are zero-based + // but the algorithm is one-based + // that's why there's no +1 when indexing the sequences + while (i < N && j < M && orig[i].equals(rev[j])) + { + i++; + j++; + } + if (i > node.i) + node = new Snake(i, j, node); + + diagonal[kmiddle] = node; + + if (i >= N && j >= M) + { + return diagonal[kmiddle]; + } + } + diagonal[middle+d-1] = null; + + } + // According to Myers, this cannot happen + throw new DifferentiationFailedException("could not find a diff path"); + } + + /** + * Constructs a {@link Revision} from a difference path. + * + * @param path The path. + * @param orig The original sequence. + * @param rev The revised sequence. + * @return A {@link Revision} script corresponding to the path. + * @throws DifferentiationFailedException if a {@link Revision} could + * not be built from the given path. + */ + public static Revision buildRevision(PathNode path, Object[] orig, Object[] rev) + { + if (path == null) + throw new IllegalArgumentException("path is null"); + if (orig == null) + throw new IllegalArgumentException("original sequence is null"); + if (rev == null) + throw new IllegalArgumentException("revised sequence is null"); + + Revision revision = new Revision(); + if (path.isSnake()) + path = path.prev; + while (path != null && path.prev != null && path.prev.j >= 0) + { + if(path.isSnake()) + throw new IllegalStateException("bad diffpath: found snake when looking for diff"); + int i = path.i; + int j = path.j; + + path = path.prev; + int ianchor = path.i; + int janchor = path.j; + + Delta delta = Delta.newDelta(new Chunk(orig, ianchor, i - ianchor), + new Chunk(rev, janchor, j - janchor)); + revision.insertDelta(delta); + if (path.isSnake()) + path = path.prev; + } + return revision; + } + +} diff --git a/source/org/apache/commons/jrcs/diff/myers/PathNode.java b/source/org/apache/commons/jrcs/diff/myers/PathNode.java new file mode 100644 index 0000000..99ba15a --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/myers/PathNode.java @@ -0,0 +1,146 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff.myers; + +/** + * A node in a diffpath. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:30 $ + * @author Juanco Anez + * + * @see DiffNode + * @see Snake + * + */ +public abstract class PathNode +{ + /** Position in the original sequence. */ + public final int i; + /** Position in the revised sequence. */ + public final int j; + /** The previous node in the path. */ + public final PathNode prev; + + /** + * Concatenates a new path node with an existing diffpath. + * @param i The position in the original sequence for the new node. + * @param j The position in the revised sequence for the new node. + * @param prev The previous node in the path. + */ + public PathNode(int i, int j, PathNode prev) + { + this.i = i; + this.j = j; + this.prev = prev; + } + + /** + * Is this node a {@link Snake Snake node}? + * @return true if this is a {@link Snake Snake node} + */ + public abstract boolean isSnake(); + + /** + * Is this a bootstrap node? + *

+ * In bottstrap nodes one of the two corrdinates is + * less than zero. + * @return tru if this is a bootstrap node. + */ + public boolean isBootstrap() + { + return i < 0 || j < 0; + } + + /** + * Skips sequences of {@link DiffNode DiffNodes} until a + * {@link Snake} or bootstrap node is found, or the end + * of the path is reached. + * @return The next first {@link Snake} or bootstrap node in the path, or + * null + * if none found. + */ + public final PathNode previousSnake() + { + if (isBootstrap()) + return null; + if (!isSnake() && prev != null) + return prev.previousSnake(); + return this; + } + + /** + * {@inheritDoc} + */ + public String toString() + { + StringBuffer buf = new StringBuffer("["); + PathNode node = this; + while (node != null) + { + buf.append("("); + buf.append(Integer.toString(node.i)); + buf.append(","); + buf.append(Integer.toString(node.j)); + buf.append(")"); + node = node.prev; + } + buf.append("]"); + return buf.toString(); + } +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/diff/myers/Snake.java b/source/org/apache/commons/jrcs/diff/myers/Snake.java new file mode 100644 index 0000000..46c1d69 --- /dev/null +++ b/source/org/apache/commons/jrcs/diff/myers/Snake.java @@ -0,0 +1,97 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.diff.myers; + +/** + * Represents a snake in a diffpath. + *

+ * + * {@link DiffNode DiffNodes} and {@link Snake Snakes} allow for compression + * of diffpaths, as each snake is represented by a single {@link Snake Snake} + * node and each contiguous series of insertions and deletions is represented + * by a single {@link DiffNode DiffNodes}. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:30 $ + * @author Juanco Anez + * + */ +public final class Snake + extends PathNode +{ + /** + * Constructs a snake node. + * + * @param the position in the original sequence + * @param the position in the revised sequence + * @param prev the previous node in the path. + */ + public Snake(int i, int j, PathNode prev) + { + super(i, j, prev); + } + + /** + * {@inheritDoc} + * @return true always + */ + public boolean isSnake() + { + return true; + } + +} \ No newline at end of file diff --git a/source/org/apache/commons/jrcs/tools/JDiff.java b/source/org/apache/commons/jrcs/tools/JDiff.java new file mode 100644 index 0000000..c41a847 --- /dev/null +++ b/source/org/apache/commons/jrcs/tools/JDiff.java @@ -0,0 +1,153 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.tools; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.commons.jrcs.diff.Diff; +import org.apache.commons.jrcs.diff.Revision; + + +/** + * A program to compare two files. + *

JDiff produces the deltas between the two given files in Unix diff + * format. + *

+ *

The program was written as a simple test of the + * {@linkplain org.apache.commons.jrcs.diff diff} package. + */ +public class JDiff +{ + + static final String[] loadFile(String name) throws IOException + { + BufferedReader data = new BufferedReader(new FileReader(name)); + List lines = new ArrayList(); + String s; + while ((s = data.readLine()) != null) + { + lines.add(s); + } + return (String[])lines.toArray(new String[lines.size()]); + } + + static final void usage(String name) + { + System.err.println("Usage: " + name + " file1 file2"); + } + + public static void main(String[] argv) throws Exception + { + if (argv.length < 2) + { + usage("JDiff"); + System.exit(2); // THDL modification + } + else + { + Object[] orig = loadFile(argv[0]); + Object[] rev = loadFile(argv[1]); + + Diff df = new Diff(orig); + Revision r = df.diff(rev); + if (r.size() == 0) // THDL modification + System.exit(0); // THDL modification + + System.err.println("------"); + System.out.print(r.toString()); + System.err.println("------" + new Date()); + + try + { + Object[] reco = r.patch(orig); + //String recos = Diff.arrayToString(reco); + if (!Diff.compare(rev, reco)) + { + System.err.println("INTERNAL ERROR:" + + "files differ after patching!"); + } + } + catch (Throwable o) + { + System.out.println("Patch failed"); + } + System.exit(1); // THDL modification + } + } + + /** THDL modification -- returns the Revision that gets you from + file x to file y, or null on error. */ + public static Revision getDiff(String x, String y) + { + try { + Object[] orig = loadFile(x); + Object[] rev = loadFile(y); + + Diff df = new Diff(orig); + return df.diff(rev); + } catch (Exception e) { + return null; + } + } +} + diff --git a/source/org/apache/commons/jrcs/util/ToString.java b/source/org/apache/commons/jrcs/util/ToString.java new file mode 100644 index 0000000..fda3240 --- /dev/null +++ b/source/org/apache/commons/jrcs/util/ToString.java @@ -0,0 +1,154 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.commons.jrcs.util; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.util.List; +import java.util.LinkedList; + +/** + * This class delegates handling of the to a StringBuffer based version. + * + * @version $Revision: 1.1 $ $Date: 2003/07/14 12:22:30 $ + * @author Juanco Anez + */ +public class ToString +{ + public ToString() + { + } + + /** + * Default implementation of the + * {@link java.lang.Object#toString toString() } method that + * delegates work to a {@link java.lang.StringBuffer StringBuffer} + * base version. + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + toString(s); + return s.toString(); + } + + /** + * Place a string image of the object in a StringBuffer. + * @param s the string buffer. + */ + public void toString(StringBuffer s) + { + s.append(super.toString()); + } + + + + /** + * Breaks a string into an array of strings. + * Use the value of the line.separator system property + * as the linebreak character. + * @param value the string to convert. + */ + public static String[] stringToArray(String value) + { + BufferedReader reader = new BufferedReader(new StringReader(value)); + List l = new LinkedList(); + String s; + try + { + while ((s = reader.readLine()) != null) + { + l.add(s); + } + } + catch (java.io.IOException e) + { + } + return (String[]) l.toArray(new String[l.size()]); + } + + /** + * Converts an array of {@link Object Object} to a string + * Use the value of the line.separator system property + * the line separator. + * @param o the array of objects. + */ + public static String arrayToString(Object[] o) + { + return arrayToString(o, System.getProperty("line.separator")); + } + + /** + * Converts an array of {@link Object Object} to a string + * using the given line separator. + * @param o the array of objects. + * @param EOL the string to use as line separator. + */ + public static String arrayToString(Object[] o, String EOL) + { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < o.length - 1; i++) + { + buf.append(o[i]); + buf.append(EOL); + } + buf.append(o[o.length - 1]); + return buf.toString(); + } +} +