cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject [16/50] git commit: Android: Refactor File API
Date Mon, 10 Feb 2014 23:22:42 GMT
Android: Refactor File API

Also gets content file copying working
Promote Filesystem interface to base class
Remove duplicated code; push to Filesystem class
Stream file output where possible between methods


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/eaeb5981
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/eaeb5981
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/eaeb5981

Branch: refs/heads/master
Commit: eaeb598124c01176c1c9191910b5761e56c00904
Parents: e7f83cb
Author: Ian Clelland <iclelland@chromium.org>
Authored: Wed Jan 8 13:24:50 2014 -0500
Committer: Ian Clelland <iclelland@chromium.org>
Committed: Thu Jan 9 14:03:38 2014 -0500

----------------------------------------------------------------------
 src/android/ContentFilesystem.java  | 148 +++++++++++++++++----------
 src/android/FileUtils.java          |  34 +++++--
 src/android/Filesystem.java         | 167 +++++++++++++++++++++++++++----
 src/android/LocalFilesystem.java    | 143 +++++++-------------------
 src/android/LocalFilesystemURL.java |   7 +-
 src/android/ReadFileCallback.java   |   7 --
 6 files changed, 308 insertions(+), 198 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/eaeb5981/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index 03a1939..535a2fe 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -1,26 +1,30 @@
 package org.apache.cordova.file;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
+import java.io.OutputStream;
 
 import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.CordovaWebView;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.ContentResolver;
 import android.database.Cursor;
+import android.net.Uri;
 import android.provider.MediaStore;
 
-public class ContentFilesystem implements Filesystem {
+public class ContentFilesystem extends Filesystem {
 
 	private CordovaInterface cordova;
+	private CordovaResourceApi resourceApi;
 	
-	public ContentFilesystem(CordovaInterface cordova) {
+	public ContentFilesystem(CordovaInterface cordova, CordovaWebView webView) {
 		this.cordova = cordova;
+		this.resourceApi = new CordovaResourceApi(webView.getContext(), webView.pluginManager);
 	}
 	
 	@Override
@@ -41,23 +45,37 @@ public class ContentFilesystem implements Filesystem {
           throw new IOException();
       }
       try {
-    	  JSONObject entry = new JSONObject();
-    	  entry.put("isFile", fp.isFile());
-    	  entry.put("isDirectory", fp.isDirectory());
-    	  entry.put("name", fp.getName());
-    	  entry.put("fullPath", "file://" + fp.getAbsolutePath());
-    	  // The file system can't be specified, as it would lead to an infinite loop.
-    	  entry.put("filesystem", FileUtils.APPLICATION);
-          return entry;
+    	  return makeEntryForPath(inputURL.fullPath, inputURL.filesystemType, fp.isDirectory());
       } catch (JSONException e) {
     	  throw new IOException();
       }
 	}
-
-	@Override
+	
+    @Override
 	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
-			String fileName, JSONObject options, boolean directory) throws IOException {
-		throw new IOException("Cannot create content url");
+			String fileName, JSONObject options, boolean directory) throws IOException, TypeMismatchException,
JSONException {
+        if (options != null) {
+            if (options.optBoolean("create")) {
+        		throw new IOException("Cannot create content url");
+            }
+        }
+        LocalFilesystemURL requestedURL = new LocalFilesystemURL(Uri.withAppendedPath(inputURL.URL,
fileName));
+        File fp = new File(this.filesystemPathForURL(requestedURL));
+        if (!fp.exists()) {
+            throw new FileNotFoundException("path does not exist");
+        }
+        if (directory) {
+            if (fp.isFile()) {
+                throw new TypeMismatchException("path doesn't exist or is file");
+            }
+        } else {
+            if (fp.isDirectory()) {
+                throw new TypeMismatchException("path doesn't exist or is directory");
+            }
+        }
+        // Return the directory
+        return makeEntryForPath(requestedURL.fullPath, requestedURL.filesystemType, directory);
+
 	}
 
 	@Override
@@ -93,55 +111,72 @@ public class ContentFilesystem implements Filesystem {
 
 	@Override
 	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException
{
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL)
-			throws IOException {
-		LocalFilesystemURL newURL = new LocalFilesystemURL(inputURL.URL);
-
-    	if (!("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath))) {
-    		int end = inputURL.fullPath.endsWith("/") ? 1 : 0;
-            int lastPathStartsAt = inputURL.fullPath.lastIndexOf('/', inputURL.fullPath.length()-end)+1;
-    		newURL.fullPath = newURL.fullPath.substring(0,lastPathStartsAt);
-    	}
-    	return getEntryForLocalURL(newURL);
+		String path = filesystemPathForURL(inputURL);
+		if (path == null) {
+			throw new FileNotFoundException();
+		}	
+		File file = new File(path);
+        JSONObject metadata = new JSONObject();
+        try {
+        	metadata.put("size", file.length());
+        	metadata.put("type", resourceApi.getMimeType(inputURL.URL));
+        	metadata.put("name", file.getName());
+        	metadata.put("fullPath", inputURL.fullPath);
+        	metadata.put("lastModifiedDate", file.lastModified());
+        } catch (JSONException e) {
+        	return null;
+        }
+        return metadata;
 	}
 
 	@Override
 	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
 			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move)
-			throws IOException, InvalidModificationException, JSONException,
-			NoModificationAllowedException, FileExistsException {
-		// TODO Auto-generated method stub
-		return null;
+                    throws IOException, InvalidModificationException, JSONException,
+                    NoModificationAllowedException, FileExistsException {
+        if (LocalFilesystem.class.isInstance(srcFs)) {
+            /* Same FS, we can shortcut with CordovaResourceApi operations */
+            // Figure out where we should be copying to
+            final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL,
destURL);
+
+            OutputStream os = resourceApi.openOutputStream(destURL.URL);
+            CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcURL.URL);
+            if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
+                throw new NoModificationAllowedException("Cannot move file at source URL");
+            }
+            try {
+                resourceApi.copyResource(ofrr, os);
+            } catch (IOException e) {
+                throw new IOException("Cannot read file at source URL");
+            }
+            if (move) {
+                srcFs.removeFileAtLocalURL(srcURL);
+            }
+            return makeEntryForURL(destinationURL, false);
+        } else {
+            // Need to copy the hard way
+            return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
+		}
 	}
 
