1 36 37 package jnlp.sample.jardiff; 38 39 import java.io.*; 40 import java.util.*; 41 import java.util.jar.*; 42 import java.util.zip.*; 43 44 45 54 public class JarDiff implements JarDiffConstants { 55 private static final int DEFAULT_READ_SIZE = 2048; 56 private static byte[] newBytes = new byte[DEFAULT_READ_SIZE]; 57 private static byte[] oldBytes = new byte[DEFAULT_READ_SIZE]; 58 private static ResourceBundle _resources = null; 59 60 private static boolean _debug; 64 65 public static ResourceBundle getResources() { 66 if (_resources == null) { 67 _resources = ResourceBundle.getBundle("jnlp/sample/jardiff/resources/strings"); 68 } 69 return _resources; 70 } 71 72 76 public static void createPatch(String oldPath, String newPath, 77 OutputStream os, boolean minimal) throws IOException{ 78 JarFile2 oldJar = new JarFile2(oldPath); 79 JarFile2 newJar = new JarFile2(newPath); 80 81 try { 82 Iterator entries; 83 HashMap moved = new HashMap(); 84 HashSet visited = new HashSet(); 85 HashSet implicit = new HashSet(); 86 HashSet moveSrc = new HashSet(); 87 HashSet newEntries = new HashSet(); 88 89 90 entries = newJar.getJarEntries(); 98 if (entries != null) { 99 while (entries.hasNext()) { 100 JarEntry newEntry = (JarEntry)entries.next(); 101 String newname = newEntry.getName(); 102 103 String oldname = oldJar.getBestMatch(newJar, newEntry); 105 if (oldname == null) { 106 if (_debug) { 108 System.out.println("NEW: "+ newname); 109 } 110 newEntries.add(newname); 111 } else { 112 114 if (oldname.equals(newname) && !moveSrc.contains(oldname)) { 117 if (_debug) { 118 System.out.println(newname + " added to implicit set!"); 119 } 120 implicit.add(newname); 121 } else { 122 if (!minimal && (implicit.contains(oldname) || 130 moveSrc.contains(oldname) )) { 131 132 135 if (_debug) { 136 137 System.out.println("NEW: "+ newname); 138 } 139 newEntries.add(newname); 140 } else { 141 if (_debug) { 143 System.err.println("moved.put " + newname + " " + oldname); 144 } 145 moved.put(newname, oldname); 146 moveSrc.add(oldname); 147 } 148 if (implicit.contains(oldname) && minimal) { 150 151 if (_debug) { 152 System.err.println("implicit.remove " + oldname); 153 154 System.err.println("moved.put " + oldname + " " + oldname); 155 156 } 157 implicit.remove(oldname); 158 moved.put(oldname, oldname); 159 moveSrc.add(oldname); 160 } 161 162 163 } 164 } 165 } 166 } 168 ArrayList deleted = new ArrayList(); 171 entries = oldJar.getJarEntries(); 172 if (entries != null) { 173 while (entries.hasNext()) { 174 JarEntry oldEntry = (JarEntry)entries.next(); 175 String oldName = oldEntry.getName(); 176 if (!implicit.contains(oldName) && !moveSrc.contains(oldName) 177 && !newEntries.contains(oldName)) { 178 if (_debug) { 179 System.err.println("deleted.add " + oldName); 180 } 181 deleted.add(oldName); 182 } 183 } 184 } 185 186 if (_debug) { 188 entries = moved.keySet().iterator(); 190 if (entries != null) { 191 System.out.println("MOVED MAP!!!"); 192 while (entries.hasNext()) { 193 String newName = (String )entries.next(); 194 String oldName = (String )moved.get(newName); 195 System.out.println("key is " + newName + " value is " + oldName); 196 } 197 } 198 199 entries = implicit.iterator(); 201 if (entries != null) { 202 System.out.println("IMOVE MAP!!!"); 203 while (entries.hasNext()) { 204 String newName = (String )entries.next(); 205 System.out.println("key is " + newName); 206 } 207 } 208 } 209 210 JarOutputStream jos = new JarOutputStream(os); 211 212 createIndex(jos, deleted, moved); 214 215 entries = newEntries.iterator(); 217 if (entries != null) { 218 219 while (entries.hasNext()) { 220 String newName = (String )entries.next(); 221 if (_debug) { 222 System.out.println("New File: " + newName); 223 } 224 writeEntry(jos, newJar.getEntryByName(newName), newJar); 225 } 226 } 227 228 229 jos.finish(); 230 jos.close(); 231 232 } catch (IOException ioE){ 233 throw ioE; 234 } finally { 235 try { 236 oldJar.getJarFile().close(); 237 } catch (IOException e1) { 238 } 240 try { 241 newJar.getJarFile().close(); 242 } catch (IOException e1) { 243 } 245 } } 247 248 253 private static void createIndex(JarOutputStream jos, List oldEntries, 254 Map movedMap) throws 255 IOException { 256 StringWriter writer = new StringWriter(); 257 258 writer.write(VERSION_HEADER); 259 writer.write("\r\n"); 260 261 for (int counter = 0; counter < oldEntries.size(); counter++) { 263 String name = (String )oldEntries.get(counter); 264 265 writer.write(REMOVE_COMMAND); 266 writer.write(" "); 267 writeEscapedString(writer, name); 268 writer.write("\r\n"); 269 } 270 271 Iterator names = movedMap.keySet().iterator(); 273 274 if (names != null) { 275 while (names.hasNext()) { 276 String newName = (String )names.next(); 277 String oldName = (String )movedMap.get(newName); 278 279 writer.write(MOVE_COMMAND); 280 writer.write(" "); 281 writeEscapedString(writer, oldName); 282 writer.write(" "); 283 writeEscapedString(writer, newName); 284 writer.write("\r\n"); 285 286 } 287 } 288 289 JarEntry je = new JarEntry(INDEX_NAME); 290 byte[] bytes = writer.toString().getBytes("UTF-8"); 291 292 writer.close(); 293 jos.putNextEntry(je); 294 jos.write(bytes, 0, bytes.length); 295 } 296 297 private static void writeEscapedString(Writer writer, String string) 298 throws IOException { 299 int index = 0; 300 int last = 0; 301 char[] chars = null; 302 303 while ((index = string.indexOf(' ', index)) != -1) { 304 if (last != index) { 305 if (chars == null) { 306 chars = string.toCharArray(); 307 } 308 writer.write(chars, last, index - last); 309 } 310 last = index; 311 index++; 312 writer.write('\\'); 313 } 314 if (last != 0) { 315 writer.write(chars, last, chars.length - last); 316 } 317 else { 318 writer.write(string); 320 } 321 } 322 323 private static void writeEntry(JarOutputStream jos, JarEntry entry, 324 JarFile2 file) throws IOException { 325 writeEntry(jos, entry, file.getJarFile().getInputStream(entry)); 326 } 327 328 private static void writeEntry(JarOutputStream jos, JarEntry entry, 329 InputStream data) throws IOException { 330 jos.putNextEntry(entry); 331 332 try { 333 int size = data.read(newBytes); 335 336 while (size != -1) { 337 jos.write(newBytes, 0, size); 338 size = data.read(newBytes); 339 } 340 } catch(IOException ioE) { 341 throw ioE; 342 } finally { 343 try { 344 data.close(); 345 } catch(IOException e){ 346 } 348 349 } 350 } 351 352 353 354 355 358 private static class JarFile2 { 359 private JarFile _jar; 360 private List _entries; 361 private HashMap _nameToEntryMap; 362 private HashMap _crcToEntryMap; 363 364 public JarFile2(String path) throws IOException { 365 _jar = new JarFile(new File(path)); 366 index(); 367 } 368 369 public JarFile getJarFile() { 370 return _jar; 371 } 372 373 public Iterator getJarEntries() { 374 return _entries.iterator(); 375 } 376 377 public JarEntry getEntryByName(String name) { 378 return (JarEntry)_nameToEntryMap.get(name); 379 } 380 381 384 private static boolean differs(InputStream oldIS, InputStream newIS) 385 throws IOException { 386 int newSize = 0; 387 int oldSize; 388 int total = 0; 389 boolean retVal = false; 390 391 try{ 392 while (newSize != -1) { 393 newSize = newIS.read(newBytes); 394 oldSize = oldIS.read(oldBytes); 395 396 if (newSize != oldSize) { 397 if (_debug) { 398 System.out.println("\tread sizes differ: " + newSize + 399 " " + oldSize + " total " + total); 400 } 401 retVal = true; 402 break; 403 } 404 if (newSize > 0) { 405 while (--newSize >= 0) { 406 total++; 407 if (newBytes[newSize] != oldBytes[newSize]) { 408 if (_debug) { 409 System.out.println("\tbytes differ at " + 410 total); 411 } 412 retVal = true; 413 break; 414 } 415 if ( retVal ) { 416 break; 418 } 419 newSize = 0; 420 } 421 } 422 } 423 } catch(IOException ioE){ 424 throw ioE; 425 } finally { 426 try { 427 oldIS.close(); 428 } catch(IOException e){ 429 } 431 try { 432 newIS.close(); 433 } catch(IOException e){ 434 } 436 } 437 return retVal; 438 } 439 440 public String getBestMatch(JarFile2 file, JarEntry entry) throws IOException { 441 if (contains(file, entry)) { 443 return (entry.getName()); 444 } 445 446 return (hasSameContent(file,entry)); 448 } 449 450 public boolean contains(JarFile2 f, JarEntry e) throws IOException { 451 452 JarEntry thisEntry = getEntryByName(e.getName()); 453 454 if (thisEntry == null) 456 return false; 457 458 if (thisEntry.getCrc() != e.getCrc()) 460 return false; 461 462 InputStream oldIS = getJarFile().getInputStream(thisEntry); 464 InputStream newIS = f.getJarFile().getInputStream(e); 465 boolean retValue = differs(oldIS, newIS); 466 467 return !retValue; 468 } 469 470 public String hasSameContent(JarFile2 file, JarEntry entry) throws 471 IOException { 472 473 String thisName = null; 474 475 Long crcL = new Long (entry.getCrc()); 476 477 if (_crcToEntryMap.containsKey(crcL)) { 479 LinkedList ll = (LinkedList)_crcToEntryMap.get(crcL); 481 ListIterator li = ll.listIterator(0); 483 if (li != null) { 484 while (li.hasNext()) { 485 JarEntry thisEntry = (JarEntry)li.next(); 486 487 InputStream oldIS = getJarFile().getInputStream(thisEntry); 489 InputStream newIS = file.getJarFile().getInputStream(entry); 490 491 if (!differs(oldIS, newIS)) { 492 thisName = thisEntry.getName(); 493 return thisName; 494 } 495 } 496 } 497 } 498 499 return thisName; 500 501 } 502 503 504 505 506 507 private void index() throws IOException { 508 Enumeration entries = _jar.entries(); 509 510 _nameToEntryMap = new HashMap(); 511 _crcToEntryMap = new HashMap(); 512 513 _entries = new ArrayList(); 514 if (_debug) { 515 System.out.println("indexing: " + _jar.getName()); 516 } 517 if (entries != null) { 518 while (entries.hasMoreElements()) { 519 JarEntry entry = (JarEntry)entries.nextElement(); 520 521 long crc = entry.getCrc(); 522 523 Long crcL = new Long (crc); 524 525 if (_debug) { 526 System.out.println("\t" + entry.getName() + " CRC " + 527 crc); 528 } 529 530 _nameToEntryMap.put(entry.getName(), entry); 531 _entries.add(entry); 532 533 if (_crcToEntryMap.containsKey(crcL)) { 535 538 LinkedList ll = (LinkedList)_crcToEntryMap.get(crcL); 540 541 ll.add(entry); 543 544 _crcToEntryMap.put(crcL, ll); 546 } else { 547 549 LinkedList ll = new LinkedList(); 552 ll.add(entry); 553 554 _crcToEntryMap.put(crcL, ll); 556 } 557 558 } 559 } 560 } 561 562 } 563 564 565 private static void showHelp() { 566 System.out.println("JarDiff: [-nonminimal (for backward compatibility with 1.0.1/1.0] [-creatediff | -applydiff] [-output file] old.jar new.jar"); 567 } 568 569 public static void main(String [] args) throws IOException { 571 boolean diff = true; 572 boolean minimal = true; 573 String outputFile = "out.jardiff"; 574 575 for (int counter = 0; counter < args.length; counter++) { 576 if (args[counter].equals("-nonminimal") || 578 args[counter].equals("-n")) { 579 minimal = false; 580 } 581 else if (args[counter].equals("-creatediff") || 582 args[counter].equals("-c")) { 583 diff = true; 584 } 585 else if (args[counter].equals("-applydiff") || 586 args[counter].equals("-a")) { 587 diff = false; 588 } 589 else if (args[counter].equals("-debug") || 590 args[counter].equals("-d")) { 591 _debug = true; 592 } 593 else if (args[counter].equals("-output") || 594 args[counter].equals("-o")) { 595 if (++counter < args.length) { 596 outputFile = args[counter]; 597 } 598 } 599 else if (args[counter].equals("-applydiff") || 600 args[counter].equals("-a")) { 601 diff = false; 602 } 603 else { 604 if ((counter + 2) != args.length) { 605 showHelp(); 606 System.exit(0); 607 } 608 if (diff) { 609 try { 610 OutputStream os = new FileOutputStream(outputFile); 611 612 JarDiff.createPatch(args[counter], 613 args[counter + 1], os, minimal); 614 os.close(); 615 } catch (IOException ioe) { 616 try { 617 System.out.println(getResources().getString("jardiff.error.create") + " " + ioe); 618 } catch (MissingResourceException mre) { 619 } 620 } 621 } 622 else { 623 try { 624 OutputStream os = new FileOutputStream(outputFile); 625 626 new JarDiffPatcher().applyPatch( 627 null, 628 args[counter], 629 args[counter + 1], 630 os); 631 os.close(); 632 } catch (IOException ioe) { 633 try { 634 System.out.println(getResources().getString("jardiff.error.apply") + " " + ioe); 635 } catch (MissingResourceException mre) { 636 } 637 } 638 } 639 System.exit(0); 640 } 641 } 642 showHelp(); 643 } 644 } 645 | Popular Tags |