Added some automated JUnit tests for TMW_RTF_TO_THDL_WYLIE.
This commit is contained in:
parent
e2a9720d9b
commit
ec7fec695f
17 changed files with 1670 additions and 39 deletions
203
source/org/thdl/util/javaxdelta/Checksum.java
Normal file
203
source/org/thdl/util/javaxdelta/Checksum.java
Normal file
|
@ -0,0 +1,203 @@
|
|||
/* Taken from the javaxdelta project.
|
||||
|
||||
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/javaxdelta/javaxdelta/com/nothome/delta/Checksum.java?rev=1.1.1.1&content-type=text/vnd.viewcvs-markup */
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2001 Torgeir Veimo
|
||||
* Copyright (c) 2002 Nicolas PERIDONT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
// DC: import cmp.Primes.*; // Please note that this package has a slightly different copyright style.
|
||||
|
||||
public class Checksum {
|
||||
|
||||
public static final int BASE = 65521;
|
||||
public static final int S = (1 << 4); // 16
|
||||
|
||||
public static boolean debug = false;
|
||||
|
||||
protected int hashtable[];
|
||||
protected long checksums[];
|
||||
protected int prime;
|
||||
|
||||
public Checksum() { }
|
||||
|
||||
protected static final char single_hash[] = {
|
||||
/* Random numbers generated using SLIB's pseudo-random number generator. */
|
||||
0xbcd1, 0xbb65, 0x42c2, 0xdffe, 0x9666, 0x431b, 0x8504, 0xeb46,
|
||||
0x6379, 0xd460, 0xcf14, 0x53cf, 0xdb51, 0xdb08, 0x12c8, 0xf602,
|
||||
0xe766, 0x2394, 0x250d, 0xdcbb, 0xa678, 0x02af, 0xa5c6, 0x7ea6,
|
||||
0xb645, 0xcb4d, 0xc44b, 0xe5dc, 0x9fe6, 0x5b5c, 0x35f5, 0x701a,
|
||||
0x220f, 0x6c38, 0x1a56, 0x4ca3, 0xffc6, 0xb152, 0x8d61, 0x7a58,
|
||||
0x9025, 0x8b3d, 0xbf0f, 0x95a3, 0xe5f4, 0xc127, 0x3bed, 0x320b,
|
||||
0xb7f3, 0x6054, 0x333c, 0xd383, 0x8154, 0x5242, 0x4e0d, 0x0a94,
|
||||
0x7028, 0x8689, 0x3a22, 0x0980, 0x1847, 0xb0f1, 0x9b5c, 0x4176,
|
||||
0xb858, 0xd542, 0x1f6c, 0x2497, 0x6a5a, 0x9fa9, 0x8c5a, 0x7743,
|
||||
0xa8a9, 0x9a02, 0x4918, 0x438c, 0xc388, 0x9e2b, 0x4cad, 0x01b6,
|
||||
0xab19, 0xf777, 0x365f, 0x1eb2, 0x091e, 0x7bf8, 0x7a8e, 0x5227,
|
||||
0xeab1, 0x2074, 0x4523, 0xe781, 0x01a3, 0x163d, 0x3b2e, 0x287d,
|
||||
0x5e7f, 0xa063, 0xb134, 0x8fae, 0x5e8e, 0xb7b7, 0x4548, 0x1f5a,
|
||||
0xfa56, 0x7a24, 0x900f, 0x42dc, 0xcc69, 0x02a0, 0x0b22, 0xdb31,
|
||||
0x71fe, 0x0c7d, 0x1732, 0x1159, 0xcb09, 0xe1d2, 0x1351, 0x52e9,
|
||||
0xf536, 0x5a4f, 0xc316, 0x6bf9, 0x8994, 0xb774, 0x5f3e, 0xf6d6,
|
||||
0x3a61, 0xf82c, 0xcc22, 0x9d06, 0x299c, 0x09e5, 0x1eec, 0x514f,
|
||||
0x8d53, 0xa650, 0x5c6e, 0xc577, 0x7958, 0x71ac, 0x8916, 0x9b4f,
|
||||
0x2c09, 0x5211, 0xf6d8, 0xcaaa, 0xf7ef, 0x287f, 0x7a94, 0xab49,
|
||||
0xfa2c, 0x7222, 0xe457, 0xd71a, 0x00c3, 0x1a76, 0xe98c, 0xc037,
|
||||
0x8208, 0x5c2d, 0xdfda, 0xe5f5, 0x0b45, 0x15ce, 0x8a7e, 0xfcad,
|
||||
0xaa2d, 0x4b5c, 0xd42e, 0xb251, 0x907e, 0x9a47, 0xc9a6, 0xd93f,
|
||||
0x085e, 0x35ce, 0xa153, 0x7e7b, 0x9f0b, 0x25aa, 0x5d9f, 0xc04d,
|
||||
0x8a0e, 0x2875, 0x4a1c, 0x295f, 0x1393, 0xf760, 0x9178, 0x0f5b,
|
||||
0xfa7d, 0x83b4, 0x2082, 0x721d, 0x6462, 0x0368, 0x67e2, 0x8624,
|
||||
0x194d, 0x22f6, 0x78fb, 0x6791, 0xb238, 0xb332, 0x7276, 0xf272,
|
||||
0x47ec, 0x4504, 0xa961, 0x9fc8, 0x3fdc, 0xb413, 0x007a, 0x0806,
|
||||
0x7458, 0x95c6, 0xccaa, 0x18d6, 0xe2ae, 0x1b06, 0xf3f6, 0x5050,
|
||||
0xc8e8, 0xf4ac, 0xc04c, 0xf41c, 0x992f, 0xae44, 0x5f1b, 0x1113,
|
||||
0x1738, 0xd9a8, 0x19ea, 0x2d33, 0x9698, 0x2fe9, 0x323f, 0xcde2,
|
||||
0x6d71, 0xe37d, 0xb697, 0x2c4f, 0x4373, 0x9102, 0x075d, 0x8e25,
|
||||
0x1672, 0xec28, 0x6acb, 0x86cc, 0x186e, 0x9414, 0xd674, 0xd1a5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* assumes the buffer is of length S
|
||||
*/
|
||||
public static long queryChecksum(byte buf[], int len) {
|
||||
int high = 0; int low = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
low += single_hash[buf[i]+128];
|
||||
high += low;
|
||||
}
|
||||
return ((high & 0xffff) << 16) | (low & 0xffff);
|
||||
}
|
||||
|
||||
public static long incrementChecksum(long checksum, byte out, byte in) {
|
||||
char old_c = single_hash[out+128];
|
||||
char new_c = single_hash[in+128];
|
||||
int low = ((int)((checksum) & 0xffff) - old_c + new_c) & 0xffff;
|
||||
int high = ((int)((checksum) >> 16) - (old_c * S) + low) & 0xffff;
|
||||
return (high << 16) | (low & 0xffff);
|
||||
}
|
||||
|
||||
public static int generateHash(long checksum) {
|
||||
long high = (checksum >> 16) & 0xffff;
|
||||
long low = checksum & 0xffff;
|
||||
long it = (high >> 2) + (low << 3) + (high << 16);
|
||||
int hash = (int) (it ^ high ^ low);
|
||||
return hash > 0 ? hash : -hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize checksums for source. The checksum for the S bytes at offset
|
||||
* S * i is inserted into an array at index i.
|
||||
*
|
||||
* This is not good enough, we also need a hashtable into these indexes.
|
||||
*
|
||||
*/
|
||||
public void generateChecksums(File sourceFile, int length) throws IOException {
|
||||
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(sourceFile));
|
||||
int checksumcount = (int)sourceFile.length() / S;
|
||||
// DC: System.out.println("generating checksum array of size " + checksumcount);
|
||||
|
||||
// DC: added this:
|
||||
if (checksumcount == 0) checksumcount = 16;
|
||||
|
||||
checksums = new long[checksumcount];
|
||||
hashtable = new int[checksumcount];
|
||||
prime = findClosestPrime(checksumcount);
|
||||
|
||||
// DC: added this but I think it isn't needed thanks to the above addition:
|
||||
if (0 == prime) throw new Error("Checksum failed 304ffe");
|
||||
|
||||
// DC: System.out.println("using prime " + prime);
|
||||
|
||||
// generate cheksums at each interval
|
||||
for (int i = 0; i < checksumcount; i++) {
|
||||
|
||||
byte buf[] = new byte[S];
|
||||
|
||||
is.read(buf, 0, S);
|
||||
|
||||
checksums[i] = queryChecksum(buf, S);
|
||||
}
|
||||
is.close();
|
||||
|
||||
// generate hashtable entries for all checksums
|
||||
for (int i = 0; i < checksumcount; i++) hashtable[i] = -1;
|
||||
|
||||
for (int i = 0; i < checksumcount; i++) {
|
||||
int hash = generateHash(checksums[i]) % prime;
|
||||
if (debug)
|
||||
System.out.println("checking with hash: " + hash);
|
||||
if (hashtable[hash] != -1) {
|
||||
if (debug)
|
||||
System.out.println("hash table collision for index " + i);
|
||||
} else {
|
||||
hashtable[hash] = i;
|
||||
}
|
||||
}
|
||||
//System.out.println("checksums : " + printLongArray(checksums));
|
||||
//System.out.println("hashtable : " + printIntArray(hashtable));
|
||||
}
|
||||
|
||||
public int findChecksumIndex(long checksum) {
|
||||
return hashtable[generateHash(checksum) % prime];
|
||||
}
|
||||
|
||||
public static int findClosestPrime(int size) {
|
||||
// since it is used only one, we initialize the prime number generator here
|
||||
Primes primes = new Primes(size);
|
||||
return primes.below(size);
|
||||
}
|
||||
|
||||
private String printIntArray(int[] a) {
|
||||
String result = "";
|
||||
result += "[";
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
result += a[i];
|
||||
if (i != (a.length - 1))
|
||||
result += ",";
|
||||
else
|
||||
result += "]";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String printLongArray(long[] a) {
|
||||
String result = "";
|
||||
result += "[";
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
result += a[i];
|
||||
if (i != (a.length - 1))
|
||||
result += ",";
|
||||
else
|
||||
result += "]";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
79
source/org/thdl/util/javaxdelta/DebugDiffWriter.java
Normal file
79
source/org/thdl/util/javaxdelta/DebugDiffWriter.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* Taken from the javaxdelta project.
|
||||
|
||||
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/javaxdelta/javaxdelta/com/nothome/delta/DebugDiffWriter.java?rev=1.1.1.1&content-type=text/vnd.viewcvs-markup */
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2001 Torgeir Veimo
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
|
||||
/**
|
||||
* This class implements a GDIFF output queue, that will contatenate
|
||||
* subsequent copy statements when necessary, and write both
|
||||
* copy statement and insert statement to the specified OutputStream.
|
||||
*
|
||||
* The output follows the GDIFF file specification available at
|
||||
* http://www.w3.org/TR/NOTE-gdiff-19970901.html.
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class DebugDiffWriter implements DiffWriter {
|
||||
|
||||
byte buf[] = new byte[256]; int buflen = 0;
|
||||
|
||||
public DebugDiffWriter() {}
|
||||
|
||||
public void addCopy(int offset, int length) throws IOException {
|
||||
if (buflen > 0)
|
||||
writeBuf();
|
||||
System.err.println("COPY off: " + offset + ", len: " + length);
|
||||
}
|
||||
|
||||
public void addData(byte b) throws IOException {
|
||||
if (buflen < 256)
|
||||
buf[buflen++] = b;
|
||||
else
|
||||
writeBuf();
|
||||
}
|
||||
private void writeBuf() {
|
||||
if (buflen > 0) { // DC: added this
|
||||
System.err.print("DATA: ");
|
||||
for (int ix = 0; ix < buflen; ix++) {
|
||||
if (buf[ix] == '\n')
|
||||
System.err.print("\\n");
|
||||
else
|
||||
System.err.print(String.valueOf((char)((char) buf[ix])));
|
||||
//System.err.print("0x" + Integer.toHexString(buf[ix]) + " "); // hex output
|
||||
}
|
||||
System.err.println("");
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException { writeBuf(); } // DC: these did nothing, but that's not correct.
|
||||
public void close() throws IOException { flush(); } // DC: these did nothing, but that's not correct.
|
||||
}
|
269
source/org/thdl/util/javaxdelta/Delta.java
Normal file
269
source/org/thdl/util/javaxdelta/Delta.java
Normal file
|
@ -0,0 +1,269 @@
|
|||
/* Taken from the javaxdelta project.
|
||||
|
||||
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/javaxdelta/javaxdelta/com/nothome/delta/Delta.java?rev=1.1.1.1&content-type=text/vnd.viewcvs-markup */
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2001 Torgeir Veimo
|
||||
* Copyright (c) 2002 Nicolas PERIDONT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class Delta {
|
||||
|
||||
public final static int S = Checksum.S;
|
||||
public final static boolean debug = false;
|
||||
public final static int buff_size = 64*S;
|
||||
|
||||
|
||||
public Delta() { }
|
||||
|
||||
public void computeDelta(File sourceFile, File targetFile, DiffWriter output) throws IOException {
|
||||
|
||||
int targetLength = (int) targetFile.length();
|
||||
int sourceLength = (int) sourceFile.length();
|
||||
int targetidx = 0;
|
||||
|
||||
Checksum checksum = new Checksum();
|
||||
|
||||
if (debug) {
|
||||
System.out.println("source len: " + sourceLength);
|
||||
System.out.println("target len: " + targetLength);
|
||||
System.out.println("using match length S = " + S);
|
||||
}
|
||||
|
||||
checksum.generateChecksums(sourceFile, sourceLength);
|
||||
|
||||
PushbackInputStream target = new PushbackInputStream(new BufferedInputStream(new FileInputStream(targetFile)),buff_size);
|
||||
RandomAccessFile source = new RandomAccessFile(sourceFile, "r");
|
||||
|
||||
|
||||
boolean done = false;
|
||||
byte buf[] = new byte[S];
|
||||
long hashf = 0; byte b[] = new byte[1]; byte sourcebyte[] = new byte[S];
|
||||
|
||||
if (targetLength-targetidx <= S) {
|
||||
System.err.println("too short input file");
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize first complete checksum.
|
||||
target.read(buf, 0, S);
|
||||
targetidx += S;
|
||||
|
||||
hashf = checksum.queryChecksum(buf, S);
|
||||
|
||||
// The check for alternative hashf is only because I wanted to verify that the
|
||||
// update method really is correct. I will remove it shortly.
|
||||
long alternativehashf = hashf;
|
||||
|
||||
if (debug)
|
||||
System.out.println("my hashf: " + hashf + ", adler32: " + alternativehashf);
|
||||
|
||||
while (!done) {
|
||||
|
||||
int index = checksum.findChecksumIndex(hashf);
|
||||
if (index != -1) {
|
||||
|
||||
// possible match, need to check byte for byte
|
||||
boolean match = true;
|
||||
int offset = index * S;
|
||||
int length = S - 1;
|
||||
source.seek(offset);
|
||||
source.read(sourcebyte, 0, S);
|
||||
for (int ix = 0; ix < S; ix++) {
|
||||
if (sourcebyte[ix] != buf[ix]) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
//System.out.println("before targetidx : " + targetidx );
|
||||
// The length of the match is determined by comparing bytes.
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
boolean ok = true;
|
||||
byte[] sourceBuff = new byte[buff_size];
|
||||
byte[] targetBuff = new byte[buff_size];
|
||||
int source_idx = 0;
|
||||
int target_idx = 0;
|
||||
|
||||
do{
|
||||
source_idx = source.read(sourceBuff, 0, buff_size);
|
||||
target_idx = target.read(targetBuff, 0, buff_size);
|
||||
int read_idx = Math.max(source_idx,target_idx);
|
||||
int i = 0;
|
||||
do {
|
||||
targetidx++;
|
||||
++length;
|
||||
ok = sourceBuff[i] == targetBuff[i];
|
||||
i++;
|
||||
if(!ok) {
|
||||
b[0] = targetBuff[i-1];
|
||||
target.unread(targetBuff,i,target_idx-i);
|
||||
}
|
||||
} while(i < read_idx && ok);
|
||||
} while(ok && targetLength-targetidx > 0);
|
||||
|
||||
// this is a insert instruction
|
||||
//System.out.println("output.addCopy("+offset+","+length+")");
|
||||
output.addCopy(offset, length);
|
||||
|
||||
if (targetLength-targetidx <= S) { // eof reached, special case for last bytes
|
||||
if (debug)
|
||||
System.out.println("last part of file");
|
||||
buf[0] = b[0]; // don't loose this byte
|
||||
int remaining = targetLength-targetidx;
|
||||
target.read(buf, 1 , remaining);
|
||||
targetidx += remaining;
|
||||
for (int ix = 0; ix < (remaining + 1); ix++)
|
||||
output.addData(buf[ix]);
|
||||
done = true;
|
||||
} else {
|
||||
buf[0] = b[0];
|
||||
target.read(buf, 1, S - 1);
|
||||
targetidx += S-1;
|
||||
alternativehashf = hashf = checksum.queryChecksum(buf, S);
|
||||
}
|
||||
continue; //continue loop
|
||||
}
|
||||
}
|
||||
|
||||
if (targetLength-targetidx > 0) {
|
||||
// update the adler fingerpring with a single byte
|
||||
|
||||
target.read(b, 0, 1);
|
||||
targetidx += 1;
|
||||
|
||||
// insert instruction with the old byte we no longer use...
|
||||
output.addData(buf[0]);
|
||||
|
||||
alternativehashf = checksum.incrementChecksum(alternativehashf, buf[0], b[0]);
|
||||
|
||||
for (int j = 0; j < 15; j++)
|
||||
buf[j] = buf[j+1];
|
||||
buf[15] = b[0];
|
||||
hashf = checksum.queryChecksum(buf, S);
|
||||
|
||||
|
||||
if (debug)
|
||||
System.out.println("raw: " + Integer.toHexString((int)hashf) + ", incremental: " + Integer.toHexString((int)alternativehashf));
|
||||
|
||||
} else {
|
||||
for (int ix = 0; ix < S; ix++)
|
||||
output.addData(buf[ix]);
|
||||
done = true;
|
||||
}
|
||||
|
||||
}
|
||||
output.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// sample program to compute the difference between two input files.
|
||||
public static void main(String argv[]) {
|
||||
// DC: javaxdeltamain(argv);
|
||||
thdltoolsmain(argv);
|
||||
}
|
||||
|
||||
public static void javaxdeltamain(String argv[]) {
|
||||
Delta delta = new Delta();
|
||||
|
||||
if (argv.length != 3) {
|
||||
System.err.println("usage Delta [-d] source target [output]");
|
||||
System.err.println("either -d or an output filename must be specified.");
|
||||
System.err.println("aborting..");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
DiffWriter output = null;
|
||||
File sourceFile = null;
|
||||
File targetFile = null;
|
||||
if (argv[0].equals("-d")) {
|
||||
sourceFile = new File(argv[1]);
|
||||
targetFile = new File(argv[2]);
|
||||
output = new DebugDiffWriter();
|
||||
} else {
|
||||
sourceFile = new File(argv[0]);
|
||||
targetFile = new File(argv[1]);
|
||||
output = new GDiffWriter(new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File(argv[2])))));
|
||||
}
|
||||
|
||||
if (sourceFile.length() > Integer.MAX_VALUE || targetFile.length() > Integer.MAX_VALUE) {
|
||||
System.err.println("source or target is too large, max length is " + Integer.MAX_VALUE);
|
||||
System.err.println("aborting..");
|
||||
return;
|
||||
}
|
||||
|
||||
//output.close();
|
||||
|
||||
delta.computeDelta(sourceFile, targetFile, output);
|
||||
output.flush();
|
||||
output.close();
|
||||
// DC: System.out.println("finished generating delta");
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("error while generating delta; " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public static void thdltoolsmain(String argv[]) {
|
||||
Delta delta = new Delta();
|
||||
|
||||
if (argv.length != 2) {
|
||||
System.err.println("usage Delta source target");
|
||||
System.err.println("aborting..");
|
||||
System.exit(-2);
|
||||
}
|
||||
int rc = Delta.areFilesDifferent(argv[0], argv[1]);
|
||||
if (rc == 1)
|
||||
System.out.println("files differ");
|
||||
else if (rc == 0)
|
||||
System.out.println("files are the same");
|
||||
else
|
||||
System.out.println("error comparing files");
|
||||
System.exit(rc);
|
||||
}
|
||||
|
||||
/** Returns 1 if source and target differ, 0 if they don't, -1 on
|
||||
error. David Chandler wrote this based on main(). */
|
||||
public static int areFilesDifferent(String source, String target) {
|
||||
Delta delta = new Delta();
|
||||
|
||||
try {
|
||||
YesOrNoDiffWriter output = new YesOrNoDiffWriter();
|
||||
File sourceFile = new File(source);
|
||||
File targetFile = new File(target);
|
||||
if (sourceFile.length() > Integer.MAX_VALUE || targetFile.length() > Integer.MAX_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
delta.computeDelta(sourceFile, targetFile, output);
|
||||
return (output.areFilesDifferent()) ? 1 : 0;
|
||||
} catch (IOException ioe) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
43
source/org/thdl/util/javaxdelta/DiffWriter.java
Normal file
43
source/org/thdl/util/javaxdelta/DiffWriter.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Taken from the javaxdelta project.
|
||||
|
||||
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/javaxdelta/javaxdelta/com/nothome/delta/DiffWriter.java?rev=1.1.1.1&content-type=text/vnd.viewcvs-markup */
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2001 Torgeir Veimo
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author torgeir
|
||||
*/
|
||||
public interface DiffWriter {
|
||||
public void addCopy(int offset, int length) throws IOException;
|
||||
//public void addInsert(String insertString) throws IOException;
|
||||
public void addData(byte b) throws IOException;
|
||||
public void flush() throws IOException;
|
||||
public void close() throws IOException;
|
||||
}
|
141
source/org/thdl/util/javaxdelta/GDiffWriter.java
Normal file
141
source/org/thdl/util/javaxdelta/GDiffWriter.java
Normal file
|
@ -0,0 +1,141 @@
|
|||
/* Taken from the javaxdelta project.
|
||||
|
||||
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/javaxdelta/javaxdelta/com/nothome/delta/GDiffWriter.java?rev=1.1.1.1&content-type=text/vnd.viewcvs-markup */
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2001 Torgeir Veimo
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
|
||||
/**
|
||||
* The output follows the GDIFF file specification available at
|
||||
* http://www.w3.org/TR/NOTE-gdiff-19970901.html.
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class GDiffWriter implements DiffWriter {
|
||||
|
||||
byte buf[] = new byte[256]; int buflen = 0;
|
||||
|
||||
protected boolean debug = false;
|
||||
|
||||
//Vector writeQueue = new Vector();
|
||||
DataOutputStream output = null;
|
||||
|
||||
public GDiffWriter(DataOutputStream os) throws IOException {
|
||||
this.output = os;
|
||||
// write magic string "d1 ff d1 ff 04"
|
||||
output.writeByte(0xd1);
|
||||
output.writeByte(0xff);
|
||||
output.writeByte(0xd1);
|
||||
output.writeByte(0xff);
|
||||
output.writeByte(0x04);
|
||||
}
|
||||
|
||||
public void setDebug(boolean flag) { debug = flag; }
|
||||
|
||||
public void addCopy(int offset, int length) throws IOException {
|
||||
if (buflen > 0)
|
||||
writeBuf();
|
||||
|
||||
//output debug data
|
||||
if (debug)
|
||||
System.err.println("COPY off: " + offset + ", len: " + length);
|
||||
|
||||
// output real data
|
||||
byte command;
|
||||
if (offset > Integer.MAX_VALUE) {
|
||||
// use long, int format
|
||||
output.writeByte(255);
|
||||
// Actually, we don't support longer files than int.MAX_VALUE at the moment..
|
||||
} else if (offset < 65536) {
|
||||
if (length < 256) {
|
||||
// use ushort, ubyte
|
||||
output.writeByte(249);
|
||||
output.writeShort(offset);
|
||||
output.writeByte(length);
|
||||
} else if (length > 65535) {
|
||||
// use ushort, int
|
||||
output.writeByte(251);
|
||||
output.writeShort(offset);
|
||||
output.writeInt(length);
|
||||
} else {
|
||||
// use ushort, ushort
|
||||
output.writeByte(250);
|
||||
output.writeShort(offset);
|
||||
output.writeShort(length);
|
||||
}
|
||||
} else {
|
||||
if (length < 256) {
|
||||
// use int, ubyte
|
||||
output.writeByte(252);
|
||||
output.writeInt(offset);
|
||||
output.writeByte(length);
|
||||
} else if (length > 65535) {
|
||||
// use int, int
|
||||
output.writeByte(254);
|
||||
output.writeInt(offset);
|
||||
output.writeInt(length);
|
||||
} else {
|
||||
// use int, ushort
|
||||
output.writeByte(253);
|
||||
output.writeInt(offset);
|
||||
output.writeShort(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addData(byte b) throws IOException {
|
||||
if (buflen >= 246)
|
||||
writeBuf();
|
||||
buf[buflen] = b; buflen++;
|
||||
}
|
||||
|
||||
private void writeBuf() throws IOException {
|
||||
// output debug data
|
||||
if (debug) {
|
||||
System.err.print("DATA:");
|
||||
for (int ix = 0; ix < buflen; ix++) {
|
||||
if (buf[ix] == '\n')
|
||||
System.err.print("\\n");
|
||||
else
|
||||
System.err.print(String.valueOf((char)((char) buf[ix])));
|
||||
}
|
||||
System.err.println("");
|
||||
}
|
||||
|
||||
if (buflen > 0) {
|
||||
// output real data
|
||||
output.writeByte(buflen);
|
||||
output.write(buf, 0, buflen);
|
||||
}
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
public void flush() throws IOException { if (buflen > 0) writeBuf(); output.flush(); }
|
||||
public void close() throws IOException { this.flush(); }
|
||||
}
|
228
source/org/thdl/util/javaxdelta/Primes.java
Normal file
228
source/org/thdl/util/javaxdelta/Primes.java
Normal file
|
@ -0,0 +1,228 @@
|
|||
/* Taken from the javaxdelta project. */
|
||||
|
||||
/*
|
||||
Primes 1.1 calculates the primes 1..N, tells you if N is prime,
|
||||
computes the prime just below or above N. It is useful in computing
|
||||
optimal HashTable sizes. Java source included. Copyright 1998 by
|
||||
Roedy Green of Canadian Mind Products. May be freely distbributed
|
||||
for any purpose but military.
|
||||
*/
|
||||
|
||||
// Primes.java
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
/** Copyright 1998
|
||||
* Roedy Green
|
||||
* Canadian Mind Products
|
||||
* #208 - 525 Ninth Street
|
||||
* New Westminster, BC Canada V3M 5T9
|
||||
* tel: (604) 777-1804
|
||||
* mailto:roedy@mindprod.com
|
||||
* http://mindprod.com
|
||||
*/
|
||||
// May be freely distributed for any purpose but military
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* @author Roedy Green
|
||||
* @version 1.10 1998 November 10
|
||||
* Calculate primes using Eratostheses Sieve.
|
||||
* Tell if a given number is prime.
|
||||
* Find a prime just below a given number.
|
||||
* Find a prime just above a given number.
|
||||
*/
|
||||
|
||||
/*
|
||||
* version 1.1 1998 November 10 - new address and phone.
|
||||
*/
|
||||
public class Primes
|
||||
{
|
||||
|
||||
|
||||
private static final String EmbeddedCopyright =
|
||||
"Copyright 1997-2000 Roedy Green, Canadian Mind Products, http://mindprod.com";
|
||||
|
||||
/**
|
||||
* constructors
|
||||
*/
|
||||
public Primes()
|
||||
{
|
||||
ensureCapacity(1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param capacity - largest number you will be asking if prime.
|
||||
* If give too small a number, it will automatically grow by
|
||||
* recomputing the sieve array.
|
||||
*/
|
||||
public Primes (int capacity)
|
||||
{
|
||||
ensureCapacity(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param candidate - is this a prime?
|
||||
*/
|
||||
public boolean isPrime(int candidate)
|
||||
{
|
||||
ensureCapacity(candidate);
|
||||
if (candidate < 3) return candidate != 0;
|
||||
if (candidate % 2 == 0 ) return false;
|
||||
return !b.get(candidate/2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first prime higher than candidate
|
||||
*/
|
||||
public int above(int candidate)
|
||||
{
|
||||
do
|
||||
{
|
||||
// see what we can find in the existing sieve
|
||||
for (int i=candidate+1; i<= sieveCapacity; i++)
|
||||
{
|
||||
if (isPrime(i)) return i;
|
||||
}
|
||||
// Keep building ever bigger sieves till we succeed.
|
||||
// The next prime P' is between P+2 and P^2 - 2.
|
||||
// However that is a rather pessimistic upper bound.
|
||||
// Ideally some theorem would tell us how big we need to build
|
||||
// to find one.
|
||||
ensureCapacity(Math.max(candidate*2, sieveCapacity*2));
|
||||
} // end do
|
||||
while (true);
|
||||
} // end above
|
||||
|
||||
/**
|
||||
* @param return first prime less than candidate
|
||||
*/
|
||||
public int below (int candidate)
|
||||
{
|
||||
for (candidate--; candidate > 0; candidate--)
|
||||
{
|
||||
if (isPrime(candidate)) return candidate;
|
||||
}
|
||||
// candidate was 1 or 0 or -ve
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* calc all primes in the range 1..n,
|
||||
* not the first n primes.
|
||||
* @param n, highest candidate, not necessarily prime.
|
||||
* @return list of primes 1..n in an array
|
||||
*/
|
||||
public final int[] getPrimes(int n)
|
||||
{
|
||||
// calculate the primes
|
||||
ensureCapacity(n);
|
||||
|
||||
// pass 1: count primes
|
||||
int countPrimes = 0;
|
||||
for (int i = 0; i <= n; i++)
|
||||
{
|
||||
if (isPrime(i)) countPrimes++;
|
||||
}
|
||||
|
||||
// pass 2: construct array of primes
|
||||
int [] primes = new int[countPrimes];
|
||||
countPrimes = 0;
|
||||
for (int i = 0; i <= n; i++)
|
||||
{
|
||||
if (isPrime(i)) primes[countPrimes++] = i;
|
||||
}
|
||||
return primes;
|
||||
} // end getPrimes
|
||||
|
||||
/**
|
||||
* calculate the sieve, bit map of all primes 0..n
|
||||
* @param n highest number evalutated by the sieve, not necessarily prime.
|
||||
*/
|
||||
private final void sieve ( int n )
|
||||
{
|
||||
// Presume BitSet b set is big enough for our purposes.
|
||||
// Presume all even numbers are already marked composite, effectively.
|
||||
// Presume all odd numbers are already marked prime (0 in bit map).
|
||||
int last = (int)(Math.sqrt(n))+1;
|
||||
for (int candidate = 3; candidate <= last; candidate += 2)
|
||||
{
|
||||
// only look at odd numbers
|
||||
if (!b.get(candidate/2) /* if candidate is prime */)
|
||||
{
|
||||
// Our candidate is prime.
|
||||
// Only bother to mark multiples of primes. Others already done.
|
||||
// no need to mark even multiples, already done
|
||||
int incr = candidate*2;
|
||||
for ( int multiple = candidate + incr; multiple < n; multiple += incr)
|
||||
{
|
||||
b.set(multiple/2); // mark multiple as composite
|
||||
} // end for multiple
|
||||
} // end if
|
||||
} // end for candidate
|
||||
// at this point our sieve b is correct, except for 0..2
|
||||
} // end sieve
|
||||
|
||||
/**
|
||||
* Ensure have a sieve to tackle primes as big as n.
|
||||
* If we don't allocate a sieve big enough and calculate it.
|
||||
* @param n - ensure sieve big enough to evaluate n for primality.
|
||||
*/
|
||||
private void ensureCapacity (int n)
|
||||
{
|
||||
if ( n > sieveCapacity )
|
||||
{
|
||||
b = new BitSet((n+1)/2);
|
||||
// starts out all 0, presume all numbers prime
|
||||
sieveCapacity = n;
|
||||
sieve(n);
|
||||
}
|
||||
// otherwise existing sieve is fine
|
||||
} // end ensureCapacity
|
||||
|
||||
private int sieveCapacity;
|
||||
// biggest number we have computed in our sieve.
|
||||
// our BitSet array is indexed 0..N (odd only)
|
||||
|
||||
private BitSet b; /* true for each odd number if is composite */
|
||||
|
||||
/**
|
||||
* Demonstrate and test the methods
|
||||
*/
|
||||
public static void main (String[] args)
|
||||
{
|
||||
// print primes 1..101
|
||||
Primes calc = new Primes(106);
|
||||
int[] primes = calc.getPrimes(101);
|
||||
for (int i=0; i<primes.length; i++)
|
||||
{
|
||||
System.out.println(primes[i]);
|
||||
}
|
||||
|
||||
// demonstrate isPrime, above, below
|
||||
System.out.println(calc.isPrime(149));
|
||||
System.out.println(calc.below(149));
|
||||
System.out.println(calc.above(149));
|
||||
|
||||
// print all the primes just greater than powers of 2
|
||||
calc = new Primes(10000000);
|
||||
for (int pow=8; pow < 10000000; pow*=2)
|
||||
System.out.println(calc.above(pow));
|
||||
|
||||
// Validate that isPrime works by comparing it with brute force
|
||||
for (int i=3; i<=151; i++)
|
||||
{
|
||||
boolean prime = true;
|
||||
for (int j=2; j<i; j++)
|
||||
{
|
||||
if (i % j == 0 )
|
||||
{
|
||||
prime = false;
|
||||
break;
|
||||
}
|
||||
} // end for j
|
||||
if ( calc.isPrime(i) != prime ) System.out.println(i + " oops");
|
||||
} // end for i
|
||||
|
||||
} // end main
|
||||
} // end Primes
|
60
source/org/thdl/util/javaxdelta/YesOrNoDiffWriter.java
Normal file
60
source/org/thdl/util/javaxdelta/YesOrNoDiffWriter.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* Added by David Chandler, based on stuff in this package. */
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2001 Torgeir Veimo
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.thdl.util.javaxdelta;
|
||||
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
/** We look to see that one special DATA statement and only one COPY statment
|
||||
are generated. If so, there's no difference between the input and
|
||||
the output. Otherwise there is.
|
||||
@author David Chandler */
|
||||
public class YesOrNoDiffWriter implements DiffWriter {
|
||||
|
||||
public YesOrNoDiffWriter() {}
|
||||
|
||||
private int numCopies = 0;
|
||||
private int numDatas = 0;
|
||||
public void addCopy(int offset, int length) throws IOException {
|
||||
if (numCopies == 1) numCopies = 2;
|
||||
if (numCopies == 0) numCopies = 1;
|
||||
}
|
||||
|
||||
public void addData(byte b) throws IOException {
|
||||
if (numDatas == 1) numDatas = 2;
|
||||
if (numDatas == 0) numDatas = 1;
|
||||
}
|
||||
|
||||
public boolean areFilesDifferent() {
|
||||
return numCopies != 1 || numDatas != 1;
|
||||
}
|
||||
|
||||
private void writeBuf() { }
|
||||
public void flush() throws IOException { }
|
||||
public void close() throws IOException { }
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue