/* Copyright 2009 Hauke Rehfeld This file is part of QuakeInjector. QuakeInjector 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. QuakeInjector 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 QuakeInjector. If not, see <http://www.gnu.org/licenses/>. */ package de.haukerehfeld.quakeinjector; import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.swing.SwingWorker; /** * Install maps in a worker thread * Init once and let swing start it - don't reuse */ public class InstallWorker extends SwingWorker<PackageFileList, Void> implements ProgressListener, Cancelable { private final static int BUFFERSIZE = 1024; private File baseDirectory; private String unzipDirectory; private Package map; private InputStream input; private List<File> overwrites; private long downloadSize = 0; /** * files that got installed */ private PackageFileList files; /** * @param inputSize size of the input stream in bytes, for progress reporting * @param overwrites a list of files that we should overwrite, or * null if everything should be overwritten */ public InstallWorker(InputStream input, long inputSize, Package map, File baseDirectory, String unzipDirectory, List<File> overwrites) { this.map = map; this.input = input; this.downloadSize = inputSize; this.baseDirectory = baseDirectory; this.unzipDirectory = unzipDirectory; this.files = new PackageFileList(map.getId()); this.overwrites = overwrites; } @Override public PackageFileList doInBackground() throws IOException, FileNotFoundException, Installer.CancelledException { System.out.println("Installing " + map.getId()); unzip(input, baseDirectory, unzipDirectory, map.getId(), overwrites); map.setInstalled(true); return files; } /** * Unzip from the inputstream to the quake base dir */ public void unzip(InputStream in, File basedir, String unzipdir, String mapid, List<File> overwrites) throws IOException, FileNotFoundException, Installer.CancelledException { //build progress filter chain ProgressListener progress = new SumProgressListener( new PercentageProgressListener(downloadSize, new CheckCanceledProgressListener(this, this))); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(in)); ZipEntry entry; boolean extracted = false; while((entry = zis.getNextEntry()) != null) { File f = new File(unzipdir + File.separator + entry.getName()); String filename = RelativePath.getRelativePath(basedir, f).toString(); if (overwrites != null && overwrites.indexOf(f) < 0) { System.out.println("Skipping " + filename + ", because it isn't supposed to be overwritten."); continue; } //create dirs List<File> createdDirs = Utils.mkdirs(f); //do nothing for directories other than creating them if (!entry.isDirectory()) { File original = f; if (f.exists()) { //create Temp file and rename later f = File.createTempFile("quakeinjector", ".tmp", f.getParentFile()); System.out.println("create Temp file " + f); } System.out.println("Writing " + filename + " (" + entry.getCompressedSize() + "b)"); long crc; try { crc = Utils.writeFile(zis, f, new CompressedProgressListener(entry.getCompressedSize() / (double) entry.getSize(), progress)); } catch (FileNotFoundException e) { throw new FileNotWritableException(e.getMessage()); } if (crc != entry.getCrc()) { System.err.println("Crc32 didn't match on extraction of " + original + ", removing..."); f.delete(); continue; } /** @todo 2009-12-19 03:03 hrehfeld add crc calculation */ FileInfo info = new FileInfo(filename, crc); files.add(info); for (File dirname: createdDirs) { //save relative paths to files so we can delete dirs later files.add(new FileInfo(RelativePath.getRelativePath(basedir, dirname).toString(), 0)); } //if we extracted to temp, rename if (!f.equals(original)) { original.delete(); System.out.println("moving Temp file to " + original); f.renameTo(original); } extracted = true; } } if (!extracted) { throw new java.util.zip.ZipException("No files extracted from zip, is it an empty file?"); } zis.close(); } public void publish(long progress) { if (progress <= 100) { setProgress((int) progress); } } public void checkCancelled() throws Installer.CancelledException { if (isCancelled()) { System.out.println("canceling..."); throw new Installer.CancelledException(); } } public PackageFileList getInstalledFiles() { return files; } }