+    
 	@Override
-	public void readFileAtURL(LocalFilesystemURL inputURL, int start, int end,
+    public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
 			ReadFileCallback readFileCallback) throws IOException {
-		int numBytesToRead = end - start;
-		byte[] bytes = new byte[numBytesToRead];
-		String contentType;
-		
-		File file = new File(this.filesystemPathForURL(inputURL));
-		contentType = FileHelper.getMimeTypeForExtension(file.getAbsolutePath());
-		
-		InputStream inputStream = new FileInputStream(file);
-		int numBytesRead = 0;
+		CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(inputURL.URL);
+        if (end < 0) {
+            end = ofrr.length;
+        }
+        long numBytesToRead = end - start;
 		try {
 			if (start > 0) {
-				inputStream.skip(start);
-			}
-			while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead,
numBytesToRead)) >= 0) {
-				numBytesToRead -= numBytesRead;
+                ofrr.inputStream.skip(start);
 			}
+            LimitedInputStream inputStream = new LimitedInputStream(ofrr.inputStream, numBytesToRead);
+            readFileCallback.handleData(inputStream, ofrr.mimeType);
 		} finally {
-			inputStream.close();
+            ofrr.inputStream.close();
 		}
-		readFileCallback.handleData(bytes, contentType);
 	}
 
 	@Override
