42
42
import java .nio .ByteBuffer ;
43
43
import java .nio .CharBuffer ;
44
44
import java .nio .charset .CharacterCodingException ;
45
- import java .nio .charset .Charset ;
45
+ import java .nio .charset .StandardCharsets ;
46
46
import java .nio .charset .CharsetDecoder ;
47
47
import java .nio .charset .CoderResult ;
48
48
import java .util .HashMap ;
@@ -80,14 +80,9 @@ public class HttpZipLocator implements AssetLocator {
80
80
private int tableLength ;
81
81
private HashMap <String , ZipEntry2 > entries ;
82
82
83
- private static final ByteBuffer byteBuf = ByteBuffer .allocate (250 );
84
- private static final CharBuffer charBuf = CharBuffer .allocate (250 );
85
- private static final CharsetDecoder utf8Decoder ;
86
-
87
- static {
88
- Charset utf8 = Charset .forName ("UTF-8" );
89
- utf8Decoder = utf8 .newDecoder ();
90
- }
83
+ private final ByteBuffer byteBuf = ByteBuffer .allocate (250 );
84
+ private final CharBuffer charBuf = CharBuffer .allocate (250 );
85
+ private final CharsetDecoder utf8Decoder = StandardCharsets .UTF_8 .newDecoder ();
91
86
92
87
private static class ZipEntry2 {
93
88
String name ;
@@ -96,6 +91,10 @@ private static class ZipEntry2 {
96
91
int compSize ;
97
92
long crc ;
98
93
boolean deflate ;
94
+ // These fields will be fetched later from local file header,
95
+ // once asset requested.
96
+ Integer nameLength ;
97
+ Integer extraLength ;
99
98
100
99
@ Override
101
100
public String toString (){
@@ -125,7 +124,7 @@ private static long getu32(byte[] b, int off) throws IOException{
125
124
(((long )(b [off ]&0xff )) << 24 );
126
125
}
127
126
128
- private static String getUTF8String (byte [] b , int off , int len ) throws CharacterCodingException {
127
+ private String getUTF8String (byte [] b , int off , int len ) throws CharacterCodingException {
129
128
StringBuilder sb = new StringBuilder ();
130
129
131
130
int read = 0 ;
@@ -143,7 +142,7 @@ private static String getUTF8String(byte[] b, int off, int len) throws Character
143
142
byteBuf .flip ();
144
143
145
144
// decode data in byteBuf
146
- CoderResult result = utf8Decoder .decode (byteBuf , charBuf , endOfInput );
145
+ CoderResult result = utf8Decoder .decode (byteBuf , charBuf , endOfInput );
147
146
148
147
// If the result is not an underflow, it's an error
149
148
// that cannot be handled.
@@ -234,10 +233,6 @@ private int readTableEntry(byte[] table, int offset) throws IOException{
234
233
entry .compSize = get32 (table , offset + ZipEntry .CENSIZ );
235
234
entry .offset = get32 (table , offset + ZipEntry .CENOFF );
236
235
237
- // We want the offset in the file data:
238
- // move the offset forward to skip the LOC header.
239
- entry .offset += ZipEntry .LOCHDR + nameLen + extraLen ;
240
-
241
236
entries .put (entry .name , entry );
242
237
243
238
return newOffset ;
@@ -256,16 +251,15 @@ private void fillByteArray(byte[] array, InputStream source) throws IOException{
256
251
}
257
252
258
253
private void readCentralDirectory () throws IOException {
259
- InputStream in = readData (tableOffset , tableLength );
260
254
byte [] header = new byte [tableLength ];
261
-
262
- // Fix for "PK12 bug in town.zip": sometimes
263
- // not entire byte array will be read with InputStream.read()
264
- // (especially for big headers)
265
- fillByteArray (header , in );
255
+ try ( InputStream in = readData ( tableOffset , tableLength )) {
256
+ // Fix for "PK12 bug in town.zip": sometimes
257
+ // not entire byte array will be read with InputStream.read()
258
+ // (especially for big headers)
259
+ fillByteArray (header , in );
266
260
267
261
// in.read(header);
268
- in . close ();
262
+ }
269
263
270
264
entries = new HashMap <String , ZipEntry2 >(numEntries );
271
265
int offset = 0 ;
@@ -292,10 +286,10 @@ private void readEndHeader() throws IOException{
292
286
// In that case, we have to search for it.
293
287
// Increase search space to 200 bytes
294
288
295
- InputStream in = readData (Integer .MAX_VALUE , 200 );
296
289
byte [] header = new byte [200 ];
297
- fillByteArray (header , in );
298
- in .close ();
290
+ try (InputStream in = readData (Integer .MAX_VALUE , 200 )) {
291
+ fillByteArray (header , in );
292
+ }
299
293
300
294
int offset = -1 ;
301
295
for (int i = 200 - 22 ; i >= 0 ; i --){
@@ -323,9 +317,23 @@ public void load(URL url) throws IOException {
323
317
readCentralDirectory ();
324
318
}
325
319
326
- private InputStream openStream (ZipEntry2 entry ) throws IOException {
327
- InputStream in = readData (entry .offset , entry .compSize );
328
- if (entry .deflate ){
320
+ private InputStream openStream (ZipEntry2 entry ) throws IOException {
321
+ if (entry .nameLength == null && entry .extraLength == null ) {
322
+ // Need to fetch local file header to obtain file name length
323
+ // and extra field length.
324
+ try (InputStream in = readData (entry .offset , ZipEntry .LOCHDR )) {
325
+ byte [] localHeader = new byte [ZipEntry .LOCHDR ];
326
+ in .read (localHeader );
327
+ entry .nameLength = get16 (localHeader , ZipEntry .LOCNAM );
328
+ entry .extraLength = get16 (localHeader , ZipEntry .LOCEXT );
329
+ }
330
+ }
331
+
332
+ // We want the offset in the file data:
333
+ // move the offset forward to skip the LOC header.
334
+ int fileDataOffset = entry .offset + ZipEntry .LOCHDR + entry .nameLength + entry .extraLength ;
335
+ InputStream in = readData (fileDataOffset , entry .compSize );
336
+ if (entry .deflate ) {
329
337
return new InflaterInputStream (in , new Inflater (true ));
330
338
}
331
339
return in ;
0 commit comments