package net.krazyweb.helpers;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.ISevenZipInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.message.ParameterizedMessage;
public class Archive {
private static final org.apache.logging.log4j.Logger log = LogManager.getLogger(Archive.class);
private Path path;
private Set<ArchiveFile> files = new HashSet<>();
public Archive(final Path path) {
this.path = path;
}
public Archive(final String path) {
this(Paths.get(path));
}
public ArchiveFile getFile(String fileName) {
for (ArchiveFile file : files) {
if (file.getPath().toString().endsWith(fileName)) {
return file;
}
}
return null;
}
public ArchiveFile getFile(final Path filePath) {
for (ArchiveFile file : files) {
if (file.getPath().equals(filePath)) {
return file;
}
}
return null;
}
public Set<ArchiveFile> getFiles() {
return files;
}
public boolean extract() {
log.debug("Extracting: {}", path);
try {
long time = System.currentTimeMillis();
if (!FileHelper.isSupported(path, false)) {
/*
* TODO Inform user of invalid filetype.
* Change boolean return to error codes to be passed along to the UI.
*/
return false;
}
RandomAccessFile randomAccessFile = new RandomAccessFile(path.toFile(), "r");
ISevenZipInArchive inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
for (ISimpleInArchiveItem item : inArchive.getSimpleInterface().getArchiveItems()) {
final ArchiveFile file = new ArchiveFile();
file.setPath(Paths.get(item.getPath()));
if (item.isFolder()) {
log.debug("{}", item.getPath());
file.setFolder(true);
files.add(file);
continue;
}
ExtractOperationResult result;
final byte[] outputData = new byte[item.getSize().intValue()];
result = item.extractSlow(new ISequentialOutStream() {
int offset = 0;
public int write(byte[] data) throws SevenZipException {
for (int i = 0; i < data.length; i++) {
outputData[i + offset] = data[i];
}
offset += data.length;
return data.length;
}
});
file.setData(outputData);
if (result != ExtractOperationResult.OK) {
return false;
}
files.add(file);
}
inArchive.close();
randomAccessFile.close();
log.debug("Time to extract '{}' to memory: {}ms", path, (System.currentTimeMillis() - time));
return true;
} catch (IOException | SevenZipException e) {
log.error(new ParameterizedMessage("Extracting archive: ", path), e);
return false;
}
}
public boolean writeToFile(final File file) {
//TODO Explore updating this to use the Java 7 filesystem.
try {
long time = System.currentTimeMillis();
FileOutputStream fileOutput = new FileOutputStream(file);
ZipOutputStream zipOutput = new ZipOutputStream(fileOutput);
for (ArchiveFile archiveFile : files) {
if (archiveFile.isFolder()) {
continue;
}
log.trace("Writing file to {}: {}", file.getName(), archiveFile.getPath());
ZipEntry entry = new ZipEntry(archiveFile.getPath().toString());
zipOutput.putNextEntry(entry);
zipOutput.write(archiveFile.getData());
zipOutput.closeEntry();
}
zipOutput.close();
fileOutput.close();
log.debug("Time to write '{}': {}ms", file.getName(), (System.currentTimeMillis() - time));
return true;
} catch (IOException e) {
log.error("", e);
return false;
}
}
public boolean writeToFile() {
return writeToFile(path.toFile()); //TODO use path
}
public boolean extractToFolder(final Path folder) {
try {
for (ArchiveFile file : files) {
if (file.isFolder()) {
continue;
}
Files.createDirectories(folder.resolve(file.getPath()).getParent());
OutputStream output = Files.newOutputStream(folder.resolve(file.getPath()), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
output.write(file.getData());
output.close();
}
return true;
} catch (IOException e) {
log.error("Extracting archive to folder.", e);
return false;
}
}
public boolean extractFileToFolder(final Path file, final Path folder) {
Path newPath = folder.resolve(file);
try {
Files.createDirectories(newPath.getParent());
OutputStream output = Files.newOutputStream(newPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
output.write(getFile(file).getData());
output.close();
} catch (IOException e) {
log.error("Extracting file to folder.", e);
return false;
}
return true;
}
public String getFileName() {
return path.getFileName().toString().replace(".rar", ".zip").replace(".7z", ".zip");
}
public void addFile(final ArchiveFile file) {
files.add(file);
}
}