/[classpath]/classpath/java/util/zip/ZipFile.java
ViewVC logotype

Diff of /classpath/java/util/zip/ZipFile.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.10 by mark, Fri Nov 29 14:04:19 2002 UTC revision 1.11 by mark, Thu Jan 2 21:07:47 2003 UTC
# Line 1  Line 1 
1  /* java.util.zip.ZipFile  /* java.util.zip.ZipFile
2     Copyright (C) 2001, 2002 Free Software Foundation, Inc.     Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
3    
4  This file is part of GNU Classpath.  This file is part of GNU Classpath.
5    
# Line 37  exception statement from your version. * Line 37  exception statement from your version. *
37    
38  package java.util.zip;  package java.util.zip;
39    
40    import java.io.BufferedInputStream;
41  import java.io.ByteArrayInputStream;  import java.io.ByteArrayInputStream;
42  import java.io.DataInput;  import java.io.DataInput;
43  import java.io.DataInputStream;  import java.io.DataInputStream;
# Line 46  import java.io.IOException; Line 47  import java.io.IOException;
47  import java.io.EOFException;  import java.io.EOFException;
48  import java.io.RandomAccessFile;  import java.io.RandomAccessFile;
49  import java.util.Enumeration;  import java.util.Enumeration;
50  import java.util.Hashtable;  import java.util.HashMap;
51    import java.util.Iterator;
52  import java.util.NoSuchElementException;  import java.util.NoSuchElementException;
53    
54  /**  /**
# Line 58  import java.util.NoSuchElementException; Line 60  import java.util.NoSuchElementException;
60   * entries in different threads.   * entries in different threads.
61   *   *
62   * @author Jochen Hoenicke   * @author Jochen Hoenicke
63     * @author Artur Biesiadowski
64   */   */
65  public class ZipFile implements ZipConstants  public class ZipFile implements ZipConstants
66  {  {
# Line 79  public class ZipFile implements ZipConst Line 82  public class ZipFile implements ZipConst
82    private final RandomAccessFile raf;    private final RandomAccessFile raf;
83    
84    // The entries of this zip file when initialized and not yet closed.    // The entries of this zip file when initialized and not yet closed.
85    private Hashtable entries;    private HashMap entries;
86    
87    private boolean closed = false;    private boolean closed = false;
88    
# Line 137  public class ZipFile implements ZipConst Line 140  public class ZipFile implements ZipConst
140    }    }
141    
142    /**    /**
143     * Read an unsigned short in little endian byte order.     * Read an unsigned short in little endian byte order from the given
144       * DataInput stream using the given byte buffer.
145       *
146       * @param di DataInput stream to read from.
147       * @param b the byte buffer to read in (must be at least 2 bytes long).
148       * @return The value read.
149       *
150     * @exception IOException if a i/o error occured.     * @exception IOException if a i/o error occured.
151     * @exception EOFException if the file ends prematurely     * @exception EOFException if the file ends prematurely
152     */     */
153    private final int readLeShort(DataInput di) throws IOException    private final int readLeShort(DataInput di, byte[] b) throws IOException
154    {    {
155      byte[] b = new byte[2];      di.readFully(b, 0, 2);
     di.readFully(b);  
156      return (b[0] & 0xff) | (b[1] & 0xff) << 8;      return (b[0] & 0xff) | (b[1] & 0xff) << 8;
157    }    }
158    
159    /**    /**
160     * Read an int in little endian byte order.     * Read an int in little endian byte order from the given
161       * DataInput stream using the given byte buffer.
162       *
163       * @param di DataInput stream to read from.
164       * @param b the byte buffer to read in (must be at least 4 bytes long).
165       * @return The value read.
166       *
167     * @exception IOException if a i/o error occured.     * @exception IOException if a i/o error occured.
168     * @exception EOFException if the file ends prematurely     * @exception EOFException if the file ends prematurely
169     */     */
170    private final int readLeInt(DataInput di) throws IOException    private final int readLeInt(DataInput di, byte[] b) throws IOException
171    {    {
172      byte[] b = new byte[4];      di.readFully(b, 0, 4);
     di.readFully(b);  
173      return ((b[0] & 0xff) | (b[1] & 0xff) << 8)      return ((b[0] & 0xff) | (b[1] & 0xff) << 8)
174              | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16;              | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16;
175    }    }
176    
177      
178      /**
179       * Read an unsigned short in little endian byte order from the given
180       * byte buffer at the given offset.
181       *
182       * @param b the byte array to read from.
183       * @param off the offset to read from.
184       * @return The value read.
185       */
186      private final int readLeShort(byte[] b, int off)
187      {
188        return (b[off] & 0xff) | (b[off+1] & 0xff) << 8;
189      }
190    
191      /**
192       * Read an int in little endian byte order from the given
193       * byte buffer at the given offset.
194       *
195       * @param b the byte array to read from.
196       * @param off the offset to read from.
197       * @return The value read.
198       */
199      private final int readLeInt(byte[] b, int off)
200      {
201        return ((b[off] & 0xff) | (b[off+1] & 0xff) << 8)
202                | ((b[off+2] & 0xff) | (b[off+3] & 0xff) << 8) << 16;
203      }
204      
205    
206    /**    /**
207     * Read the central directory of a zip file and fill the entries     * Read the central directory of a zip file and fill the entries
208     * array.  This is called exactly once when first needed.     * array.  This is called exactly once when first needed. It is called
209       * while holding the lock on <code>raf</code>.
210       *
211     * @exception IOException if a i/o error occured.     * @exception IOException if a i/o error occured.
212     * @exception ZipException if the central directory is malformed     * @exception ZipException if the central directory is malformed
213     */     */
# Line 175  public class ZipFile implements ZipConst Line 219  public class ZipFile implements ZipConst
219       * file isn't a zip file.       * file isn't a zip file.
220       */       */
221      long pos = raf.length() - ENDHDR;      long pos = raf.length() - ENDHDR;
222        byte[] ebs  = new byte[CENHDR];
223        
224      do      do
225        {        {
226          if (pos < 0)          if (pos < 0)
# Line 182  public class ZipFile implements ZipConst Line 228  public class ZipFile implements ZipConst
228              ("central directory not found, probably not a zip file: " + name);              ("central directory not found, probably not a zip file: " + name);
229          raf.seek(pos--);          raf.seek(pos--);
230        }        }
231      while (readLeInt(raf) != ENDSIG);      while (readLeInt(raf, ebs) != ENDSIG);
232        
233      if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD)      if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD)
234        throw new EOFException(name);        throw new EOFException(name);
235      int count = readLeShort(raf);      int count = readLeShort(raf, ebs);
236      if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ)      if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ)
237        throw new EOFException(name);        throw new EOFException(name);
238      int centralOffset = readLeInt(raf);      int centralOffset = readLeInt(raf, ebs);
239    
240      entries = new Hashtable(count);      entries = new HashMap(count+count/2);
241      raf.seek(centralOffset);      raf.seek(centralOffset);
242      byte[] ebs  = new byte[24];      
243      ByteArrayInputStream ebais = new ByteArrayInputStream(ebs);      byte[] buffer = new byte[16];
     DataInputStream edip = new DataInputStream(ebais);  
