project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/FileUtils.java
changeset 7508 763d3961400b
parent 7485 0481bd74267c
child 7584 7831c84cc644
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/FileUtils.java	Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,265 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ *
+ * This program 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; version 2 of the License
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+package org.hedgewars.hedgeroid.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+public class FileUtils {
+	private static final String ROOT_DIR = "Data";
+	private static final String TAG = FileUtils.class.getSimpleName();
+
+	/**
+	 * @return true if the data path is currently available. However, it can vanish at any time so
+	 * normally you should just try to use it and rely on the exceptions.
+	 */
+	public static boolean isDataPathAvailable() {
+		return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
+	}
+	
+	/**
+	 * get the path to which we should download all the data files
+	 * @param c context 
+	 * @return The directory
+	 * @throws FileNotFoundException if external storage is not available at the moment
+	 */
+	public static File getCachePath(Context c) throws FileNotFoundException {
+		File cachePath = null;
+		if(Build.VERSION.SDK_INT < 8){//8 == Build.VERSION_CODES.FROYO
+			cachePath = PreFroyoSDCardDir.getDownloadPath(c);
+		} else {
+			cachePath = FroyoSDCardDir.getDownloadPath(c);
+		}
+		if(cachePath==null) {
+			throw new FileNotFoundException("External storage is currently unavailable");
+		} else {
+			return cachePath;
+		}
+	}
+
+	public static File getDataPathFile(Context c) throws FileNotFoundException {
+		return new File(getCachePath(c), ROOT_DIR);
+	}
+	
+	// TODO Several callers are unaware that this may fail, so it throws an RTE now.
+	// Should be handled better though.
+	@Deprecated
+	public static String getDataPath(Context c) {
+		try {
+			return getDataPathFile(c).getAbsolutePath()+"/";
+		} catch(FileNotFoundException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	@TargetApi(8)
+	private static class FroyoSDCardDir{
+		public static File getDownloadPath(Context c){
+			return c.getExternalCacheDir();
+		}
+	}
+
+	private static class PreFroyoSDCardDir{
+		public static File getDownloadPath(Context c){
+			if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
+				File extStorageDir = Environment.getExternalStorageDirectory();
+				if(extStorageDir != null) {
+					return new File(extStorageDir, "Hedgewars");
+				}
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * Return a File array with all the files from dirName
+	 * @param c
+	 * @param dirName
+	 * @return
+	 * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dirName" does not exist
+	 */
+	public static File[] getFilesFromRelativeDir(Context c, String dirName) throws FileNotFoundException {
+		File f = new File(getDataPathFile(c), dirName);
+
+		if(f.isDirectory()) {
+			return f.listFiles();
+		} else {
+			throw new FileNotFoundException("Directory "+dirName+" does not exist.");
+		}
+	}
+
+	/**
+	 * Checks if this directory has a file with suffix suffix
+	 * @param f - directory
+	 * @return
+	 */
+	public static boolean hasFileWithSuffix(File f, String suffix){
+		if(f.isDirectory()){
+			for(String s : f.list()){
+				if(s.endsWith(suffix)) return true;
+			}
+			return false;
+		}else{
+			return false;
+		}
+	}
+
+	/**
+	 * Gives back all dirs which contain a file with suffix fileSuffix
+	 * @param c
+	 * @param path
+	 * @param fileSuffix
+	 * @return
+	 * @throws FileNotFoundException If the sdcard is not available or the subdirectory "path" does not exist
+	 */
+	public static List<String> getDirsWithFileSuffix(Context c, String path, String fileSuffix) throws FileNotFoundException{
+		File[] files = getFilesFromRelativeDir(c,path);
+		ArrayList<String> ret = new ArrayList<String>();
+
+		for(File f : files){
+			if(hasFileWithSuffix(f, fileSuffix)) ret.add(f.getName());
+		}
+		return ret;
+	}
+
+	/**
+	 * Get all files from directory dir which have the given suffix
+	 * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dir" does not exist
+	 */
+	public static ArrayList<String> getFileNamesFromDirWithSuffix(Context c, String dir, String suffix, boolean removeSuffix) throws FileNotFoundException{
+		File[] files = FileUtils.getFilesFromRelativeDir(c, dir);
+		ArrayList<String> ret = new ArrayList<String>();
+		for(File file : files){
+			String s = file.getName();
+			if(s.endsWith(suffix)){
+				if(removeSuffix) ret.add(s.substring(0, s.length()-suffix.length()));
+				else ret.add(s);
+			}
+		}
+		return ret;
+	}
+
+	/**
+	 * Close a resource (possibly null), ignoring any IOException.
+	 */
+	public static void closeQuietly(Closeable c) {
+		if(c!=null) {
+			try {
+				c.close();
+			} catch(IOException e) {
+				Log.w(TAG, e);
+			}
+		}
+	}
+	
+	/**
+	 * Write all data from the input stream to the file, creating or overwriting it.
+	 * The input stream will be closed.
+	 * 
+	 * @throws IOException
+	 */
+	public static void writeStreamToFile(InputStream is, File file) throws IOException {
+		OutputStream os = null;
+		byte[] buffer = new byte[8192];
+		try {
+			os = new FileOutputStream(file);
+			int size;
+			while((size=is.read(buffer)) != -1) {
+				os.write(buffer, 0, size);
+			}
+			os.close(); // Important to close this non-quietly, in case of exceptions when flushing
+		} finally {
+			FileUtils.closeQuietly(is);
+			FileUtils.closeQuietly(os);
+		}
+	}
+	
+	/**
+	 * Moves resources pointed to by sourceResId (from @res/raw/) to the app's private data directory
+	 * @param c
+	 * @param sourceResId
+	 * @param directory
+	 */
+	public static void resRawToFilesDir(Context c, int sourceResId, int targetFilenames, String directory) throws IOException {
+		File targetDir = new File(c.getFilesDir(), directory);
+		targetDir.mkdirs();
+
+		//Get an array with the resource files ID
+		Resources resources = c.getResources();
+		TypedArray ta = resources.obtainTypedArray(sourceResId);
+		TypedArray filenames = resources.obtainTypedArray(targetFilenames);
+		for(int i = 0; i < ta.length(); i++){
+			int resId =  ta.getResourceId(i, 0);
+			String fileName = filenames.getString(i);
+			File f = new File(targetDir, fileName);
+			writeStreamToFile(resources.openRawResource(resId), f);
+		}
+	}
+
+	public static String readToString(InputStream is) throws IOException {
+		try {
+			ByteArrayOutputStream os = new ByteArrayOutputStream();
+			byte[] buffer = new byte[8192];
+			int size;
+			while((size=is.read(buffer)) != -1) {
+				os.write(buffer, 0, size);
+			}
+			return new String(os.toByteArray());
+		} finally {
+			closeQuietly(is);
+		}
+	}
+	
+	private static final char[] badFilenameChars = new char[] { '/', '\\', ':', '*', '?', '\"', '<', '>', '|', '.', '\0' };
+	
+	/**
+	 * Modify the given String so that it can be used as part of a filename
+	 * without causing problems from illegal/special characters.
+	 * 
+	 * The result should be similar to the input, but isn't necessarily
+	 * reversible.
+	 */
+	public static String replaceBadChars(String name) {
+		if (name == null || name.trim().length()==0) {
+			return "_";
+		}
+		name = name.trim();
+		for (char badChar : badFilenameChars) {
+			name = name.replace(badChar, '_');
+		}
+		return name;
+	}
+}