OSDN Git Service

2000-08-20 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / java / util / zip / ZipInputStream.java
1 /* Copyright (C) 1999, 2000  Free Software Foundation
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8
9 package java.util.zip;
10 import java.io.*;
11
12 /**
13  * @author Per Bothner
14  * @date May 1999.
15  */
16
17 /*
18  * Written using on-line Java Platform 1.2 API Specification, as well
19  * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
20  * Status:  Quite incomplete, but can read uncompressed .zip archives.
21  */
22
23 // JDK1.2 has "protected ZipEntry createZipEntry(String)" but is very
24 // vague about what the method does.  FIXME.
25 // We do not calculate the CRC and compare it with the specified value;
26 // we probably should.  FIXME.
27    
28
29 public class ZipInputStream extends InflaterInputStream implements ZipConstants
30 {
31   public ZipInputStream (InputStream in)
32   {
33     super (in, new Inflater (true));
34   }
35
36   public ZipEntry getNextEntry () throws IOException
37   {
38     if (current != null)
39       closeEntry();
40     if (in.read() != 'P'
41         || in.read() != 'K')
42       return null;
43     int code = in.read();
44     while (code == '\001')
45       {
46         code = in.read();
47         if (code != '\002')
48           return null;
49         in.skip(16);
50         int size = read4();
51         in.skip(4);
52         int fname_length = readu2();
53         int extra_length = readu2();
54         int fcomment_length = readu2();
55         // `12' is the number of bytes between the comment length
56         // field and the end of the fixed part of the header:
57         // 2 bytes for `disk number start'
58         // 2 bytes for `internal file attributes'
59         // 4 bytes for `external file attributes'
60         // 4 bytes for `relative offset of local header'
61         in.skip(12 + fname_length + extra_length + fcomment_length);
62         if (in.read() != 'P' || in.read() != 'K')
63           return null;
64         code = in.read();
65       }
66     if (code == '\005')
67       {
68         if (in.read() != '\006')
69           return null;
70         in.skip(16);
71         int comment_size = readu2();
72         in.skip(comment_size);
73         if (in.read() != 'P' || in.read() != 'K')
74           return null;
75         code = in.read();
76       }
77     if (code != '\003'
78         || in.read() != '\004')
79       return null;
80     int ex_version = readu2();
81     current_flags = readu2();
82     int method = readu2();
83     int modtime = readu2();
84     int moddate = readu2();
85     int crc = read4();
86     int compressedSize = read4();
87     int uncompressedSize = read4();
88     int filenameLength = readu2();
89     int extraLength = readu2();
90     byte[] bname = new byte[filenameLength];
91     readFully(bname);
92     ZipEntry entry = createZipEntry(new String(bname, "8859_1"));
93     if (extraLength > 0)
94       {
95         byte[] bextra = new byte[extraLength];
96         readFully(bextra);
97         entry.extra = bextra;
98       }
99     entry.compressedSize = compressedSize;
100     entry.size = uncompressedSize;
101     entry.crc = (long) crc & 0xffffffffL;
102     entry.method = method;
103     entry.time = ZipEntry.timeFromDOS(moddate, modtime);
104     current = entry;
105     avail = uncompressedSize;
106     compressed_bytes = compressedSize;
107     return entry;
108   }
109
110   // We override fill to let us control how much data gets read from
111   // the underlying input stream.  This lets us avoid having to push
112   // back data.
113   protected void fill () throws IOException
114   {
115     int count = buf.length;
116     if (count > compressed_bytes)
117       count = compressed_bytes;
118     len = in.read(buf, 0, count);
119     if (len != -1)
120       {
121         compressed_bytes -= len;
122         inf.setInput(buf, 0, len);
123       }
124   }
125
126   protected ZipEntry createZipEntry (String name)
127   {
128     return new ZipEntry (name);
129   }
130   
131   public int read (byte[] b, int off, int len)  throws IOException
132   {
133     if (len > avail)
134       len = avail;
135     int count;
136     if (current.method == Deflater.DEFLATED)
137       count = super.read(b, off, len);
138     else
139       count = in.read(b, off, len);
140     if (count == -1 || avail == 0)
141       {
142         inf.reset();
143         count = -1;
144       }
145     else
146       avail -= count;
147     return count;
148   }
149
150   public long skip (long n)  throws IOException
151   {
152     if (n > avail)
153       n = avail;
154     long count;
155     if (current.method == Deflater.DEFLATED)
156       count = super.skip(n);
157     else
158       count = in.skip(n);
159     avail = avail - (int) count;
160     return count;
161   }
162
163   public int available() {
164     if (closed)
165       return 0;
166     else
167       return 1;
168   }
169
170   private void readFully (byte[] b)  throws IOException
171   {
172     int off = 0;
173     int len = b.length;
174     while (len > 0)
175       {
176         int count = in.read(b, off, len);
177         if (count <= 0)
178           throw new EOFException(".zip archive ended prematurely");
179         off += count;
180         len -= count;
181       }
182   }
183
184   private int readu2 ()  throws IOException
185   {
186     int byte0 = in.read();
187     int byte1 = in.read();
188     if (byte0 < 0 || byte1 < 0)
189       throw new EOFException(".zip archive ended prematurely");
190     return ((byte1 & 0xFF) << 8) | (byte0 & 0xFF);
191   }
192
193   private int read4 () throws IOException
194   {
195     int byte0 = in.read();
196     int byte1 = in.read();
197     int byte2 = in.read();
198     int byte3 = in.read();
199     if (byte3 < 0)
200       throw new EOFException(".zip archive ended prematurely");
201     return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16)
202       + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF);
203   }
204
205   public void closeEntry ()  throws IOException
206   {
207     if (current != null)
208       {
209         if (avail > 0)
210           skip (avail);
211         if ((current_flags & 8) != 0)
212           {
213             int sig = read4();
214             if (sig != 0x04034b50)
215               throw new ZipException("bad/missing magic number at end of .zip entry");
216             int crc = read4();
217             int compressedSize = read4();
218             int uncompressedSize = read4();
219             if (current.compressedSize != compressedSize
220                 || current.size != uncompressedSize
221                 || current.crc != crc)
222               throw new ZipException("bad data descriptor at end of .zip entry");
223           }
224         current = null;
225         avail = 0;
226       }
227   }
228
229   public void close ()  throws IOException
230   {
231     current = null;
232     closed = true;
233     super.close();
234   }
235
236   private ZipEntry current;
237   private int current_flags;
238   // Number of uncompressed bytes to be read.
239   private int avail;
240   // Number of bytes we can read from underlying stream.
241   private int compressed_bytes;
242   // Is this ZipInputStream closed? Set by the close() method.
243   private boolean closed = false;
244 }