@@ -178,7 +213,7 @@ public class ContentFilesystem implements Filesystem {
 
 	@Override
 	public LocalFilesystemURL URLforFilesystemPath(String path) {
-		// TODO Auto-generated method stub
+		// Returns null as we don't support reverse mapping back to content:// URLs
 		return null;
 	}
 
@@ -188,4 +223,11 @@ public class ContentFilesystem implements Filesystem {
 		File file = new File(path);
 		return file.exists();
 	}
-}
+
+	@Override
+	OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL)
+			throws IOException {
+		OutputStream os = resourceApi.openOutputStream(inputURL.URL);
+		return os;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/eaeb5981/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 20a2700..d1c1b59 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -20,7 +20,6 @@ package org.apache.cordova.file;
 
 import android.net.Uri;
 import android.os.Environment;
-import android.provider.MediaStore;
 import android.util.Base64;
 import android.util.Log;
 
@@ -34,9 +33,11 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URLDecoder;
 import java.util.ArrayList;
@@ -68,6 +69,7 @@ public class FileUtils extends CordovaPlugin {
     public static int PERSISTENT = 1;
     public static int RESOURCE = 2;
     public static int APPLICATION = 3;
+    public static int CONTENT = 4;
     
     // This field exists only to support getEntry, below, which has been deprecated
     private static FileUtils filePlugin;
@@ -99,8 +101,9 @@ public class FileUtils extends CordovaPlugin {
     	fp.mkdirs();
     	this.filesystems.add(new LocalFilesystem(cordova, "temporary", tempRoot));
     	this.filesystems.add(new LocalFilesystem(cordova, "persistent", persistentRoot));
-    	this.filesystems.add(null);
-    	this.filesystems.add(new ContentFilesystem(cordova));
+    	this.filesystems.add(null); // Hold for 'resource' FS
+    	this.filesystems.add(null); // Hold for 'application' FS
+    	this.filesystems.add(new ContentFilesystem(cordova, webView));
 
     	// Initialize static plugin reference for deprecated getEntry method
     	if (filePlugin == null) {
@@ -764,22 +767,35 @@ public class FileUtils extends CordovaPlugin {
         		throw new MalformedURLException("No installed handlers for this URL");
         	}
         
-            fs.readFileAtURL(inputURL, start, end, new ReadFileCallback() {
-            	public void handleData(byte[] bytes, String contentType) {
+            fs.readFileAtURL(inputURL, start, end, new Filesystem.ReadFileCallback() {
+                public void handleData(InputStream inputStream, String contentType) {
             		try {
+                        ByteArrayOutputStream os = new ByteArrayOutputStream();
+                        final int BUFFER_SIZE = 8192;
+                        byte[] buffer = new byte[BUFFER_SIZE];
+                        
+                        for (;;) {
+                            int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+                            
+                            if (bytesRead <= 0) {
+                                break;
+                            }
+                            os.write(buffer, 0, bytesRead);
+                        }
+                                
             			PluginResult result;
             			switch (resultType) {
             			case PluginResult.MESSAGE_TYPE_STRING:
-            				result = new PluginResult(PluginResult.Status.OK, new String(bytes, encoding));
+                            result = new PluginResult(PluginResult.Status.OK, os.toString(encoding));
             				break;
             			case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
-            				result = new PluginResult(PluginResult.Status.OK, bytes);
+                            result = new PluginResult(PluginResult.Status.OK, os.toByteArray());
             				break;
             			case PluginResult.MESSAGE_TYPE_BINARYSTRING:
-            				result = new PluginResult(PluginResult.Status.OK, bytes, true);
+                            result = new PluginResult(PluginResult.Status.OK, os.toByteArray(),
true);
             				break;
             			default: // Base64.
-            			byte[] base64 = Base64.encode(bytes, Base64.NO_WRAP);
+                        byte[] base64 = Base64.encode(os.toByteArray(), Base64.NO_WRAP);
             			String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
             			result = new PluginResult(PluginResult.Status.OK, s);
             			}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/eaeb5981/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index ba2c7bd..1f869c9 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -1,47 +1,174 @@
 package org.apache.cordova.file;
 
 import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
-import org.apache.cordova.CordovaInterface;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-public interface Filesystem {
+public abstract class Filesystem {
 
-	JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException;
+	public interface ReadFileCallback {
+		public void handleData(InputStream inputStream, String contentType) throws IOException;
+	}
 
-	JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String fileName,
-			JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException,
EncodingException, JSONException;
+	public static JSONObject makeEntryForPath(String path, int fsType, Boolean isDir)
+			throws JSONException {
+        JSONObject entry = new JSONObject();
 
-	boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException,
NoModificationAllowedException;
+        int end = path.endsWith("/") ? 1 : 0;
+        String[] parts = path.substring(0,path.length()-end).split("/");
+        String name = parts[parts.length-1];
+        entry.put("isFile", !isDir);
+        entry.put("isDirectory", isDir);
+        entry.put("name", name);
+        entry.put("fullPath", path);
+        // The file system can't be specified, as it would lead to an infinite loop,
+        // but the filesystem type can
+        entry.put("filesystem", fsType);
 
-	boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException,
NoModificationAllowedException;
+        return entry;
 
-	JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
+    }
 
-	JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
+    public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Boolean isDir)
throws JSONException {
+        return makeEntryForPath(inputURL.fullPath, inputURL.filesystemType, isDir);
+    }
 
-	JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException;
+	abstract JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException;
 
-	JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
-			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException,
JSONException, NoModificationAllowedException, FileExistsException;
+	abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String fileName,
+			JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException,
EncodingException, JSONException;
 
-	void readFileAtURL(LocalFilesystemURL inputURL, int start, int end,
+	abstract boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException,
NoModificationAllowedException;
+
+	abstract boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException,
NoModificationAllowedException;
+
+	abstract JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
+
+	abstract JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
+
+	public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException {
+		LocalFilesystemURL newURL = new LocalFilesystemURL(inputURL.URL);
+	
+		if (!("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath))) {
+			int end = inputURL.fullPath.endsWith("/") ? 1 : 0;
+	        int lastPathStartsAt = inputURL.fullPath.lastIndexOf('/', inputURL.fullPath.length()-end)+1;
+			newURL.fullPath = newURL.fullPath.substring(0,lastPathStartsAt);
+		}
+		return getEntryForLocalURL(newURL);
+	}
+
+    protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL,
LocalFilesystemURL destURL) {
+        // I know this looks weird but it is to work around a JSON bug.
+        if ("null".equals(newName) || "".equals(newName)) {
+            newName = srcURL.URL.getLastPathSegment();;
+        }
+
+        String newDest = destURL.URL.toString();
+        if (newDest.endsWith("/")) {
+            newDest = newDest + newName;
+        } else {
+            newDest = newDest + "/" + newName;
+        }
+        return new LocalFilesystemURL(newDest);
+    }
+    
+	/* Read a source URL (possibly from a different filesystem, srcFs,) and copy it to
+	 * the destination URL on this filesystem, optionally with a new filename.
+	 * If move is true, then this method should either perform an atomic move operation
+	 * or remove the source file when finished.
+	 */
+    JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
+            Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException,
InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException
{
+        // This is "the hard way" -- transfer data between arbitrary filesystem urls/
+        // Gets an input stream from src, and writes its contents to an output stream
+        // from dest.
+
+        // First, check to see that we can do it
+        if (!move || srcFs.canRemoveFileAtLocalURL(srcURL)) {
+            final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL);
+            srcFs.readFileAtURL(srcURL, 0, -1, new ReadFileCallback() {
+                public void handleData(InputStream inputStream, String contentType) throws
IOException {
+                    if (inputStream != null) {
+                        //write data to file
+                        OutputStream os = getOutputStreamForURL(destination);
+                        final int BUFFER_SIZE = 8192;
+                        byte[] buffer = new byte[BUFFER_SIZE];
+
+                        for (;;) {
+                            int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+
+                            if (bytesRead <= 0) {
+                                break;
+                            }
+                            os.write(buffer, 0, bytesRead);
+                        }
+                        os.close();
+                    } else {
+                        throw new IOException("Cannot read file at source URL");
+                    }
+                }
+            });
+            if (move) {
+                // Delete original
+                srcFs.removeFileAtLocalURL(srcURL);
+            }
+            return makeEntryForURL(destination, false);
+        } else {
+            throw new NoModificationAllowedException("Cannot move file at source URL");
+        }
+    }
+
+    abstract OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws IOException;
+
+    abstract void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
 			ReadFileCallback readFileCallback) throws IOException;
 
-	long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset,
+	abstract long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset,
 			boolean isBinary) throws NoModificationAllowedException, IOException;
 
-	long truncateFileAtURL(LocalFilesystemURL inputURL, long size)
+	abstract long truncateFileAtURL(LocalFilesystemURL inputURL, long size)
 			throws IOException, NoModificationAllowedException;
 
 	// This method should return null if filesystem urls cannot be mapped to paths
-	String filesystemPathForURL(LocalFilesystemURL url);
-
-	LocalFilesystemURL URLforFilesystemPath(String path);
-
-	boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL);
+	abstract String filesystemPathForURL(LocalFilesystemURL url);
+
+	abstract LocalFilesystemURL URLforFilesystemPath(String path);
+
+	abstract boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL);
+
+    protected class LimitedInputStream extends FilterInputStream {
+        long numBytesToRead;
+        public LimitedInputStream(InputStream in, long numBytesToRead) {
+            super(in);
+            this.numBytesToRead = numBytesToRead;
+        }
+        @Override
+        public int read() throws IOException {
+            if (numBytesToRead <= 0) {
+                return -1;
+            }
+            numBytesToRead--;
+            return in.read();
+        }
+        @Override
+        public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException
{
+            if (numBytesToRead <= 0) {
+                return -1;
+            }
+            int bytesToRead = byteCount;
+            if (byteCount > numBytesToRead) {
+                bytesToRead = (int)numBytesToRead; // Cast okay; long is less than int here.
+            }
+            int numBytesRead = in.read(buffer, byteOffset, bytesToRead);
+            numBytesToRead -= numBytesRead;
+            return numBytesRead;
+        }
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/eaeb5981/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 6c16e45..f0d919f 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -7,6 +7,7 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.RandomAccessFile;
 import java.nio.channels.FileChannel;
 
@@ -18,7 +19,7 @@ import org.json.JSONObject;
 import android.util.Base64;
 import android.net.Uri;
 
-public class LocalFilesystem implements Filesystem {
+public class LocalFilesystem extends Filesystem {
 
 	private String name;
 	private String fsRoot;
@@ -55,24 +56,6 @@ public class LocalFilesystem implements Filesystem {
 	    return null;
 	}
 
-    public static JSONObject makeEntryForPath(String path, int fsType, Boolean isDir) throws
JSONException {
-        JSONObject entry = new JSONObject();
-
-        int end = path.endsWith("/") ? 1 : 0;
-        String[] parts = path.substring(0,path.length()-end).split("/");
-        String name = parts[parts.length-1];
-        entry.put("isFile", !isDir);
-        entry.put("isDirectory", isDir);
-        entry.put("name", name);
-        entry.put("fullPath", path);
-        // The file system can't be specified, as it would lead to an infinite loop,
-        // but the filesystem type can
-        entry.put("filesystem", fsType);
-
-        return entry;
-    	
-    }
-    
     public JSONObject makeEntryForFile(File file, int fsType) throws JSONException {
     	String path = this.fullPathForFilesystemPath(file.getAbsolutePath());
     	if (path != null) {
@@ -240,18 +223,6 @@ public class LocalFilesystem implements Filesystem {
         return metadata;
 	}
 
-	@Override
-	public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException {
-		LocalFilesystemURL newURL = new LocalFilesystemURL(inputURL.URL);
-
-    	if (!("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath))) {
-    		int end = inputURL.fullPath.endsWith("/") ? 1 : 0;
-            int lastPathStartsAt = inputURL.fullPath.lastIndexOf('/', inputURL.fullPath.length()-end)+1;
-    		newURL.fullPath = newURL.fullPath.substring(0,lastPathStartsAt);
-    	}
-    	return getEntryForLocalURL(newURL);
-	}
-
     /**
      * Check to see if the user attempted to copy an entry into its parent without changing
its name,
      * or attempted to copy a directory into a directory that it contains directly or indirectly.
@@ -272,31 +243,6 @@ public class LocalFilesystem implements Filesystem {
         return false;
     }
 
-
-    /**
-     * Creates the destination File object based on name passed in
-     *
-     * @param newName for the file directory to be called, if null use existing file name
-     * @param fp represents the source file
-     * @param destination represents the destination file
-     * @return a File object that represents the destination
-     */
-    private File createDestination(String newName, String oldName, File destination) {
-        File destFile = null;
-
-        // I know this looks weird but it is to work around a JSON bug.
-        if ("null".equals(newName) || "".equals(newName)) {
-            newName = null;
-        }
-
-        if (newName != null) {
-            destFile = new File(destination.getAbsolutePath() + File.separator + newName);
-        } else {
-            destFile = new File(destination.getAbsolutePath() + File.separator + oldName);
-        }
-        return destFile;
-    }
-
     /**
      * Copy a file
      *
@@ -473,92 +419,71 @@ public class LocalFilesystem implements Filesystem {
             throw new FileNotFoundException("The source does not exist");
         }
         
-        // Figure out where we should be copying to
-        String originalName = srcURL.URL.getLastPathSegment();
-        final File destination = createDestination(newName, originalName, destinationDir);
-
 	    if (LocalFilesystem.class.isInstance(srcFs)) {
 	        /* Same FS, we can shortcut with NSFileManager operations */
+
+            // Figure out where we should be copying to
+            final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL,
destURL);
+
 	        String srcFilesystemPath = this.filesystemPathForURL(srcURL);
-	        File source = new File(srcFilesystemPath);
+            File sourceFile = new File(srcFilesystemPath);
+            String destFilesystemPath = this.filesystemPathForURL(destinationURL);
+            File destinationFile = new File(destFilesystemPath);
 
-	        if (!source.exists()) {
+            if (!sourceFile.exists()) {
 	            // The file/directory we are copying doesn't exist so we should fail.
 	            throw new FileNotFoundException("The source does not exist");
 	        }
 
 	        // Check to see if source and destination are the same file
-	        if (source.getAbsolutePath().equals(destination.getAbsolutePath())) {
+            if (sourceFile.getAbsolutePath().equals(destinationFile.getAbsolutePath())) {
 	            throw new InvalidModificationException("Can't copy a file onto itself");
 	        }
 
-	        if (source.isDirectory()) {
+            if (sourceFile.isDirectory()) {
 	            if (move) {
-	                return moveDirectory(source, destination, destURL.filesystemType);
+                    return moveDirectory(sourceFile, destinationFile, destURL.filesystemType);
 	            } else {
-	                return copyDirectory(source, destination, destURL.filesystemType);
+                    return copyDirectory(sourceFile, destinationFile, destURL.filesystemType);
 	            }
 	        } else {
 	            if (move) {
-	                return moveFile(source, destination, destURL.filesystemType);
+                    return moveFile(sourceFile, destinationFile, destURL.filesystemType);
 	            } else {
-	                return copyFile(source, destination, destURL.filesystemType);
+                    return copyFile(sourceFile, destinationFile, destURL.filesystemType);
 	            }
 	        }
 	    	
 	    } else {
 	        // Need to copy the hard way
-	    	// First, check to see that we can do it
-	    	if (!move || srcFs.canRemoveFileAtLocalURL(srcURL)) {
-	    		srcFs.readFileAtURL(srcURL, 0, -1, new ReadFileCallback() {
-	    			public void handleData(byte[] data, String contentType) throws IOException {
-	    				if (data != null) {
-	    					//write data to file
-	    					FileOutputStream os = new FileOutputStream(destination);
-	    					os.write(data);
-	    					os.close();
-	    				} else {
-	    					throw new IOException("Cannot read file at source URL");
-	    				}
-	    			}
-	    		});
-				if (move) {
-					// Delete original
-					srcFs.removeFileAtLocalURL(srcURL);
-				}
-		        return makeEntryForFile(destination, destURL.filesystemType);
-	    	} else {
-	    		throw new NoModificationAllowedException("Cannot move file at source URL");
-	    	}
+            return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
     	}
 	}
 
 	@Override
-	public void readFileAtURL(LocalFilesystemURL inputURL, int start, int end,
+    public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
 			ReadFileCallback readFileCallback) throws IOException {
 
-		int numBytesToRead = end - start;
-		byte[] bytes = new byte[numBytesToRead];
-		String contentType;
-		
 		File file = new File(this.filesystemPathForURL(inputURL));
-		contentType = FileHelper.getMimeTypeForExtension(file.getAbsolutePath());
+        String contentType = FileHelper.getMimeTypeForExtension(file.getAbsolutePath());
 		
-		InputStream inputStream = new FileInputStream(file);
-		int numBytesRead = 0;
+        if (end < 0) {
+            end = file.length();
+        }
+        long numBytesToRead = end - start;
+
+        InputStream rawInputStream = new FileInputStream(file);
 		try {
 			if (start > 0) {
-				inputStream.skip(start);
-			}
-			while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead,
numBytesToRead)) >= 0) {
-				numBytesToRead -= numBytesRead;
+                rawInputStream.skip(start);
 			}
+            LimitedInputStream inputStream = new LimitedInputStream(rawInputStream, numBytesToRead);
+            readFileCallback.handleData(inputStream, contentType);
 		} finally {
-			inputStream.close();
+            rawInputStream.close();
 		}
-		readFileCallback.handleData(bytes, contentType);
 	}
-
+    
 	@Override
 	public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
 			int offset, boolean isBinary) throws IOException, NoModificationAllowedException {
@@ -630,4 +555,12 @@ public class LocalFilesystem implements Filesystem {
 		return file.exists();
 	}
 
+	@Override
+	OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws FileNotFoundException
{
+		String path = filesystemPathForURL(inputURL);
+		File file = new File(path);
+		FileOutputStream os = new FileOutputStream(file);
+		return os;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/eaeb5981/src/android/LocalFilesystemURL.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystemURL.java b/src/android/LocalFilesystemURL.java
index 0dc547e..1065382 100644
--- a/src/android/LocalFilesystemURL.java
+++ b/src/android/LocalFilesystemURL.java
@@ -24,8 +24,8 @@ public class LocalFilesystemURL {
 		if (fsType == FileUtils.PERSISTENT) {
 			return URL.getPath().substring(11);
 		}
-		if (fsType == FileUtils.APPLICATION) {
-			return URL.getPath();
+		if (fsType == FileUtils.CONTENT) {
+			return '/' + URL.getHost() + URL.getPath();
 		}
 		return null;
 	}
@@ -41,7 +41,7 @@ public class LocalFilesystemURL {
 				}
 			}
 		} else if ("content".equals(URL.getScheme())) {
-			return FileUtils.APPLICATION;
+			return FileUtils.CONTENT;
 		}
 		return -1;
 	}
@@ -50,5 +50,4 @@ public class LocalFilesystemURL {
 		this(Uri.parse(strURL));
 	}
 	
-	
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/eaeb5981/src/android/ReadFileCallback.java
----------------------------------------------------------------------
diff --git a/src/android/ReadFileCallback.java b/src/android/ReadFileCallback.java
deleted file mode 100644
index b8ba02d..0000000
--- a/src/android/ReadFileCallback.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.apache.cordova.file;
-
-import java.io.IOException;
-
-public interface ReadFileCallback {
-	public void handleData(byte[] data, String contentType) throws IOException;
-}


Mime
View raw message