Skip to content

Commit

Permalink
Added support for GZip compressions/extractions.
Browse files Browse the repository at this point in the history
Improvements to piped compressions.
  • Loading branch information
dscalzi committed Dec 13, 2018
1 parent 427aa74 commit 1c88ec5
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
package com.dscalzi.zipextractor.core;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Deque;
import java.util.List;
import java.util.Map;

import com.dscalzi.zipextractor.core.managers.MessageManager;
import com.dscalzi.zipextractor.core.provider.TypeProvider;
import com.dscalzi.zipextractor.core.util.ICommandSender;
import com.dscalzi.zipextractor.core.util.OpTuple;

public class ZCompressor {

Expand All @@ -40,56 +42,65 @@ public static void asyncCompress(ICommandSender sender, File src, File dest, boo
return;
}

String[] srcSplit = src.toPath().toAbsolutePath().normalize().toString().split("\\.", 2);
String[] destSplit = dest.toPath().toAbsolutePath().normalize().toString().split("\\.", 2);
Path destNorm = dest.toPath().toAbsolutePath().normalize();

// Split at first dot.
String[] destSplit = destNorm.getFileName().toString().split("\\.", 2);

// We need an extension.
if(destSplit.length < 2) {
mm.invalidCompressionExtension(sender);
return;
}

String[] srcExts = srcSplit.length > 1 ? srcSplit[1].split("\\.") : new String[0];
String[] destExts = destSplit[1].split("\\.");

Map<File, File> pMap = new LinkedHashMap<File, File>();
Deque<OpTuple> pDeque = new ArrayDeque<OpTuple>();
if(destExts.length < 2) {
pMap.put(src, dest);
pDeque.push(new OpTuple(src, dest));
} else {
File dTemp = dest;
File sTemp = src;
String extAcc = "";
for (int i=0; i<destExts.length; i++) {
extAcc += '.' + destExts[i];
if (i<srcExts.length && !srcExts[i].equals(destExts[i]) || !(i<srcExts.length)) {
dTemp = new File(destSplit[0] + extAcc);
pMap.put(sTemp, dTemp);
sTemp = dTemp;
File sTemp = null;

String pth = destNorm.toString();

for(int i=destExts.length-1; i>=0; i--) {
if(supportedExtensions().contains(destExts[i].toLowerCase())) {
pth = pth.substring(0, pth.length()-destExts[i].length()-1);
sTemp = new File(pth);
pDeque.push(new OpTuple(i == 0 ? src : sTemp, dTemp));
dTemp = sTemp;
} else {
pDeque.peek().setSrc(src);
break;
}
}
}

Runnable task = null;
int c = 0;
boolean piped = false;
final Runnable[] pipes = new Runnable[pMap.size()];
for (final Map.Entry<File, File> e : pMap.entrySet()) {
final Runnable[] pipes = new Runnable[pDeque.size()];
for (final OpTuple e : pDeque) {
for (final TypeProvider p : TypeProvider.getProviders()) {
if (p.destValidForCompression(e.getValue())) {
if (p.srcValidForCompression(e.getKey())) {
if (e.getValue().exists() && !override) {
mm.destExists(sender);
if (p.destValidForCompression(e.getDest())) {
if (p.srcValidForCompression(e.getSrc())) {
final boolean interOp = c != pDeque.size()-1;

if (e.getDest().exists() && !override) {
if(!interOp) mm.destExists(sender);
else mm.destExistsPiped(sender, e.getDest());
return;
}
final boolean printFinish = c != pMap.size()-1;

if(piped) {
pipes[c] = () -> {
p.compress(sender, e.getKey(), e.getValue(), log, printFinish);
e.getKey().delete();
p.compress(sender, e.getSrc(), e.getDest(), log, interOp);
e.getSrc().delete();
};
} else {
pipes[c] = () -> {
p.compress(sender, e.getKey(), e.getValue(), log, printFinish);
p.compress(sender, e.getSrc(), e.getDest(), log, interOp);
};
}
piped = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package com.dscalzi.zipextractor.core.managers;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -153,6 +154,12 @@ public void destExists(ICommandSender sender) {
sendError(sender, "Warning, the destination of this compression already exists.");
sendError(sender, "To proceed with the compression: " + "&o" + "/ze compress -override");
}

public void destExistsPiped(ICommandSender sender, File path) {
sendError(sender, "Warning, an intermediate destination of this piped compression already exists.");
sendError(sender, "&o" + path.toPath().toAbsolutePath().normalize().toString());
sendError(sender, "To proceed with the compression: " + "&o" + "/ze compress -override");
}

public void noWarnData(ICommandSender sender) {
sendError(sender, "You have no data to view!");
Expand Down Expand Up @@ -291,23 +298,23 @@ public void startingProcess(ICommandSender sender, ZTask task, String fileName)
plugin.info("Starting asynchronous " + task.getProcessName() + " of the file '" + fileName + "'..");
}

public void extractionComplete(ICommandSender sender, String destPath) {
public void extractionComplete(ICommandSender sender, File dest) {
if (!sender.isConsole()) {
sendSuccess(sender, "Extraction complete.");
}
plugin.info("---------------------------------------------------");
plugin.info("Extraction complete.");
plugin.info("The archive's contents have been extracted to\n" + destPath);
plugin.info("The archive's contents have been extracted to\n" + dest.toPath().toAbsolutePath().normalize().toString());
plugin.info("---------------------------------------------------");
}

public void compressionComplete(ICommandSender sender, String destPath) {
public void compressionComplete(ICommandSender sender, File dest) {
if (!sender.isConsole()) {
sendSuccess(sender, "Compression complete.");
}
plugin.info("---------------------------------------------------");
plugin.info("Compression complete.");
plugin.info("The folder's contents have been compressed to\n" + destPath);
plugin.info("The folder's contents have been compressed to\n" + dest.toPath().toAbsolutePath().normalize().toString());
plugin.info("---------------------------------------------------");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* This file is part of ZipExtractor.
* Copyright (C) 2016-2018 Daniel D. Scalzi <https://github.com/dscalzi/ZipExtractor>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.dscalzi.zipextractor.core.provider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import com.dscalzi.zipextractor.core.TaskInterruptedException;
import com.dscalzi.zipextractor.core.ZTask;
import com.dscalzi.zipextractor.core.managers.MessageManager;
import com.dscalzi.zipextractor.core.util.ICommandSender;

public class GZProvider implements TypeProvider {

// Shared pattern by GZProviders
public static final Pattern PATH_END = Pattern.compile("\\.gz$");
public static final List<String> SUPPORTED_EXTRACT = new ArrayList<String>(Arrays.asList("gz"));
public static final List<String> SUPPORTED_COMPRESS = new ArrayList<String>(Arrays.asList("non-directory"));

@Override
public List<String> scanForExtractionConflicts(ICommandSender sender, File src, File dest) {
final MessageManager mm = MessageManager.inst();
mm.scanningForConflics(sender);
File realDest = new File(dest.getAbsolutePath(), PATH_END.matcher(src.getName()).replaceAll(""));
List<String> ret = new ArrayList<String>();
if (realDest.exists()) {
ret.add(realDest.getAbsolutePath());
}
return ret;
}

@Override
public void extract(ICommandSender sender, File src, File dest, boolean log) {
final MessageManager mm = MessageManager.inst();
mm.startingProcess(sender, ZTask.EXTRACT, src.getName());
File realDest = new File(dest.getAbsolutePath(), PATH_END.matcher(src.getName()).replaceAll(""));
try (GZIPInputStream xzis = new GZIPInputStream(new FileInputStream(src));
FileOutputStream fos = new FileOutputStream(realDest)) {
if (log)
mm.info("Extracting : " + src.getAbsoluteFile());
byte[] buf = new byte[65536];
int len = 0;
while ((len = xzis.read(buf)) > 0) {
if (Thread.interrupted())
throw new TaskInterruptedException();
fos.write(buf, 0, len);
}
mm.extractionComplete(sender, realDest);
} catch (TaskInterruptedException e) {
mm.taskInterruption(sender, ZTask.EXTRACT);
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void compress(ICommandSender sender, File src, File dest, boolean log, boolean pipe) {
final MessageManager mm = MessageManager.inst();
mm.startingProcess(sender, ZTask.COMPRESS, src.getName());
try (GZIPOutputStream xzos = new GZIPOutputStream(new FileOutputStream(dest));
FileInputStream fis = new FileInputStream(src)) {
if (log)
mm.info("Compressing : " + src.getAbsolutePath());
byte[] buf = new byte[65536];
int len = 0;
while ((len = fis.read(buf)) > 0) {
if (Thread.interrupted())
throw new TaskInterruptedException();
xzos.write(buf, 0, len);
}
if(!pipe)
mm.compressionComplete(sender, dest);
} catch (TaskInterruptedException e) {
mm.taskInterruption(sender, ZTask.COMPRESS);
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public boolean validForExtraction(File src) {
return PATH_END.matcher(src.getAbsolutePath()).find();
}

@Override
public boolean srcValidForCompression(File src) {
return !src.isDirectory();
}

@Override
public boolean destValidForCompression(File dest) {
return validForExtraction(dest);
}

@Override
public List<String> supportedExtractionTypes() {
return SUPPORTED_EXTRACT;
}

@Override
public List<String> canCompressTo() {
return SUPPORTED_EXTRACT;
}

@Override
public List<String> canCompressFrom() {
return SUPPORTED_COMPRESS;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public void extract(ICommandSender sender, File src, File dest, boolean log) {
je = jis.getNextJarEntry();
}
jis.closeEntry();
mm.extractionComplete(sender, dest.getAbsolutePath());
mm.extractionComplete(sender, dest);
} catch (AccessDeniedException e) {
mm.fileAccessDenied(sender, ZTask.EXTRACT, e.getMessage());
} catch (TaskInterruptedException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void extract(ICommandSender sender, File src, File dest, boolean log) {
if (log)
mm.info("Extracting : " + src.getAbsoluteFile());
Pack200.newUnpacker().unpack(src, jarStream);
mm.extractionComplete(sender, realDest.getAbsolutePath());
mm.extractionComplete(sender, realDest);
} catch (IOException e) {
e.printStackTrace();
}
Expand All @@ -78,7 +78,7 @@ public void compress(ICommandSender sender, File src, File dest, boolean log, bo
mm.info("Compressing : " + src.getAbsolutePath());
Pack200.newPacker().pack(in, out);
if(!pipe)
mm.compressionComplete(sender, dest.getAbsolutePath());
mm.compressionComplete(sender, dest);
} catch (IOException e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void extract(ICommandSender sender, File src, File dest, boolean log) {
} catch (RarException | IOException e) {
e.printStackTrace();
}
mm.extractionComplete(sender, dest.getAbsolutePath());
mm.extractionComplete(sender, dest);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public interface TypeProvider {
new RarProvider(),
new JarProvider(),
new PackProvider(),
new XZProvider()
new XZProvider(),
new GZProvider()
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -61,20 +60,18 @@ public void extract(ICommandSender sender, File src, File dest, boolean log) {
final MessageManager mm = MessageManager.inst();
mm.startingProcess(sender, ZTask.EXTRACT, src.getName());
File realDest = new File(dest.getAbsolutePath(), PATH_END.matcher(src.getName()).replaceAll(""));
try (FileInputStream fis = new FileInputStream(src);
XZInputStream xzis = new XZInputStream(fis);
try (XZInputStream xzis = new XZInputStream(new FileInputStream(src));
FileOutputStream fos = new FileOutputStream(realDest)) {
if (log)
mm.info("Extracting : " + src.getAbsoluteFile());
byte[] buf = new byte[65536];
int read = xzis.read(buf);
while (read >= 1) {
int len = 0;
while ((len = xzis.read(buf)) > 0) {
if (Thread.interrupted())
throw new TaskInterruptedException();
fos.write(buf, 0, read);
read = xzis.read(buf);
fos.write(buf, 0, len);
}
mm.extractionComplete(sender, realDest.getAbsolutePath());
mm.extractionComplete(sender, realDest);
} catch (TaskInterruptedException e) {
mm.taskInterruption(sender, ZTask.EXTRACT);
} catch (IOException e) {
Expand All @@ -86,13 +83,21 @@ public void extract(ICommandSender sender, File src, File dest, boolean log) {
public void compress(ICommandSender sender, File src, File dest, boolean log, boolean pipe) {
final MessageManager mm = MessageManager.inst();
mm.startingProcess(sender, ZTask.COMPRESS, src.getName());
try (FileOutputStream fos = new FileOutputStream(dest);
XZOutputStream xzos = new XZOutputStream(fos, new LZMA2Options());) {
try (XZOutputStream xzos = new XZOutputStream(new FileOutputStream(dest), new LZMA2Options());
FileInputStream fis = new FileInputStream(src)) {
if (log)
mm.info("Compressing : " + src.getAbsolutePath());
xzos.write(Files.readAllBytes(src.toPath()));
byte[] buf = new byte[8*1024];
int len = 0;
while ((len = fis.read(buf)) > 0) {
if (Thread.interrupted())
throw new TaskInterruptedException();
xzos.write(buf, 0, len);
}
if(!pipe)
mm.compressionComplete(sender, dest.getAbsolutePath());
mm.compressionComplete(sender, dest);
} catch (TaskInterruptedException e) {
mm.taskInterruption(sender, ZTask.COMPRESS);
} catch (IOException e) {
e.printStackTrace();
}
Expand Down
Loading

0 comments on commit 1c88ec5

Please sign in to comment.