2003/09/30 21:30:49
[org.ibex.core.git] / src / org / xwt / Res.java
index bb63940..cd0fc86 100644 (file)
@@ -6,6 +6,7 @@ import java.util.*;
 import java.util.zip.*;
 import org.xwt.js.*;
 import org.xwt.util.*;
+import org.bouncycastle.util.encoders.Base64;
 
 /** base class for XWT resources */
 public abstract class Res extends JS {
@@ -15,6 +16,8 @@ public abstract class Res extends JS {
     /** cache of subresources so that the equality operator works on them */
     private Hash refCache = null;
 
+    public Template t = null;
+
     public Res getParent() { return null; }
 
     /** returns an InputStream containing the Resource's contents */
@@ -45,19 +48,37 @@ public abstract class Res extends JS {
     public static Res stringToRes(String url) { return stringToRes(url, false); }
     public static Res stringToRes(String url, boolean permitLocalFilesystem) {
         if (url.indexOf('!') != -1)
-            return (Res)(new Zip(stringToRes(url.substring(0, url.lastIndexOf('!')))).get(url.substring(url.lastIndexOf('!') + 1)));
+            return (Res)(new Zip(stringToRes(url.substring(0, url.lastIndexOf('!')))).
+                         get(url.substring(url.lastIndexOf('!') + 1)));
         if (url.startsWith("http://")) return new HTTP(url);
         if (url.startsWith("https://")) return new HTTP(url);
         if (url.startsWith("file:") && permitLocalFilesystem) return new File(url.substring(5));
         if (url.startsWith("cab:")) return new CAB(stringToRes(url.substring(4)));
-        throw new JS.Exn("invalid resource specifier");
+        if (url.startsWith("data:")) return new ByteArray(Base64.decode(url.substring(5)));
+        if (url.startsWith("utf8:")) return new ByteArray(url.substring(5).getBytes());
+        throw new JS.Exn("invalid resource specifier " + url);
+    }
+
+    /** subclass from this if you want a CachedInputStream for each path */
+    public static abstract class CachedRes extends Res {
+        private Hash cachedInputStreams = new Hash();
+        abstract InputStream _getInputStream(String path) throws IOException;
+        public final InputStream getInputStream(String path) throws IOException {
+            CachedInputStream cis = (CachedInputStream)cachedInputStreams.get(path);
+            if (cis == null) {
+                cis = new CachedInputStream(_getInputStream(path));
+                cachedInputStreams.put(path, cis);
+            }
+            return cis.getInputStream();
+        }
     }
 
     /** HTTP or HTTPS resource */
-    public static class HTTP extends Res {
+    public static class HTTP extends CachedRes {
         private String url;
         HTTP(String url) { this.url = url; }
-        public InputStream getInputStream(String path) throws IOException { return new org.xwt.HTTP(url + path).GET(); }
+        public InputStream _getInputStream(String path) throws IOException {
+            return new org.xwt.HTTP(url + path).GET(); }
     }
 
     /** byte arrays */
@@ -135,6 +156,34 @@ public abstract class Res extends JS {
         public Res getParent() { return graftee.getParent(); }
     }
 
+    /** shadow resource which replaces the graft */
+    public static class ProgressWatcher extends Res {
+        Res watchee;
+        JS.Callable callback;
+        ProgressWatcher(Res watchee, JS.Callable callback) { this.watchee = watchee; this.callback = callback; }
+        public InputStream getInputStream(String s) throws IOException {
+            return new FilterInputStream(watchee.getInputStream(s)) {
+                    int bytesDownloaded = 0;
+                    public int read() throws IOException {
+                        int ret = super.read();
+                        if (ret != -1) bytesDownloaded++;
+                        return ret;
+                    }
+                    public int read(byte[] b, int off, int len) throws IOException {
+                        int ret = super.read(b, off, len);
+                        if (ret != 1) bytesDownloaded += ret;
+                        ThreadMessage.newthread(new JS.Callable() { public Object call(JS.Array a) {
+                            JS.Array args = new JS.Array();
+                            args.addElement(new Integer(bytesDownloaded));
+                            callback.call(args);
+                            return null;
+                        } });
+                        return ret;
+                    }
+                };
+        }
+    }
+
     /** unpacks a Microsoft CAB file (possibly embedded in another file; we scan for 'MSCF' */
     public static class CAB extends Res {
         private Res parent;
@@ -143,22 +192,13 @@ public abstract class Res extends JS {
             return ((i & 0xff) << 24) | ((i & 0xff00) << 8) | ((i & 0xff0000) >>> 8) | (i >>> 24);
         }
         public InputStream getInputStream(String path) throws IOException {
-            InputStream is = parent.getInputStream();
-            byte[] scan = new byte[4];
-            int ofs = 0;
-            for(int i=0; i<2; i++)  {
-                // wierdly, .exe files have three MSCF's
-                while(scan[0] != 'M' || scan[1] != 'S' || scan[2] != 'C' || scan[3] != 'F') {
-                    System.arraycopy(scan, 1, scan, 0, 3);
-                    int read = is.read();
-                    if (read == -1) throw new JS.Exn("MSCF header tag not found in file");
-                    scan[3] = (byte)read;
-                    ofs++;
-                }
-                scan[0] = 0;
+            try {
+               return org.xwt.util.CAB.getFileInputStream(parent.getInputStream(), 2, path);
+            } catch (EOFException eof) {
+               throw new JS.Exn("MSCF header tag not found in file");
+            } catch (IOException ioe) {
+               throw new JS.Exn("IOException while reading file");
             }
-            Log.log(this, "found MSCF header at offset " + ofs);
-            return org.xwt.util.CAB.getFileInputStream(is, path, true);
         }
     }