1 /*
   2  * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util.zip;
  27 
  28 import java.io.Closeable;
  29 import java.io.InputStream;
  30 import java.io.IOException;
  31 import java.io.EOFException;
  32 import java.io.File;
  33 import java.nio.charset.Charset;
  34 import java.util.Vector;
  35 import java.util.Enumeration;
  36 import java.util.Set;
  37 import java.util.HashSet;
  38 import java.util.NoSuchElementException;
  39 import java.security.AccessController;
  40 import sun.security.action.GetPropertyAction;
  41 import static java.util.zip.ZipConstants64.*;
  42 
  43 /**
  44  * This class is used to read entries from a zip file.
  45  *
  46  * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
  47  * or method in this class will cause a {@link NullPointerException} to be
  48  * thrown.
  49  *
  50  * @author      David Connelly
  51  */
  52 public
  53 class ZipFile implements ZipConstants, Closeable {
  54     private long jzfile;  // address of jzfile data
  55     private String name;  // zip file name
  56     private int total;    // total number of entries
  57     private boolean closeRequested;
  58 
  59     private static final int STORED = ZipEntry.STORED;
  60     private static final int DEFLATED = ZipEntry.DEFLATED;
  61 
  62     /**
  63      * Mode flag to open a zip file for reading.
  64      */
  65     public static final int OPEN_READ = 0x1;
  66 
  67     /**
  68      * Mode flag to open a zip file and mark it for deletion.  The file will be
  69      * deleted some time between the moment that it is opened and the moment
  70      * that it is closed, but its contents will remain accessible via the
  71      * <tt>ZipFile</tt> object until either the close method is invoked or the
  72      * virtual machine exits.
  73      */
  74     public static final int OPEN_DELETE = 0x4;
  75 
  76     static {
  77         /* Zip library is loaded from System.initializeSystemClass */
  78         initIDs();
  79     }
  80 
  81     private static native void initIDs();
  82 
  83     private static final boolean usemmap;
  84 
  85     static {
  86         // A system prpperty to disable mmap use to avoid vm crash when
  87         // in-use zip file is accidently overwritten by others.
  88         String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
  89         usemmap = (prop == null ||
  90                    !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
  91     }
  92 
  93     /**
  94      * Opens a zip file for reading.
  95      *
  96      * <p>First, if there is a security manager, its <code>checkRead</code>
  97      * method is called with the <code>name</code> argument as its argument
  98      * to ensure the read is allowed.
  99      *
 100      * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
 101      * decode the entry names and comments.
 102      *
 103      * @param name the name of the zip file
 104      * @throws ZipException if a ZIP format error has occurred
 105      * @throws IOException if an I/O error has occurred
 106      * @throws SecurityException if a security manager exists and its
 107      *         <code>checkRead</code> method doesn't allow read access to the file.
 108      *
 109      * @see SecurityManager#checkRead(java.lang.String)
 110      */
 111     public ZipFile(String name) throws IOException {
 112         this(new File(name), OPEN_READ);
 113     }
 114 
 115     /**
 116      * Opens a new <code>ZipFile</code> to read from the specified
 117      * <code>File</code> object in the specified mode.  The mode argument
 118      * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
 119      *
 120      * <p>First, if there is a security manager, its <code>checkRead</code>
 121      * method is called with the <code>name</code> argument as its argument to
 122      * ensure the read is allowed.
 123      *
 124      * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
 125      * decode the entry names and comments
 126      *
 127      * @param file the ZIP file to be opened for reading
 128      * @param mode the mode in which the file is to be opened
 129      * @throws ZipException if a ZIP format error has occurred
 130      * @throws IOException if an I/O error has occurred
 131      * @throws SecurityException if a security manager exists and
 132      *         its <code>checkRead</code> method
 133      *         doesn't allow read access to the file,
 134      *         or its <code>checkDelete</code> method doesn't allow deleting
 135      *         the file when the <tt>OPEN_DELETE</tt> flag is set.
 136      * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
 137      * @see SecurityManager#checkRead(java.lang.String)
 138      * @since 1.3
 139      */
 140     public ZipFile(File file, int mode) throws IOException {
 141         this(file, mode, Charset.forName("UTF-8"));
 142     }
 143 
 144     /**
 145      * Opens a ZIP file for reading given the specified File object.
 146      *
 147      * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
 148      * decode the entry names and comments.
 149      *
 150      * @param file the ZIP file to be opened for reading
 151      * @throws ZipException if a ZIP format error has occurred
 152      * @throws IOException if an I/O error has occurred
 153      */
 154     public ZipFile(File file) throws ZipException, IOException {
 155         this(file, OPEN_READ);
 156     }
 157 
 158     private ZipCoder zc;
 159 
 160     /**
 161      * Opens a new <code>ZipFile</code> to read from the specified
 162      * <code>File</code> object in the specified mode.  The mode argument
 163      * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
 164      *
 165      * <p>First, if there is a security manager, its <code>checkRead</code>
 166      * method is called with the <code>name</code> argument as its argument to
 167      * ensure the read is allowed.
 168      *
 169      * @param file the ZIP file to be opened for reading
 170      * @param mode the mode in which the file is to be opened
 171      * @param charset
 172      *        the {@linkplain java.nio.charset.Charset charset} to
 173      *        be used to decode the ZIP entry name and comment that are not
 174      *        encoded by using UTF-8 encoding (indicated by entry's general
 175      *        purpose flag).
 176      *
 177      * @throws ZipException if a ZIP format error has occurred
 178      * @throws IOException if an I/O error has occurred
 179      *
 180      * @throws SecurityException
 181      *         if a security manager exists and its <code>checkRead</code>
 182      *         method doesn't allow read access to the file,or its
 183      *         <code>checkDelete</code> method doesn't allow deleting the
 184      *         file when the <tt>OPEN_DELETE</tt> flag is set
 185      *
 186      * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
 187      *
 188      * @see SecurityManager#checkRead(java.lang.String)
 189      *
 190      * @since 1.7
 191      */
 192     public ZipFile(File file, int mode, Charset charset) throws IOException
 193     {
 194         if (((mode & OPEN_READ) == 0) ||
 195             ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
 196             throw new IllegalArgumentException("Illegal mode: 0x"+
 197                                                Integer.toHexString(mode));
 198         }
 199         String name = file.getPath();
 200         SecurityManager sm = System.getSecurityManager();
 201         if (sm != null) {
 202             sm.checkRead(name);
 203             if ((mode & OPEN_DELETE) != 0) {
 204                 sm.checkDelete(name);
 205             }
 206         }
 207         if (charset == null)
 208             throw new NullPointerException("charset is null");
 209         this.zc = ZipCoder.get(charset);
 210         long t0 = System.nanoTime();
 211         jzfile = open(name, mode, file.lastModified(), usemmap);
 212         sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
 213         sun.misc.PerfCounter.getZipFileCount().increment();
 214         this.name = name;
 215         this.total = getTotal(jzfile);
 216     }
 217 
 218     /**
 219      * Opens a zip file for reading.
 220      *
 221      * <p>First, if there is a security manager, its <code>checkRead</code>
 222      * method is called with the <code>name</code> argument as its argument
 223      * to ensure the read is allowed.
 224      *
 225      * @param name the name of the zip file
 226      * @param charset
 227      *        the {@linkplain java.nio.charset.Charset charset} to
 228      *        be used to decode the ZIP entry name and comment that are not
 229      *        encoded by using UTF-8 encoding (indicated by entry's general
 230      *        purpose flag).
 231      *
 232      * @throws ZipException if a ZIP format error has occurred
 233      * @throws IOException if an I/O error has occurred
 234      * @throws SecurityException
 235      *         if a security manager exists and its <code>checkRead</code>
 236      *         method doesn't allow read access to the file
 237      *
 238      * @see SecurityManager#checkRead(java.lang.String)
 239      *
 240      * @since 1.7
 241      */
 242     public ZipFile(String name, Charset charset) throws IOException
 243     {
 244         this(new File(name), OPEN_READ, charset);
 245     }
 246 
 247     /**
 248      * Opens a ZIP file for reading given the specified File object.
 249      * @param file the ZIP file to be opened for reading
 250      * @param charset
 251      *        The {@linkplain java.nio.charset.Charset charset} to be
 252      *        used to decode the ZIP entry name and comment (ignored if
 253      *        the <a href="package-summary.html#lang_encoding"> language
 254      *        encoding bit</a> of the ZIP entry's general purpose bit
 255      *        flag is set).
 256      *
 257      * @throws ZipException if a ZIP format error has occurred
 258      * @throws IOException if an I/O error has occurred
 259      *
 260      * @since 1.7
 261      */
 262     public ZipFile(File file, Charset charset) throws IOException
 263     {
 264         this(file, OPEN_READ, charset);
 265     }
 266 
 267     /**
 268      * Returns the zip file comment, or null if none.
 269      *
 270      * @return the comment string for the zip file, or null if none
 271      *
 272      * @throws IllegalStateException if the zip file has been closed
 273      *
 274      * Since 1.7
 275      */
 276     public String getComment() {
 277         synchronized (this) {
 278             ensureOpen();
 279             byte[] bcomm = getCommentBytes(jzfile);
 280             if (bcomm == null)
 281                 return null;
 282             return zc.toString(bcomm, bcomm.length);
 283         }
 284     }
 285 
 286     /**
 287      * Returns the zip file entry for the specified name, or null
 288      * if not found.
 289      *
 290      * @param name the name of the entry
 291      * @return the zip file entry, or null if not found
 292      * @throws IllegalStateException if the zip file has been closed
 293      */
 294     public ZipEntry getEntry(String name) {
 295         if (name == null) {
 296             throw new NullPointerException("name");
 297         }
 298         long jzentry = 0;
 299         synchronized (this) {
 300             ensureOpen();
 301             jzentry = getEntry(jzfile, zc.getBytes(name), true);
 302             if (jzentry != 0) {
 303                 ZipEntry ze = getZipEntry(name, jzentry);
 304                 freeEntry(jzfile, jzentry);
 305                 return ze;
 306             }
 307         }
 308         return null;
 309     }
 310 
 311     private static native long getEntry(long jzfile, byte[] name,
 312                                         boolean addSlash);
 313 
 314     // freeEntry releases the C jzentry struct.
 315     private static native void freeEntry(long jzfile, long jzentry);
 316 
 317     // the outstanding inputstreams that need to be closed.
 318     private Set<InputStream> streams = new HashSet<>();
 319 
 320     /**
 321      * Returns an input stream for reading the contents of the specified
 322      * zip file entry.
 323      *
 324      * <p> Closing this ZIP file will, in turn, close all input
 325      * streams that have been returned by invocations of this method.
 326      *
 327      * @param entry the zip file entry
 328      * @return the input stream for reading the contents of the specified
 329      * zip file entry.
 330      * @throws ZipException if a ZIP format error has occurred
 331      * @throws IOException if an I/O error has occurred
 332      * @throws IllegalStateException if the zip file has been closed
 333      */
 334     public InputStream getInputStream(ZipEntry entry) throws IOException {
 335         if (entry == null) {
 336             throw new NullPointerException("entry");
 337         }
 338         long jzentry = 0;
 339         ZipFileInputStream in = null;
 340         synchronized (this) {
 341             ensureOpen();
 342             if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
 343                 jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
 344             } else {
 345                 jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
 346             }
 347             if (jzentry == 0) {
 348                 return null;
 349             }
 350             in = new ZipFileInputStream(jzentry);
 351 
 352             switch (getEntryMethod(jzentry)) {
 353             case STORED:
 354                 streams.add(in);
 355                 return in;
 356             case DEFLATED:
 357                 final ZipFileInputStream zfin = in;
 358                 // MORE: Compute good size for inflater stream:
 359                 long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
 360                 if (size > 65536) size = 8192;
 361                 if (size <= 0) size = 4096;
 362                 InputStream is = new InflaterInputStream(zfin, getInflater(), (int)size) {
 363                     private boolean isClosed = false;
 364 
 365                     public void close() throws IOException {
 366                         if (!isClosed) {
 367                             super.close();
 368                             releaseInflater(inf);
 369                             isClosed = true;
 370                         }
 371                     }
 372                     // Override fill() method to provide an extra "dummy" byte
 373                     // at the end of the input stream. This is required when
 374                     // using the "nowrap" Inflater option.
 375                     protected void fill() throws IOException {
 376                         if (eof) {
 377                             throw new EOFException(
 378                                 "Unexpected end of ZLIB input stream");
 379                         }
 380                         len = this.in.read(buf, 0, buf.length);
 381                         if (len == -1) {
 382                             buf[0] = 0;
 383                             len = 1;
 384                             eof = true;
 385                         }
 386                         inf.setInput(buf, 0, len);
 387                     }
 388                     private boolean eof;
 389 
 390                     public int available() throws IOException {
 391                         if (isClosed)
 392                             return 0;
 393                         long avail = zfin.size() - inf.getBytesWritten();
 394                         return avail > (long) Integer.MAX_VALUE ?
 395                             Integer.MAX_VALUE : (int) avail;
 396                     }
 397                 };
 398                 streams.add(is);
 399                 return is;
 400             default:
 401                 throw new ZipException("invalid compression method");
 402             }
 403         }
 404     }
 405 
 406     /*
 407      * Gets an inflater from the list of available inflaters or allocates
 408      * a new one.
 409      */
 410     private Inflater getInflater() {
 411         synchronized (inflaters) {
 412             int size = inflaters.size();
 413             if (size > 0) {
 414                 Inflater inf = (Inflater)inflaters.remove(size - 1);
 415                 return inf;
 416             } else {
 417                 return new Inflater(true);
 418             }
 419         }
 420     }
 421 
 422     /*
 423      * Releases the specified inflater to the list of available inflaters.
 424      */
 425     private void releaseInflater(Inflater inf) {
 426         synchronized (inflaters) {
 427             inf.reset();
 428             inflaters.add(inf);
 429         }
 430     }
 431 
 432     // List of available Inflater objects for decompression
 433     private Vector inflaters = new Vector();
 434 
 435     /**
 436      * Returns the path name of the ZIP file.
 437      * @return the path name of the ZIP file
 438      */
 439     public String getName() {
 440         return name;
 441     }
 442 
 443     /**
 444      * Returns an enumeration of the ZIP file entries.
 445      * @return an enumeration of the ZIP file entries
 446      * @throws IllegalStateException if the zip file has been closed
 447      */
 448     public Enumeration<? extends ZipEntry> entries() {
 449         ensureOpen();
 450         return new Enumeration<ZipEntry>() {
 451                 private int i = 0;
 452                 public boolean hasMoreElements() {
 453                     synchronized (ZipFile.this) {
 454                         ensureOpen();
 455                         return i < total;
 456                     }
 457                 }
 458                 public ZipEntry nextElement() throws NoSuchElementException {
 459                     synchronized (ZipFile.this) {
 460                         ensureOpen();
 461                         if (i >= total) {
 462                             throw new NoSuchElementException();
 463                         }
 464                         long jzentry = getNextEntry(jzfile, i++);
 465                         if (jzentry == 0) {
 466                             String message;
 467                             if (closeRequested) {
 468                                 message = "ZipFile concurrently closed";
 469                             } else {
 470                                 message = getZipMessage(ZipFile.this.jzfile);
 471                             }
 472                             throw new ZipError("jzentry == 0" +
 473                                                ",\n jzfile = " + ZipFile.this.jzfile +
 474                                                ",\n total = " + ZipFile.this.total +
 475                                                ",\n name = " + ZipFile.this.name +
 476                                                ",\n i = " + i +
 477                                                ",\n message = " + message
 478                                 );
 479                         }
 480                         ZipEntry ze = getZipEntry(null, jzentry);
 481                         freeEntry(jzfile, jzentry);
 482                         return ze;
 483                     }
 484                 }
 485             };
 486     }
 487 
 488     private ZipEntry getZipEntry(String name, long jzentry) {
 489         ZipEntry e = new ZipEntry();
 490         e.flag = getEntryFlag(jzentry);  // get the flag first
 491         if (name != null) {
 492             e.name = name;
 493         } else {
 494             byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
 495             if (!zc.isUTF8() && (e.flag & EFS) != 0) {
 496                 e.name = zc.toStringUTF8(bname, bname.length);
 497             } else {
 498                 e.name = zc.toString(bname, bname.length);
 499             }
 500         }
 501         e.time = getEntryTime(jzentry);
 502         e.crc = getEntryCrc(jzentry);
 503         e.size = getEntrySize(jzentry);
 504         e. csize = getEntryCSize(jzentry);
 505         e.method = getEntryMethod(jzentry);
 506         e.extra = getEntryBytes(jzentry, JZENTRY_EXTRA);
 507         byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
 508         if (bcomm == null) {
 509             e.comment = null;
 510         } else {
 511             if (!zc.isUTF8() && (e.flag & EFS) != 0) {
 512                 e.comment = zc.toStringUTF8(bcomm, bcomm.length);
 513             } else {
 514                 e.comment = zc.toString(bcomm, bcomm.length);
 515             }
 516         }
 517         return e;
 518     }
 519 
 520     private static native long getNextEntry(long jzfile, int i);
 521 
 522     /**
 523      * Returns the number of entries in the ZIP file.
 524      * @return the number of entries in the ZIP file
 525      * @throws IllegalStateException if the zip file has been closed
 526      */
 527     public int size() {
 528         ensureOpen();
 529         return total;
 530     }
 531 
 532     /**
 533      * Closes the ZIP file.
 534      * <p> Closing this ZIP file will close all of the input streams
 535      * previously returned by invocations of the {@link #getInputStream
 536      * getInputStream} method.
 537      *
 538      * @throws IOException if an I/O error has occurred
 539      */
 540     public void close() throws IOException {
 541         synchronized (this) {
 542             closeRequested = true;
 543 
 544             if (streams.size() !=0) {
 545                 Set<InputStream> copy = streams;
 546                 streams = new HashSet<InputStream>();
 547                 for (InputStream is: copy)
 548                     is.close();
 549             }
 550 
 551             if (jzfile != 0) {
 552                 // Close the zip file
 553                 long zf = this.jzfile;
 554                 jzfile = 0;
 555 
 556                 close(zf);
 557 
 558                 // Release inflaters
 559                 synchronized (inflaters) {
 560                     int size = inflaters.size();
 561                     for (int i = 0; i < size; i++) {
 562                         Inflater inf = (Inflater)inflaters.get(i);
 563                         inf.end();
 564                     }
 565                 }
 566             }
 567         }
 568     }
 569 
 570 
 571     /**
 572      * Ensures that the <code>close</code> method of this ZIP file is
 573      * called when there are no more references to it.
 574      *
 575      * <p>
 576      * Since the time when GC would invoke this method is undetermined,
 577      * it is strongly recommended that applications invoke the <code>close</code>
 578      * method as soon they have finished accessing this <code>ZipFile</code>.
 579      * This will prevent holding up system resources for an undetermined
 580      * length of time.
 581      *
 582      * @throws IOException if an I/O error has occurred
 583      * @see    java.util.zip.ZipFile#close()
 584      */
 585     protected void finalize() throws IOException {
 586         close();
 587     }
 588 
 589     private static native void close(long jzfile);
 590 
 591     private void ensureOpen() {
 592         if (closeRequested) {
 593             throw new IllegalStateException("zip file closed");
 594         }
 595 
 596         if (jzfile == 0) {
 597             throw new IllegalStateException("The object is not initialized.");
 598         }
 599     }
 600 
 601     private void ensureOpenOrZipException() throws IOException {
 602         if (closeRequested) {
 603             throw new ZipException("ZipFile closed");
 604         }
 605     }
 606 
 607     /*
 608      * Inner class implementing the input stream used to read a
 609      * (possibly compressed) zip file entry.
 610      */
 611    private class ZipFileInputStream extends InputStream {
 612         protected long jzentry; // address of jzentry data
 613         private   long pos;     // current position within entry data
 614         protected long rem;     // number of remaining bytes within entry
 615         protected long size;    // uncompressed size of this entry
 616 
 617         ZipFileInputStream(long jzentry) {
 618             pos = 0;
 619             rem = getEntryCSize(jzentry);
 620             size = getEntrySize(jzentry);
 621             this.jzentry = jzentry;
 622         }
 623 
 624         public int read(byte b[], int off, int len) throws IOException {
 625             if (rem == 0) {
 626                 return -1;
 627             }
 628             if (len <= 0) {
 629                 return 0;
 630             }
 631             if (len > rem) {
 632                 len = (int) rem;
 633             }
 634             synchronized (ZipFile.this) {
 635                 ensureOpenOrZipException();
 636 
 637                 len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
 638                                    off, len);
 639             }
 640             if (len > 0) {
 641                 pos += len;
 642                 rem -= len;
 643             }
 644             if (rem == 0) {
 645                 close();
 646             }
 647             return len;
 648         }
 649 
 650         public int read() throws IOException {
 651             byte[] b = new byte[1];
 652             if (read(b, 0, 1) == 1) {
 653                 return b[0] & 0xff;
 654             } else {
 655                 return -1;
 656             }
 657         }
 658 
 659         public long skip(long n) {
 660             if (n > rem)
 661                 n = rem;
 662             pos += n;
 663             rem -= n;
 664             if (rem == 0) {
 665                 close();
 666             }
 667             return n;
 668         }
 669 
 670         public int available() {
 671             return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
 672         }
 673 
 674         public long size() {
 675             return size;
 676         }
 677 
 678         public void close() {
 679             rem = 0;
 680             synchronized (ZipFile.this) {
 681                 if (jzentry != 0 && ZipFile.this.jzfile != 0) {
 682                     freeEntry(ZipFile.this.jzfile, jzentry);
 683                     jzentry = 0;
 684                 }
 685                 streams.remove(this);
 686             }
 687         }
 688     }
 689 
 690 
 691     private static native long open(String name, int mode, long lastModified,
 692                                     boolean usemmap) throws IOException;
 693     private static native int getTotal(long jzfile);
 694     private static native int read(long jzfile, long jzentry,
 695                                    long pos, byte[] b, int off, int len);
 696 
 697     // access to the native zentry object
 698     private static native long getEntryTime(long jzentry);
 699     private static native long getEntryCrc(long jzentry);
 700     private static native long getEntryCSize(long jzentry);
 701     private static native long getEntrySize(long jzentry);
 702     private static native int getEntryMethod(long jzentry);
 703     private static native int getEntryFlag(long jzentry);
 704     private static native byte[] getCommentBytes(long jzfile);
 705 
 706     private static final int JZENTRY_NAME = 0;
 707     private static final int JZENTRY_EXTRA = 1;
 708     private static final int JZENTRY_COMMENT = 2;
 709     private static native byte[] getEntryBytes(long jzentry, int type);
 710 
 711     private static native String getZipMessage(long jzfile);
 712 }