1 11 package org.eclipse.compare.internal.patch; 12 13 import java.io.BufferedReader ; 14 import java.io.IOException ; 15 import java.text.ParseException ; 16 import java.util.*; 17 18 import org.eclipse.core.resources.IProject; 19 import org.eclipse.core.resources.ResourcesPlugin; 20 import org.eclipse.core.runtime.*; 21 import org.eclipse.swt.SWT; 22 23 import com.ibm.icu.text.DateFormat; 24 import com.ibm.icu.text.SimpleDateFormat; 25 26 public class PatchReader { 27 28 private static final boolean DEBUG= false; 29 30 private static final String DEV_NULL= "/dev/null"; 32 static protected final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; 34 40 private static DateFormat[] DATE_FORMATS= new DateFormat[] { 42 new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy"), new SimpleDateFormat("yyyy/MM/dd kk:mm:ss"), new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy", Locale.US) }; 46 47 private boolean fIsWorkspacePatch; 48 private DiffProject[] fDiffProjects; 49 private FileDiff[] fDiffs; 50 51 public static final String MULTIPROJECTPATCH_HEADER= "### Eclipse Workspace Patch"; 54 public static final String MULTIPROJECTPATCH_VERSION= "1.0"; 56 public static final String MULTIPROJECTPATCH_PROJECT= "#P"; 58 public void parse(BufferedReader reader) throws IOException { 59 List diffs= new ArrayList(); 60 HashMap diffProjects= new HashMap(4); 61 String line= null; 62 boolean reread= false; 63 String diffArgs= null; 64 String fileName= null; 65 String project= ""; fIsWorkspacePatch= false; 69 70 LineReader lr= new LineReader(reader); 71 if (!"carbon".equals(SWT.getPlatform())) lr.ignoreSingleCR(); 73 74 line= lr.readLine(); 76 if (line != null && line.startsWith(PatchReader.MULTIPROJECTPATCH_HEADER)) { 77 fIsWorkspacePatch= true; 78 } else { 79 parse(lr, line); 80 return; 81 } 82 83 while (true) { 85 if (!reread) 86 line= lr.readLine(); 87 reread= false; 88 if (line == null) 89 break; 90 if (line.length() < 4) 91 continue; 93 if (line.startsWith(PatchReader.MULTIPROJECTPATCH_PROJECT)) { 94 project= line.substring(2).trim(); 95 continue; 96 } 97 98 if (line.startsWith("Index: ")) { fileName= line.substring(7).trim(); 100 continue; 101 } 102 if (line.startsWith("diff")) { diffArgs= line.substring(4).trim(); 104 continue; 105 } 106 107 if (line.startsWith("--- ")) { DiffProject diffProject; 113 if (!diffProjects.containsKey(project)) { 114 IProject iproject= ResourcesPlugin.getWorkspace().getRoot().getProject(project); 115 diffProject= new DiffProject(iproject); 116 diffProjects.put(project, diffProject); 117 } else { 118 diffProject= (DiffProject) diffProjects.get(project); 119 } 120 121 line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName, diffProject); 122 diffArgs= fileName= null; 123 reread= true; 124 } 125 } 126 127 lr.close(); 128 129 fDiffProjects= (DiffProject[]) diffProjects.values().toArray(new DiffProject[diffProjects.size()]); 130 fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); 131 } 132 133 private String readUnifiedDiff(List diffs, LineReader lr, String line, String diffArgs, String fileName, DiffProject diffProject) throws IOException { 134 List newDiffs= new ArrayList(); 135 String nextLine= readUnifiedDiff(newDiffs, lr, line, diffArgs, fileName); 136 for (Iterator iter= newDiffs.iterator(); iter.hasNext();) { 137 FileDiff diff= (FileDiff) iter.next(); 138 diffProject.add(diff); 139 diffs.add(diff); 140 } 141 return nextLine; 142 } 143 144 public void parse(LineReader lr, String line) throws IOException { 145 List diffs= new ArrayList(); 146 boolean reread= false; 147 String diffArgs= null; 148 String fileName= null; 149 List headerLines = new ArrayList(); 150 151 reread= line!=null; 153 while (true) { 154 if (!reread) 155 line= lr.readLine(); 156 reread= false; 157 if (line == null) 158 break; 159 160 if (line.startsWith("Index: ")) { fileName= line.substring(7).trim(); 163 } else if (line.startsWith("diff")) { diffArgs= line.substring(4).trim(); 165 } else if (line.startsWith("--- ")) { line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName); 167 if (!headerLines.isEmpty()) 168 setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); 169 diffArgs= fileName= null; 170 reread= true; 171 } else if (line.startsWith("*** ")) { line= readContextDiff(diffs, lr, line, diffArgs, fileName); 173 if (!headerLines.isEmpty()) 174 setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); 175 diffArgs= fileName= null; 176 reread= true; 177 } 178 179 if (!reread) { 182 headerLines.add(line); 183 } 184 } 185 186 lr.close(); 187 188 fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); 189 } 190 191 private void setHeader(FileDiff diff, List headerLines) { 192 String header = Patcher.createString(false, headerLines); 193 diff.setHeader(header); 194 headerLines.clear(); 195 } 196 197 200 protected String readUnifiedDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { 201 202 String [] oldArgs= split(line.substring(4)); 203 204 line= reader.readLine(); 206 if (line == null || !line.startsWith("+++ ")) return line; 208 209 String [] newArgs= split(line.substring(4)); 210 211 FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), 212 extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); 213 diffs.add(diff); 214 215 int[] oldRange= new int[2]; 216 int[] newRange= new int[2]; 217 List lines= new ArrayList(); 218 219 boolean encounteredPlus = false; 220 boolean encounteredMinus = false; 221 boolean encounteredSpace = false; 222 223 try { 224 while (true) { 226 227 line= reader.readLine(); 228 if (line == null) 229 return null; 230 231 if (reader.lineContentLength(line) == 0) { 232 continue; 235 } 236 237 char c= line.charAt(0); 238 switch (c) { 239 case '@': 240 if (line.startsWith("@@ ")) { if (lines.size() > 0) { 243 new Hunk(diff, oldRange, newRange, lines,encounteredPlus, encounteredMinus, encounteredSpace); 244 lines.clear(); 245 } 246 247 extractPair(line, '-', oldRange); 249 extractPair(line, '+', newRange); 250 continue; 251 } 252 break; 253 case ' ': 254 encounteredSpace = true; 255 lines.add(line); 256 continue; 257 case '+': 258 encounteredPlus = true; 259 lines.add(line); 260 continue; 261 case '-': 262 encounteredMinus = true; 263 lines.add(line); 264 continue; 265 case '\\': 266 if (line.indexOf("newline at end") > 0) { int lastIndex= lines.size(); 268 if (lastIndex > 0) { 269 line= (String ) lines.get(lastIndex-1); 270 int end= line.length()-1; 271 char lc= line.charAt(end); 272 if (lc == '\n') { 273 end--; 274 if (end > 0 && line.charAt(end) == '\r') 275 end--; 276 } else if (lc == '\r') { 277 end--; 278 } 279 line= line.substring(0, end+1); 280 lines.set(lastIndex-1, line); 281 } 282 continue; 283 } 284 break; 285 default: 286 if (DEBUG) { 287 int a1= c, a2= 0; 288 if (line.length() > 1) 289 a2= line.charAt(1); 290 System.out.println("char: " + a1 + " " + a2); } 292 break; 293 } 294 return line; 295 } 296 } finally { 297 if (lines.size() > 0) 298 new Hunk(diff, oldRange, newRange, lines, encounteredPlus, encounteredMinus, encounteredSpace); 299 } 300 } 301 302 305 private String readContextDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { 306 307 String [] oldArgs= split(line.substring(4)); 308 309 line= reader.readLine(); 311 if (line == null || !line.startsWith("--- ")) return line; 313 314 String [] newArgs= split(line.substring(4)); 315 316 FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), 317 extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); 318 diffs.add(diff); 319 320 int[] oldRange= new int[2]; 321 int[] newRange= new int[2]; 322 List oldLines= new ArrayList(); 323 List newLines= new ArrayList(); 324 List lines= oldLines; 325 326 327 boolean encounteredPlus = false; 328 boolean encounteredMinus = false; 329 boolean encounteredSpace = false; 330 331 try { 332 while (true) { 334 335 line= reader.readLine(); 336 if (line == null) 337 return line; 338 339 int l= line.length(); 340 if (l == 0) 341 continue; 342 if (l > 1) { 343 switch (line.charAt(0)) { 344 case '*': 345 if (line.startsWith("***************")) { if (oldLines.size() > 0 || newLines.size() > 0) { 348 new Hunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); 349 oldLines.clear(); 350 newLines.clear(); 351 } 352 continue; 353 } 354 if (line.startsWith("*** ")) { extractPair(line, ' ', oldRange); 357 oldRange[1]= oldRange[1]-oldRange[0]+1; 358 lines= oldLines; 359 continue; 360 } 361 break; 362 case ' ': if (line.charAt(1) == ' ') { 364 lines.add(line); 365 continue; 366 } 367 break; 368 case '+': if (line.charAt(1) == ' ') { 370 encounteredPlus = true; 371 lines.add(line); 372 continue; 373 } 374 break; 375 case '!': if (line.charAt(1) == ' ') { 377 encounteredSpace = true; 378 lines.add(line); 379 continue; 380 } 381 break; 382 case '-': 383 if (line.charAt(1) == ' ') { encounteredMinus = true; 385 lines.add(line); 386 continue; 387 } 388 if (line.startsWith("--- ")) { extractPair(line, ' ', newRange); 391 newRange[1]= newRange[1]-newRange[0]+1; 392 lines= newLines; 393 continue; 394 } 395 break; 396 default: 397 break; 398 } 399 } 400 return line; 401 } 402 } finally { 403 if (oldLines.size() > 0 || newLines.size() > 0) 405 new Hunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); 406 } 407 } 408 409 413 private List unifyLines(List oldLines, List newLines) { 414 List result= new ArrayList(); 415 416 String [] ol= (String []) oldLines.toArray(new String [oldLines.size()]); 417 String [] nl= (String []) newLines.toArray(new String [newLines.size()]); 418 419 int oi= 0, ni= 0; 420 421 while (true) { 422 423 char oc= 0; 424 String o= null; 425 if (oi < ol.length) { 426 o= ol[oi]; 427 oc= o.charAt(0); 428 } 429 430 char nc= 0; 431 String n= null; 432 if (ni < nl.length) { 433 n= nl[ni]; 434 nc= n.charAt(0); 435 } 436 437 if (oc == 0 && nc == 0) 439 break; 440 441 if (oc == '-') { 443 do { 444 result.add('-' + o.substring(2)); 445 oi++; 446 if (oi >= ol.length) 447 break; 448 o= ol[oi]; 449 } while (o.charAt(0) == '-'); 450 continue; 451 } 452 453 if (nc == '+') { 455 do { 456 result.add('+' + n.substring(2)); 457 ni++; 458 if (ni >= nl.length) 459 break; 460 n= nl[ni]; 461 } while (n.charAt(0) == '+'); 462 continue; 463 } 464 465 if (oc == '!' && nc == '!') { 467 do { 469 result.add('-' + o.substring(2)); 470 oi++; 471 if (oi >= ol.length) 472 break; 473 o= ol[oi]; 474 } while (o.charAt(0) == '!'); 475 476 do { 478 result.add('+' + n.substring(2)); 479 ni++; 480 if (ni >= nl.length) 481 break; 482 n= nl[ni]; 483 } while (n.charAt(0) == '!'); 484 485 continue; 486 } 487 488 if (oc == ' ' && nc == ' ') { 490 do { 491 Assert.isTrue(o.equals(n), "non matching context lines"); result.add(' ' + o.substring(2)); 493 oi++; 494 ni++; 495 if (oi >= ol.length || ni >= nl.length) 496 break; 497 o= ol[oi]; 498 n= nl[ni]; 499 } while (o.charAt(0) == ' ' && n.charAt(0) == ' '); 500 continue; 501 } 502 503 if (oc == ' ') { 504 do { 505 result.add(' ' + o.substring(2)); 506 oi++; 507 if (oi >= ol.length) 508 break; 509 o= ol[oi]; 510 } while (o.charAt(0) == ' '); 511 continue; 512 } 513 514 if (nc == ' ') { 515 do { 516 result.add(' ' + n.substring(2)); 517 ni++; 518 if (ni >= nl.length) 519 break; 520 n= nl[ni]; 521 } while (n.charAt(0) == ' '); 522 continue; 523 } 524 525 Assert.isTrue(false, "unexpected char <" + oc + "> <" + nc + ">"); } 527 528 return result; 529 } 530 531 534 private long extractDate(String [] args, int n) { 535 if (n < args.length) { 536 String line= args[n]; 537 for (int i= 0; i < DATE_FORMATS.length; i++) { 538 DATE_FORMATS[i].setLenient(true); 539 try { 540 Date date= DATE_FORMATS[i].parse(line); 541 return date.getTime(); 542 } catch (ParseException ex) { 543 } 545 } 546 } 548 return -1; 549 } 550 551 554 private IPath extractPath(String [] args, int n, String path2) { 555 if (n < args.length) { 556 String path= args[n]; 557 if (DEV_NULL.equals(path)) 558 return null; 559 int pos= path.lastIndexOf(':'); 560 if (pos >= 0) 561 path= path.substring(0, pos); 562 if (path2 != null && !path2.equals(path)) { 563 if (DEBUG) System.out.println("path mismatch: " + path2); path= path2; 565 } 566 return new Path(path); 567 } 568 return null; 569 } 570 571 579 private void extractPair(String line, char start, int[] pair) { 580 pair[0]= pair[1]= -1; 581 int startPos= line.indexOf(start); 582 if (startPos < 0) { 583 if (DEBUG) System.out.println("parsing error in extractPair: couldn't find \'" + start + "\'"); return; 585 } 586 line= line.substring(startPos+1); 587 int endPos= line.indexOf(' '); 588 if (endPos < 0) { 589 if (DEBUG) System.out.println("parsing error in extractPair: couldn't find end blank"); return; 591 } 592 line= line.substring(0, endPos); 593 int comma= line.indexOf(','); 594 if (comma >= 0) { 595 pair[0]= Integer.parseInt(line.substring(0, comma)); 596 pair[1]= Integer.parseInt(line.substring(comma+1)); 597 } else { pair[0]= Integer.parseInt(line); 599 pair[1]= 1; 600 } 601 } 602 603 604 608 private String [] split(String line) { 609 List l= new ArrayList(); 610 StringTokenizer st= new StringTokenizer(line, "\t"); while (st.hasMoreElements()) { 612 String token= st.nextToken().trim(); 613 if (token.length() > 0) 614 l.add(token); 615 } 616 return (String []) l.toArray(new String [l.size()]); 617 } 618 619 public boolean isWorkspacePatch() { 620 return fIsWorkspacePatch; 621 } 622 623 public DiffProject[] getDiffProjects() { 624 return fDiffProjects; 625 } 626 627 public FileDiff[] getDiffs() { 628 return fDiffs; 629 } 630 631 public FileDiff[] getAdjustedDiffs() { 632 if (!isWorkspacePatch() || fDiffs.length == 0) 633 return fDiffs; 634 List result = new ArrayList(); 635 for (int i = 0; i < fDiffs.length; i++) { 636 FileDiff diff = fDiffs[i]; 637 result.add(diff.asRelativeDiff()); 638 } 639 return (FileDiff[]) result.toArray(new FileDiff[result.size()]); 640 } 641 } 642 | Popular Tags |