/**
* Add some padding on text start and end so that edges can match something.
* Intended to be called only from within patch_apply.
* @param patches Array of Patch objects.
* @return The padding string added to each side.
*/
public String patch_addPadding(LinkedList<Patch> patches) {
short paddingLength = this.Patch_Margin;
String nullPadding = "";
for (short x = 1; x <= paddingLength; x++) {
nullPadding += String.valueOf((char) x);
}
// Bump all the patches forward.
for (Patch aPatch : patches) {
aPatch.start1 += paddingLength;
aPatch.start2 += paddingLength;
}
// Add some padding on start of first diff.
Patch patch = patches.getFirst();
LinkedList<Diff> diffs = patch.diffs;
if (diffs.isEmpty() || diffs.getFirst().operation != Operation.EQUAL) {
// Add nullPadding equality.
diffs.addFirst(new Diff(Operation.EQUAL, nullPadding));
patch.start1 -= paddingLength; // Should be 0.
patch.start2 -= paddingLength; // Should be 0.
patch.length1 += paddingLength;
patch.length2 += paddingLength;
} else if (paddingLength > diffs.getFirst().text.length()) {
// Grow first equality.
Diff firstDiff = diffs.getFirst();
int extraLength = paddingLength - firstDiff.text.length();
firstDiff.text = nullPadding.substring(firstDiff.text.length())
+ firstDiff.text;
patch.start1 -= extraLength;
patch.start2 -= extraLength;
patch.length1 += extraLength;
patch.length2 += extraLength;
}
// Add some padding on end of last diff.
patch = patches.getLast();
diffs = patch.diffs;
if (diffs.isEmpty() || diffs.getLast().operation != Operation.EQUAL) {
// Add nullPadding equality.
diffs.addLast(new Diff(Operation.EQUAL, nullPadding));
patch.length1 += paddingLength;
patch.length2 += paddingLength;
} else if (paddingLength > diffs.getLast().text.length()) {
// Grow last equality.
Diff lastDiff = diffs.getLast();
int extraLength = paddingLength - lastDiff.text.length();
lastDiff.text += nullPadding.substring(0, extraLength);
patch.length1 += extraLength;
patch.length2 += extraLength;
}
return nullPadding;
}
/**
* Look through the patches and break up any which are longer than the
* maximum limit of the match algorithm.
* Intended to be called only from within patch_apply.
* @param patches LinkedList of Patch objects.
*/
public void patch_splitMax(LinkedList<Patch> patches) {
short patch_size = Match_MaxBits;
String precontext, postcontext;
Patch patch;
int start1, start2;
boolean empty;
Operation diff_type;
String diff_text;
ListIterator<Patch> pointer = patches.listIterator();
Patch bigpatch = pointer.hasNext() ? pointer.next() : null;
while (bigpatch != null) {
if (bigpatch.length1 <= Match_MaxBits) {
bigpatch = pointer.hasNext() ? pointer.next() : null;
continue;
}
// Remove the big old patch.
pointer.remove();
start1 = bigpatch.start1;
start2 = bigpatch.start2;
precontext = "";
while (!bigpatch.diffs.isEmpty()) {
// Create one of several smaller patches.
patch = new Patch();
empty = true;
patch.start1 = start1 - precontext.length();
patch.start2 = start2 - precontext.length();
if (precontext.length() != 0) {
patch.length1 = patch.length2 = precontext.length();
patch.diffs.add(new Diff(Operation.EQUAL, precontext));
}
while (!bigpatch.diffs.isEmpty()
&& patch.length1 < patch_size - Patch_Margin) {
diff_type = bigpatch.diffs.getFirst().operation;
diff_text = bigpatch.diffs.getFirst().text;
if (diff_type == Operation.INSERT) {
// Insertions are harmless.
patch.length2 += diff_text.length();
start2 += diff_text.length();
patch.diffs.addLast(bigpatch.diffs.removeFirst());
empty = false;
} else if (diff_type == Operation.DELETE && patch.diffs.size() == 1
&& patch.diffs.getFirst().operation == Operation.EQUAL
&& diff_text.length() > 2 * patch_size) {
// This is a large deletion. Let it pass in one chunk.
patch.length1 += diff_text.length();
start1 += diff_text.length();
empty = false;
patch.diffs.add(new Diff(diff_type, diff_text));
bigpatch.diffs.removeFirst();
} else {
// Deletion or equality. Only take as much as we can stomach.
diff_text = diff_text.substring(0, Math.min(diff_text.length(),
patch_size - patch.length1 - Patch_Margin));
patch.length1 += diff_text.length();
start1 += diff_text.length();
if (diff_type == Operation.EQUAL) {
patch.length2 += diff_text.length();
start2 += diff_text.length();
} else {
empty = false;
}
patch.diffs.add(new Diff(diff_type, diff_text));
if (diff_text.equals(bigpatch.diffs.getFirst().text)) {
bigpatch.diffs.removeFirst();
} else {
bigpatch.diffs.getFirst().text = bigpatch.diffs.getFirst().text
.substring(diff_text.length());
}
}
}
// Compute the head context for the next patch.
precontext = diff_text2(patch.diffs);
precontext = precontext.substring(Math.max(0, precontext.length()
- Patch_Margin));
// Append the end context for this patch.
if (diff_text1(bigpatch.diffs).length() > Patch_Margin) {
postcontext = diff_text1(bigpatch.diffs).substring(0, Patch_Margin);
} else {
postcontext = diff_text1(bigpatch.diffs);
}
if (postcontext.length() != 0) {
patch.length1 += postcontext.length();
patch.length2 += postcontext.length();
if (!patch.diffs.isEmpty()
&& patch.diffs.getLast().operation == Operation.EQUAL) {
patch.diffs.getLast().text += postcontext;
} else {
patch.diffs.add(new Diff(Operation.EQUAL, postcontext));
}
}
if (!empty) {
pointer.add(patch);
}
}
bigpatch = pointer.hasNext() ? pointer.next() : null;
}
}
/**
* Take a list of patches and return a textual representation.
* @param patches List of Patch objects.
* @return Text representation of patches.
*/
public String patch_toText(List<Patch> patches) {
StringBuilder text = new StringBuilder();
for (Patch aPatch : patches) {
text.append(aPatch);
}
return text.toString();
}