aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java
diff options
context:
space:
mode:
authorGravatar Han-Wen Nienhuys <hanwen@google.com>2015-07-07 16:13:40 +0000
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-07-07 16:33:30 +0000
commit5a9ec720d1224f1360fa2bf732a869a22c17afc1 (patch)
tree0a5263ae5814f49c6d4099d3176d6b346f3ac5fb /src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java
parent2fd9960f0bc43eff04b8bc317e635c754a67dd27 (diff)
Open source tests for android/ziputils.
-- MOS_MIGRATED_REVID=97677526
Diffstat (limited to 'src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java558
1 files changed, 558 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java b/src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java
new file mode 100644
index 0000000000..9ce75d528c
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/ziputils/ZipInTest.java
@@ -0,0 +1,558 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.android.ziputils;
+
+import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENHOW;
+import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENLEN;
+import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENOFF;
+import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENSIZ;
+import static com.google.devtools.build.android.ziputils.EndOfCentralDirectory.ENDOFF;
+import static com.google.devtools.build.android.ziputils.EndOfCentralDirectory.ENDSIG;
+import static com.google.devtools.build.android.ziputils.EndOfCentralDirectory.ENDSIZ;
+import static com.google.devtools.build.android.ziputils.EndOfCentralDirectory.ENDSUB;
+import static com.google.devtools.build.android.ziputils.EndOfCentralDirectory.ENDTOT;
+import static com.google.devtools.build.android.ziputils.ZipIn.ZipEntry;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Unit tests for {@link ZipIn}.
+ */
+@RunWith(JUnit4.class)
+public class ZipInTest {
+
+ private static final int ENTRY_COUNT = 1000;
+ private FakeFileSystem fileSystem;
+
+ @Before
+ public void setUp() throws Exception {
+ fileSystem = new FakeFileSystem();
+ }
+
+ /**
+ * Test of endOfCentralDirectory method, of class ZipIn.
+ */
+ @Test
+ public void testEndOfCentralDirectory() throws Exception {
+
+ String filename = "test.zip";
+ byte[] bytes;
+ ByteBuffer buffer;
+ String comment;
+ int commentLen;
+ int offset;
+ ZipIn zipIn;
+ EndOfCentralDirectory result;
+ String subcase;
+
+ // Find it, even if it's the only useful thing in the file.
+ subcase = " EOCD found it, ";
+ bytes = new byte[] {
+ 0x50, 0x4b, 0x05, 0x06, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ result = zipIn.endOfCentralDirectory();
+ assertNotNull(subcase + "found", result);
+
+ subcase = " EOCD not there at all, ";
+ bytes = new byte[]{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ try {
+ zipIn.endOfCentralDirectory();
+ fail(subcase + "expected IllegalStateException");
+ } catch (Exception ex) {
+ assertSame(subcase + "caught exception", IllegalStateException.class, ex.getClass());
+ }
+
+ // If we can't read it, it's not there
+ subcase = " EOCD too late to read, ";
+ bytes = new byte[] {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x50, 0x4b, 0x05, 0x06, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ try {
+ zipIn.endOfCentralDirectory();
+ fail(subcase + "expected IndexOutOfBoundsException");
+ } catch (Exception ex) {
+ assertSame(subcase + "caught exception", IndexOutOfBoundsException.class, ex.getClass());
+ }
+
+ // Current implementation doesn't know to scan past a bad EOCD record.
+ // I'm not sure if it should.
+ subcase = " EOCD good hidden by bad, ";
+ bytes = new byte[] {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x50, 0x4b, 0x05, 0x06, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x50, 0x4b, 0x05, 0x06, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ try {
+ zipIn.endOfCentralDirectory();
+ fail(subcase + "expected IndexOutOfBoundsException");
+ } catch (Exception ex) {
+ assertSame(subcase + "caught exception", IndexOutOfBoundsException.class, ex.getClass());
+ }
+
+ // Minimal format checking here, assuming the EndOfDirectoryTest class
+ // test for that.
+
+ subcase = " EOCD truncated comment, ";
+ bytes = new byte[100];
+ buffer = ByteBuffer.wrap(bytes);
+ comment = "optional file comment";
+ commentLen = comment.getBytes(UTF_8).length;
+ offset = bytes.length - ZipInputStream.ENDHDR - commentLen;
+ buffer.position(offset);
+ EndOfCentralDirectory.view(buffer, comment);
+ byte[] truncated = Arrays.copyOf(bytes, bytes.length - 5);
+ fileSystem.addFile(filename, truncated);
+ zipIn = newZipIn(filename);
+ try { // not sure this is the exception we want!
+ zipIn.endOfCentralDirectory();
+ fail(subcase + "expected IllegalArgumentException");
+ } catch (Exception ex) {
+ assertSame(subcase + "caught exception", IllegalArgumentException.class, ex.getClass());
+ }
+
+ subcase = " EOCD no comment, ";
+ bytes = new byte[100];
+ buffer = ByteBuffer.wrap(bytes);
+ comment = null;
+ commentLen = 0;
+ offset = bytes.length - ZipInputStream.ENDHDR - commentLen;
+ buffer.position(offset);
+ EndOfCentralDirectory.view(buffer, comment);
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ result = zipIn.endOfCentralDirectory();
+ assertNotNull(subcase + "found", result);
+ assertEquals(subcase + "comment", "", result.getComment());
+ assertEquals(subcase + "marker", ZipInputStream.ENDSIG, (int) result.get(ENDSIG));
+
+ subcase = " EOCD comment, ";
+ bytes = new byte[100];
+ buffer = ByteBuffer.wrap(bytes);
+ comment = "optional file comment";
+ commentLen = comment.getBytes(UTF_8).length;
+ offset = bytes.length - ZipInputStream.ENDHDR - commentLen;
+ buffer.position(offset);
+ EndOfCentralDirectory.view(buffer, comment);
+ assertEquals(subcase + "setup", comment,
+ new String(bytes, bytes.length - commentLen, commentLen, UTF_8));
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ result = zipIn.endOfCentralDirectory();
+ assertNotNull(subcase + "found", result);
+ assertEquals(subcase + "comment", comment, result.getComment());
+ assertEquals(subcase + "marker", ZipInputStream.ENDSIG, (int) result.get(ENDSIG));
+
+ subcase = " EOCD extra data, ";
+ bytes = new byte[100];
+ buffer = ByteBuffer.wrap(bytes);
+ comment = null;
+ commentLen = 0;
+ offset = bytes.length - ZipInputStream.ENDHDR - commentLen - 10;
+ buffer.position(offset);
+ EndOfCentralDirectory.view(buffer, comment);
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ result = zipIn.endOfCentralDirectory();
+ assertNotNull(subcase + "found", result);
+ assertEquals(subcase + "comment", "", result.getComment());
+ assertEquals(subcase + "marker", ZipInputStream.ENDSIG, (int) result.get(ENDSIG));
+ }
+
+ /**
+ * Test of centralDirectory method, of class ZipIn.
+ */
+ @Test
+ public void testCentralDirectory() throws Exception {
+ String filename = "test.zip";
+ ByteBuffer buffer;
+ int offset;
+ ZipIn zipIn;
+ String subcase;
+ subcase = " EOCD extra data, ";
+ String commonName = "thisIsNotNormal.txt";
+ int filenameLen = commonName.getBytes(UTF_8).length;
+ int count = ENTRY_COUNT;
+ int dirEntry = ZipInputStream.CENHDR;
+ int before = count;
+ int between = 0; // implementation doesn't tolerate data between dir entries, does the spec?
+ int after = 20;
+ int eocd = ZipInputStream.ENDHDR;
+ int total = before + (count * (dirEntry + filenameLen)) + ((count - 1) * between)
+ + after + eocd;
+ byte[] bytes = new byte[total];
+ offset = before;
+ for (int i = 0; i < count; i++) {
+ if (i > 0) {
+ offset += between;
+ }
+ buffer = ByteBuffer.wrap(bytes, offset, bytes.length - offset);
+ DirectoryEntry.view(buffer, commonName, null, null)
+ .set(CENHOW, (short) 8)
+ .set(CENSIZ, before)
+ .set(CENLEN, 2 * before)
+ .set(CENOFF, i); // Not valid of course, but we're only testing central dir parsing.
+ // and there are currently no checks in the parser to see if offset makes sense.
+ offset += dirEntry + filenameLen;
+ }
+ offset += after;
+ buffer = ByteBuffer.wrap(bytes, offset, bytes.length - offset);
+ EndOfCentralDirectory.view(buffer, null)
+ .set(ENDOFF, before)
+ .set(ENDSIZ, offset - before - after)
+ .set(ENDTOT, (short) count)
+ .set(ENDSUB, (short) count);
+
+ fileSystem.addFile(filename, bytes);
+ zipIn = newZipIn(filename);
+ CentralDirectory result = zipIn.centralDirectory();
+ assertNotNull(subcase + "found", result);
+ List<DirectoryEntry> list = result.list();
+ assertEquals(subcase + "size", count, list.size());
+ for (int i = 0; i < list.size(); i++) {
+ assertEquals(subcase + "offset check[" + i + "]", i, list.get(i).get(CENOFF));
+ }
+ }
+
+ /**
+ * Test of scanEntries method, of class ZipIn.
+ */
+ @Test
+ public void testScanEntries() throws Exception {
+ int count = ENTRY_COUNT * 100;
+ String filename = "test.jar";
+
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.scanEntries(new EntryHandler() {
+ int count = 0;
+ @Override
+ public void handle(ZipIn in, LocalFileHeader header, DirectoryEntry dirEntry,
+ ByteBuffer data) throws IOException {
+ assertSame(zipIn, in);
+ String filename = "pkg/f" + count + ".class";
+ assertEquals(filename, header.getFilename());
+ assertEquals(filename, dirEntry.getFilename());
+ count++;
+ }
+ });
+ }
+
+ /**
+ * Test of nextHeaderFrom method, of class ZipIn.
+ */
+ @Test
+ public void testNextHeaderFrom_long() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.endOfCentralDirectory();
+ count = 0;
+ int offset = 0;
+ LocalFileHeader header;
+ do {
+ header = zipIn.nextHeaderFrom(offset);
+ String name = "pkg/f" + count + ".class";
+ if (header != null) {
+ assertEquals(name, header.getFilename());
+ count++;
+ offset = (int) header.fileOffset() + 4;
+ }
+ } while(header != null);
+ assertEquals(ENTRY_COUNT, count);
+ }
+
+ /**
+ * Test of nextHeaderFrom method, of class ZipIn.
+ */
+ @Test
+ public void testNextHeaderFrom_DirectoryEntry() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ List<DirectoryEntry> list = zipIn.centralDirectory().list();
+ count = 0;
+ String name;
+ LocalFileHeader header = zipIn.nextHeaderFrom(null);
+ for (DirectoryEntry dirEntry : list) {
+ name = "pkg/f" + count + ".class";
+ assertEquals(name, dirEntry.getFilename());
+ assertEquals(name, header.getFilename());
+ header = zipIn.nextHeaderFrom(dirEntry);
+ count++;
+ }
+ assertNull(header);
+ }
+
+ /**
+ * Test of localHeaderFor method, of class ZipIn.
+ */
+ @Test
+ public void testLocalHeaderFor() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ List<DirectoryEntry> list = zipIn.centralDirectory().list();
+ count = 0;
+ String name;
+ LocalFileHeader header;
+ for (DirectoryEntry dirEntry : list) {
+ name = "pkg/f" + count + ".class";
+ header = zipIn.localHeaderFor(dirEntry);
+ assertEquals(name, dirEntry.getFilename());
+ assertEquals(name, header.getFilename());
+ count++;
+ }
+ }
+
+ /**
+ * Test of localHeaderAt method, of class ZipIn.
+ */
+ @Test
+ public void testLocalHeaderAt() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ List<DirectoryEntry> list = zipIn.centralDirectory().list();
+ count = 0;
+ String name;
+ LocalFileHeader header;
+ for (DirectoryEntry dirEntry : list) {
+ name = "pkg/f" + count + ".class";
+ header = zipIn.localHeaderAt(dirEntry.get(CENOFF));
+ assertEquals(name, dirEntry.getFilename());
+ assertEquals(name, header.getFilename());
+ count++;
+ }
+ }
+
+ /**
+ * Test of nextFrom method, of class ZipIn.
+ */
+ @Test
+ public void testNextFrom_long() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ count = 0;
+ int offset = 0;
+ ZipEntry zipEntry;
+ do {
+ zipEntry = zipIn.nextFrom(offset);
+ String name = "pkg/f" + count + ".class";
+ if (zipEntry.getCode() != ZipEntry.Status.ENTRY_NOT_FOUND) {
+ assertNotNull(zipEntry.getHeader());
+ assertNotNull(zipEntry.getDirEntry());
+ assertEquals(name, zipEntry.getHeader().getFilename());
+ assertEquals(name, zipEntry.getDirEntry().getFilename());
+ count++;
+ offset = (int) zipEntry.getHeader().fileOffset() + 4;
+ }
+ } while(zipEntry.getCode() != ZipEntry.Status.ENTRY_NOT_FOUND);
+ assertEquals(ENTRY_COUNT, count);
+ }
+
+ /**
+ * Test of nextFrom method, of class ZipIn.
+ */
+ @Test
+ public void testNextFrom_DirectoryEntry() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ List<DirectoryEntry> list = zipIn.centralDirectory().list();
+ count = 0;
+ String name;
+ ZipEntry zipEntry = zipIn.nextFrom(null);
+ for (DirectoryEntry dirEntry : list) {
+ if (zipEntry.getCode() == ZipEntry.Status.ENTRY_NOT_FOUND) {
+ break;
+ }
+ name = "pkg/f" + count + ".class";
+ assertNotNull(zipEntry.getHeader());
+ assertNotNull(zipEntry.getDirEntry());
+ assertEquals(name, zipEntry.getHeader().getFilename());
+ assertEquals(name, zipEntry.getDirEntry().getFilename());
+ zipEntry = zipIn.nextFrom(dirEntry);
+ count++;
+ }
+ assertEquals(ENTRY_COUNT, count);
+ }
+
+ /**
+ * Test of entryAt method, of class ZipIn.
+ */
+ @Test
+ public void testEntryAt() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ List<DirectoryEntry> list = zipIn.centralDirectory().list();
+ count = 0;
+ String name;
+ ZipEntry zipEntry;
+ for (DirectoryEntry dirEntry : list) {
+ zipEntry = zipIn.entryAt(dirEntry.get(CENOFF));
+ name = "pkg/f" + count + ".class";
+ assertNotNull(zipEntry.getHeader());
+ assertNotNull(zipEntry.getDirEntry());
+ assertEquals(name, zipEntry.getHeader().getFilename());
+ assertEquals(name, zipEntry.getDirEntry().getFilename());
+ count++;
+ }
+ assertEquals(ENTRY_COUNT, count);
+ }
+
+ /**
+ * Test of entryWith method, of class ZipIn.
+ */
+ @Test
+ public void testEntryWith() throws Exception {
+ int count = ENTRY_COUNT;
+ String filename = "test.jar";
+ ZipFileBuilder builder = new ZipFileBuilder();
+ for (int i = 0; i < count; i++) {
+ builder.add("pkg/f" + i + ".class", "All day long");
+ }
+ builder.create(filename);
+ final ZipIn zipIn = newZipIn(filename);
+ zipIn.centralDirectory();
+ count = 0;
+ int offset = 0;
+ LocalFileHeader header;
+ do {
+ header = zipIn.nextHeaderFrom(offset);
+ String name = "pkg/f" + count + ".class";
+ if (header != null) {
+ ZipEntry zipEntry = zipIn.entryWith(header);
+ assertNotNull(zipEntry.getDirEntry());
+ assertSame(header, zipEntry.getHeader());
+ assertEquals(name, zipEntry.getHeader().getFilename());
+ assertEquals(name, zipEntry.getDirEntry().getFilename());
+ assertEquals(name, header.getFilename());
+ count++;
+ offset = (int) header.fileOffset() + 4;
+ }
+ } while(header != null);
+ assertEquals(ENTRY_COUNT, count);
+ }
+
+ private ZipIn newZipIn(String filename) throws IOException {
+ return new ZipIn(fileSystem.getInputChannel(filename), filename);
+ }
+}