/* ** 2015 December 01 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ package info.ata4.disunity.cli.command.bundle; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import info.ata4.disunity.cli.command.FileCommand; import info.ata4.disunity.cli.converters.PathConverter; import info.ata4.io.util.PathUtils; import info.ata4.junity.bundle.Bundle; import info.ata4.junity.bundle.BundleReader; import info.ata4.log.LogUtils; import static info.ata4.util.function.IOConsumer.uncheck; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import java.nio.file.Paths; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Nico Bergemann <barracuda415 at yahoo.de> */ @Parameters( commandDescription = "Extract files from bundles." ) public class BundleUnpack extends FileCommand { private static final Logger L = LogUtils.getLogger(); @Parameter( names = {"-o", "--output"}, description = "Output directory", converter = PathConverter.class ) private Path outputDir; @Parameter( names = {"-f", "--filename"}, description = "Extract file with this name only." ) private String filename; @Parameter( names = {"-p", "--prop"}, description = "Write bundle property file." ) private boolean writeProp; @Override protected void runFile(Path file) { try (BundleReader bundleReader = new BundleReader(file)) { Bundle bundle = bundleReader.read(); AtomicInteger done = new AtomicInteger(); long total = bundle.entryInfos().size(); // define output directory, if not yet defined if (outputDir == null) { // if there's only one file inside the bundle, then don't bother // with sub-directories if (bundle.entryInfos().size() == 1) { outputDir = file.getParent(); if (outputDir == null) { // Passed a filename only. Use the current directory. outputDir = Paths.get("."); } } else { String fileName = PathUtils.getBaseName(file); outputDir = file.resolveSibling(fileName); } } try { bundle.entries() .stream() .filter(entry -> filename == null || entry.name().equals(filename)) .forEach(uncheck(entry -> { progress.update(Optional.of(entry.name()), done.getAndIncrement() / (double) total); Path entryFile = outputDir.resolve(entry.name()); Files.createDirectories(entryFile.getParent()); Files.copy(entry.inputStream(), entryFile, REPLACE_EXISTING); if (done.get() == total) { progress.update(Optional.empty(), 1); } })); } catch (UncheckedIOException ex) { throw ex.getCause(); } if (writeProp && filename == null) { String bundleName = outputDir.getFileName().toString(); Path propsFile = outputDir.getParent().resolve(bundleName + ".json"); BundleProps.write(propsFile, bundle); } } catch (IOException ex) { L.log(Level.WARNING, "Can't unpack asset bundle " + file, ex); } } }