1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17package org.apache.harmony.archive.tests.java.util.jar; 18 19import java.io.ByteArrayOutputStream; 20import java.io.File; 21import java.io.FileOutputStream; 22import java.io.IOException; 23import java.io.InputStream; 24import java.net.URL; 25import java.security.cert.Certificate; 26import java.util.Enumeration; 27import java.util.Vector; 28import java.util.jar.Attributes; 29import java.util.jar.JarEntry; 30import java.util.jar.JarFile; 31import java.util.jar.JarOutputStream; 32import java.util.jar.Manifest; 33import java.util.zip.ZipEntry; 34 35import junit.framework.TestCase; 36import tests.support.Support_PlatformFile; 37import tests.support.resource.Support_Resources; 38 39public class JarFileTest extends TestCase { 40 41 /** 42 * The file contains the following entries: 43 * 44 * <pre> 45 * META-INF/ META-INF/MANIFEST.MF 46 * foo/ foo/bar/ foo/bar/A.class 47 * Blah.txt 48 * </pre> 49 */ 50 private final String JAR1 = "hyts_patch.jar"; 51 52 private final String JAR2 = "hyts_patch2.jar"; 53 54 private final String JAR3 = "hyts_manifest1.jar"; 55 56 private final String JAR4 = "hyts_signed.jar"; 57 58 private final String JAR5 = "Integrate.jar"; 59 60 private final String JAR1_ENTRY1 = "foo/bar/A.class"; 61 62 private final String JAR5_SIGNED_ENTRY = "Test.class"; 63 64 private final String JAR4_SIGNED_ENTRY = "coucou/FileAccess.class"; 65 66 private File resources; 67 68 private final String jarName = "hyts_patch.jar"; // a 'normal' jar file 69 70 private final String entryName = "foo/bar/A.class"; 71 72 private final String emptyEntryJar = "EmptyEntries_signed.jar"; 73 74 private final String emptyEntry1 = "subfolder/internalSubset01.js"; 75 76 private final String emptyEntry2 = "svgtest.js"; 77 78 private final String emptyEntry3 = "svgunit.js"; 79 80 @Override 81 protected void setUp() { 82 resources = Support_Resources.createTempFolder(); 83 } 84 85 /** 86 * Constructs JarFile object. 87 * 88 * @tests java.util.jar.JarFile#JarFile(java.io.File) 89 * @tests java.util.jar.JarFile#JarFile(java.lang.String) 90 */ 91 public void testConstructor() throws IOException { 92 File f = new File(resources, JAR1); 93 Support_Resources.copyFile(resources, null, JAR1); 94 assertTrue(new JarFile(f).getEntry(JAR1_ENTRY1).getName().equals( 95 JAR1_ENTRY1)); 96 assertTrue(new JarFile(f.getPath()).getEntry(JAR1_ENTRY1).getName() 97 .equals(JAR1_ENTRY1)); 98 } 99 100 /** 101 * @tests java.util.jar.JarFile#entries() 102 */ 103 public void testEntries() throws Exception { 104 Support_Resources.copyFile(resources, null, JAR1); 105 JarFile jarFile = new JarFile(new File(resources, JAR1)); 106 Enumeration<JarEntry> e = jarFile.entries(); 107 int i; 108 for (i = 0; e.hasMoreElements(); i++) { 109 e.nextElement(); 110 } 111 assertEquals(jarFile.size(), i); 112 jarFile.close(); 113 assertEquals(6, i); 114 } 115 116 public void testEntriesIterator() throws Exception { 117 Support_Resources.copyFile(resources, null, JAR1); 118 JarFile jarFile = new JarFile(new File(resources, JAR1)); 119 Enumeration<JarEntry> enumeration = jarFile.entries(); 120 jarFile.close(); 121 try { 122 enumeration.hasMoreElements(); 123 fail("hasMoreElements() did not detect a closed jar file"); 124 } catch (IllegalStateException e) { 125 } 126 Support_Resources.copyFile(resources, null, JAR1); 127 jarFile = new JarFile(new File(resources, JAR1)); 128 enumeration = jarFile.entries(); 129 jarFile.close(); 130 try { 131 enumeration.nextElement(); 132 fail("nextElement() did not detect closed jar file"); 133 } catch (IllegalStateException e) { 134 } 135 } 136 137 public void test_getEntryLjava_lang_String() throws IOException { 138 try { 139 Support_Resources.copyFile(resources, null, jarName); 140 JarFile jarFile = new JarFile(new File(resources, jarName)); 141 assertEquals("Error in returned entry", 311, jarFile.getEntry( 142 entryName).getSize()); 143 jarFile.close(); 144 } catch (Exception e) { 145 fail("Exception during test: " + e.toString()); 146 } 147 148 Support_Resources.copyFile(resources, null, jarName); 149 JarFile jarFile = new JarFile(new File(resources, jarName)); 150 Enumeration<JarEntry> enumeration = jarFile.entries(); 151 assertTrue(enumeration.hasMoreElements()); 152 while (enumeration.hasMoreElements()) { 153 JarEntry je = enumeration.nextElement(); 154 jarFile.getEntry(je.getName()); 155 } 156 157 enumeration = jarFile.entries(); 158 assertTrue(enumeration.hasMoreElements()); 159 JarEntry je = enumeration.nextElement(); 160 try { 161 jarFile.close(); 162 jarFile.getEntry(je.getName()); 163 // fail("IllegalStateException expected."); 164 } catch (IllegalStateException ee) { // Per documentation exception 165 // may be thrown. 166 // expected 167 } 168 } 169 170 public void test_getJarEntryLjava_lang_String() throws IOException { 171 try { 172 Support_Resources.copyFile(resources, null, jarName); 173 JarFile jarFile = new JarFile(new File(resources, jarName)); 174 assertEquals("Error in returned entry", 311, jarFile.getJarEntry( 175 entryName).getSize()); 176 jarFile.close(); 177 } catch (Exception e) { 178 fail("Exception during test: " + e.toString()); 179 } 180 181 Support_Resources.copyFile(resources, null, jarName); 182 JarFile jarFile = new JarFile(new File(resources, jarName)); 183 Enumeration<JarEntry> enumeration = jarFile.entries(); 184 assertTrue(enumeration.hasMoreElements()); 185 while (enumeration.hasMoreElements()) { 186 JarEntry je = enumeration.nextElement(); 187 jarFile.getJarEntry(je.getName()); 188 } 189 190 enumeration = jarFile.entries(); 191 assertTrue(enumeration.hasMoreElements()); 192 JarEntry je = enumeration.nextElement(); 193 try { 194 jarFile.close(); 195 jarFile.getJarEntry(je.getName()); 196 // fail("IllegalStateException expected."); 197 } catch (IllegalStateException ee) { // Per documentation exception 198 // may be thrown. 199 // expected 200 } 201 } 202 203 /** 204 * @tests java.util.jar.JarFile#getJarEntry(java.lang.String) 205 */ 206 public void testGetJarEntry() throws Exception { 207 Support_Resources.copyFile(resources, null, JAR1); 208 JarFile jarFile = new JarFile(new File(resources, JAR1)); 209 assertEquals("Error in returned entry", 311, jarFile.getEntry( 210 JAR1_ENTRY1).getSize()); 211 jarFile.close(); 212 213 // tests for signed jars 214 // test all signed jars in the /Testres/Internal/SignedJars directory 215 String jarDirUrl = Support_Resources 216 .getResourceURL("/../internalres/signedjars"); 217 Vector<String> signedJars = new Vector<String>(); 218 try { 219 InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream(); 220 while (is.available() > 0) { 221 StringBuilder linebuff = new StringBuilder(80); // Typical line 222 // length 223 done: while (true) { 224 int nextByte = is.read(); 225 switch (nextByte) { 226 case -1: 227 break done; 228 case (byte) '\r': 229 if (linebuff.length() == 0) { 230 // ignore 231 } 232 break done; 233 case (byte) '\n': 234 if (linebuff.length() == 0) { 235 // ignore 236 } 237 break done; 238 default: 239 linebuff.append((char) nextByte); 240 } 241 } 242 if (linebuff.length() == 0) { 243 break; 244 } 245 String line = linebuff.toString(); 246 signedJars.add(line); 247 } 248 is.close(); 249 } catch (IOException e) { 250 // no list of jars found 251 } 252 253 for (int i = 0; i < signedJars.size(); i++) { 254 String jarName = signedJars.get(i); 255 try { 256 File file = Support_Resources.getExternalLocalFile(jarDirUrl 257 + "/" + jarName); 258 jarFile = new JarFile(file, true); 259 boolean foundCerts = false; 260 Enumeration<JarEntry> e = jarFile.entries(); 261 while (e.hasMoreElements()) { 262 JarEntry entry = e.nextElement(); 263 InputStream is = jarFile.getInputStream(entry); 264 is.skip(100000); 265 is.close(); 266 Certificate[] certs = entry.getCertificates(); 267 if (certs != null && certs.length > 0) { 268 foundCerts = true; 269 break; 270 } 271 } 272 assertTrue( 273 "No certificates found during signed jar test for jar \"" 274 + jarName + "\"", foundCerts); 275 } catch (IOException e) { 276 fail("Exception during signed jar test for jar \"" + jarName 277 + "\": " + e.toString()); 278 } 279 } 280 } 281 282 /** 283 * @tests java.util.jar.JarFile#getManifest() 284 */ 285 public void testGetManifest() throws Exception { 286 // Test for method java.util.jar.Manifest 287 // java.util.jar.JarFile.getManifest() 288 Support_Resources.copyFile(resources, null, JAR1); 289 JarFile jarFile = new JarFile(new File(resources, JAR1)); 290 InputStream is = jarFile.getInputStream(jarFile.getEntry(JAR1_ENTRY1)); 291 assertTrue(is.available() > 0); 292 assertNotNull("Error--Manifest not returned", jarFile.getManifest()); 293 jarFile.close(); 294 295 Support_Resources.copyFile(resources, null, JAR2); 296 jarFile = new JarFile(new File(resources, JAR2)); 297 assertNull("Error--should have returned null", jarFile.getManifest()); 298 jarFile.close(); 299 300 // jarName3 was created using the following test 301 Support_Resources.copyFile(resources, null, JAR3); 302 jarFile = new JarFile(new File(resources, JAR3)); 303 assertNotNull("Should find manifest without verifying", jarFile 304 .getManifest()); 305 jarFile.close(); 306 307 // this is used to create jarName3 used in the previous test 308 Manifest manifest = new Manifest(); 309 Attributes attributes = manifest.getMainAttributes(); 310 attributes.put(new Attributes.Name("Manifest-Version"), "1.0"); 311 ByteArrayOutputStream manOut = new ByteArrayOutputStream(); 312 manifest.write(manOut); 313 byte[] manBytes = manOut.toByteArray(); 314 File file = new File(Support_PlatformFile.getNewPlatformFile( 315 "hyts_manifest1", ".jar")); 316 JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(file 317 .getAbsolutePath())); 318 ZipEntry entry = new ZipEntry("META-INF/"); 319 entry.setSize(0); 320 jarOut.putNextEntry(entry); 321 entry = new ZipEntry(JarFile.MANIFEST_NAME); 322 entry.setSize(manBytes.length); 323 jarOut.putNextEntry(entry); 324 jarOut.write(manBytes); 325 entry = new ZipEntry("myfile"); 326 entry.setSize(1); 327 jarOut.putNextEntry(entry); 328 jarOut.write(65); 329 jarOut.close(); 330 JarFile jar = new JarFile(file.getAbsolutePath(), false); 331 assertNotNull("Should find manifest without verifying", jar 332 .getManifest()); 333 jar.close(); 334 file.delete(); 335 336 try { 337 Support_Resources.copyFile(resources, null, JAR2); 338 JarFile jF = new JarFile(new File(resources, JAR2)); 339 jF.close(); 340 jF.getManifest(); 341 fail("IllegalStateException expected"); 342 } catch (IllegalStateException ise) { 343 // expected; 344 } 345 } 346 347 /** 348 * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) 349 */ 350 public void testGetInputStream() throws Exception { 351 File localFile; 352 byte[] b = new byte[1024]; 353 JarFile jf; 354 InputStream is; 355 356 Support_Resources.copyFile(resources, null, JAR1); 357 localFile = new File(resources, JAR1); 358 359 jf = new JarFile(localFile); 360 361 is = jf.getInputStream(new JarEntry("invalid")); 362 assertNull("Got stream for non-existent entry", is); 363 364 is = jf.getInputStream(jf.getEntry(JAR1_ENTRY1)); 365 assertTrue("Returned invalid stream", is.available() > 0); 366 367 // try to read class file header 368 is.read(b, 0, 1024); 369 jf.close(); 370 assertEquals("Invalid bytes were read", (byte) 0xCA, b[0]); 371 assertEquals("Invalid bytes were read", (byte) 0xFE, b[1]); 372 assertEquals("Invalid bytes were read", (byte) 0xBA, b[2]); 373 assertEquals("Invalid bytes were read", (byte) 0xBE, b[3]); 374 } 375 376 /** 377 * Signed file is verified by default. 378 * 379 * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) 380 */ 381 public void testInputStreamOperations() throws Exception { 382 Support_Resources.copyFile(resources, null, JAR4); 383 File signedFile = new File(resources, JAR4); 384 385 JarFile jar = new JarFile(signedFile); 386 JarEntry entry = new JarEntry(JAR4_SIGNED_ENTRY); 387 InputStream in = jar.getInputStream(entry); 388 in.read(); 389 390 // RI verifies only entries which appear via getJarEntry method 391 jar = new JarFile(signedFile); 392 entry = jar.getJarEntry(JAR4_SIGNED_ENTRY); 393 in = jar.getInputStream(entry); 394 readExactly(in, (int) entry.getSize() - 1); 395 assertNull(entry.getCertificates()); 396 in.read(); 397 assertNotNull(entry.getCertificates()); 398 assertEquals(-1, in.read()); 399 400 jar = new JarFile(signedFile); 401 entry = jar.getJarEntry(JAR4_SIGNED_ENTRY); 402 entry.setSize(entry.getSize() - 1); 403 in = jar.getInputStream(entry); 404 readExactly(in, (int) entry.getSize() - 1); 405 assertNull(entry.getCertificates()); 406 try { 407 in.read(); 408 fail("SecurityException expected"); 409 } catch (SecurityException e) { 410 // desired 411 } 412 assertEquals(-1, in.read()); 413 } 414 415 /** 416 * Performs as many read() calls as necessary to read {@code numBytes} from 417 * the stream. Should the stream exhaust early, this method will fail. 418 */ 419 private void readExactly(InputStream in, int numBytes) throws IOException { 420 byte[] buffer = new byte[1024]; 421 while (numBytes > 0) { 422 int read = in.read(buffer, 0, Math.min(numBytes, 1024)); 423 assertTrue(read != -1); 424 numBytes -= read; 425 } 426 } 427 428 /* 429 * The jar created by 1.4 which does not provide a 430 * algorithm-Digest-Manifest-Main-Attributes entry in .SF file. 431 */ 432 public void testJar14() throws IOException { 433 String modifiedJarName = "Created_by_1_4.jar"; 434 Support_Resources.copyFile(resources, null, modifiedJarName); 435 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 436 true); 437 Enumeration<JarEntry> entries = jarFile.entries(); 438 while (entries.hasMoreElements()) { 439 ZipEntry zipEntry = entries.nextElement(); 440 jarFile.getInputStream(zipEntry); 441 } 442 } 443 444 /** 445 * The jar is intact, then everything is all right. 446 */ 447 public void testJarVerification() throws IOException { 448 Support_Resources.copyFile(resources, null, JAR5); 449 JarFile jarFile = new JarFile(new File(resources, JAR5), true); 450 Enumeration<JarEntry> entries = jarFile.entries(); 451 while (entries.hasMoreElements()) { 452 ZipEntry zipEntry = entries.nextElement(); 453 jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 454 } 455 } 456 457 /** 458 * The jar is intact, but the entry object is modified. 459 */ 460 public void testJarVerificationModifiedEntry() throws IOException { 461 Support_Resources.copyFile(resources, null, JAR5); 462 File f = new File(resources, JAR5); 463 464 JarFile jarFile = new JarFile(f); 465 ZipEntry zipEntry = jarFile.getJarEntry(JAR5_SIGNED_ENTRY); 466 zipEntry.setSize(zipEntry.getSize() + 1); 467 jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 468 469 jarFile = new JarFile(f); 470 zipEntry = jarFile.getJarEntry(JAR5_SIGNED_ENTRY); 471 zipEntry.setSize(zipEntry.getSize() - 1); 472 try { 473 //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 474 jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000); 475 fail("SecurityException expected"); 476 } catch (SecurityException e) { 477 // desired 478 } 479 } 480 481 /* 482 * If another entry is inserted into Manifest, no security exception will be 483 * thrown out. 484 */ 485 public void testJarFileInsertEntryInManifestJar() throws IOException { 486 String modifiedJarName = "Inserted_Entry_Manifest.jar"; 487 Support_Resources.copyFile(resources, null, modifiedJarName); 488 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 489 true); 490 Enumeration<JarEntry> entries = jarFile.entries(); 491 int count = 0; 492 while (entries.hasMoreElements()) { 493 494 ZipEntry zipEntry = entries.nextElement(); 495 jarFile.getInputStream(zipEntry); 496 count++; 497 } 498 assertEquals(5, count); 499 } 500 501 /* 502 * If another entry is inserted into Manifest, no security exception will be 503 * thrown out. 504 */ 505 public void testInsertedEntryManifestWithDigestCode() throws IOException { 506 String modifiedJarName = "Inserted_Entry_Manifest_with_DigestCode.jar"; 507 Support_Resources.copyFile(resources, null, modifiedJarName); 508 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 509 true); 510 Enumeration<JarEntry> entries = jarFile.entries(); 511 int count = 0; 512 while (entries.hasMoreElements()) { 513 ZipEntry zipEntry = entries.nextElement(); 514 jarFile.getInputStream(zipEntry); 515 count++; 516 } 517 assertEquals(5, count); 518 } 519 520 /* 521 * The content of Test.class is modified, jarFile.getInputStream will not 522 * throw security Exception, but it will anytime before the inputStream got 523 * from getInputStream method has been read to end. 524 */ 525 public void testJarFileModifiedClass() throws IOException { 526 String modifiedJarName = "Modified_Class.jar"; 527 Support_Resources.copyFile(resources, null, modifiedJarName); 528 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 529 true); 530 Enumeration<JarEntry> entries = jarFile.entries(); 531 while (entries.hasMoreElements()) { 532 ZipEntry zipEntry = entries.nextElement(); 533 jarFile.getInputStream(zipEntry); 534 } 535 /* The content of Test.class has been tampered. */ 536 ZipEntry zipEntry = jarFile.getEntry("Test.class"); 537 InputStream in = jarFile.getInputStream(zipEntry); 538 byte[] buffer = new byte[1024]; 539 try { 540 while (in.available() > 0) { 541 in.read(buffer); 542 } 543 fail("SecurityException expected"); 544 } catch (SecurityException e) { 545 // desired 546 } 547 } 548 549 /* 550 * In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is 551 * tampered manually. Hence the RI 5.0 JarFile.getInputStream of any 552 * JarEntry will throw security exception. 553 */ 554 public void testJarFileModifiedManifestMainAttributes() throws IOException { 555 String modifiedJarName = "Modified_Manifest_MainAttributes.jar"; 556 Support_Resources.copyFile(resources, null, modifiedJarName); 557 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 558 true); 559 Enumeration<JarEntry> entries = jarFile.entries(); 560 while (entries.hasMoreElements()) { 561 ZipEntry zipEntry = entries.nextElement(); 562 try { 563 jarFile.getInputStream(zipEntry); 564 fail("SecurityException expected"); 565 } catch (SecurityException e) { 566 // desired 567 } 568 } 569 } 570 571 /* 572 * It is all right in our original JarFile. If the Entry Attributes, for 573 * example Test.class in our jar, the jarFile.getInputStream will throw 574 * Security Exception. 575 */ 576 public void testJarFileModifiedManifestEntryAttributes() throws IOException { 577 String modifiedJarName = "Modified_Manifest_EntryAttributes.jar"; 578 Support_Resources.copyFile(resources, null, modifiedJarName); 579 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 580 true); 581 Enumeration<JarEntry> entries = jarFile.entries(); 582 while (entries.hasMoreElements()) { 583 ZipEntry zipEntry = entries.nextElement(); 584 try { 585 jarFile.getInputStream(zipEntry); 586 fail("should throw Security Exception"); 587 } catch (SecurityException e) { 588 // desired 589 } 590 } 591 } 592 593 /* 594 * If the content of the .SA file is modified, no matter what it resides, 595 * JarFile.getInputStream of any JarEntry will throw Security Exception. 596 */ 597 public void testJarFileModifiedSfEntryAttributes() throws IOException { 598 String modifiedJarName = "Modified_SF_EntryAttributes.jar"; 599 Support_Resources.copyFile(resources, null, modifiedJarName); 600 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 601 true); 602 Enumeration<JarEntry> entries = jarFile.entries(); 603 while (entries.hasMoreElements()) { 604 ZipEntry zipEntry = entries.nextElement(); 605 try { 606 jarFile.getInputStream(zipEntry); 607 fail("should throw Security Exception"); 608 } catch (SecurityException e) { 609 // desired 610 } 611 } 612 } 613 614 /* 615 * @test JarFile.getInputStream() 616 */ 617 public void testGetInputStreamLjava_util_jar_JarEntry() throws IOException { 618 Support_Resources.copyFile(resources, null, JAR1); 619 JarFile jf = new JarFile(new File(resources, JAR1)); 620 InputStream is = jf.getInputStream(jf.getEntry(JAR1_ENTRY1)); 621 assertTrue(is.available() > 0); 622 623 byte[] buffer = new byte[1024]; 624 int r = is.read(buffer, 0, 1024); 625 jf.close(); 626 is.close(); 627 628 StringBuilder sb = new StringBuilder(r); 629 for (int i = 0; i < r; i++) { 630 sb.append((char) (buffer[i] & 0xff)); 631 } 632 String contents = sb.toString(); 633 assertTrue(contents.indexOf("foo") > 0); 634 assertTrue(contents.indexOf("bar") > 0); 635 636 try { 637 jf.getInputStream(jf.getEntry(JAR1_ENTRY1)); 638 fail("should throw IllegalStateException"); 639 } catch (IllegalStateException e) { 640 // Expected 641 } 642 643 jf = new JarFile(new File(resources, JAR1)); 644 is = jf.getInputStream(new JarEntry("invalid")); 645 assertNull(is); 646 jf.close(); 647 } 648 649 public void testJarVerificationEmptyEntry() throws IOException { 650 Support_Resources.copyFile(resources, null, emptyEntryJar); 651 File f = new File(resources, emptyEntryJar); 652 653 JarFile jarFile = new JarFile(f); 654 655 ZipEntry zipEntry = jarFile.getJarEntry(emptyEntry1); 656 int res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); 657 assertEquals("Wrong length of empty jar entry", -1, res); 658 659 zipEntry = jarFile.getJarEntry(emptyEntry2); 660 res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); 661 assertEquals("Wrong length of empty jar entry", -1, res); 662 663 zipEntry = jarFile.getJarEntry(emptyEntry3); 664 res = jarFile.getInputStream(zipEntry).read(); 665 assertEquals("Wrong length of empty jar entry", -1, res); 666 } 667 668 // Regression test for HARMONY-6384 669 public void testJarWrittenWithFlush() throws IOException { 670 File f = new File(resources, "hyts_flushed.jar"); 671 Support_Resources.copyFile(resources, null, "hyts_flushed.jar"); 672 673 // Used to crash with ZipException: Central Directory Entry not found 674 new JarFile(f); 675 } 676} 677