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
19
20import dalvik.annotation.AndroidOnly;
21import dalvik.annotation.TestLevel;
22import dalvik.annotation.TestTargetClass;
23import dalvik.annotation.TestTargetNew;
24
25import junit.framework.TestCase;
26
27import tests.support.Support_PlatformFile;
28import tests.support.resource.Support_Resources;
29
30import java.io.ByteArrayOutputStream;
31import java.io.File;
32import java.io.FileOutputStream;
33import java.io.IOException;
34import java.io.InputStream;
35import java.net.URL;
36import java.security.Permission;
37import java.security.cert.Certificate;
38import java.util.Enumeration;
39import java.util.Vector;
40import java.util.jar.Attributes;
41import java.util.jar.JarEntry;
42import java.util.jar.JarFile;
43import java.util.jar.JarOutputStream;
44import java.util.jar.Manifest;
45import java.util.zip.ZipEntry;
46import java.util.zip.ZipException;
47import java.util.zip.ZipFile;
48
49
50@TestTargetClass(JarFile.class)
51public class JarFileTest extends TestCase {
52
53    // BEGIN android-added
54    public byte[] getAllBytesFromStream(InputStream is) throws IOException {
55        ByteArrayOutputStream bs = new ByteArrayOutputStream();
56        byte[] buf = new byte[666];
57        int iRead;
58        int off;
59        while (is.available() > 0) {
60            iRead = is.read(buf, 0, buf.length);
61            if (iRead > 0) bs.write(buf, 0, iRead);
62        }
63        return bs.toByteArray();
64    }
65
66    // END android-added
67
68    private final String jarName = "hyts_patch.jar"; // a 'normal' jar file
69
70    private final String jarName2 = "hyts_patch2.jar";
71
72    private final String jarName3 = "hyts_manifest1.jar";
73
74    private final String jarName4 = "hyts_signed.jar";
75
76    private final String jarName5 = "hyts_signed_inc.jar";
77
78    private final String entryName = "foo/bar/A.class";
79
80    private final String entryName3 = "coucou/FileAccess.class";
81
82    private final String integrateJar = "Integrate.jar";
83
84    private final String integrateJarEntry = "Test.class";
85
86    private final String emptyEntryJar = "EmptyEntries_signed.jar";
87
88    private final String emptyEntry1 = "subfolder/internalSubset01.js";
89
90    private final String emptyEntry2 = "svgtest.js";
91
92    private final String emptyEntry3 = "svgunit.js";
93
94    private File resources;
95
96    // custom security manager
97    SecurityManager sm = new SecurityManager() {
98        final String forbidenPermissionName = "user.dir";
99
100        public void checkPermission(Permission perm) {
101            if (perm.getName().equals(forbidenPermissionName)) {
102                throw new SecurityException();
103            }
104        }
105    };
106
107    @Override
108    protected void setUp() {
109        resources = Support_Resources.createTempFolder();
110    }
111
112    /**
113     * @tests java.util.jar.JarFile#JarFile(java.io.File)
114     */
115    @TestTargetNew(
116        level = TestLevel.PARTIAL_COMPLETE,
117        notes = "",
118        method = "JarFile",
119        args = {java.io.File.class}
120    )
121    public void test_ConstructorLjava_io_File() {
122        try {
123            JarFile jarFile = new JarFile(new File("Wrong.file"));
124            fail("Should throw IOException");
125        } catch (IOException e) {
126            // expected
127        }
128        SecurityManager oldSm = System.getSecurityManager();
129        System.setSecurityManager(sm);
130        try {
131            JarFile jarFile = new JarFile(new File("tmp.jar"));
132            fail("Should throw SecurityException");
133        } catch (IOException e) {
134            fail("Should throw SecurityException");
135        } catch (SecurityException e) {
136            // expected
137        } finally {
138            System.setSecurityManager(oldSm);
139        }
140
141        try {
142            Support_Resources.copyFile(resources, null, jarName);
143            JarFile jarFile = new JarFile(new File(resources, jarName));
144        } catch (IOException e) {
145            fail("Should not throw IOException");
146        }
147    }
148
149    /**
150     * @tests java.util.jar.JarFile#JarFile(java.lang.String)
151     */
152    @TestTargetNew(
153        level = TestLevel.COMPLETE,
154        notes = "",
155        method = "JarFile",
156        args = {java.lang.String.class}
157    )
158    public void test_ConstructorLjava_lang_String() {
159        try {
160            JarFile jarFile = new JarFile("Wrong.file");
161            fail("Should throw IOException");
162        } catch (IOException e) {
163            // expected
164        }
165        SecurityManager oldSm = System.getSecurityManager();
166        System.setSecurityManager(sm);
167        try {
168            JarFile jarFile = new JarFile("tmp.jar");
169            fail("Should throw SecurityException");
170        } catch (IOException e) {
171            fail("Should throw SecurityException");
172        } catch (SecurityException e) {
173            // expected
174        } finally {
175            System.setSecurityManager(oldSm);
176        }
177
178        try {
179            Support_Resources.copyFile(resources, null, jarName);
180            String fileName = (new File(resources, jarName)).getCanonicalPath();
181            JarFile jarFile = new JarFile(fileName);
182        } catch (IOException e) {
183            fail("Should not throw IOException");
184        }
185    }
186
187    /**
188     * @tests java.util.jar.JarFile#JarFile(java.lang.String, boolean)
189     */
190    @TestTargetNew(
191        level = TestLevel.COMPLETE,
192        notes = "",
193        method = "JarFile",
194        args = {java.lang.String.class, boolean.class}
195    )
196    public void test_ConstructorLjava_lang_StringZ() {
197        try {
198            JarFile jarFile = new JarFile("Wrong.file", false);
199            fail("Should throw IOException");
200        } catch (IOException e) {
201            // expected
202        }
203        SecurityManager oldSm = System.getSecurityManager();
204        System.setSecurityManager(sm);
205        try {
206            JarFile jarFile = new JarFile("tmp.jar", true);
207            fail("Should throw SecurityException");
208        } catch (IOException e) {
209            fail("Should throw SecurityException");
210        } catch (SecurityException e) {
211            // expected
212        } finally {
213            System.setSecurityManager(oldSm);
214        }
215
216        try {
217            Support_Resources.copyFile(resources, null, jarName);
218            String fileName = (new File(resources, jarName)).getCanonicalPath();
219            JarFile jarFile = new JarFile(fileName, true);
220        } catch (IOException e) {
221            fail("Should not throw IOException");
222        }
223    }
224
225    /**
226     * @tests java.util.jar.JarFile#JarFile(java.io.File, boolean)
227     */
228    @TestTargetNew(
229        level = TestLevel.COMPLETE,
230        notes = "",
231        method = "JarFile",
232        args = {java.io.File.class, boolean.class}
233    )
234    public void test_ConstructorLjava_io_FileZ() {
235        try {
236            JarFile jarFile = new JarFile(new File("Wrong.file"), true);
237            fail("Should throw IOException");
238        } catch (IOException e) {
239            // expected
240        }
241        SecurityManager oldSm = System.getSecurityManager();
242        System.setSecurityManager(sm);
243        try {
244            JarFile jarFile = new JarFile(new File("tmp.jar"), false);
245            fail("Should throw SecurityException");
246        } catch (IOException e) {
247            fail("Should throw SecurityException");
248        } catch (SecurityException e) {
249            // expected
250        } finally {
251            System.setSecurityManager(oldSm);
252        }
253
254        try {
255            Support_Resources.copyFile(resources, null, jarName);
256            JarFile jarFile = new JarFile(new File(resources, jarName), false);
257        } catch (IOException e) {
258            fail("Should not throw IOException");
259        }
260    }
261
262    /**
263     * @tests java.util.jar.JarFile#JarFile(java.io.File, boolean, int)
264     */
265    @TestTargetNew(
266        level = TestLevel.COMPLETE,
267        notes = "",
268        method = "JarFile",
269        args = {java.io.File.class, boolean.class, int.class}
270    )
271    public void test_ConstructorLjava_io_FileZI() {
272        try {
273            JarFile jarFile = new JarFile(new File("Wrong.file"), true,
274                    ZipFile.OPEN_READ);
275            fail("Should throw IOException");
276        } catch (IOException e) {
277            // expected
278        }
279        SecurityManager oldSm = System.getSecurityManager();
280        System.setSecurityManager(sm);
281        try {
282            JarFile jarFile = new JarFile(new File("tmp.jar"), false,
283                    ZipFile.OPEN_READ);
284            fail("Should throw SecurityException");
285        } catch (IOException e) {
286            fail("Should throw SecurityException");
287        } catch (SecurityException e) {
288            // expected
289        } finally {
290            System.setSecurityManager(oldSm);
291        }
292
293        try {
294            Support_Resources.copyFile(resources, null, jarName);
295            JarFile jarFile = new JarFile(new File(resources, jarName), false,
296                    ZipFile.OPEN_READ);
297        } catch (IOException e) {
298            fail("Should not throw IOException");
299        }
300
301        try {
302            Support_Resources.copyFile(resources, null, jarName);
303            JarFile jarFile = new JarFile(new File(resources, jarName), false,
304                    ZipFile.OPEN_READ | ZipFile.OPEN_DELETE + 33);
305            fail("Should throw IllegalArgumentException");
306        } catch (IOException e) {
307            fail("Should not throw IOException");
308        } catch (IllegalArgumentException e) {
309            // expected
310        }
311    }
312
313    /**
314     * Constructs JarFile object.
315     *
316     * @tests java.util.jar.JarFile#JarFile(java.io.File)
317     * @tests java.util.jar.JarFile#JarFile(java.lang.String)
318     */
319    @TestTargetNew(
320            level = TestLevel.PARTIAL_COMPLETE,
321            notes = "",
322            method = "JarFile",
323            args = {java.io.File.class}
324    )
325    public void testConstructor_file() throws IOException {
326        File f = new File(resources, jarName);
327        Support_Resources.copyFile(resources, null, jarName);
328        assertTrue(new JarFile(f).getEntry(entryName).getName().equals(
329                entryName));
330        assertTrue(new JarFile(f.getPath()).getEntry(entryName).getName()
331                .equals(entryName));
332    }
333
334    /**
335     * @tests java.util.jar.JarFile#entries()
336     */
337    @TestTargetNew(
338        level = TestLevel.COMPLETE,
339        notes = "",
340        method = "entries",
341        args = {}
342    )
343    public void test_entries() throws Exception {
344        /*
345         * Note only (and all of) the following should be contained in the file
346         * META-INF/ META-INF/MANIFEST.MF foo/ foo/bar/ foo/bar/A.class Blah.txt
347         */
348        Support_Resources.copyFile(resources, null, jarName);
349        JarFile jarFile = new JarFile(new File(resources, jarName));
350        Enumeration<JarEntry> e = jarFile.entries();
351        int i;
352        for (i = 0; e.hasMoreElements(); i++) {
353            e.nextElement();
354        }
355        assertEquals(jarFile.size(), i);
356        jarFile.close();
357        assertEquals(6, i);
358    }
359
360    @TestTargetNew(
361        level = TestLevel.COMPLETE,
362        notes = "",
363        method = "entries",
364        args = {}
365    )
366    public void test_entries2() throws Exception {
367        Support_Resources.copyFile(resources, null, jarName);
368        JarFile jarFile = new JarFile(new File(resources, jarName));
369        Enumeration<JarEntry> enumeration = jarFile.entries();
370        jarFile.close();
371        try {
372            enumeration.hasMoreElements();
373            fail("hasMoreElements() did not detect a closed jar file");
374        } catch (IllegalStateException e) {
375        }
376        Support_Resources.copyFile(resources, null, jarName);
377        jarFile = new JarFile(new File(resources, jarName));
378        enumeration = jarFile.entries();
379        jarFile.close();
380        try {
381            enumeration.nextElement();
382            fail("nextElement() did not detect closed jar file");
383        } catch (IllegalStateException e) {
384        }
385    }
386
387    /**
388     * @throws IOException
389     * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
390     */
391    @TestTargetNew(
392        level = TestLevel.PARTIAL_COMPLETE,
393        notes = "",
394        method = "getEntry",
395        args = {java.lang.String.class}
396    )
397    public void test_getEntryLjava_lang_String() throws IOException {
398        try {
399            Support_Resources.copyFile(resources, null, jarName);
400            JarFile jarFile = new JarFile(new File(resources, jarName));
401            assertEquals("Error in returned entry", 311, jarFile.getEntry(
402                    entryName).getSize());
403            jarFile.close();
404        } catch (Exception e) {
405            fail("Exception during test: " + e.toString());
406        }
407
408        Support_Resources.copyFile(resources, null, jarName);
409        JarFile jarFile = new JarFile(new File(resources, jarName));
410        Enumeration<JarEntry> enumeration = jarFile.entries();
411        assertTrue(enumeration.hasMoreElements());
412        while (enumeration.hasMoreElements()) {
413            JarEntry je = enumeration.nextElement();
414            jarFile.getEntry(je.getName());
415        }
416
417        enumeration = jarFile.entries();
418        assertTrue(enumeration.hasMoreElements());
419        JarEntry je = enumeration.nextElement();
420        try {
421            jarFile.close();
422            jarFile.getEntry(je.getName());
423            // fail("IllegalStateException expected.");
424        } catch (IllegalStateException ee) { // Per documentation exception
425            // may be thrown.
426            // expected
427        }
428    }
429
430    /**
431     * @throws IOException
432     * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
433     */
434    @TestTargetNew(
435        level = TestLevel.COMPLETE,
436        notes = "",
437        method = "getJarEntry",
438        args = {java.lang.String.class}
439    )
440    public void test_getJarEntryLjava_lang_String() throws IOException {
441        try {
442            Support_Resources.copyFile(resources, null, jarName);
443            JarFile jarFile = new JarFile(new File(resources, jarName));
444            assertEquals("Error in returned entry", 311, jarFile.getJarEntry(
445                    entryName).getSize());
446            jarFile.close();
447        } catch (Exception e) {
448            fail("Exception during test: " + e.toString());
449        }
450
451        Support_Resources.copyFile(resources, null, jarName);
452        JarFile jarFile = new JarFile(new File(resources, jarName));
453        Enumeration<JarEntry> enumeration = jarFile.entries();
454        assertTrue(enumeration.hasMoreElements());
455        while (enumeration.hasMoreElements()) {
456            JarEntry je = enumeration.nextElement();
457            jarFile.getJarEntry(je.getName());
458        }
459
460        enumeration = jarFile.entries();
461        assertTrue(enumeration.hasMoreElements());
462        JarEntry je = enumeration.nextElement();
463        try {
464            jarFile.close();
465            jarFile.getJarEntry(je.getName());
466            // fail("IllegalStateException expected.");
467        } catch (IllegalStateException ee) { // Per documentation exception
468            // may be thrown.
469            // expected
470        }
471    }
472
473
474    /**
475     * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
476     */
477    @TestTargetNew(
478            level = TestLevel.PARTIAL_COMPLETE,
479            notes = "",
480            method = "getEntry",
481            args = {java.lang.String.class}
482    )
483    public void testGetJarEntry() throws Exception {
484        Support_Resources.copyFile(resources, null, jarName);
485        JarFile jarFile = new JarFile(new File(resources, jarName));
486        assertEquals("Error in returned entry", 311, jarFile.getEntry(
487                entryName).getSize());
488        jarFile.close();
489
490        // tests for signed jars
491        // test all signed jars in the /Testres/Internal/SignedJars directory
492        String jarDirUrl = Support_Resources
493                .getResourceURL("/../internalres/signedjars");
494        Vector<String> signedJars = new Vector<String>();
495        try {
496            InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream();
497            while (is.available() > 0) {
498                StringBuilder linebuff = new StringBuilder(80); // Typical line
499                // length
500                done: while (true) {
501                    int nextByte = is.read();
502                    switch (nextByte) {
503                        case -1:
504                            break done;
505                        case (byte) '\r':
506                            if (linebuff.length() == 0) {
507                                // ignore
508                            }
509                            break done;
510                        case (byte) '\n':
511                            if (linebuff.length() == 0) {
512                                // ignore
513                            }
514                            break done;
515                        default:
516                            linebuff.append((char) nextByte);
517                    }
518                }
519                if (linebuff.length() == 0) {
520                    break;
521                }
522                String line = linebuff.toString();
523                signedJars.add(line);
524            }
525            is.close();
526        } catch (IOException e) {
527            // no list of jars found
528        }
529
530        for (int i = 0; i < signedJars.size(); i++) {
531            String jarName = signedJars.get(i);
532            try {
533                File file = Support_Resources.getExternalLocalFile(jarDirUrl
534                        + "/" + jarName);
535                jarFile = new JarFile(file, true);
536                boolean foundCerts = false;
537                Enumeration<JarEntry> e = jarFile.entries();
538                while (e.hasMoreElements()) {
539                    JarEntry entry = e.nextElement();
540                    InputStream is = jarFile.getInputStream(entry);
541                    is.skip(100000);
542                    is.close();
543                    Certificate[] certs = entry.getCertificates();
544                    if (certs != null && certs.length > 0) {
545                        foundCerts = true;
546                        break;
547                    }
548                }
549                assertTrue(
550                        "No certificates found during signed jar test for jar \""
551                                + jarName + "\"", foundCerts);
552            } catch (IOException e) {
553                fail("Exception during signed jar test for jar \"" + jarName
554                        + "\": " + e.toString());
555            }
556        }
557    }
558
559    /**
560     * @tests java.util.jar.JarFile#getManifest()
561     */
562    @TestTargetNew(
563        level = TestLevel.COMPLETE,
564        notes = "",
565        method = "getManifest",
566        args = {}
567    )
568    public void test_getManifest() {
569        // Test for method java.util.jar.Manifest
570        // java.util.jar.JarFile.getManifest()
571        try {
572            Support_Resources.copyFile(resources, null, jarName);
573            JarFile jarFile = new JarFile(new File(resources, jarName));
574            assertNotNull("Error--Manifest not returned", jarFile.getManifest());
575            jarFile.close();
576        } catch (Exception e) {
577            fail("Exception during 1st test: " + e.toString());
578        }
579        try {
580            Support_Resources.copyFile(resources, null, jarName2);
581            JarFile jarFile = new JarFile(new File(resources, jarName2));
582            assertNull("Error--should have returned null", jarFile
583                    .getManifest());
584            jarFile.close();
585        } catch (Exception e) {
586            fail("Exception during 2nd test: " + e.toString());
587        }
588
589        try {
590            // jarName3 was created using the following test
591            Support_Resources.copyFile(resources, null, jarName3);
592            JarFile jarFile = new JarFile(new File(resources, jarName3));
593            assertNotNull("Should find manifest without verifying", jarFile
594                    .getManifest());
595            jarFile.close();
596        } catch (Exception e) {
597            fail("Exception during 3rd test: " + e.toString());
598        }
599
600        try {
601            // this is used to create jarName3 used in the previous test
602            Manifest manifest = new Manifest();
603            Attributes attributes = manifest.getMainAttributes();
604            attributes.put(new Attributes.Name("Manifest-Version"), "1.0");
605            ByteArrayOutputStream manOut = new ByteArrayOutputStream();
606            manifest.write(manOut);
607            byte[] manBytes = manOut.toByteArray();
608            File file = File.createTempFile(
609                    Support_PlatformFile.getNewPlatformFile("hyts_manifest1",
610                            ""), ".jar");
611            JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(
612                    file.getAbsolutePath()));
613            ZipEntry entry = new ZipEntry("META-INF/");
614            entry.setSize(0);
615            jarOut.putNextEntry(entry);
616            entry = new ZipEntry(JarFile.MANIFEST_NAME);
617            entry.setSize(manBytes.length);
618            jarOut.putNextEntry(entry);
619            jarOut.write(manBytes);
620            entry = new ZipEntry("myfile");
621            entry.setSize(1);
622            jarOut.putNextEntry(entry);
623            jarOut.write(65);
624            jarOut.close();
625            JarFile jar = new JarFile(file.getAbsolutePath(), false);
626            assertNotNull("Should find manifest without verifying", jar
627                    .getManifest());
628            jar.close();
629            file.delete();
630        } catch (IOException e) {
631            fail("IOException 3");
632        }
633        try {
634            Support_Resources.copyFile(resources, null, jarName2);
635            JarFile jF = new JarFile(new File(resources, jarName2));
636            jF.close();
637            jF.getManifest();
638            fail("FAILED: expected IllegalStateException");
639        } catch (IllegalStateException ise) {
640            // expected;
641        } catch (Exception e) {
642            fail("Exception during 4th test: " + e.toString());
643        }
644
645        Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
646        JarFile jf;
647        try {
648            jf = new JarFile(new File(resources, "Broken_manifest.jar"));
649            jf.getManifest();
650            fail("IOException expected.");
651        } catch (IOException e) {
652            // expected.
653        }
654    }
655
656    /**
657     * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
658     */
659    @TestTargetNew(
660        level = TestLevel.PARTIAL_COMPLETE,
661        notes = "SecurityException and functionality checked.",
662        method = "getInputStream",
663        args = {java.util.zip.ZipEntry.class}
664    )
665    @AndroidOnly("This test doesn't pass on RI. If entry size is set up " +
666            "incorrectly, SecurityException is thrown. " +
667            "But SecurityException is thrown on RI only " +
668            "if jar file is signed incorreclty.")
669    public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() {
670        File signedFile = null;
671        try {
672            Support_Resources.copyFile(resources, null, jarName4);
673            signedFile = new File(resources, jarName4);
674        } catch (Exception e) {
675            fail("Failed to create local file 2: " + e);
676        }
677
678        try {
679            JarFile jar = new JarFile(signedFile);
680            JarEntry entry = new JarEntry(entryName3);
681            InputStream in = jar.getInputStream(entry);
682            in.read();
683        } catch (Exception e) {
684            fail("Exception during test 3: " + e);
685        }
686
687        try {
688            JarFile jar = new JarFile(signedFile);
689            JarEntry entry = new JarEntry(entryName3);
690            InputStream in = jar.getInputStream(entry);
691            // BEGIN android-added
692            byte[] dummy = getAllBytesFromStream(in);
693            // END android-added
694            assertNull("found certificates", entry.getCertificates());
695        } catch (Exception e) {
696            fail("Exception during test 4: " + e);
697        }
698
699        try {
700            JarFile jar = new JarFile(signedFile);
701            JarEntry entry = new JarEntry(entryName3);
702            entry.setSize(1076);
703            InputStream in = jar.getInputStream(entry);
704            // BEGIN android-added
705            byte[] dummy = getAllBytesFromStream(in);
706            // END android-added
707            fail("SecurityException should be thrown.");
708        } catch (SecurityException e) {
709            // expected
710        } catch (Exception e) {
711            fail("Exception during test 5: " + e);
712        }
713
714        try {
715            Support_Resources.copyFile(resources, null, jarName5);
716            signedFile = new File(resources, jarName5);
717        } catch (Exception e) {
718            fail("Failed to create local file 5: " + e);
719        }
720
721        try {
722            JarFile jar = new JarFile(signedFile);
723            JarEntry entry = new JarEntry(entryName3);
724            InputStream in = jar.getInputStream(entry);
725            fail("SecurityException should be thrown.");
726        } catch (SecurityException e) {
727            // expected
728        } catch (Exception e) {
729            fail("Exception during test 5: " + e);
730        }
731    }
732
733    /*
734     * The jar created by 1.4 which does not provide a
735     * algorithm-Digest-Manifest-Main-Attributes entry in .SF file.
736     */
737    @TestTargetNew(
738        level = TestLevel.COMPLETE,
739        notes = "",
740        method = "entries",
741        args = {}
742    )
743    public void test_Jar_created_before_java_5() throws IOException {
744        String modifiedJarName = "Created_by_1_4.jar";
745        Support_Resources.copyFile(resources, null, modifiedJarName);
746        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
747                true);
748        Enumeration<JarEntry> entries = jarFile.entries();
749        while (entries.hasMoreElements()) {
750            ZipEntry zipEntry = entries.nextElement();
751            jarFile.getInputStream(zipEntry);
752        }
753    }
754
755    /* The jar is intact, then everything is all right. */
756    @TestTargetNew(
757        level = TestLevel.COMPLETE,
758        notes = "",
759        method = "entries",
760        args = {}
761    )
762    public void test_JarFile_Integrate_Jar() throws IOException {
763        String modifiedJarName = "Integrate.jar";
764        Support_Resources.copyFile(resources, null, modifiedJarName);
765        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
766                true);
767        Enumeration<JarEntry> entries = jarFile.entries();
768        while (entries.hasMoreElements()) {
769            ZipEntry zipEntry = entries.nextElement();
770            jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
771        }
772    }
773
774    /**
775     * The jar is intact, but the entry object is modified.
776     */
777    @TestTargetNew(
778            level = TestLevel.PARTIAL_COMPLETE,
779            notes = "",
780            method = "getInputStream",
781            args = {ZipEntry.class}
782    )
783    public void testJarVerificationModifiedEntry() throws IOException {
784        Support_Resources.copyFile(resources, null, integrateJar);
785        File f = new File(resources, integrateJar);
786
787        JarFile jarFile = new JarFile(f);
788        ZipEntry zipEntry = jarFile.getJarEntry(integrateJarEntry);
789        zipEntry.setSize(zipEntry.getSize() + 1);
790        jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
791
792        jarFile = new JarFile(f);
793        zipEntry = jarFile.getJarEntry(integrateJarEntry);
794        zipEntry.setSize(zipEntry.getSize() - 1);
795        try {
796            //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
797            jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000);
798            fail("SecurityException expected");
799        } catch (SecurityException e) {
800            // desired
801        }
802    }
803
804    /*
805     * If another entry is inserted into Manifest, no security exception will be
806     * thrown out.
807     */
808    @TestTargetNew(
809        level = TestLevel.COMPLETE,
810        notes = "",
811        method = "entries",
812        args = {}
813    )
814    public void test_JarFile_InsertEntry_in_Manifest_Jar() throws IOException {
815        String modifiedJarName = "Inserted_Entry_Manifest.jar";
816        Support_Resources.copyFile(resources, null, modifiedJarName);
817        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
818                true);
819        Enumeration<JarEntry> entries = jarFile.entries();
820        int count = 0;
821        while (entries.hasMoreElements()) {
822
823            ZipEntry zipEntry = entries.nextElement();
824            jarFile.getInputStream(zipEntry);
825            count++;
826        }
827        assertEquals(5, count);
828    }
829
830    /*
831     * If another entry is inserted into Manifest, no security exception will be
832     * thrown out.
833     */
834    @TestTargetNew(
835        level = TestLevel.COMPLETE,
836        notes = "",
837        method = "entries",
838        args = {}
839    )
840    public void test_Inserted_Entry_Manifest_with_DigestCode()
841            throws IOException {
842        String modifiedJarName = "Inserted_Entry_Manifest_with_DigestCode.jar";
843        Support_Resources.copyFile(resources, null, modifiedJarName);
844        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
845                true);
846        Enumeration<JarEntry> entries = jarFile.entries();
847        int count = 0;
848        while (entries.hasMoreElements()) {
849            ZipEntry zipEntry = entries.nextElement();
850            jarFile.getInputStream(zipEntry);
851            count++;
852        }
853        assertEquals(5, count);
854    }
855
856    /*
857     * The content of Test.class is modified, jarFile.getInputStream will not
858     * throw security Exception, but it will anytime before the inputStream got
859     * from getInputStream method has been read to end.
860     */
861    @TestTargetNew(
862        level = TestLevel.PARTIAL_COMPLETE,
863        notes = "SecurityException and functionality checked.",
864        method = "getInputStream",
865        args = {java.util.zip.ZipEntry.class}
866    )
867    public void test_JarFile_Modified_Class() throws IOException {
868        String modifiedJarName = "Modified_Class.jar";
869        Support_Resources.copyFile(resources, null, modifiedJarName);
870        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
871                true);
872        Enumeration<JarEntry> entries = jarFile.entries();
873        while (entries.hasMoreElements()) {
874            ZipEntry zipEntry = entries.nextElement();
875            jarFile.getInputStream(zipEntry);
876        }
877        /* The content of Test.class has been tampered. */
878        ZipEntry zipEntry = jarFile.getEntry("Test.class");
879        InputStream in = jarFile.getInputStream(zipEntry);
880        byte[] buffer = new byte[1024];
881        try {
882            while (in.available() > 0) {
883                in.read(buffer);
884            }
885            fail("SecurityException expected");
886        } catch (SecurityException e) {
887            // desired
888        }
889    }
890
891    /*
892     * In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is
893     * tampered manually. Hence the RI 5.0 JarFile.getInputStream of any
894     * JarEntry will throw security exception.
895     */
896    @TestTargetNew(
897        level = TestLevel.PARTIAL_COMPLETE,
898        notes = "SecurityException and functionality checked.",
899        method = "getInputStream",
900        args = {java.util.zip.ZipEntry.class}
901    )
902    public void test_JarFile_Modified_Manifest_MainAttributes()
903            throws IOException {
904        String modifiedJarName = "Modified_Manifest_MainAttributes.jar";
905        Support_Resources.copyFile(resources, null, modifiedJarName);
906        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
907                true);
908        Enumeration<JarEntry> entries = jarFile.entries();
909        while (entries.hasMoreElements()) {
910            ZipEntry zipEntry = entries.nextElement();
911            try {
912                jarFile.getInputStream(zipEntry);
913                fail("SecurityException expected");
914            } catch (SecurityException e) {
915                // desired
916            }
917        }
918    }
919
920    /*
921     * It is all right in our original JarFile. If the Entry Attributes, for
922     * example Test.class in our jar, the jarFile.getInputStream will throw
923     * Security Exception.
924     */
925    @TestTargetNew(
926        level = TestLevel.PARTIAL_COMPLETE,
927        notes = "SecurityException and functionality checked.",
928        method = "getInputStream",
929        args = {java.util.zip.ZipEntry.class}
930    )
931    public void test_JarFile_Modified_Manifest_EntryAttributes()
932            throws IOException {
933        String modifiedJarName = "Modified_Manifest_EntryAttributes.jar";
934        Support_Resources.copyFile(resources, null, modifiedJarName);
935        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
936                true);
937        Enumeration<JarEntry> entries = jarFile.entries();
938        while (entries.hasMoreElements()) {
939            ZipEntry zipEntry = entries.nextElement();
940            try {
941                jarFile.getInputStream(zipEntry);
942                fail("should throw Security Exception");
943            } catch (SecurityException e) {
944                // desired
945            }
946        }
947    }
948
949    /*
950     * If the content of the .SA file is modified, no matter what it resides,
951     * JarFile.getInputStream of any JarEntry will throw Security Exception.
952     */
953    @TestTargetNew(
954        level = TestLevel.PARTIAL_COMPLETE,
955        notes = "SecurityException and functionality checked.",
956        method = "getInputStream",
957        args = {java.util.zip.ZipEntry.class}
958    )
959    public void test_JarFile_Modified_SF_EntryAttributes() throws IOException {
960        String modifiedJarName = "Modified_SF_EntryAttributes.jar";
961        Support_Resources.copyFile(resources, null, modifiedJarName);
962        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
963                true);
964        Enumeration<JarEntry> entries = jarFile.entries();
965        while (entries.hasMoreElements()) {
966            ZipEntry zipEntry = entries.nextElement();
967            try {
968                jarFile.getInputStream(zipEntry);
969                fail("should throw Security Exception");
970            } catch (SecurityException e) {
971                // desired
972            }
973        }
974    }
975
976    @TestTargetNew(
977        level = TestLevel.COMPLETE,
978        notes = "",
979        method = "close",
980        args = {}
981    )
982    public void test_close() throws IOException {
983        String modifiedJarName = "Modified_SF_EntryAttributes.jar";
984        Support_Resources.copyFile(resources, null, modifiedJarName);
985        JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
986                true);
987        Enumeration<JarEntry> entries = jarFile.entries();
988
989        jarFile.close();
990        jarFile.close();
991
992        // Can not check IOException
993    }
994
995    /**
996     * @throws IOException
997     * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
998     */
999    @TestTargetNew(
1000            level = TestLevel.COMPLETE,
1001            notes = "",
1002            method = "getInputStream",
1003            args = {java.util.zip.ZipEntry.class}
1004    )
1005    public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
1006        File localFile = null;
1007        try {
1008            Support_Resources.copyFile(resources, null, jarName);
1009            localFile = new File(resources, jarName);
1010        } catch (Exception e) {
1011            fail("Failed to create local file: " + e);
1012        }
1013
1014        byte[] b = new byte[1024];
1015        try {
1016            JarFile jf = new JarFile(localFile);
1017            java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
1018            // BEGIN android-removed
1019            // jf.close();
1020            // END android-removed
1021            assertTrue("Returned invalid stream", is.available() > 0);
1022            int r = is.read(b, 0, 1024);
1023            is.close();
1024            StringBuffer sb = new StringBuffer(r);
1025            for (int i = 0; i < r; i++) {
1026                sb.append((char) (b[i] & 0xff));
1027            }
1028            String contents = sb.toString();
1029            assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
1030            // BEGIN android-added
1031            jf.close();
1032            // END android-added
1033        } catch (Exception e) {
1034            fail("Exception during test: " + e.toString());
1035        }
1036
1037        try {
1038            JarFile jf = new JarFile(localFile);
1039            InputStream in = jf.getInputStream(new JarEntry("invalid"));
1040            assertNull("Got stream for non-existent entry", in);
1041        } catch (Exception e) {
1042            fail("Exception during test 2: " + e);
1043        }
1044
1045        try {
1046            Support_Resources.copyFile(resources, null, jarName);
1047            File signedFile = new File(resources, jarName);
1048            JarFile jf = new JarFile(signedFile);
1049            JarEntry jre = new JarEntry("foo/bar/A.class");
1050            jf.getInputStream(jre);
1051            // InputStream returned in any way, exception can be thrown in case
1052            // of reading from this stream only.
1053            // fail("Should throw ZipException");
1054        } catch (ZipException ee) {
1055            // expected
1056        }
1057
1058        try {
1059            Support_Resources.copyFile(resources, null, jarName);
1060            File signedFile = new File(resources, jarName);
1061            JarFile jf = new JarFile(signedFile);
1062            JarEntry jre = new JarEntry("foo/bar/A.class");
1063            jf.close();
1064            jf.getInputStream(jre);
1065            // InputStream returned in any way, exception can be thrown in case
1066            // of reading from this stream only.
1067            // The same for IOException
1068            fail("Should throw IllegalStateException");
1069        } catch (IllegalStateException ee) {
1070            // expected
1071        }
1072    }
1073
1074    /**
1075     * The jar is intact, but the entry object is modified.
1076     */
1077    @TestTargetNew(
1078            level = TestLevel.PARTIAL_COMPLETE,
1079            notes = "Regression test for issue introduced by HAROMNY-4569. "
1080                + "signed archives containing files with size 0 could not get verified",
1081            method = "getInputStream",
1082            args = {ZipEntry.class}
1083    )
1084    public void testJarVerificationEmptyEntry() throws IOException {
1085        Support_Resources.copyFile(resources, null, emptyEntryJar);
1086        File f = new File(resources, emptyEntryJar);
1087
1088        JarFile jarFile = new JarFile(f);
1089
1090        ZipEntry zipEntry = jarFile.getJarEntry(emptyEntry1);
1091        int res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100);
1092        assertEquals("Wrong length of empty jar entry", -1, res);
1093
1094        zipEntry = jarFile.getJarEntry(emptyEntry2);
1095        res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100);
1096        assertEquals("Wrong length of empty jar entry", -1, res);
1097
1098        zipEntry = jarFile.getJarEntry(emptyEntry3);
1099        res = jarFile.getInputStream(zipEntry).read();
1100        assertEquals("Wrong length of empty jar entry", -1, res);
1101    }
1102}
1103