001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.vfs2.provider.zip; 018 019import java.io.InputStream; 020import java.util.HashSet; 021import java.util.zip.ZipEntry; 022 023import org.apache.commons.vfs2.FileName; 024import org.apache.commons.vfs2.FileSystemException; 025import org.apache.commons.vfs2.FileType; 026import org.apache.commons.vfs2.provider.AbstractFileName; 027import org.apache.commons.vfs2.provider.AbstractFileObject; 028 029/** 030 * A file in a ZIP file system. 031 */ 032public class ZipFileObject extends AbstractFileObject<ZipFileSystem> { 033 /** The ZipEntry. */ 034 protected ZipEntry entry; 035 private final HashSet<String> children = new HashSet<>(); 036 private FileType type; 037 038 protected ZipFileObject(final AbstractFileName name, final ZipEntry entry, final ZipFileSystem fs, 039 final boolean zipExists) throws FileSystemException { 040 super(name, fs); 041 setZipEntry(entry); 042 if (!zipExists) { 043 type = FileType.IMAGINARY; 044 } 045 } 046 047 /** 048 * Sets the details for this file object. 049 * 050 * @param entry ZIP information related to this file. 051 */ 052 protected void setZipEntry(final ZipEntry entry) { 053 if (this.entry != null) { 054 return; 055 } 056 057 if (entry == null || entry.isDirectory()) { 058 type = FileType.FOLDER; 059 } else { 060 type = FileType.FILE; 061 } 062 063 this.entry = entry; 064 } 065 066 /** 067 * Attaches a child. 068 * <p> 069 * TODO: Shouldn't this method have package-only visibility? Cannot change this without breaking binary 070 * compatibility. 071 * </p> 072 * 073 * @param childName The name of the child. 074 */ 075 public void attachChild(final FileName childName) { 076 children.add(childName.getBaseName()); 077 } 078 079 /** 080 * Determines if this file can be written to. 081 * 082 * @return {@code true} if this file is writable, {@code false} if not. 083 * @throws FileSystemException if an error occurs. 084 */ 085 @Override 086 public boolean isWriteable() throws FileSystemException { 087 return false; 088 } 089 090 /** 091 * Returns the file's type. 092 */ 093 @Override 094 protected FileType doGetType() { 095 return type; 096 } 097 098 /** 099 * Lists the children of the file. 100 */ 101 @Override 102 protected String[] doListChildren() { 103 try { 104 if (!getType().hasChildren()) { 105 return null; 106 } 107 } catch (final FileSystemException e) { 108 // should not happen as the type has already been cached. 109 throw new RuntimeException(e); 110 } 111 112 return children.toArray(new String[children.size()]); 113 } 114 115 /** 116 * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns 117 * {@link FileType#FILE}. 118 */ 119 @Override 120 protected long doGetContentSize() { 121 return entry.getSize(); 122 } 123 124 /** 125 * Returns the last modified time of this file. 126 */ 127 @Override 128 protected long doGetLastModifiedTime() throws Exception { 129 return entry.getTime(); 130 } 131 132 /** 133 * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns 134 * {@link FileType#FILE}. The input stream returned by this method is guaranteed to be closed before this method is 135 * called again. 136 */ 137 @Override 138 protected InputStream doGetInputStream() throws Exception { 139 // VFS-210: zip allows to gather an input stream even from a directory and will 140 // return -1 on the first read. getType should not be expensive and keeps the tests 141 // running 142 if (!getType().hasContent()) { 143 throw new FileSystemException("vfs.provider/read-not-file.error", getName()); 144 } 145 146 return getAbstractFileSystem().getZipFile().getInputStream(entry); 147 } 148 149 @Override 150 protected void doAttach() throws Exception { 151 getAbstractFileSystem().getZipFile(); 152 } 153 154 @Override 155 protected void doDetach() throws Exception { 156 ZipFileSystem afs = getAbstractFileSystem(); 157 if (!afs.isOpen()) { 158 afs.close(); 159 } 160 } 161}