CB-2432 CB-3185 CB-5975: Correctly handle content:// urls especially when 
non-local-to-device


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/c56b3303
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/c56b3303
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/c56b3303

Branch: refs/heads/master
Commit: c56b33035edcfae3327369cb64c4e6818e3d84b4
Parents: c2df6d6
Author: Ian Clelland <[email protected]>
Authored: Fri Feb 14 10:15:12 2014 -0500
Committer: Ian Clelland <[email protected]>
Committed: Fri Feb 14 10:15:12 2014 -0500

----------------------------------------------------------------------
 src/android/ContentFilesystem.java  | 121 ++++++++++++++++++++-----------
 src/android/FileUtils.java          |   6 +-
 src/android/LocalFilesystemURL.java |   4 +-
 www/android/FileSystem.js           |   2 +-
 4 files changed, 86 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/c56b3303/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java 
b/src/android/ContentFilesystem.java
index f116b31..5c34ea2 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -16,6 +16,7 @@ import android.content.ContentResolver;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore;
+import android.provider.OpenableColumns;
 
 public class ContentFilesystem extends Filesystem {
 
@@ -29,27 +30,22 @@ public class ContentFilesystem extends Filesystem {
        }
        
        @Override
-    @SuppressWarnings("deprecation")
        public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) 
throws IOException {
-      File fp = null;
-
-          Cursor cursor = 
this.cordova.getActivity().managedQuery(inputURL.URL, new String[] { 
MediaStore.Images.Media.DATA }, null, null, null);
-          // Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data"
-          int column_index = 
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
-          cursor.moveToFirst();
-          fp = new File(cursor.getString(column_index));
-
-      if (!fp.exists()) {
-          throw new FileNotFoundException();
-      }
-      if (!fp.canRead()) {
-          throw new IOException();
-      }
-      try {
-         return makeEntryForPath(inputURL.fullPath, inputURL.filesystemName, 
fp.isDirectory());
-      } catch (JSONException e) {
-         throw new IOException();
-      }
+               // Get the cursor to validate that the file exists
+               Cursor cursor = openCursorForURL(inputURL);
+               try {
+                       if (cursor == null || !cursor.moveToFirst()) {
+                               throw new FileNotFoundException();
+                       }
+               } finally {
+                       if (cursor != null)
+                               cursor.close();
+               }
+               try {
+                       return makeEntryForPath(inputURL.fullPath, 
inputURL.filesystemName, false /*fp.isDirectory()*/);
+               } catch (JSONException e) {
+                       throw new IOException();
+               }
        }
        
     @Override
