1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codehaus.plexus.archiver.zip;
17
18 import java.io.Closeable;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URL;
23 import java.net.URLClassLoader;
24 import java.nio.charset.Charset;
25 import java.nio.charset.StandardCharsets;
26 import java.util.Enumeration;
27 import java.util.Iterator;
28 import java.util.jar.JarFile;
29
30 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
31 import org.apache.commons.compress.archivers.zip.ZipFile;
32 import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier;
33 import org.codehaus.plexus.components.io.resources.AbstractPlexusIoArchiveResourceCollection;
34 import org.codehaus.plexus.components.io.resources.EncodingSupported;
35 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
36 import org.codehaus.plexus.components.io.resources.PlexusIoURLResource;
37
38
39
40 public class PlexusIoZipFileResourceCollection extends AbstractPlexusIoArchiveResourceCollection
41 implements EncodingSupported {
42
43 private Charset charset = StandardCharsets.UTF_8;
44
45 public PlexusIoZipFileResourceCollection() {}
46
47 @Override
48 public boolean isConcurrentAccessSupported() {
49
50 return false;
51 }
52
53 @Override
54 protected Iterator<PlexusIoResource> getEntries() throws IOException {
55 final File f = getFile();
56 if (f == null) {
57 throw new IOException("The zip file has not been set.");
58 }
59 final URLClassLoader urlClassLoader =
60 new URLClassLoader(new URL[] {f.toURI().toURL()}, null) {
61
62 @Override
63 public URL getResource(String name) {
64 return findResource(name);
65 }
66 };
67
68 final URL url = new URL("jar:" + f.toURI().toURL() + "!/");
69 final JarFile jarFile = new JarFile(f);
70 final ZipFile zipFile = ZipFile.builder()
71 .setFile(f)
72 .setCharset(charset != null ? charset : StandardCharsets.UTF_8)
73 .get();
74 final Enumeration<ZipArchiveEntry> en = zipFile.getEntriesInPhysicalOrder();
75 return new ZipFileResourceIterator(en, url, jarFile, zipFile, urlClassLoader);
76 }
77
78 private static class ZipFileResourceIterator implements Iterator<PlexusIoResource>, Closeable {
79
80 private class ZipFileResource extends PlexusIoURLResource {
81 private final JarFile jarFile;
82
83 private ZipFileResource(JarFile jarFile, ZipArchiveEntry entry) {
84 super(
85 entry.getName(),
86 entry.getTime() == -1 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : entry.getTime(),
87 entry.isDirectory() ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : entry.getSize(),
88 !entry.isDirectory(),
89 entry.isDirectory(),
90 true);
91
92 this.jarFile = jarFile;
93 }
94
95 @Override
96 public InputStream getContents() throws IOException {
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 return jarFile.getInputStream(jarFile.getEntry(getName()));
112 }
113
114 @Override
115 public URL getURL() throws IOException {
116 String spec = getName();
117 if (spec.startsWith("/")) {
118
119
120
121 spec = "./" + spec;
122 return new URL(url, spec);
123 }
124 return urlClassLoader.getResource(spec);
125 }
126 }
127
128 private class ZipFileSymlinkResource extends ZipFileResource implements SymlinkDestinationSupplier {
129
130 private final ZipArchiveEntry entry;
131
132 private ZipFileSymlinkResource(JarFile jarFile, ZipArchiveEntry entry) {
133 super(jarFile, entry);
134
135 this.entry = entry;
136 }
137
138 @Override
139 public String getSymlinkDestination() throws IOException {
140 return zipFile.getUnixSymlink(entry);
141 }
142
143 @Override
144 public boolean isSymbolicLink() {
145 return true;
146 }
147 }
148
149 private final Enumeration<ZipArchiveEntry> en;
150
151 private final URL url;
152
153 private final JarFile jarFile;
154
155 private final ZipFile zipFile;
156
157 private final URLClassLoader urlClassLoader;
158
159 public ZipFileResourceIterator(
160 Enumeration<ZipArchiveEntry> en,
161 URL url,
162 JarFile jarFile,
163 ZipFile zipFile,
164 URLClassLoader urlClassLoader) {
165 this.en = en;
166 this.url = url;
167 this.jarFile = jarFile;
168 this.zipFile = zipFile;
169 this.urlClassLoader = urlClassLoader;
170 }
171
172 @Override
173 public boolean hasNext() {
174 return en.hasMoreElements();
175 }
176
177 @Override
178 public PlexusIoResource next() {
179 final ZipArchiveEntry entry = en.nextElement();
180 return entry.isUnixSymlink()
181 ? new ZipFileSymlinkResource(jarFile, entry)
182 : new ZipFileResource(jarFile, entry);
183 }
184
185 @Override
186 public void remove() {
187 throw new UnsupportedOperationException("Removing isn't implemented.");
188 }
189
190 @Override
191 public void close() throws IOException {
192 try {
193 urlClassLoader.close();
194 } finally {
195 try {
196 zipFile.close();
197 } finally {
198 jarFile.close();
199 }
200 }
201 }
202 }
203
204 @Override
205 public void setEncoding(Charset charset) {
206 this.charset = charset;
207 }
208 }