File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\store\fs\FilePathZip.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.store.fs;
8
9 import java.io.FileNotFoundException;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.OutputStream;
13 import java.nio.ByteBuffer;
14 import java.nio.channels.FileChannel;
15 import java.nio.channels.FileLock;
16 import java.util.ArrayList;
17 import java.util.Enumeration;
18 import java.util.zip.ZipEntry;
19 import java.util.zip.ZipFile;
20 import org.h2.message.DbException;
21 import org.h2.util.IOUtils;
22 import org.h2.util.New;
23
24 /**
25 * This is a read-only file system that allows
26 * to access databases stored in a .zip or .jar file.
27 */
28 public class FilePathZip extends FilePath {
29
30 public FilePathZip getPath(String path) {
31 FilePathZip p = new FilePathZip();
32 p.name = path;
33 return p;
34 }
35
36 public void createDirectory() {
37 // ignore
38 }
39
40 public boolean createFile() {
41 throw DbException.getUnsupportedException("write");
42 }
43
44 public void delete() {
45 throw DbException.getUnsupportedException("write");
46 }
47
48 public boolean exists() {
49 try {
50 String entryName = getEntryName();
51 if (entryName.length() == 0) {
52 return true;
53 }
54 ZipFile file = openZipFile();
55 return file.getEntry(entryName) != null;
56 } catch (IOException e) {
57 return false;
58 }
59 }
60
61 public long lastModified() {
62 return 0;
63 }
64
65 public FilePath getParent() {
66 int idx = name.lastIndexOf('/');
67 return idx < 0 ? null : getPath(name.substring(0, idx));
68 }
69
70 public boolean isAbsolute() {
71 String fileName = translateFileName(name);
72 return FilePath.get(fileName).isAbsolute();
73 }
74
75 public FilePath unwrap() {
76 return FilePath.get(name.substring(getScheme().length() + 1));
77 }
78
79 public boolean isDirectory() {
80 try {
81 String entryName = getEntryName();
82 if (entryName.length() == 0) {
83 return true;
84 }
85 ZipFile file = openZipFile();
86 Enumeration<? extends ZipEntry> en = file.entries();
87 while (en.hasMoreElements()) {
88 ZipEntry entry = en.nextElement();
89 String n = entry.getName();
90 if (n.equals(entryName)) {
91 return entry.isDirectory();
92 } else if (n.startsWith(entryName)) {
93 if (n.length() == entryName.length() + 1) {
94 if (n.equals(entryName + "/")) {
95 return true;
96 }
97 }
98 }
99 }
100 return false;
101 } catch (IOException e) {
102 return false;
103 }
104 }
105
106 public boolean canWrite() {
107 return false;
108 }
109
110 public boolean setReadOnly() {
111 return true;
112 }
113
114 public long size() {
115 try {
116 ZipFile file = openZipFile();
117 ZipEntry entry = file.getEntry(getEntryName());
118 return entry == null ? 0 : entry.getSize();
119 } catch (IOException e) {
120 return 0;
121 }
122 }
123
124 public ArrayList<FilePath> newDirectoryStream() {
125 String path = name;
126 ArrayList<FilePath> list = New.arrayList();
127 try {
128 if (path.indexOf('!') < 0) {
129 path += "!";
130 }
131 if (!path.endsWith("/")) {
132 path += "/";
133 }
134 ZipFile file = openZipFile();
135 String dirName = getEntryName();
136 String prefix = path.substring(0, path.length() - dirName.length());
137 Enumeration<? extends ZipEntry> en = file.entries();
138 while (en.hasMoreElements()) {
139 ZipEntry entry = en.nextElement();
140 String name = entry.getName();
141 if (!name.startsWith(dirName)) {
142 continue;
143 }
144 if (name.length() <= dirName.length()) {
145 continue;
146 }
147 int idx = name.indexOf('/', dirName.length());
148 if (idx < 0 || idx >= name.length() - 1) {
149 list.add(getPath(prefix + name));
150 }
151 }
152 return list;
153 } catch (IOException e) {
154 throw DbException.convertIOException(e, "listFiles " + path);
155 }
156 }
157
158 public InputStream newInputStream() throws IOException {
159 return new FileChannelInputStream(open("r"));
160 }
161
162 public FileChannel open(String mode) throws IOException {
163 ZipFile file = openZipFile();
164 ZipEntry entry = file.getEntry(getEntryName());
165 if (entry == null) {
166 throw new FileNotFoundException(name);
167 }
168 return new FileZip(file, entry);
169 }
170
171 public OutputStream newOutputStream(boolean append) {
172 throw DbException.getUnsupportedException("write");
173 }
174
175 public void moveTo(FilePath newName) {
176 throw DbException.getUnsupportedException("write");
177 }
178
179 private static String translateFileName(String fileName) {
180 if (fileName.startsWith("zip:")) {
181 fileName = fileName.substring("zip:".length());
182 }
183 int idx = fileName.indexOf('!');
184 if (idx >= 0) {
185 fileName = fileName.substring(0, idx);
186 }
187 return FilePathDisk.expandUserHomeDirectory(fileName);
188 }
189
190 public FilePath toRealPath() {
191 return this;
192 }
193
194 private String getEntryName() {
195 int idx = name.indexOf('!');
196 String fileName;
197 if (idx <= 0) {
198 fileName = "";
199 } else {
200 fileName = name.substring(idx + 1);
201 }
202 fileName = fileName.replace('\\', '/');
203 if (fileName.startsWith("/")) {
204 fileName = fileName.substring(1);
205 }
206 return fileName;
207 }
208
209 private ZipFile openZipFile() throws IOException {
210 String fileName = translateFileName(name);
211 return new ZipFile(fileName);
212 }
213
214 public FilePath createTempFile(String suffix, boolean deleteOnExit, boolean inTempDir) throws IOException {
215 if (!inTempDir) {
216 throw new IOException("File system is read-only");
217 }
218 return new FilePathDisk().getPath(name).createTempFile(suffix, deleteOnExit, true);
219 }
220
221 public String getScheme() {
222 return "zip";
223 }
224
225 }
226
227 /**
228 * The file is read from a stream. When reading from start to end, the same
229 * input stream is re-used, however when reading from end to start, a new input
230 * stream is opened for each request.
231 */
232 class FileZip extends FileBase {
233
234 private static final byte[] SKIP_BUFFER = new byte[1024];
235
236 private final ZipFile file;
237 private final ZipEntry entry;
238 private long pos;
239 private InputStream in;
240 private long inPos;
241 private final long length;
242 private boolean skipUsingRead;
243
244 FileZip(ZipFile file, ZipEntry entry) {
245 this.file = file;
246 this.entry = entry;
247 length = entry.getSize();
248 }
249
250 public long position() {
251 return pos;
252 }
253
254 public long size() {
255 return length;
256 }
257
258 public int read(ByteBuffer dst) throws IOException {
259 seek();
260 int len = in.read(dst.array(), dst.position(), dst.remaining());
261 if (len > 0) {
262 dst.position(dst.position() + len);
263 pos += len;
264 inPos += len;
265 }
266 return len;
267 }
268
269 private void seek() throws IOException {
270 if (inPos > pos) {
271 if (in != null) {
272 in.close();
273 }
274 in = null;
275 }
276 if (in == null) {
277 in = file.getInputStream(entry);
278 inPos = 0;
279 }
280 if (inPos < pos) {
281 long skip = pos - inPos;
282 if (!skipUsingRead) {
283 try {
284 IOUtils.skipFully(in, skip);
285 } catch (NullPointerException e) {
286 // workaround for Android
287 skipUsingRead = true;
288 }
289 }
290 if (skipUsingRead) {
291 while (skip > 0) {
292 int s = (int) Math.min(SKIP_BUFFER.length, skip);
293 s = in.read(SKIP_BUFFER, 0, s);
294 skip -= s;
295 }
296 }
297 inPos = pos;
298 }
299 }
300
301 public FileChannel position(long newPos) {
302 this.pos = newPos;
303 return this;
304 }
305
306 public FileChannel truncate(long newLength) throws IOException {
307 throw new IOException("File is read-only");
308 }
309
310 public void force(boolean metaData) throws IOException {
311 // nothing to do
312 }
313
314 public int write(ByteBuffer src) throws IOException {
315 throw new IOException("File is read-only");
316 }
317
318 public synchronized FileLock tryLock(long position, long size, boolean shared) throws IOException {
319 if (shared) {
320 return new FileLock(null, position, size, shared) {
321
322 @Override
323 public boolean isValid() {
324 return true;
325 }
326
327 @Override
328 public void release() throws IOException {
329 // ignore
330 }};
331 }
332 return null;
333 }
334
335 }
336