@@ -112,18 +108,28 @@ public class ContentFilesystem extends Filesystem {
 
        @Override
        public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL 
inputURL) throws FileNotFoundException {
-               String path = filesystemPathForURL(inputURL);
-               if (path == null) {
-                       throw new FileNotFoundException();
-               }       
-               File file = new File(path);
+               Integer size = null;
+               Integer lastModified = null;
+        Cursor cursor = openCursorForURL(inputURL);
+        try {
+               if (cursor != null && cursor.moveToFirst()) {
+                       size = resourceSizeForCursor(cursor);
+                       lastModified = lastModifiedDateForCursor(cursor);
+               } else {
+                       throw new FileNotFoundException();
+               }
+        } finally {
+               if (cursor != null)
+                       cursor.close();
+        }
+
         JSONObject metadata = new JSONObject();
         try {
-               metadata.put("size", file.length());
+               metadata.put("size", size);
                metadata.put("type", resourceApi.getMimeType(inputURL.URL));
-               metadata.put("name", file.getName());
+               metadata.put("name", inputURL.filesystemName);
                metadata.put("fullPath", inputURL.fullPath);
-               metadata.put("lastModifiedDate", file.lastModified());
+               metadata.put("lastModifiedDate", lastModified);
         } catch (JSONException e) {
                return null;
         }
@@ -191,25 +197,56 @@ public class ContentFilesystem extends Filesystem {
         throw new NoModificationAllowedException("Couldn't truncate file given 
its content URI");
        }
 
-    @Override
-    public String filesystemPathForURL(LocalFilesystemURL url) {
+       protected Cursor openCursorForURL(LocalFilesystemURL url) {
+        ContentResolver contentResolver = 
this.cordova.getActivity().getContentResolver();
+        Cursor cursor = contentResolver.query(url.URL, null, null, null, null);
+        return cursor;
+       }
+
+       protected String filesystemPathForCursor(Cursor cursor) {
         final String[] LOCAL_FILE_PROJECTION = { MediaStore.Images.Media.DATA 
};
+        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
+        if (columnIndex != -1) {
+            return cursor.getString(columnIndex);
+        }
+        return null;
+       }
 
-        ContentResolver contentResolver = 
this.cordova.getActivity().getContentResolver();
-        Cursor cursor = contentResolver.query(url.URL, LOCAL_FILE_PROJECTION, 
null, null, null);
-        if (cursor != null) {
-            try {
-                int columnIndex = 
cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
-                if (columnIndex != -1 && cursor.getCount() > 0) {
-                    cursor.moveToFirst();
-                    String path = cursor.getString(columnIndex);
-                    return path;
-                }
-            } finally {
-                cursor.close();
+       protected Integer resourceSizeForCursor(Cursor cursor) {
+        int columnIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
+        if (columnIndex != -1) {
+            String sizeStr = cursor.getString(columnIndex);
+            if (sizeStr != null) {
+               return Integer.parseInt(sizeStr,10);
+            }
+        }
+        return null;
+       }
+       
+       protected Integer lastModifiedDateForCursor(Cursor cursor) {
+        final String[] LOCAL_FILE_PROJECTION = { 
MediaStore.MediaColumns.DATE_MODIFIED };
+        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
+        if (columnIndex != -1) {
+            String dateStr = cursor.getString(columnIndex);
+            if (dateStr != null) {
+               return Integer.parseInt(dateStr,10);
             }
         }
         return null;
+       }
+
+    @Override
+    public String filesystemPathForURL(LocalFilesystemURL url) {
+        Cursor cursor = openCursorForURL(url);
+        try {
+               if (cursor != null && cursor.moveToFirst()) {
+                       return filesystemPathForCursor(cursor);
+               }
+        } finally {
+            if (cursor != null)
+               cursor.close();
+        }
+        return null;
     }
 
        @Override

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/c56b3303/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 6acc101..ca643b3 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -501,14 +501,14 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject resolveLocalFileSystemURI(String url) throws 
IOException, JSONException {
-        String decoded = URLDecoder.decode(url, "UTF-8");
        LocalFilesystemURL inputURL;
        if (url == null) {
                throw new MalformedURLException("Unrecognized filesystem URL");
        }
        
                /* Backwards-compatibility: Check for file:// urls */
-       if (decoded.startsWith("file://")) {
+       if (url.startsWith("file://")) {
+            String decoded = URLDecoder.decode(url, "UTF-8");
                /* This looks like a file url. Get the path, and see if any 
handlers recognize it. */
                String path;
                int questionMark = decoded.indexOf("?");
@@ -519,7 +519,7 @@ public class FileUtils extends CordovaPlugin {
                }
                inputURL = this.filesystemURLforLocalPath(path);
        } else {
-               inputURL = new LocalFilesystemURL(decoded);
+               inputURL = new LocalFilesystemURL(url);
        }
 
         try {

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/c56b3303/src/android/LocalFilesystemURL.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystemURL.java 
b/src/android/LocalFilesystemURL.java
index 8583a8f..f18a03a 100644
--- a/src/android/LocalFilesystemURL.java
+++ b/src/android/LocalFilesystemURL.java
@@ -26,7 +26,9 @@ public class LocalFilesystemURL {
             }
                        return path.substring(path.indexOf('/', 1));
                } else if ("content".equals(URL.getScheme())) {
-                       return '/' + URL.getHost() + URL.getPath();
+                       String path = '/' + URL.getHost() + URL.getPath();
+                       // Re-encode path component to handle Android 4.4+ 
Content URLs
+                       return Uri.encode(path,"/");
                }
                return null;
        }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/c56b3303/www/android/FileSystem.js
----------------------------------------------------------------------
diff --git a/www/android/FileSystem.js b/www/android/FileSystem.js
index 73332f8..fde9c7a 100644
--- a/www/android/FileSystem.js
+++ b/www/android/FileSystem.js
@@ -24,7 +24,7 @@ FILESYSTEM_PROTOCOL = "cdvfile";
 module.exports = {
     __format__: function(fullPath) {
         if (this.name === 'content') {
-            return 'content:/' + encodeURI(fullPath);
+            return 'content:/' + fullPath;
         }
         var path = 
('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/');
         return FILESYSTEM_PROTOCOL + '://localhost' + path;

Reply via email to