diff options
Diffstat (limited to 'src/com/cyanogenmod')
6 files changed, 525 insertions, 10 deletions
diff --git a/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java b/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java index 59b38b4f..e54c7d56 100644 --- a/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java +++ b/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java @@ -408,4 +408,16 @@ public interface ExecutableCreator { CompressionMode mode, String src, AsyncResultListener asyncResultListener) throws CommandNotFoundException; + /** + * Method that creates an executable for uncompress file system objects. + * + * @param src The compressed file + * @param asyncResultListener The listener where to return partial results + * @return UncompressExecutable A {@link UncompressExecutable} executable implementation reference + * @throws CommandNotFoundException If the executable can't be created + */ + UncompressExecutable createUncompressExecutable( + String src, AsyncResultListener asyncResultListener) + throws CommandNotFoundException; + } diff --git a/src/com/cyanogenmod/explorer/commands/UncompressExecutable.java b/src/com/cyanogenmod/explorer/commands/UncompressExecutable.java new file mode 100644 index 00000000..aa9358ae --- /dev/null +++ b/src/com/cyanogenmod/explorer/commands/UncompressExecutable.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.commands; + +/** + * An interface that represents an executable for uncompress file system objects. + */ +public interface UncompressExecutable extends AsyncResultExecutable { + + /** + * Method that returns the result of the operation + * + * @return Boolean The result of the operation + */ + Boolean getResult(); + + /** + * Method that returns the path out uncompressed file or folder + * + * @return String The path of the uncompressed file or folder + */ + String getOutUncompressedFile(); + + /** + * Method that returns if the uncompress process will create a file or a folder + * + * @return boolean If the uncompress process will create a file or a folder + */ + boolean IsArchive(); +} diff --git a/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java b/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java index be91a8d3..3bf05878 100644 --- a/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java +++ b/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java @@ -518,4 +518,19 @@ public class ShellExecutableCreator implements ExecutableCreator { } } + /** + * {@inheritDoc} + */ + @Override + public UncompressCommand createUncompressExecutable( + String src, + AsyncResultListener asyncResultListener) + throws CommandNotFoundException { + try { + return new UncompressCommand(src, asyncResultListener); + } catch (InvalidCommandDefinitionException icdEx) { + throw new CommandNotFoundException("UncompressCommand", icdEx); //$NON-NLS-1$ + } + } + } diff --git a/src/com/cyanogenmod/explorer/commands/shell/UncompressCommand.java b/src/com/cyanogenmod/explorer/commands/shell/UncompressCommand.java new file mode 100644 index 00000000..7a51f525 --- /dev/null +++ b/src/com/cyanogenmod/explorer/commands/shell/UncompressCommand.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.commands.shell; + +import com.cyanogenmod.explorer.commands.AsyncResultListener; +import com.cyanogenmod.explorer.commands.SIGNAL; +import com.cyanogenmod.explorer.commands.UncompressExecutable; +import com.cyanogenmod.explorer.console.CommandNotFoundException; +import com.cyanogenmod.explorer.console.ExecutionException; +import com.cyanogenmod.explorer.console.InsufficientPermissionsException; +import com.cyanogenmod.explorer.util.FileHelper; + +import java.io.File; + +/** + * A class for uncompress file system objects. + * + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?tar"} + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?unzip"} + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?gunzip"} + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?bunzip2"} + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?xz"} + */ +public class UncompressCommand extends AsyncResultProgram implements UncompressExecutable { + + /** + * An enumeration of implemented uncompression modes. + */ + public enum UncompressionMode { + /** + * Uncompress using Tar algorithm + */ + A_UNTAR(UNTAR_ID, "", "tar", true), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Tar algorithm + */ + A_UNZIP(UNZIP_ID, "", "zip", true), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Gzip algorithm + */ + AC_GUNZIP(GUNZIP_ID, "z", "tar.gz", true), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Gzip algorithm + */ + AC_GUNZIP2(GUNZIP_ID, "z", "tgz", true), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Bzip algorithm + */ + AC_BUNZIP(BUNZIP_ID, "j", "tar.bz2", true), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Lzma algorithm + */ + AC_UNLZMA(UNLZMA_ID, "a", "tar.lzma", true), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Gzip algorithm + */ + C_GUNZIP(GUNZIP_ID, "", "gz", false), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Bzip algorithm + */ + C_BUNZIP(BUNZIP_ID, "", "bz2", false), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Lzma algorithm + */ + C_UNLZMA(UNLZMA_ID, "", "lzma", false), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Unix compress algorithm + */ + C_UNCOMPRESS(UNCOMPRESS_ID, "", ".Z", false), //$NON-NLS-1$ //$NON-NLS-2$ + /** + * Uncompress using Unix compress algorithm + */ + C_UNXZ(UNXZ_ID, "", ".xz", false); //$NON-NLS-1$ //$NON-NLS-2$ + + String mId; + String mFlag; + String mExtension; + boolean mArchive; + + /** + * Constructor of <code>UncompressionMode</code> + * + * @param id The command identifier + * @param flag The tar compression flag + * @param extension The file extension + * @param archive If the file is an archive or archive-compressed + */ + private UncompressionMode(String id, String flag, String extension, boolean archive) { + this.mId = id; + this.mFlag = flag; + this.mExtension = extension; + this.mArchive = archive; + } + } + + private static final String UNTAR_ID = "untar"; //$NON-NLS-1$ + private static final String UNZIP_ID = "unzip"; //$NON-NLS-1$ + private static final String GUNZIP_ID = "gunzip"; //$NON-NLS-1$ + private static final String BUNZIP_ID = "bunzip"; //$NON-NLS-1$ + private static final String UNLZMA_ID = "unlzma"; //$NON-NLS-1$ + private static final String UNCOMPRESS_ID = "uncompress"; //$NON-NLS-1$ + private static final String UNXZ_ID = "unxz"; //$NON-NLS-1$ + + private Boolean mResult; + private String mPartial; + + private final String mOutFile; + private final boolean mIsArchive; + + /** + * Constructor of <code>UncompressCommand</code>.<br/> + * <br/> + * <ul> + * <li>For archive and archive-compressed files, the file is extracted in a directory + * of the current location of the file with the name of the file without the extension.</li> + * <li>For compressed files, the file is extracted in the same directory in a file without + * the extension, and the source file is deleted.</li> + * </ul> + * + * @param src The archive-compressed file + * @param asyncResultListener The partial result listener + * @throws InvalidCommandDefinitionException If the command has an invalid definition + */ + public UncompressCommand( + String src, AsyncResultListener asyncResultListener) + throws InvalidCommandDefinitionException { + super(resolveId(src), asyncResultListener, resolveArguments(src)); + + // Check that have a valid + UncompressionMode mode = getMode(src); + if (mode == null) { + throw new InvalidCommandDefinitionException( + "Unsupported uncompress mode"); //$NON-NLS-1$ + } + + // Retrieve information about the uncompress process + this.mOutFile = resolveOutputFile(src); + this.mIsArchive = mode.mArchive; + } + + /** + * {@inheritDoc} + */ + @Override + public void onStartParsePartialResult() { + this.mResult = Boolean.FALSE; + this.mPartial = ""; //$NON-NLS-1$ + } + + /** + * {@inheritDoc} + */ + @Override + public void onEndParsePartialResult(boolean canceled) { + // Send the last partial data + if (this.mPartial != null && this.mPartial.length() > 0) { + if (getAsyncResultListener() != null) { + getAsyncResultListener().onPartialResult(this.mPartial); + } + } + this.mPartial = ""; //$NON-NLS-1$ + } + + /** + * {@inheritDoc} + */ + @Override + public void onParsePartialResult(final String partialIn) { + if (partialIn == null || partialIn.length() ==0) return; + boolean endsWithNewLine = partialIn.endsWith("\n"); //$NON-NLS-1$ + String[] lines = partialIn.split("\n"); //$NON-NLS-1$ + + // Append the pending data to the first line + lines[0] = this.mPartial + lines[0]; + + // Return all the lines, except the last + for (int i = 0; i < lines.length-1; i++) { + if (getAsyncResultListener() != null) { + getAsyncResultListener().onPartialResult(lines[i]); + } + } + + // Return the last line? + if (endsWithNewLine) { + if (getAsyncResultListener() != null) { + getAsyncResultListener().onPartialResult(lines[lines.length-1]); + } + this.mPartial = ""; //$NON-NLS-1$ + } else { + // Save the partial for next calls + this.mPartial = lines[lines.length-1]; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void onParseErrorPartialResult(String partialErr) {/**NON BLOCK**/} + + /** + * {@inheritDoc} + */ + @Override + public SIGNAL onRequestEnd() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Boolean getResult() { + return this.mResult; + } + + /** + * {@inheritDoc} + */ + @Override + public void checkExitCode(int exitCode) + throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException { + + //Ignore exit code 143 (canceled) + //Ignore exit code 137 (kill -9) + if (exitCode != 0 && exitCode != 143 && exitCode != 137) { + throw new ExecutionException( + "exitcode != 0 && != 1 && != 143 && != 137"); //$NON-NLS-1$ + } + + // Correct + this.mResult = Boolean.TRUE; + } + + /** + * {@inheritDoc} + */ + @Override + public String getOutUncompressedFile() { + return this.mOutFile; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean IsArchive() { + return this.mIsArchive; + } + + /** + * Method that resolves the identifier to use as command + * + * @param src The compressed file + * @return String The identifier of the command + */ + private static String resolveId(String src) { + UncompressionMode mode = getMode(src); + if (mode != null) { + return mode.mId; + } + return ""; //$NON-NLS-1$ + } + + /** + * Method that resolves the arguments for the uncompression + * + * @return String[] The arguments + */ + private static String[] resolveArguments(String src) { + String name = FileHelper.getName(src); + File dst = new File(new File(src).getParent(), name); + UncompressionMode mode = getMode(src); + if (mode != null) { + switch (mode) { + case A_UNTAR: + case AC_GUNZIP: + case AC_GUNZIP2: + case AC_BUNZIP: + case AC_UNLZMA: + return new String[]{mode.mFlag, dst.getAbsolutePath(), src}; + + case A_UNZIP: + return new String[]{dst.getAbsolutePath(), src}; + + case C_GUNZIP: + case C_BUNZIP: + case C_UNLZMA: + case C_UNCOMPRESS: + case C_UNXZ: + return new String[]{src}; + + default: + break; + } + } + return new String[]{}; + } + + /** + * Method that resolves the output path of the uncompressed file + * + * @return String The output path of the uncompressed file + */ + private static String resolveOutputFile(String src) { + String name = FileHelper.getName(src); + File dst = new File(new File(src).getParent(), name); + return dst.getAbsolutePath(); + } + + /** + * Method that returns the uncompression mode from the compressed file + * + * @param src The compressed file + * @return UncompressionMode The uncompression mode. <code>null</code> if no mode found + */ + private static UncompressionMode getMode(String src) { + String extension = FileHelper.getExtension(src); + UncompressionMode[] modes = UncompressionMode.values(); + for (int i = 0; i < modes.length; i++) { + UncompressionMode mode = modes[i]; + if (mode.mExtension.compareTo(extension) == 0) { + return mode; + } + } + return null; + } +} diff --git a/src/com/cyanogenmod/explorer/util/CommandHelper.java b/src/com/cyanogenmod/explorer/util/CommandHelper.java index f3032777..c094f185 100644 --- a/src/com/cyanogenmod/explorer/util/CommandHelper.java +++ b/src/com/cyanogenmod/explorer/util/CommandHelper.java @@ -50,6 +50,7 @@ import com.cyanogenmod.explorer.commands.ResolveLinkExecutable; import com.cyanogenmod.explorer.commands.SIGNAL; import com.cyanogenmod.explorer.commands.SendSignalExecutable; import com.cyanogenmod.explorer.commands.SyncResultExecutable; +import com.cyanogenmod.explorer.commands.UncompressExecutable; import com.cyanogenmod.explorer.commands.WritableExecutable; import com.cyanogenmod.explorer.commands.WriteExecutable; import com.cyanogenmod.explorer.commands.shell.CompressCommand.CompressionMode; @@ -1287,7 +1288,69 @@ public final class CommandHelper { return executable1; } throw new ExecutionException( - String.format("Fail to create file %s", compressOutFile)); //$NON-NLS-1$ + String.format("Fail to compress to file %s", compressOutFile)); //$NON-NLS-1$ + } + + /** + * Method that uncompress file system objects. + * + * @param context The current context (needed if console == null) + * @param src The file to compress + * @param asyncResultListener The partial result listener + * @param console The console in which execute the program. + * <code>null</code> to attach to the default console + * @return AsyncResultProgram The command executed in background + * @throws FileNotFoundException If the initial directory not exists + * @throws IOException If initial directory can't not be checked + * @throws InvalidCommandDefinitionException If the command has an invalid definition + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws ConsoleAllocException If the console can't be allocated + * @throws InsufficientPermissionsException If an operation requires elevated permissions + * @throws CommandNotFoundException If the command was not found + * @throws OperationTimeoutException If the operation exceeded the maximum time of wait + * @throws ExecutionException If the operation returns a invalid exit code + * @throws ReadOnlyFilesystemException If the operation writes in a read-only filesystem + * @see CompressExecutable + */ + public static UncompressExecutable uncompress( + Context context, String src, + AsyncResultListener asyncResultListener, Console console) + throws FileNotFoundException, IOException, ConsoleAllocException, + NoSuchFileOrDirectory, InsufficientPermissionsException, + CommandNotFoundException, OperationTimeoutException, + ExecutionException, InvalidCommandDefinitionException, ReadOnlyFilesystemException { + Console c = ensureConsole(context, console); + + UncompressExecutable executable1 = + c.getExecutableFactory().newCreator(). + createUncompressExecutable(src, asyncResultListener); + + // Prior to write to disk the data, ensure that can write to the disk using + // createFile or createFolder method + + String compressOutFile = executable1.getOutUncompressedFile(); + WritableExecutable executable2 = null; + if (executable1.IsArchive()) { + //- Create Folder + executable2 = + c.getExecutableFactory(). + newCreator(). + createCreateDirectoryExecutable(compressOutFile); + } else { + //- Create File + executable2 = + c.getExecutableFactory(). + newCreator(). + createCreateFileExecutable(compressOutFile); + } + writableExecute(context, executable2, c); + if (((Boolean)executable2.getResult()).booleanValue()) { + //- Compress + execute(context, executable1, c); + return executable1; + } + throw new ExecutionException( + String.format("Fail to uncompress to %s", compressOutFile)); //$NON-NLS-1$ } /** diff --git a/src/com/cyanogenmod/explorer/util/FileHelper.java b/src/com/cyanogenmod/explorer/util/FileHelper.java index 6f9f6128..aa94ce9a 100644 --- a/src/com/cyanogenmod/explorer/util/FileHelper.java +++ b/src/com/cyanogenmod/explorer/util/FileHelper.java @@ -49,11 +49,12 @@ import java.util.List; public final class FileHelper { /** - * Constructor of <code>FileHelper</code>. + * Special extension for compressed tar files */ - private FileHelper() { - super(); - } + private static final String[] COMPRESSED_TAR = + { + "tar.gz", "tar.bz2", "tar.lzma" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + }; /** * The root directory. @@ -86,6 +87,13 @@ public final class FileHelper { public static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$ /** + * Constructor of <code>FileHelper</code>. + */ + private FileHelper() { + super(); + } + + /** * Method that check if a file is a symbolic link. * * @param file File to check @@ -249,12 +257,14 @@ public final class FileHelper { return null; } - // 3 exceptions to the general form: tar.gz, tar.bz2 and tar.lzma - if (name.endsWith(".tar.gz")) return "tar.gz"; //$NON-NLS-1$ //$NON-NLS-2$ - if (name.endsWith(".tar.bz2")) return "tar.bz2"; //$NON-NLS-1$ //$NON-NLS-2$ - if (name.endsWith(".tar.lzma")) return "tar.lzma"; //$NON-NLS-1$ //$NON-NLS-2$ + // Exceptions to the general extraction method + for (int i = 0; i < COMPRESSED_TAR.length; i++) { + if (name.endsWith("." + COMPRESSED_TAR[i])) { //$NON-NLS-1$ + return COMPRESSED_TAR[i]; + } + } - // General form + // General extraction method return name.substring(pos + 1); } @@ -680,4 +690,33 @@ public final class FileHelper { } return false; } + + /** + * Method that returns is a {@link FileSystemObject} can be handled by this application + * allowing the uncompression of the file + * + * @param fso The file system object to verify + * @return boolean If the file is supported + */ + @SuppressWarnings("nls") + public static boolean isSupportedUnCompressedFile(FileSystemObject fso) { + // Valid uncompressed formats are: + final String[] VALID = + { + "tar", "tgz", "tar.gz", "tar.bz2", "tar.lzma", + "unzip", "gz", "bz2", "lzma", "xz", "Z" + }; + + //Only regular files + if (isDirectory(fso) || fso instanceof Symlink) { + return false; + } + String ext = getExtension(fso); + for (int i = 0; i < VALID.length; i++) { + if (VALID[i].compareTo(ext) == 0) { + return true; + } + } + return false; + } } |