1 19 20 package org.netbeans.modules.diff.builtin; 21 22 import java.io.BufferedReader ; 23 import java.io.PushbackReader ; 24 import java.io.Reader ; 25 import java.io.IOException ; 26 import java.util.ArrayList ; 27 import java.util.List ; 28 import java.util.Iterator ; 29 import java.util.regex.Pattern ; 30 import java.util.regex.PatternSyntaxException ; 31 32 import org.netbeans.api.diff.Difference; 33 34 import org.netbeans.modules.diff.cmdline.CmdlineDiffProvider; 35 36 41 public class Patch extends Reader { 42 43 private static final int CONTEXT_DIFF = 0; 44 private static final int NORMAL_DIFF = 1; 45 private static final int UNIFIED_DIFF = 2; 46 47 private Difference[] diffs; 48 private PushbackReader source; 49 private int currDiff = 0; 50 private int line = 1; 51 private String newLine = null; private StringBuffer buff = new StringBuffer (); 53 54 55 private Patch(Difference[] diffs, Reader source) { 56 this.diffs = diffs; 57 this.source = new PushbackReader (new BufferedReader (source), 1); 58 } 59 60 68 public static Reader apply(Difference[] diffs, Reader source) { return new Patch(diffs, source); 70 } 71 72 79 80 83 public static FileDifferences[] parse(Reader source) throws IOException { 84 List <FileDifferences> fileDifferences = new ArrayList <FileDifferences>(); 85 Patch.SinglePatchReader patchReader = new Patch.SinglePatchReader(source); 88 int[] diffType = new int[1]; 89 String [] fileName = new String [2]; 90 while (patchReader.hasNextPatch(diffType, fileName)) { 91 Difference[] diffs = null; 93 switch (diffType[0]) { 94 case CONTEXT_DIFF: 95 diffs = parseContextDiff(patchReader); 96 break; 97 case UNIFIED_DIFF: 98 diffs = parseUnifiedDiff(patchReader); 99 break; 100 case NORMAL_DIFF: 101 diffs = parseNormalDiff(patchReader); 102 break; 103 } 104 if (diffs != null) { 105 fileDifferences.add(new FileDifferences(fileName[0], fileName[1], diffs)); 106 } 107 } 108 return fileDifferences.toArray(new FileDifferences[fileDifferences.size()]); 109 } 110 111 public int read(char[] cbuf, int off, int length) throws java.io.IOException { 112 if (buff.length() < length) { 113 doRetrieve(length - buff.length()); 114 } 115 int ret = Math.min(buff.length(), length); 116 if (ret == 0) return -1; 117 String retStr = buff.substring(0, ret); 118 char[] retChars = retStr.toCharArray(); 119 System.arraycopy(retChars, 0, cbuf, off, ret); 120 buff.delete(0, ret); 121 return ret; 122 } 123 124 public void close() throws java.io.IOException { 125 if (currDiff < diffs.length) { 126 throw new IOException ("There are " + (diffs.length - currDiff) + " pending hunks!"); 127 } 128 source.close(); 129 } 130 131 private void doRetrieve(int length) throws IOException { 132 for (int size = 0; size < length; line++) { 133 if (currDiff < diffs.length && 134 ((Difference.ADD == diffs[currDiff].getType() && 135 line == (diffs[currDiff].getFirstStart() + 1)) || 136 (Difference.ADD != diffs[currDiff].getType() && 137 line == diffs[currDiff].getFirstStart()))) { 138 if (compareText(source, diffs[currDiff].getFirstText())) { 139 String text = convertNewLines(diffs[currDiff].getSecondText(), newLine); 140 buff.append(text); 141 currDiff++; 142 } else { 143 throw new IOException ("Patch not applicable."); 144 } 145 } 146 StringBuffer newLineBuffer = null; 147 if (newLine == null) { 148 newLineBuffer = new StringBuffer (); 149 } 150 String lineStr = readLine(source, newLineBuffer); 151 if (newLineBuffer != null) newLine = newLineBuffer.toString(); 152 if (lineStr == null) break; 153 buff.append(lineStr); 154 buff.append(newLine); 155 } 156 } 157 158 159 private static String readLine(PushbackReader r, StringBuffer nl) throws IOException { 160 StringBuffer line = new StringBuffer (); 161 int ic = r.read(); 162 if (ic == -1) return null; 163 char c = (char) ic; 164 while (c != '\n' && c != '\r') { 165 line.append(c); 166 ic = r.read(); 167 if (ic == -1) break; 168 c = (char) ic; 169 } 170 if (nl != null) { 171 nl.append(c); 172 } 173 if (c == '\r') { 174 try { 175 ic = r.read(); 176 if (ic != -1) { 177 c = (char) ic; 178 if (c != '\n') r.unread(c); 179 else if (nl != null) nl.append(c); 180 } 181 } catch (IOException ioex) {} 182 } 183 return line.toString(); 184 } 185 186 private static String convertNewLines(String text, String newLine) { 187 if (text == null) return ""; if (newLine == null) return text; 189 StringBuffer newText = new StringBuffer (); 190 for (int i = 0; i < text.length(); i++) { 191 char c = text.charAt(i); 192 if (c == '\n') newText.append(newLine); 193 else if (c == '\r') { 194 if ((i + 1) < text.length() && text.charAt(i + 1) == '\n') { 195 i++; 196 newText.append(newLine); 197 } 198 } else newText.append(c); 199 } 200 return newText.toString(); 201 } 202 203 private boolean compareText(PushbackReader source, String text) throws IOException { 204 if (text == null || text.length() == 0) return true; 205 text = adjustTextNL(text); 206 char[] chars = new char[text.length()]; 207 int pos = 0; 208 int n; 209 String readStr = ""; 210 do { 211 n = source.read(chars, 0, chars.length - pos); 212 if (n > 0) { 213 pos += n; 214 readStr = readStr + new String (chars, 0, n); 215 } 216 if (readStr.endsWith("\r")) { 217 try { 218 char c = (char) source.read(); 219 if (c != '\n') source.unread(c); 220 else readStr += c; 221 } catch (IOException ioex) {} 222 } 223 readStr = adjustTextNL(readStr); 224 pos = readStr.length(); 225 } while (n > 0 && pos < chars.length); 226 readStr.getChars(0, readStr.length(), chars, 0); 227 line += numChars('\n', chars); 228 return readStr.equals(text); 231 } 232 233 237 private String adjustTextNL(String text) { 238 text = org.openide.util.Utilities.replaceString(text, "\r\n", "\n"); 239 text = org.openide.util.Utilities.replaceString(text, "\n\r", "\n"); 240 text = org.openide.util.Utilities.replaceString(text, "\r", "\n"); 241 return text; 242 } 243 244 private static int numChars(char c, char[] chars) { 245 int n = 0; 246 for (int i = 0; i < chars.length; i++) { 247 if (chars[i] == c) n++; 248 } 249 return n; 250 } 251 252 private static final String CONTEXT_MARK1B = "*** "; 253 private static final String CONTEXT_MARK2B = "--- "; 255 private static final String CONTEXT_MARK_DELIMETER = ","; 257 private static final String DIFFERENCE_DELIMETER = "***************"; 258 private static final String LINE_PREP_ADD = "+ "; 260 private static final String LINE_PREP_REMOVE = "- "; 261 private static final String LINE_PREP_CHANGE = "! "; 262 263 private static Difference[] parseContextDiff(Reader in) throws IOException { 264 BufferedReader br = new BufferedReader (in); 265 ArrayList <Difference> diffs = new ArrayList <Difference>(); 266 String line = null; 267 do { 268 if (line == null || !DIFFERENCE_DELIMETER.equals(line)) { 269 do { 270 line = br.readLine(); 271 } while (line != null && !DIFFERENCE_DELIMETER.equals(line)); 272 } 273 int[] firstInterval = new int[2]; 274 line = br.readLine(); 275 if (line != null && line.startsWith(CONTEXT_MARK1B)) { 276 try { 277 readNums(line, CONTEXT_MARK1B.length(), firstInterval); 278 } catch (NumberFormatException nfex) { 279 throw new IOException (nfex.getLocalizedMessage()); 280 } 281 } else continue; 282 ArrayList <Object > firstChanges = new ArrayList <Object >(); line = fillChanges(firstInterval, br, CONTEXT_MARK2B, firstChanges); 284 int[] secondInterval = new int[2]; 285 if (line != null && line.startsWith(CONTEXT_MARK2B)) { 286 try { 287 readNums(line, CONTEXT_MARK2B.length(), secondInterval); 288 } catch (NumberFormatException nfex) { 289 throw new IOException (nfex.getLocalizedMessage()); 290 } 291 } else continue; 292 ArrayList <Object > secondChanges = new ArrayList <Object >(); line = fillChanges(secondInterval, br, DIFFERENCE_DELIMETER, secondChanges); 294 if (changesCountInvariant(firstChanges, secondChanges) == false) { 295 throw new IOException ("Diff file format error. Number of new and old file changes in one hunk must be same!"); } 297 mergeChanges(firstInterval, secondInterval, firstChanges, secondChanges, diffs); 298 } while (line != null); 299 return diffs.toArray(new Difference[diffs.size()]); 300 } 301 302 303 private static boolean changesCountInvariant(List <Object > changes1, List <Object > changes2) { int i1 = 0; 305 Iterator it = changes1.iterator(); 306 while (it.hasNext()) { 307 int[] ints = (int[]) it.next(); 308 if (ints[2] == 2) { 309 i1++; 310 } 311 String skip = (String ) it.next(); 312 } 313 314 int i2 = 0; 315 it = changes2.iterator(); 316 while (it.hasNext()) { 317 int[] ints = (int[]) it.next(); 318 if (ints[2] == 2) { 319 i2++; 320 } 321 String skip = (String ) it.next(); 322 } 323 324 return i1 == i2; 325 } 326 327 private static void readNums(String str, int off, int[] values) throws NumberFormatException { 328 int end = str.indexOf(CONTEXT_MARK_DELIMETER, off); 329 if (end > 0) { 330 values[0] = Integer.parseInt(str.substring(off, end).trim()); 331 } else throw new NumberFormatException ("Missing comma."); 332 off = end + 1; 333 end = str.indexOf(' ', off); 334 if (end > 0) { 335 values[1] = Integer.parseInt(str.substring(off, end).trim()); 336 } else throw new NumberFormatException ("Missing final space."); 337 } 338 339 private static String fillChanges(int[] interval, BufferedReader br, 340 String untilStartsWith, List <Object > changes) throws IOException { 341 String line = br.readLine(); 342 for (int pos = interval[0]; pos <= interval[1]; pos++) { 343 if (line == null || line.startsWith(untilStartsWith)) break; 344 if (line.startsWith(LINE_PREP_ADD)) { 345 int[] changeInterval = new int[3]; 346 changeInterval[0] = pos; 347 changeInterval[2] = Difference.ADD; 348 StringBuffer changeText = new StringBuffer (); 349 changeText.append(line.substring(LINE_PREP_ADD.length())); 350 changeText.append('\n'); 351 do { 352 line = br.readLine(); 353 if (line == null) 354 break; 355 if (line.startsWith(LINE_PREP_ADD)) { 356 changeText.append(line.substring(LINE_PREP_ADD.length())); 357 changeText.append('\n'); 358 } else { 359 break; 360 } 361 pos++; 362 } while (true); 363 changeInterval[1] = pos; 364 changes.add(changeInterval); 365 changes.add(changeText.toString()); 366 } else if (line.startsWith(LINE_PREP_REMOVE)) { 367 int[] changeInterval = new int[3]; 368 changeInterval[0] = pos; 369 changeInterval[2] = Difference.DELETE; 370 StringBuffer changeText = new StringBuffer (); 371 changeText.append(line.substring(LINE_PREP_REMOVE.length())); 372 changeText.append('\n'); 373 do { 374 line = br.readLine(); 375 if (line == null) 376 break; 377 if (line.startsWith(LINE_PREP_REMOVE)) { 378 changeText.append(line.substring(LINE_PREP_REMOVE.length())); 379 changeText.append('\n'); 380 } else { 381 break; 382 } 383 pos++; 384 } while (true); 385 changeInterval[1] = pos; 386 changes.add(changeInterval); 387 changes.add(changeText.toString()); 388 } else if (line.startsWith(LINE_PREP_CHANGE)) { 389 int[] changeInterval = new int[3]; 390 changeInterval[0] = pos; 391 changeInterval[2] = Difference.CHANGE; 392 StringBuffer changeText = new StringBuffer (); 393 changeText.append(line.substring(LINE_PREP_CHANGE.length())); 394 changeText.append('\n'); 395 do { 396 line = br.readLine(); 397 if (line == null) 398 break; 399 if (line.startsWith(LINE_PREP_CHANGE)) { 400 changeText.append(line.substring(LINE_PREP_CHANGE.length())); 401 changeText.append('\n'); 402 } else { 403 break; 404 } 405 pos++; 406 } while (true); 407 changeInterval[1] = pos; 408 changes.add(changeInterval); 409 changes.add(changeText.toString()); 410 } else { 411 line = br.readLine(); 412 } 413 } 414 return line; 415 } 416 417 private static void mergeChanges(int[] firstInterval, int[] secondInterval, 418 List firstChanges, List secondChanges, List <Difference> diffs) { 419 420 421 int p1, p2; 422 int n1 = firstChanges.size(); 423 int n2 = secondChanges.size(); 424 int firstToSecondIntervalShift = secondInterval[0] - firstInterval[0]; 428 for (p1 = p2 = 0; p1 < n1 || p2 < n2; ) { 430 boolean isAddRemove = true; 431 while (isAddRemove && p1 < n1) { 432 int[] interval = (int[]) firstChanges.get(p1); 433 if (p2 < n2) { 434 int[] interval2 = (int[]) secondChanges.get(p2); 435 if (interval[0] + firstToSecondIntervalShift > interval2[0]) { 436 break; 437 } 438 } 442 isAddRemove = interval[2] == Difference.ADD || interval[2] == Difference.DELETE; 443 if (isAddRemove) { 444 if (interval[2] == Difference.ADD) { 445 diffs.add(new Difference(interval[2], interval[0] - 1, 0, 446 interval[0] + firstToSecondIntervalShift, 447 interval[1] + firstToSecondIntervalShift, 448 (String ) firstChanges.get(p1 + 1), "")); 449 firstToSecondIntervalShift += interval[1] - interval[0] + 1; 450 } else { 451 diffs.add(new Difference(interval[2], interval[0], interval[1], 452 interval[0] + firstToSecondIntervalShift - 1, 0, 453 (String ) firstChanges.get(p1 + 1), "")); 454 firstToSecondIntervalShift -= interval[1] - interval[0] + 1; 455 } 456 p1 += 2; 457 } 460 } 461 isAddRemove = true; 462 while (isAddRemove && p2 < n2) { 463 int[] interval = (int[]) secondChanges.get(p2); 464 isAddRemove = interval[2] == Difference.ADD || interval[2] == Difference.DELETE; 465 if (isAddRemove) { 466 if (interval[2] == Difference.ADD) { 467 diffs.add(new Difference(interval[2], 468 interval[0] - firstToSecondIntervalShift - 1, 0, 469 interval[0], interval[1], 470 "", (String ) secondChanges.get(p2 + 1))); 471 firstToSecondIntervalShift += interval[1] - interval[0] + 1; 472 } else { 473 diffs.add(new Difference(interval[2], 474 interval[0] - firstToSecondIntervalShift, 475 interval[1] - firstToSecondIntervalShift, 476 interval[0] - 1, 0, 477 "", (String ) secondChanges.get(p2 + 1))); 478 firstToSecondIntervalShift -= interval[1] - interval[0] + 1; 479 } 480 p2 += 2; 481 } 484 } 485 if (p1 < n1 && p2 < n2) { 487 int[] interval1 = (int[]) firstChanges.get(p1); 488 if (interval1[2] == Difference.CHANGE) { int[] interval2 = (int[]) secondChanges.get(p2); 490 diffs.add(new Difference(interval1[2], interval1[0], interval1[1], 491 interval2[0], interval2[1], 492 (String ) firstChanges.get(p1 + 1), 493 (String ) secondChanges.get(p2 + 1))); 494 p1 += 2; 495 p2 += 2; 496 firstToSecondIntervalShift += interval2[1] - interval2[0] - (interval1[1] - interval1[0]); 497 } 500 } 501 } 502 } 503 504 private static final String UNIFIED_MARK = "@@"; 505 private static final String UNIFIED_MARK1 = "--- "; 506 private static final String LINE_PREP_UNIF_ADD = "+"; 508 private static final String LINE_PREP_UNIF_REMOVE = "-"; 509 511 private static Difference[] parseUnifiedDiff(Reader in) throws IOException { 512 BufferedReader br = new BufferedReader (in); 513 List <Difference> diffs = new ArrayList <Difference>(); 514 String line = null; 515 do { 516 while (line == null || !(line.startsWith(UNIFIED_MARK) && 517 line.length() > UNIFIED_MARK.length() && 518 line.endsWith(UNIFIED_MARK))) { 519 line = br.readLine(); 520 if (line == null) break; 521 } 522 if (line == null) continue; 523 int[] intervals = new int[4]; 524 try { 525 readUnifiedNums(line, UNIFIED_MARK.length(), intervals); 526 } catch (NumberFormatException nfex) { 527 IOException ioex = new IOException ("Can not parse: " + line); 528 ioex.initCause(nfex); 529 throw ioex; 530 } 531 line = fillUnidifChanges(intervals, br, diffs); 532 } while (line != null); 533 return diffs.toArray(new Difference[diffs.size()]); 534 } 535 536 private static void readUnifiedNums(String str, int off, int[] values) throws NumberFormatException { 537 while (str.charAt(off) == ' ' || str.charAt(off) == '-') off++; 538 int end = str.indexOf(CONTEXT_MARK_DELIMETER, off); 539 if (end > 0) { 540 values[0] = Integer.parseInt(str.substring(off, end).trim()); 541 } else throw new NumberFormatException ("Missing comma."); 542 off = end + 1; 543 end = str.indexOf(' ', off); 544 if (end > 0) { 545 values[1] = Integer.parseInt(str.substring(off, end).trim()); 546 } else throw new NumberFormatException ("Missing middle space."); 547 off = end + 1; 548 while (str.charAt(off) == ' ' || str.charAt(off) == '+') off++; 549 end = str.indexOf(CONTEXT_MARK_DELIMETER, off); 550 if (end > 0) { 551 values[2] = Integer.parseInt(str.substring(off, end).trim()); 552 } else throw new NumberFormatException ("Missing second comma."); 553 off = end + 1; 554 end = str.indexOf(' ', off); 555 if (end > 0) { 556 values[3] = Integer.parseInt(str.substring(off, end).trim()); 557 } else throw new NumberFormatException ("Missing final space."); 558 values[1] += values[0] - 1; 559 values[3] += values[2] - 1; 560 } 561 562 private static String fillUnidifChanges(int[] interval, BufferedReader br, 563 List <Difference> diffs) throws IOException { 564 String line = br.readLine(); 565 int pos1 = interval[0]; 566 int pos2 = interval[2]; 567 while (line != null && pos1 <= interval[1] && pos2 <= interval[3]) { 568 if (line.startsWith(LINE_PREP_UNIF_ADD)) { 569 int begin = pos2; 570 StringBuffer changeText = new StringBuffer (); 571 changeText.append(line.substring(LINE_PREP_UNIF_ADD.length())); 572 changeText.append('\n'); 573 do { 574 line = br.readLine(); 575 pos2++; 576 if (line.startsWith(LINE_PREP_UNIF_ADD)) { 577 changeText.append(line.substring(LINE_PREP_UNIF_ADD.length())); 578 changeText.append('\n'); 579 } else { 580 break; 581 } 582 } while (true); 583 Difference diff = null; 584 if (diffs.size() > 0) { 585 Difference previousDiff = (Difference) diffs.get(diffs.size() - 1); 586 if (Difference.DELETE == previousDiff.getType() && previousDiff.getFirstEnd() == (pos1 - 1)) { 587 diff = new Difference(Difference.CHANGE, 588 previousDiff.getFirstStart(), previousDiff.getFirstEnd(), 589 begin, pos2 - 1, previousDiff.getFirstText(), changeText.toString()); 590 diffs.remove(diffs.size() - 1); 591 } 592 } 593 if (diff == null) { 594 diff = new Difference(Difference.ADD, pos1 - 1, 0, begin, pos2 - 1, null, changeText.toString()); 595 } 596 diffs.add(diff); 597 } else if (line.startsWith(LINE_PREP_UNIF_REMOVE)) { 598 int begin = pos1; 599 StringBuffer changeText = new StringBuffer (); 600 changeText.append(line.substring(LINE_PREP_UNIF_REMOVE.length())); 601 changeText.append('\n'); 602 do { 603 line = br.readLine(); 604 pos1++; 605 if (line.startsWith(LINE_PREP_UNIF_REMOVE)) { 606 changeText.append(line.substring(LINE_PREP_UNIF_REMOVE.length())); 607 changeText.append('\n'); 608 } else { 609 break; 610 } 611 } while (true); 612 Difference diff = null; 613 if (diffs.size() > 0) { 614 Difference previousDiff = (Difference) diffs.get(diffs.size() - 1); 615 if (Difference.ADD == previousDiff.getType() && previousDiff.getSecondEnd() == (pos2 - 1)) { 616 diff = new Difference(Difference.CHANGE, begin, pos1 - 1, 617 previousDiff.getFirstStart(), previousDiff.getFirstEnd(), 618 changeText.toString(), previousDiff.getFirstText()); 619 diffs.remove(diffs.size() - 1); 620 } 621 } 622 if (diff == null) { 623 diff = new Difference(Difference.DELETE, begin, pos1 - 1, pos2 - 1, 0, changeText.toString(), null); 624 } 625 diffs.add(diff); 626 } else { 627 line = br.readLine(); 628 pos1++; 629 pos2++; 630 } 631 } 632 return line; 633 } 634 635 private static Difference[] parseNormalDiff(Reader in) throws IOException { 636 Pattern normRegexp; 637 try { 638 normRegexp = Pattern.compile(CmdlineDiffProvider.DIFF_REGEXP); 639 } catch (PatternSyntaxException rsex) { 640 normRegexp = null; 641 } 642 StringBuffer firstText = new StringBuffer (); 643 StringBuffer secondText = new StringBuffer (); 644 BufferedReader br = new BufferedReader (in); 645 List <Difference> diffs = new ArrayList <Difference>(); 646 String line; 647 while ((line = br.readLine()) != null) { 648 CmdlineDiffProvider.outputLine(line, normRegexp, diffs, firstText, secondText); 649 } 650 CmdlineDiffProvider.setTextOnLastDifference(diffs, firstText, secondText); 651 return diffs.toArray(new Difference[diffs.size()]); 652 } 653 654 658 private static class SinglePatchReader extends Reader { 659 660 private static final int BUFF_SIZE = 512; 661 private PushbackReader in; 662 private char[] buffer = new char[BUFF_SIZE]; 663 private int buffLength = 0; 664 private int buffPos = 0; 665 private boolean isAtEndOfPatch = false; 666 667 public SinglePatchReader(Reader in) { 668 this.in = new PushbackReader (in, BUFF_SIZE); 669 } 670 671 public int read(char[] values, int offset, int length) throws java.io.IOException { 672 int totRead = 0; 674 while (length > 0) { 675 int buffCopyLength; 676 if (length < buffLength) { 677 buffCopyLength = length; 678 length = 0; 679 } else { 680 if (buffLength > 0) { 681 buffCopyLength = buffLength; 682 length -= buffLength; 683 } else { 684 if (isAtEndOfPatch) { 685 length = 0; 686 buffCopyLength = -1; 687 } else { 688 buffLength = readTillEndOfPatch(buffer); 689 buffPos = 0; 690 if (buffLength <= 0) { 691 buffCopyLength = -1; 692 } else { 693 buffCopyLength = Math.min(length, buffLength); 694 length -= buffCopyLength; 695 } 696 } 697 } 698 } 699 if (buffCopyLength > 0) { 700 System.arraycopy(buffer, buffPos, values, offset, buffCopyLength); 701 offset += buffCopyLength; 702 buffLength -= buffCopyLength; 703 buffPos += buffCopyLength; 704 totRead += buffCopyLength; 705 } else { 706 length = 0; 707 } 708 } 709 if (totRead == 0) totRead = -1; 710 return totRead; 712 } 713 714 private int readTillEndOfPatch(char[] buffer) throws IOException { 715 int length = in.read(buffer); 716 String input = new String (buffer); 717 int end = 0; 718 if (input.startsWith(FILE_INDEX) || ((end = input.indexOf("\n"+FILE_INDEX))) >= 0) { 719 isAtEndOfPatch = true; 720 } else { 721 end = input.lastIndexOf('\n'); 722 if (end >= 0) end++; 723 } 724 if (end >= 0 && end < length) { 725 in.unread(buffer, end, length - end); 726 length = end; 727 } 728 if (end == 0) length = -1; 729 return length; 730 } 731 732 public void close() throws java.io.IOException { 733 } 735 736 private static final String FILE_INDEX = "Index: "; 738 private boolean hasNextPatch(int[] diffType, String [] fileName) throws IOException { 739 isAtEndOfPatch = false; PushbackReader patchSource = in; 741 char[] buff = new char[DIFFERENCE_DELIMETER.length()]; 742 int length; 743 Pattern normRegexp; 744 boolean contextBeginDetected = false; 745 try { 746 normRegexp = Pattern.compile(CmdlineDiffProvider.DIFF_REGEXP); 747 } catch (PatternSyntaxException rsex) { 748 normRegexp = null; 749 } 750 while ((length = patchSource.read(buff)) > 0) { 751 String input = new String (buff, 0, length); 752 int nl; 753 int nln = input.indexOf('\n'); 754 int nlr = input.indexOf('\r'); 755 if (nln < 0) nl = nlr; 756 else nl = nln; 757 if (nl >= 0) { 758 if (nln > 0 && nln == nlr + 1) { 759 input = input.substring(0, nl - 1); 760 } else { 761 input = input.substring(0, nl); 762 } 763 if (nl + 1 < length) { 764 patchSource.unread(buff, nl + 1, length - (nl + 1)); 765 length = nl + 1; 766 } 767 } 768 if (input.equals(DIFFERENCE_DELIMETER)) { 769 diffType[0] = CONTEXT_DIFF; 770 patchSource.unread(buff, 0, length); 771 return true; 772 } else if (input.startsWith(UNIFIED_MARK + " ")) { 773 diffType[0] = UNIFIED_DIFF; 774 patchSource.unread(buff, 0, length); 775 return true; 776 } else if (input.startsWith(FILE_INDEX)) { 777 StringBuffer name = new StringBuffer (input.substring(FILE_INDEX.length())); 778 if (nl < 0) { 779 int r; 780 char c; 781 while ((c = (char) (r = patchSource.read())) != '\n' && r != -1 && r != '\r') { 782 name.append(c); 783 } 784 } 785 fileName[1] = name.toString(); 786 } else if (input.startsWith(CONTEXT_MARK1B) || !contextBeginDetected && input.startsWith(UNIFIED_MARK1)) { 787 StringBuffer name; 788 if (input.startsWith(CONTEXT_MARK1B)) { 789 contextBeginDetected = true; 790 name = new StringBuffer (input.substring(CONTEXT_MARK1B.length())); 791 } else { 792 name = new StringBuffer (input.substring(UNIFIED_MARK1.length())); 793 } 794 String sname = name.toString(); 795 int spaceIndex = sname.indexOf('\t'); 796 if (spaceIndex > 0) { 797 name = name.delete(spaceIndex, name.length()); 798 } 799 if (nl < 0) { 800 int r = 0; 801 char c = 0; 802 if (spaceIndex < 0) { 803 while ((c = (char) (r = patchSource.read())) != '\n' && c != '\r' && c != '\t' && r != -1) { 804 name.append(c); 805 } 806 } 807 if (c != '\n' && c != '\r' && r != -1) { 808 while ((c = (char) (r = patchSource.read())) != '\n' && c != '\r' && r != -1) ; } 810 if (c == '\r') { 811 r = patchSource.read(); 812 if (r != -1) { 813 c = (char) r; 814 if (c != '\n') patchSource.unread(c); 815 } 816 } 817 } 818 fileName[0] = name.toString(); 819 } else if (normRegexp != null && normRegexp.matcher(input).matches()) { 820 diffType[0] = NORMAL_DIFF; 821 patchSource.unread(buff, 0, length); 822 return true; 823 } else { if (nl < 0) { 825 int r; 826 char c; 827 while ((c = (char) (r = patchSource.read())) != '\n' && c != '\r' && r != -1) ; 828 if (c == '\r') { 829 r = patchSource.read(); 830 if (r != -1) { 831 c = (char) r; 832 if (c != '\n') patchSource.unread(c); 833 } 834 } 835 } 836 } 837 } 838 return false; 839 } 840 841 } 842 843 public static class FileDifferences extends Object { 844 845 private String fileName; 846 private String indexName; 847 private Difference[] diffs; 848 849 public FileDifferences(String fileName, String indexName, Difference[] diffs) { 850 this.fileName = fileName; 851 this.diffs = diffs; 852 this.indexName = indexName; 853 } 854 855 858 public final String getFileName() { 859 return fileName; 860 } 861 862 865 public final String getIndexName() { 866 return indexName; 867 } 868 869 public final Difference[] getDifferences() { 870 return diffs; 871 } 872 } 873 874 } 875 | Popular Tags |