Repository: mit-cml/appinventor-sources
Issue: Reading images out of CloudDB is broken as of nb188

**Describe the bug**

As the title says, reading images is broken. Attempting to do so results in a CloudDB Error.

**Affects**

<!--
Please check off the part of the system that is affected by the bug.
-->

- [ ] Designer
- [ ] Blocks editor
- [x] Companion
- [x] Compiled apps
- [ ] Buildserver
- [ ] Debugging
- [ ] Other... (please describe)

**Expected behavior**

Images should be able to be read from CloudDB

**Steps to reproduce**

Attempt to read an image out of CloudDB


Changed files:
appinventor/components/src/com/google/appinventor/components/runtime/util/JsonUtil.java

diff --git a/appinventor/components/src/com/google/appinventor/components/runtime/util/JsonUtil.java b/appinventor/components/src/com/google/appinventor/components/runtime/util/JsonUtil.java
index 8f2e2f4c0..51b269d6a 100644
--- a/appinventor/components/src/com/google/appinventor/components/runtime/util/JsonUtil.java
+++ b/appinventor/components/src/com/google/appinventor/components/runtime/util/JsonUtil.java
@@ -6,6 +6,7 @@
 package com.google.appinventor.components.runtime.util;
 
 import android.content.Context;
+import android.net.Uri;
 import android.util.Base64;
 import android.util.Log;
 
@@ -445,19 +446,37 @@ public class JsonUtil {
    */
   private static String writeFile(Form context, final String input, String fileExtension) {
     String fullDirName = context.getDefaultPath(BINFILE_DIR);
-    File destDirectory = new File(fullDirName);
+    String preAmble = Uri.parse(context.getDefaultPath("")).getPath();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // What's going on here?                                                     //
+    //                                                                           //
+    // fullDirName is in fact the full path name of the BINFILE_DIR AS A URI!    //
+    // preAmble is the parent directory path as a plain path. FileWriteOperation //
+    // takes a path, but then uses the file scope to pre-pend the appropriate    //
+    // directory. However this is already included in the variable "dest"        //
+    // returned by File.createTempFile. So we use preAmble to remove it.         //
+    // Obscure for sure... but there it is!                                      //
+    ///////////////////////////////////////////////////////////////////////////////
+
+    File destDirectory = new File(Uri.parse(fullDirName).getPath());
     final Synchronizer<Boolean> result = new Synchronizer<>();
     File dest;
     try {
       dest = File.createTempFile("BinFile", "." + fileExtension, destDirectory);
       new FileWriteOperation(context, context, "Write",
-          dest.getAbsolutePath().replace(context.getDefaultPath(""), ""),
+          dest.getAbsolutePath().replace(preAmble, ""),
           context.DefaultFileScope(), false, true) {
         @Override
         protected boolean process(OutputStream stream) throws IOException {
-          stream.write(Base64.decode(input, Base64.DEFAULT));
-          result.wakeup(true);
-          return true;
+          try {
+            stream.write(Base64.decode(input, Base64.DEFAULT));
+            result.wakeup(true);
+            return true;
+          } catch (Exception e) {
+            result.caught(e);
+            return true;
+          }
         }
       }.run();
       result.waitfor();
@@ -473,7 +492,7 @@ public class JsonUtil {
         }
       }
     } catch (IOException e) {
-      throw new YailRuntimeError(e.getMessage(), "Write");
+      throw new YailRuntimeError(e.getMessage() + " destDirectory: " + destDirectory, "Write");
     }
     trimDirectory(20, destDirectory);
     return dest.getAbsolutePath();