/*
* Copyright (C) 2014 MillerV
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package aspect.resources;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import aspect.resources.ArcFile.ArcEntry;
/**
* A class for reading and writing zip archives.
*
* @author MillerV
*/
public class ArcFile extends File implements Iterable<ArcEntry> {
private static final byte[] buffer = new byte[1024 * 4096];
private ZipFile zipFile;
private boolean valid = false;
public ArcFile(String string) {
super(string);
}
public ZipFile getZipFile() throws IOException {
if (!valid) {
valid = true;
zipFile = new ZipFile(this);
}
return zipFile;
}
public static synchronized void copy(InputStream in, OutputStream out) throws IOException {
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
public InputStream getStream(File file) throws IOException {
ZipFile zip = getZipFile();
ZipEntry entry = zip.getEntry(file.getPath());
return zip.getInputStream(entry);
}
public ArcEntry getEntry(File file) throws IOException {
return new ArcEntry(getZipFile().getEntry(file.getPath()));
}
@Override
public Iterator<ArcEntry> iterator() {
try {
final Enumeration<? extends ZipEntry> entries = getZipFile().entries();
return new Iterator() {
private ArcEntry last;
@Override
public boolean hasNext() {
return entries.hasMoreElements();
}
@Override
public ArcEntry next() {
last = new ArcEntry(entries.nextElement());
return last;
}
@Override
public void remove() {
try {
deleteFile(new File(last.entry.getName()), "");
} catch (IOException ex) {
Logger.getLogger(ArcFile.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
} catch (IOException ex) {
Logger.getLogger(ArcFile.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
public void addFile(File toAdd, String path) throws IOException {
if (path == null) {
path = "";
}
File tmp = File.createTempFile(getName(), null);
tmp.delete();
if (!renameTo(tmp)) {
throw new IOException("Could not create temp file: " + getName());
}
ZipInputStream zin = new ZipInputStream(new FileInputStream(tmp));
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(this));
InputStream in = new FileInputStream(toAdd);
zout.putNextEntry(new ZipEntry(path + toAdd.getName()));
copy(in, zout);
zout.closeEntry();
in.close();
for (ZipEntry entry = zin.getNextEntry(); entry != null; entry = zin.getNextEntry()) {
if (!entry.getName().equals(path + toAdd.getName())) {
zout.putNextEntry(new ZipEntry(entry.getName()));
copy(zin, zout);
zout.closeEntry();
}
}
zout.close();
tmp.delete();
valid = false;
}
public void deleteFile(File toRemove, String path) throws IOException {
if (path == null) {
path = "";
}
File tmp = File.createTempFile(getName(), null);
tmp.delete();
if (!renameTo(tmp)) {
throw new IOException("Could not create temp file: " + getName());
}
ZipInputStream zin = new ZipInputStream(new FileInputStream(tmp));
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(this));
for (ZipEntry entry = zin.getNextEntry(); entry != null; entry = zin.getNextEntry()) {
if (!entry.getName().equals(path + toRemove.getName())) {
zout.putNextEntry(new ZipEntry(entry.getName()));
copy(zin, zout);
zout.closeEntry();
}
}
zout.close();
tmp.delete();
valid = false;
}
public class ArcEntry {
private final ZipEntry entry;
public ArcEntry(ZipEntry entry) {
this.entry = entry;
}
public ArcEntry(String name) {
this.entry = new ZipEntry(name);
}
public ZipEntry getZipEntry() {
return entry;
}
public String getName() {
return entry.getName();
}
public long getSize() {
return entry.getSize();
}
public InputStream getStream() throws IOException {
return getZipFile().getInputStream(entry);
}
}
}