244      for (int i = 0; i < count; i++)      for (int i = 0; i < count; i++)
245        {        {
246          if (readLeInt(raf) != CENSIG)          raf.readFully(ebs);
247            if (readLeInt(ebs, 0) != CENSIG)
248            throw new ZipException("Wrong Central Directory signature: " + name);            throw new ZipException("Wrong Central Directory signature: " + name);
         if (raf.skipBytes(CENHOW - CENVEM) != CENHOW - CENVEM)  
           throw new EOFException(name);  
   
         raf.readFully(ebs);  
         ebais.reset();  
         int method = readLeShort(edip);  
         int dostime = readLeInt(edip);  
         int crc = readLeInt(edip);  
         int csize = readLeInt(edip);  
         int size = readLeInt(edip);  
         int nameLen = readLeShort(edip);  
         int extraLen = readLeShort(edip);  
         int commentLen = readLeShort(edip);  
   
         if (raf.skipBytes(CENOFF - CENDSK) != CENOFF - CENDSK)  
           throw new EOFException(name);  
         int offset = readLeInt(raf);  
249    
250          byte[] buffer = new byte[Math.max(nameLen, commentLen)];          int method = readLeShort(ebs, CENHOW);
251            int dostime = readLeInt(ebs, CENTIM);
252            int crc = readLeInt(ebs, CENCRC);
253            int csize = readLeInt(ebs, CENSIZ);
254            int size = readLeInt(ebs, CENLEN);
255            int nameLen = readLeShort(ebs, CENNAM);
256            int extraLen = readLeShort(ebs, CENEXT);
257            int commentLen = readLeShort(ebs, CENCOM);
258            
259            int offset = readLeInt(ebs, CENOFF);
260    
261            int needBuffer = Math.max(nameLen, commentLen);
262            if (buffer.length < needBuffer)
263              buffer = new byte[needBuffer];
264    
265          raf.readFully(buffer, 0, nameLen);          raf.readFully(buffer, 0, nameLen);
266          String name = new String(buffer, 0, nameLen);          String name = new String(buffer, 0, 0, nameLen);
267    
268          ZipEntry entry = new ZipEntry(name);          ZipEntry entry = new ZipEntry(name);
269          entry.setMethod(method);          entry.setMethod(method);
# Line 248  public class ZipFile implements ZipConst Line 291  public class ZipFile implements ZipConst
291     * Closes the ZipFile.  This also closes all input streams given by     * Closes the ZipFile.  This also closes all input streams given by
292     * this class.  After this is called, no further method should be     * this class.  After this is called, no further method should be
293     * called.     * called.
294       *
295     * @exception IOException if a i/o error occured.     * @exception IOException if a i/o error occured.
296     */     */
297    public void close() throws IOException    public void close() throws IOException
# Line 267  public class ZipFile implements ZipConst Line 311  public class ZipFile implements ZipConst
311    {    {
312      try      try
313        {        {
314          return new ZipEntryEnumeration(getEntries().elements());          return new ZipEntryEnumeration(getEntries().values().iterator());
315        }        }
316      catch (IOException ioe)      catch (IOException ioe)
317        {        {
# Line 281  public class ZipFile implements ZipConst Line 325  public class ZipFile implements ZipConst
325     * @exception IllegalStateException when the ZipFile has already been closed.     * @exception IllegalStateException when the ZipFile has already been closed.
326     * @exception IOEexception when the entries could not be read.     * @exception IOEexception when the entries could not be read.
327     */     */
328    private Hashtable getEntries() throws IOException    private HashMap getEntries() throws IOException
329    {    {
330      synchronized(raf)      synchronized(raf)
331        {        {
# Line 297  public class ZipFile implements ZipConst Line 341  public class ZipFile implements ZipConst
341    
342    /**    /**
343     * Searches for a zip entry in this archive with the given name.     * Searches for a zip entry in this archive with the given name.
344       *
345     * @param the name. May contain directory components separated by     * @param the name. May contain directory components separated by
346     * slashes ('/').     * slashes ('/').
347     * @return the zip entry, or null if no entry with that name exists.     * @return the zip entry, or null if no entry with that name exists.
348     * @see #entries */     */
349    public ZipEntry getEntry(String name)    public ZipEntry getEntry(String name)
350    {    {
351      try      try
352        {        {
353          Hashtable entries = getEntries();          HashMap entries = getEntries();
354          ZipEntry entry = (ZipEntry) entries.get(name);          ZipEntry entry = (ZipEntry) entries.get(name);
355          return entry != null ? (ZipEntry) entry.clone() : null;          return entry != null ? (ZipEntry) entry.clone() : null;
356        }        }
# Line 315  public class ZipFile implements ZipConst Line 360  public class ZipFile implements ZipConst
360        }        }
361    }    }
362    
363    
364      //access should be protected by synchronized(raf)
365      private byte[] locBuf = new byte[LOCHDR];
366    
367    /**    /**
368     * Checks, if the local header of the entry at index i matches the     * Checks, if the local header of the entry at index i matches the
369     * central directory, and returns the offset to the data.     * central directory, and returns the offset to the data.
370       *
371       * @param entry to check.
372     * @return the start offset of the (compressed) data.     * @return the start offset of the (compressed) data.
373       *
374     * @exception IOException if a i/o error occured.     * @exception IOException if a i/o error occured.
375     * @exception ZipException if the local header doesn't match the     * @exception ZipException if the local header doesn't match the
376     * central directory header     * central directory header
# Line 328  public class ZipFile implements ZipConst Line 380  public class ZipFile implements ZipConst
380      synchronized (raf)      synchronized (raf)
381        {        {
382          raf.seek(entry.offset);          raf.seek(entry.offset);
383          if (readLeInt(raf) != LOCSIG)          raf.readFully(locBuf);
384            
385            if (readLeInt(locBuf, 0) != LOCSIG)
386            throw new ZipException("Wrong Local header signature: " + name);            throw new ZipException("Wrong Local header signature: " + name);
387    
388          /* skip version and flags */          if (entry.getMethod() != readLeShort(locBuf, LOCHOW))
         if (raf.skipBytes(LOCHOW - LOCVER) != LOCHOW - LOCVER)  
           throw new EOFException(name);  
   
         if (entry.getMethod() != readLeShort(raf))  
389            throw new ZipException("Compression method mismatch: " + name);            throw new ZipException("Compression method mismatch: " + name);
390    
391          /* Skip time, crc, size and csize */          if (entry.getName().length() != readLeShort(locBuf, LOCNAM))
         if (raf.skipBytes(LOCNAM - LOCTIM) != LOCNAM - LOCTIM)  
           throw new EOFException(name);  
   
         if (entry.getName().length() != readLeShort(raf))  
392            throw new ZipException("file name length mismatch: " + name);            throw new ZipException("file name length mismatch: " + name);
393    
394          int extraLen = entry.getName().length() + readLeShort(raf);          int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT);
395          return entry.offset + LOCHDR + extraLen;          return entry.offset + LOCHDR + extraLen;
396        }        }
397    }    }
# Line 354  public class ZipFile implements ZipConst Line 400  public class ZipFile implements ZipConst
400     * Creates an input stream reading the given zip entry as     * Creates an input stream reading the given zip entry as
401     * uncompressed data.  Normally zip entry should be an entry     * uncompressed data.  Normally zip entry should be an entry
402     * returned by getEntry() or entries().     * returned by getEntry() or entries().
403       *
404       * @param entry the entry to create an InputStream for.
405     * @return the input stream.     * @return the input stream.
406       *
407     * @exception IOException if a i/o error occured.     * @exception IOException if a i/o error occured.
408     * @exception ZipException if the Zip archive is malformed.       * @exception ZipException if the Zip archive is malformed.  
409     */     */
410    public InputStream getInputStream(ZipEntry entry) throws IOException    public InputStream getInputStream(ZipEntry entry) throws IOException
411    {    {
412      Hashtable entries = getEntries();      HashMap entries = getEntries();
413      String name = entry.getName();      String name = entry.getName();
414      ZipEntry zipEntry = (ZipEntry) entries.get(name);      ZipEntry zipEntry = (ZipEntry) entries.get(name);
415      if (zipEntry == null)      if (zipEntry == null)
# Line 368  public class ZipFile implements ZipConst Line 417  public class ZipFile implements ZipConst
417    
418      long start = checkLocalHeader(zipEntry);      long start = checkLocalHeader(zipEntry);
419      int method = zipEntry.getMethod();      int method = zipEntry.getMethod();
420      InputStream is = new PartialInputStream      InputStream is = new BufferedInputStream(new PartialInputStream
421        (raf, start, zipEntry.getCompressedSize());        (raf, start, zipEntry.getCompressedSize()));
422      switch (method)      switch (method)
423        {        {
424        case ZipOutputStream.STORED:        case ZipOutputStream.STORED:
# Line 406  public class ZipFile implements ZipConst Line 455  public class ZipFile implements ZipConst
455        
456    private static class ZipEntryEnumeration implements Enumeration    private static class ZipEntryEnumeration implements Enumeration
457    {    {
458      private final Enumeration elements;      private final Iterator elements;
459    
460      public ZipEntryEnumeration(Enumeration elements)      public ZipEntryEnumeration(Iterator elements)
461      {      {
462        this.elements = elements;        this.elements = elements;
463      }      }
464    
465      public boolean hasMoreElements()      public boolean hasMoreElements()
466      {      {
467        return elements.hasMoreElements();        return elements.hasNext();
468      }      }
469    
470      public Object nextElement()      public Object nextElement()
# Line 423  public class ZipFile implements ZipConst Line 472  public class ZipFile implements ZipConst
472        /* We return a clone, just to be safe that the user doesn't        /* We return a clone, just to be safe that the user doesn't
473         * change the entry.           * change the entry.  
474         */         */
475        return ((ZipEntry)elements.nextElement()).clone();        return ((ZipEntry)elements.next()).clone();
476      }      }
477    }    }
478    
479    private static class PartialInputStream extends InputStream    private static class PartialInputStream extends InputStream
480    {    {
481      RandomAccessFile raf;      private final RandomAccessFile raf;
482      long filepos, end;      long filepos, end;
483    
484      public PartialInputStream(RandomAccessFile raf, long start, long len)      public PartialInputStream(RandomAccessFile raf, long start, long len)

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26