Extract file related helper functions into separate class

This commit is contained in:
cketti 2014-11-11 01:04:39 +01:00
parent e64ca84f1b
commit 34cfd8e5b4
6 changed files with 181 additions and 185 deletions

View File

@ -0,0 +1,165 @@
package com.fsck.k9.helper;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Locale;
import android.util.Log;
import com.fsck.k9.K9;
public class FileHelper {
/**
* Regular expression that represents characters we won't allow in file names.
*
* <p>
* Allowed are:
* <ul>
* <li>word characters (letters, digits, and underscores): {@code \w}</li>
* <li>spaces: {@code " "}</li>
* <li>special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '},
* {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, <code>&#123;</code>,
* <code>&#125;</code>, {@code ~}, {@code .}, {@code ,}</li>
* </ul></p>
*
* @see #sanitizeFilename(String)
*/
private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
/**
* Invalid characters in a file name are replaced by this character.
*
* @see #sanitizeFilename(String)
*/
private static final String REPLACEMENT_CHARACTER = "_";
/**
* Creates a unique file in the given directory by appending a hyphen
* and a number to the given filename.
*/
public static File createUniqueFile(File directory, String filename) {
File file = new File(directory, filename);
if (!file.exists()) {
return file;
}
// Get the extension of the file, if any.
int index = filename.lastIndexOf('.');
String format;
if (index != -1) {
String name = filename.substring(0, index);
String extension = filename.substring(index);
format = name + "-%d" + extension;
} else {
format = filename + "-%d";
}
for (int i = 2; i < Integer.MAX_VALUE; i++) {
file = new File(directory, String.format(Locale.US, format, i));
if (!file.exists()) {
return file;
}
}
return null;
}
public static void touchFile(final File parentDir, final String name) {
final File file = new File(parentDir, name);
try {
if (!file.exists()) {
file.createNewFile();
} else {
file.setLastModified(System.currentTimeMillis());
}
} catch (Exception e) {
Log.d(K9.LOG_TAG, "Unable to touch file: " + file.getAbsolutePath(), e);
}
}
public static boolean move(final File from, final File to) {
if (to.exists()) {
to.delete();
}
to.getParentFile().mkdirs();
try {
FileInputStream in = new FileInputStream(from);
try {
FileOutputStream out = new FileOutputStream(to);
try {
byte[] buffer = new byte[1024];
int count = -1;
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
} finally {
out.close();
}
} finally {
try { in.close(); } catch (Throwable ignore) {}
}
from.delete();
return true;
} catch (Exception e) {
Log.w(K9.LOG_TAG, "cannot move " + from.getAbsolutePath() + " to " + to.getAbsolutePath(), e);
return false;
}
}
public static void moveRecursive(final File fromDir, final File toDir) {
if (!fromDir.exists()) {
return;
}
if (!fromDir.isDirectory()) {
if (toDir.exists()) {
if (!toDir.delete()) {
Log.w(K9.LOG_TAG, "cannot delete already existing file/directory " + toDir.getAbsolutePath());
}
}
if (!fromDir.renameTo(toDir)) {
Log.w(K9.LOG_TAG, "cannot rename " + fromDir.getAbsolutePath() + " to " + toDir.getAbsolutePath() + " - moving instead");
move(fromDir, toDir);
}
return;
}
if (!toDir.exists() || !toDir.isDirectory()) {
if (toDir.exists()) {
toDir.delete();
}
if (!toDir.mkdirs()) {
Log.w(K9.LOG_TAG, "cannot create directory " + toDir.getAbsolutePath());
}
}
File[] files = fromDir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
moveRecursive(file, new File(toDir, file.getName()));
file.delete();
} else {
File target = new File(toDir, file.getName());
if (!file.renameTo(target)) {
Log.w(K9.LOG_TAG, "cannot rename " + file.getAbsolutePath() + " to " + target.getAbsolutePath() + " - moving instead");
move(file, target);
}
}
}
if (!fromDir.delete()) {
Log.w(K9.LOG_TAG, "cannot delete " + fromDir.getAbsolutePath());
}
}
/**
* Replace characters we don't allow in file names with a replacement character.
*
* @param filename
* The original file name.
*
* @return The sanitized file name containing only allowed characters.
*/
public static String sanitizeFilename(String filename) {
return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
}
}

View File

