| 1 | /* JarFile.java - Representation of a jar file
|
|---|
| 2 | Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This file is part of GNU Classpath.
|
|---|
| 5 |
|
|---|
| 6 | GNU Classpath is free software; you can redistribute it and/or modify
|
|---|
| 7 | it under the terms of the GNU General Public License as published by
|
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 9 | any later version.
|
|---|
| 10 |
|
|---|
| 11 | GNU Classpath is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 14 | General Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License
|
|---|
| 17 | along with GNU Classpath; see the file COPYING. If not, write to the
|
|---|
| 18 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 19 | 02111-1307 USA.
|
|---|
| 20 |
|
|---|
| 21 | Linking this library statically or dynamically with other modules is
|
|---|
| 22 | making a combined work based on this library. Thus, the terms and
|
|---|
| 23 | conditions of the GNU General Public License cover the whole
|
|---|
| 24 | combination.
|
|---|
| 25 |
|
|---|
| 26 | As a special exception, the copyright holders of this library give you
|
|---|
| 27 | permission to link this library with independent modules to produce an
|
|---|
| 28 | executable, regardless of the license terms of these independent
|
|---|
| 29 | modules, and to copy and distribute the resulting executable under
|
|---|
| 30 | terms of your choice, provided that you also meet, for each linked
|
|---|
| 31 | independent module, the terms and conditions of the license of that
|
|---|
| 32 | module. An independent module is a module which is not derived from
|
|---|
| 33 | or based on this library. If you modify this library, you may extend
|
|---|
| 34 | this exception to your version of the library, but you are not
|
|---|
| 35 | obligated to do so. If you do not wish to do so, delete this
|
|---|
| 36 | exception statement from your version. */
|
|---|
| 37 |
|
|---|
| 38 | package java.util.jar;
|
|---|
| 39 |
|
|---|
| 40 | import java.util.zip.ZipEntry;
|
|---|
| 41 | import java.util.zip.ZipException;
|
|---|
| 42 | import java.util.zip.ZipFile;
|
|---|
| 43 | import java.io.File;
|
|---|
| 44 | import java.io.FileNotFoundException;
|
|---|
| 45 | import java.io.InputStream;
|
|---|
| 46 | import java.io.IOException;
|
|---|
| 47 | import java.util.Enumeration;
|
|---|
| 48 |
|
|---|
| 49 | /**
|
|---|
| 50 | * Representation of a jar file.
|
|---|
| 51 | * <p>
|
|---|
| 52 | * Note that this class is not a subclass of java.io.File but a subclass of
|
|---|
| 53 | * java.util.zip.ZipFile and you can only read JarFiles with it (although
|
|---|
| 54 | * there are constructors that take a File object).
|
|---|
| 55 | * <p>
|
|---|
| 56 | * XXX - verification of Manifest signatures is not yet implemented.
|
|---|
| 57 | *
|
|---|
| 58 | * @since 1.2
|
|---|
| 59 | * @author Mark Wielaard ([email protected])
|
|---|
| 60 | */
|
|---|
| 61 | public class JarFile extends ZipFile
|
|---|
| 62 | {
|
|---|
| 63 | // Fields
|
|---|
| 64 |
|
|---|
| 65 | /** The name of the manifest entry: META-INF/MANIFEST.MF */
|
|---|
| 66 | public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
|
|---|
| 67 |
|
|---|
| 68 | /**
|
|---|
| 69 | * The manifest of this file, if any, otherwise null.
|
|---|
| 70 | * Read when first needed.
|
|---|
| 71 | */
|
|---|
| 72 | private Manifest manifest;
|
|---|
| 73 |
|
|---|
| 74 | /** Whether to verify the manifest and all entries. */
|
|---|
| 75 | private boolean verify;
|
|---|
| 76 |
|
|---|
| 77 | /** Whether the has already been loaded. */
|
|---|
| 78 | private boolean manifestRead = false;
|
|---|
| 79 |
|
|---|
| 80 | // Constructors
|
|---|
| 81 |
|
|---|
| 82 | /**
|
|---|
| 83 | * Creates a new JarFile. All jar entries are verified (when a Manifest file
|
|---|
| 84 | * for this JarFile exists). You need to actually open and read the complete
|
|---|
| 85 | * jar entry (with <code>getInputStream()</code>) to check its signature.
|
|---|
| 86 | *
|
|---|
| 87 | * @param fileName the name of the file to open
|
|---|
| 88 | * @exception FileNotFoundException if the fileName cannot be found
|
|---|
| 89 | * @exception IOException if another IO exception occurs while reading
|
|---|
| 90 | */
|
|---|
| 91 | public JarFile(String fileName) throws FileNotFoundException, IOException
|
|---|
| 92 | {
|
|---|
| 93 | this(fileName, true);
|
|---|
| 94 | }
|
|---|
| 95 |
|
|---|
| 96 | /**
|
|---|
| 97 | * Creates a new JarFile. If verify is true then all jar entries are
|
|---|
| 98 | * verified (when a Manifest file for this JarFile exists). You need to
|
|---|
| 99 | * actually open and read the complete jar entry
|
|---|
| 100 | * (with <code>getInputStream()</code>) to check its signature.
|
|---|
| 101 | *
|
|---|
| 102 | * @param fileName the name of the file to open
|
|---|
| 103 | * @param verify checks manifest and entries when true and a manifest
|
|---|
| 104 | * exists, when false no checks are made
|
|---|
| 105 | * @exception FileNotFoundException if the fileName cannot be found
|
|---|
| 106 | * @exception IOException if another IO exception occurs while reading
|
|---|
| 107 | */
|
|---|
| 108 | public JarFile(String fileName, boolean verify) throws
|
|---|
| 109 | FileNotFoundException, IOException
|
|---|
| 110 | {
|
|---|
| 111 | super(fileName);
|
|---|
| 112 | if (verify)
|
|---|
| 113 | {
|
|---|
| 114 | manifest = readManifest();
|
|---|
| 115 | verify();
|
|---|
| 116 | }
|
|---|
| 117 | }
|
|---|
| 118 |
|
|---|
| 119 | /**
|
|---|
| 120 | * Creates a new JarFile. All jar entries are verified (when a Manifest file
|
|---|
| 121 | * for this JarFile exists). You need to actually open and read the complete
|
|---|
| 122 | * jar entry (with <code>getInputStream()</code>) to check its signature.
|
|---|
| 123 | *
|
|---|
| 124 | * @param file the file to open as a jar file
|
|---|
| 125 | * @exception FileNotFoundException if the file does not exits
|
|---|
| 126 | * @exception IOException if another IO exception occurs while reading
|
|---|
| 127 | */
|
|---|
| 128 | public JarFile(File file) throws FileNotFoundException, IOException
|
|---|
| 129 | {
|
|---|
| 130 | this(file, true);
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | /**
|
|---|
| 134 | * Creates a new JarFile. If verify is true then all jar entries are
|
|---|
| 135 | * verified (when a Manifest file for this JarFile exists). You need to
|
|---|
| 136 | * actually open and read the complete jar entry
|
|---|
| 137 | * (with <code>getInputStream()</code>) to check its signature.
|
|---|
| 138 | *
|
|---|
| 139 | * @param file the file to open to open as a jar file
|
|---|
| 140 | * @param verify checks manifest and entries when true and a manifest
|
|---|
| 141 | * exists, when false no checks are made
|
|---|
| 142 | * @exception FileNotFoundException if file does not exist
|
|---|
| 143 | * @exception IOException if another IO exception occurs while reading
|
|---|
| 144 | */
|
|---|
| 145 | public JarFile(File file, boolean verify) throws FileNotFoundException,
|
|---|
| 146 | IOException
|
|---|
| 147 | {
|
|---|
| 148 | super(file);
|
|---|
| 149 | if (verify)
|
|---|
| 150 | {
|
|---|
| 151 | manifest = readManifest();
|
|---|
| 152 | verify();
|
|---|
| 153 | }
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 | /**
|
|---|
| 157 | * Creates a new JarFile with the indicated mode. If verify is true then
|
|---|
| 158 | * all jar entries are verified (when a Manifest file for this JarFile
|
|---|
| 159 | * exists). You need to actually open and read the complete jar entry
|
|---|
| 160 | * (with <code>getInputStream()</code>) to check its signature.
|
|---|
| 161 | * manifest and if the manifest exists and verify is true verfies it.
|
|---|
| 162 | *
|
|---|
| 163 | * @param file the file to open to open as a jar file
|
|---|
| 164 | * @param verify checks manifest and entries when true and a manifest
|
|---|
| 165 | * exists, when false no checks are made
|
|---|
| 166 | * @param mode either ZipFile.OPEN_READ or
|
|---|
| 167 | * (ZipFile.OPEN_READ | ZipFile.OPEN_DELETE)
|
|---|
| 168 | * @exception FileNotFoundException if the file does not exist
|
|---|
| 169 | * @exception IOException if another IO exception occurs while reading
|
|---|
| 170 | * @exception IllegalArgumentException when given an illegal mode
|
|---|
| 171 | *
|
|---|
| 172 | * @since 1.3
|
|---|
| 173 | */
|
|---|
| 174 | public JarFile(File file, boolean verify, int mode) throws
|
|---|
| 175 | FileNotFoundException, IOException, IllegalArgumentException
|
|---|
| 176 | {
|
|---|
| 177 | super(file, mode);
|
|---|
| 178 | if (verify)
|
|---|
| 179 | {
|
|---|
| 180 | manifest = readManifest();
|
|---|
| 181 | verify();
|
|---|
| 182 | }
|
|---|
| 183 | }
|
|---|
| 184 |
|
|---|
| 185 | // Methods
|
|---|
| 186 |
|
|---|
| 187 | /**
|
|---|
| 188 | * XXX - should verify the manifest file
|
|---|
| 189 | */
|
|---|
| 190 | private void verify()
|
|---|
| 191 | {
|
|---|
| 192 | // only check if manifest is not null
|
|---|
| 193 | if (manifest == null)
|
|---|
| 194 | {
|
|---|
| 195 | verify = false;
|
|---|
| 196 | return;
|
|---|
| 197 | }
|
|---|
| 198 |
|
|---|
| 199 | verify = true;
|
|---|
| 200 | // XXX - verify manifest
|
|---|
| 201 | }
|
|---|
| 202 |
|
|---|
| 203 | /**
|
|---|
| 204 | * Parses and returns the manifest if it exists, otherwise returns null.
|
|---|
| 205 | */
|
|---|
| 206 | private Manifest readManifest()
|
|---|
| 207 | {
|
|---|
| 208 | try
|
|---|
| 209 | {
|
|---|
| 210 | ZipEntry manEntry = super.getEntry(MANIFEST_NAME);
|
|---|
| 211 | if (manEntry != null)
|
|---|
| 212 | {
|
|---|
| 213 | InputStream in = super.getInputStream(manEntry);
|
|---|
| 214 | manifestRead = true;
|
|---|
| 215 | return new Manifest(in);
|
|---|
| 216 | }
|
|---|
| 217 | else
|
|---|
| 218 | {
|
|---|
| 219 | manifestRead = true;
|
|---|
| 220 | return null;
|
|---|
| 221 | }
|
|---|
| 222 | }
|
|---|
| 223 | catch (IOException ioe)
|
|---|
| 224 | {
|
|---|
| 225 | manifestRead = true;
|
|---|
| 226 | return null;
|
|---|
| 227 | }
|
|---|
| 228 | }
|
|---|
| 229 |
|
|---|
| 230 | /**
|
|---|
| 231 | * Returns a enumeration of all the entries in the JarFile.
|
|---|
| 232 | * Note that also the Jar META-INF entries are returned.
|
|---|
| 233 | *
|
|---|
| 234 | * @exception IllegalStateException when the JarFile is already closed
|
|---|
| 235 | */
|
|---|
| 236 | public Enumeration entries() throws IllegalStateException
|
|---|
| 237 | {
|
|---|
| 238 | return new JarEnumeration(super.entries());
|
|---|
| 239 | }
|
|---|
| 240 |
|
|---|
| 241 | /**
|
|---|
| 242 | * Wraps a given Zip Entries Enumeration. For every zip entry a
|
|---|
| 243 | * JarEntry is created and the corresponding Attributes are looked up.
|
|---|
| 244 | * XXX - Should also look up the certificates.
|
|---|
| 245 | */
|
|---|
| 246 | private class JarEnumeration implements Enumeration
|
|---|
| 247 | {
|
|---|
| 248 |
|
|---|
| 249 | private final Enumeration entries;
|
|---|
| 250 |
|
|---|
| 251 | JarEnumeration(Enumeration e)
|
|---|
| 252 | {
|
|---|
| 253 | entries = e;
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | public boolean hasMoreElements()
|
|---|
| 257 | {
|
|---|
| 258 | return entries.hasMoreElements();
|
|---|
| 259 | }
|
|---|
| 260 |
|
|---|
| 261 | public Object nextElement()
|
|---|
| 262 | {
|
|---|
| 263 | ZipEntry zip = (ZipEntry) entries.nextElement();
|
|---|
| 264 | JarEntry jar = new JarEntry(zip);
|
|---|
| 265 | Manifest manifest;
|
|---|
| 266 | try
|
|---|
| 267 | {
|
|---|
| 268 | manifest = getManifest();
|
|---|
| 269 | }
|
|---|
| 270 | catch (IOException ioe)
|
|---|
| 271 | {
|
|---|
| 272 | manifest = null;
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | if (manifest != null)
|
|---|
| 276 | {
|
|---|
| 277 | jar.attr = manifest.getAttributes(jar.getName());
|
|---|
| 278 | }
|
|---|
| 279 | // XXX jar.certs
|
|---|
| 280 | return jar;
|
|---|
| 281 | }
|
|---|
| 282 | }
|
|---|
| 283 |
|
|---|
| 284 | /**
|
|---|
| 285 | * XXX
|
|---|
| 286 | * It actually returns a JarEntry not a zipEntry
|
|---|
| 287 | * @param name XXX
|
|---|
| 288 | */
|
|---|
| 289 | public ZipEntry getEntry(String name)
|
|---|
| 290 | {
|
|---|
| 291 | ZipEntry entry = super.getEntry(name);
|
|---|
| 292 | if (entry != null)
|
|---|
| 293 | {
|
|---|
| 294 | JarEntry jarEntry = new JarEntry(entry);
|
|---|
| 295 | Manifest manifest;
|
|---|
| 296 | try
|
|---|
| 297 | {
|
|---|
| 298 | manifest = getManifest();
|
|---|
| 299 | }
|
|---|
| 300 | catch (IOException ioe)
|
|---|
| 301 | {
|
|---|
| 302 | manifest = null;
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | if (manifest != null)
|
|---|
| 306 | {
|
|---|
| 307 | jarEntry.attr = manifest.getAttributes(name);
|
|---|
| 308 | // XXX jarEntry.certs
|
|---|
| 309 | }
|
|---|
| 310 | return jarEntry;
|
|---|
| 311 | }
|
|---|
| 312 | return null;
|
|---|
| 313 | }
|
|---|
| 314 |
|
|---|
| 315 | /**
|
|---|
| 316 | * XXX should verify the inputstream
|
|---|
| 317 | * @param entry XXX
|
|---|
| 318 | * @exception ZipException XXX
|
|---|
| 319 | * @exception IOException XXX
|
|---|
| 320 | */
|
|---|
| 321 | public synchronized InputStream getInputStream(ZipEntry entry) throws
|
|---|
| 322 | ZipException, IOException
|
|---|
| 323 | {
|
|---|
| 324 | return super.getInputStream(entry); // XXX verify
|
|---|
| 325 | }
|
|---|
| 326 |
|
|---|
| 327 | /**
|
|---|
| 328 | * Returns the JarEntry that belongs to the name if such an entry
|
|---|
| 329 | * exists in the JarFile. Returns null otherwise
|
|---|
| 330 | * Convenience method that just casts the result from <code>getEntry</code>
|
|---|
| 331 | * to a JarEntry.
|
|---|
| 332 | *
|
|---|
| 333 | * @param name the jar entry name to look up
|
|---|
| 334 | * @return the JarEntry if it exists, null otherwise
|
|---|
| 335 | */
|
|---|
| 336 | public JarEntry getJarEntry(String name)
|
|---|
| 337 | {
|
|---|
| 338 | return (JarEntry) getEntry(name);
|
|---|
| 339 | }
|
|---|
| 340 |
|
|---|
| 341 | /**
|
|---|
| 342 | * Returns the manifest for this JarFile or null when the JarFile does not
|
|---|
| 343 | * contain a manifest file.
|
|---|
| 344 | */
|
|---|
| 345 | public Manifest getManifest() throws IOException
|
|---|
| 346 | {
|
|---|
| 347 | if (!manifestRead)
|
|---|
| 348 | manifest = readManifest();
|
|---|
| 349 |
|
|---|
| 350 | return manifest;
|
|---|
| 351 | }
|
|---|
| 352 | }
|
|---|