@ -17,40 +17,13 @@ import android.widget.TextView;
import com.fsck.k9.K9;
import com.fsck.k9.mail.filter.Base64;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Utility {
/**
* Regular expression that represents characters we won't allow in file names.
*
* <p>
* Allowed are:
* <ul>
* <li>word characters (letters, digits, and underscores): {@code \w}</li>
* <li>spaces: {@code " "}</li>
* <li>special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '},
* {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, <code>&#123;</code>,
* <code>&#125;</code>, {@code ~}, {@code .}, {@code ,}</li>
* </ul></p>
*
* @see #sanitizeFilename(String)
*/
private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
/**
* Invalid characters in a file name are replaced by this character.
*
* @see #sanitizeFilename(String)
*/
private static final String REPLACEMENT_CHARACTER = "_";
// \u00A0 (non-breaking space) happens to be used by French MUA
@ -454,139 +427,6 @@ public class Utility {
}
}
/**
* @param parentDir
* @param name
* Never <code>null</code>.
*/
public static void touchFile(final File parentDir, final String name) {
final File file = new File(parentDir, name);
try {
if (!file.exists()) {
file.createNewFile();
} else {
file.setLastModified(System.currentTimeMillis());
}
} catch (Exception e) {
Log.d(K9.LOG_TAG, "Unable to touch file: " + file.getAbsolutePath(), e);
}
}
/**
* Creates a unique file in the given directory by appending a hyphen
* and a number to the given filename.
*
* @param directory
* @param filename
* @return
*/
public static File createUniqueFile(File directory, String filename) {
File file = new File(directory, filename);
if (!file.exists()) {
return file;
}
// Get the extension of the file, if any.
int index = filename.lastIndexOf('.');
String format;
if (index != -1) {
String name = filename.substring(0, index);
String extension = filename.substring(index);
format = name + "-%d" + extension;
} else {
format = filename + "-%d";
}
for (int i = 2; i < Integer.MAX_VALUE; i++) {
file = new File(directory, String.format(Locale.US, format, i));
if (!file.exists()) {
return file;
}
}
return null;
}
/**
* @param from
* @param to
* @return
*/
public static boolean move(final File from, final File to) {
if (to.exists()) {
to.delete();
}
to.getParentFile().mkdirs();
try {
FileInputStream in = new FileInputStream(from);
try {
FileOutputStream out = new FileOutputStream(to);
try {
byte[] buffer = new byte[1024];
int count = -1;
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
} finally {
out.close();
}
} finally {
try { in.close(); } catch (Throwable ignore) {}
}
from.delete();
return true;
} catch (Exception e) {
Log.w(K9.LOG_TAG, "cannot move " + from.getAbsolutePath() + " to " + to.getAbsolutePath(), e);
return false;
}
}
/**
* @param fromDir
* @param toDir
*/
public static void moveRecursive(final File fromDir, final File toDir) {
if (!fromDir.exists()) {
return;
}
if (!fromDir.isDirectory()) {
if (toDir.exists()) {
if (!toDir.delete()) {
Log.w(K9.LOG_TAG, "cannot delete already existing file/directory " + toDir.getAbsolutePath());
}
}
if (!fromDir.renameTo(toDir)) {
Log.w(K9.LOG_TAG, "cannot rename " + fromDir.getAbsolutePath() + " to " + toDir.getAbsolutePath() + " - moving instead");
move(fromDir, toDir);
}
return;
}
if (!toDir.exists() || !toDir.isDirectory()) {
if (toDir.exists()) {
toDir.delete();
}
if (!toDir.mkdirs()) {
Log.w(K9.LOG_TAG, "cannot create directory " + toDir.getAbsolutePath());
}
}
File[] files = fromDir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
moveRecursive(file, new File(toDir, file.getName()));
file.delete();
} else {
File target = new File(toDir, file.getName());
if (!file.renameTo(target)) {
Log.w(K9.LOG_TAG, "cannot rename " + file.getAbsolutePath() + " to " + target.getAbsolutePath() + " - moving instead");
move(file, target);
}
}
}
if (!fromDir.delete()) {
Log.w(K9.LOG_TAG, "cannot delete " + fromDir.getAbsolutePath());
}
}
private static final String IMG_SRC_REGEX = "(?is:<img[^>]+src\\s*=\\s*['\"]?([a-z]+)\\:)";
private static final Pattern IMG_PATTERN = Pattern.compile(IMG_SRC_REGEX);
@ -624,18 +464,6 @@ public class Utility {
}
}
/**
* Replace characters we don't allow in file names with a replacement character.
*
* @param filename
* The original file name.
*
* @return The sanitized file name containing only allowed characters.
*/
public static String sanitizeFilename(String filename) {
return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
}
/**
* Check to see if we have network connectivity.
* @param app Current application (Hint: see if your base class has a getApplication() method.)

View File

@ -14,7 +14,7 @@ import android.os.Build;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.mail.MessagingException;
public class LockableDatabase {
@ -337,9 +337,10 @@ public class LockableDatabase {
prepareStorage(newProviderId);
// move all database files
Utility.moveRecursive(oldDatabase, storageManager.getDatabase(uUid, newProviderId));
FileHelper.moveRecursive(oldDatabase, storageManager.getDatabase(uUid, newProviderId));
// move all attachment files
Utility.moveRecursive(storageManager.getAttachmentDirectory(uUid, oldProviderId), storageManager.getAttachmentDirectory(uUid, newProviderId));
FileHelper.moveRecursive(storageManager.getAttachmentDirectory(uUid, oldProviderId),
storageManager.getAttachmentDirectory(uUid, newProviderId));
// remove any remaining old journal files
deleteDatabase(oldDatabase);
@ -425,7 +426,7 @@ public class LockableDatabase {
// Android seems to be unmounting the storage...
throw new UnavailableStorageException("Unable to access: " + databaseParentDir);
}
Utility.touchFile(databaseParentDir, ".nomedia");
FileHelper.touchFile(databaseParentDir, ".nomedia");
}
final File attachmentDir;
@ -435,7 +436,7 @@ public class LockableDatabase {
attachmentParentDir = attachmentDir.getParentFile();
if (!attachmentParentDir.exists()) {
attachmentParentDir.mkdirs();
Utility.touchFile(attachmentParentDir, ".nomedia");
FileHelper.touchFile(attachmentParentDir, ".nomedia");
}
if (!attachmentDir.exists()) {
attachmentDir.mkdirs();

View File

@ -12,6 +12,8 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import com.fsck.k9.helper.FileHelper;
import org.xmlpull.v1.XmlSerializer;
import android.content.Context;
@ -23,7 +25,6 @@ import android.util.Xml;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.Transport;
@ -87,7 +88,7 @@ public class SettingsExporter {
File dir = new File(Environment.getExternalStorageDirectory() + File.separator
+ context.getPackageName());
dir.mkdirs();
File file = Utility.createUniqueFile(dir, EXPORT_FILENAME);
File file = FileHelper.createUniqueFile(dir, EXPORT_FILENAME);
filename = file.getAbsolutePath();
os = new FileOutputStream(filename);

View File

@ -34,9 +34,9 @@ import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.helper.MediaScannerNotifier;
import com.fsck.k9.helper.SizeFormatter;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
@ -237,8 +237,8 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
}
private File writeAttachmentToStorage(File directory) throws IOException {
String filename = Utility.sanitizeFilename(name);
File file = Utility.createUniqueFile(directory, filename);
String filename = FileHelper.sanitizeFilename(name);
File file = FileHelper.createUniqueFile(directory, filename);
Uri uri = AttachmentProvider.getAttachmentUri(account, part.getAttachmentId());
InputStream in = context.getContentResolver().openInputStream(uri);
@ -317,7 +317,7 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
Intent intent;
int activitiesCount;
File dummyFile = new File(Utility.sanitizeFilename(name));
File dummyFile = new File(FileHelper.sanitizeFilename(name));
Uri fileUri = Uri.fromFile(dummyFile);
Intent originalMimeTypeIntent = createViewIntentForFileUri(contentType, fileUri);

View File

@ -46,6 +46,7 @@ import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.fragment.MessageViewFragment;
import com.fsck.k9.helper.ClipboardManager;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Address;
@ -842,10 +843,10 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
filename += "." + extension;
}
String sanitized = Utility.sanitizeFilename(filename);
String sanitized = FileHelper.sanitizeFilename(filename);
File directory = new File(K9.getAttachmentDefaultPath());
File file = Utility.createUniqueFile(directory, sanitized);
File file = FileHelper.createUniqueFile(directory, sanitized);
FileOutputStream out = new FileOutputStream(file);
try {
IOUtils.copy(in, out);