[wasm] Include data archives and timezone data by default (#39586)
authorLarry Ewing <lewing@microsoft.com>
Mon, 20 Jul 2020 16:40:17 +0000 (11:40 -0500)
committerGitHub <noreply@github.com>
Mon, 20 Jul 2020 16:40:17 +0000 (11:40 -0500)
* Add data archive loading to the generic loading logic

eng/testing/tests.mobile.targets
src/mono/wasm/runtime-test.js
src/mono/wasm/runtime/library_mono.js
tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.cs

index 266a6d3..284ae30 100644 (file)
@@ -14,7 +14,7 @@
 
   <PropertyGroup Condition="'$(TargetOS)' == 'Browser'">
     <!-- We need to set this in order to get extensibility on xunit category traits and other arguments we pass down to xunit via MSBuild properties -->
-    <RunScriptCommand>$HARNESS_RUNNER wasm test --engine=$(JSEngine) $(JSEngineArgs) --js-file=runtime.js -v --output-directory=$XHARNESS_OUT -- --enable-zoneinfo --run WasmTestRunner.dll $(AssemblyName).dll</RunScriptCommand>
+    <RunScriptCommand>$HARNESS_RUNNER wasm test --engine=$(JSEngine) $(JSEngineArgs) --js-file=runtime.js -v --output-directory=$XHARNESS_OUT -- --run WasmTestRunner.dll $(AssemblyName).dll</RunScriptCommand>
   </PropertyGroup>
 
   <!-- Generate a self-contained app bundle for Android with tests. -->
index b63c8fc..a2a66b6 100644 (file)
@@ -130,9 +130,6 @@ while (true) {
        } else if (args [0] == "--disable-on-demand-gc") {
                enable_gc = false;
                args = args.slice (1);
-       } else if (args [0] == "--enable-zoneinfo") {
-               enable_zoneinfo = true;
-               args = args.slice (1);
        } else {
                break;
        }
@@ -173,26 +170,6 @@ var Module = {
                if (!enable_gc) {
                        Module.ccall ('mono_wasm_enable_on_demand_gc', 'void', ['number'], [0]);
                }
-               if (enable_zoneinfo) {
-                       // The timezone file is generated by https://github.com/dotnet/blazor/tree/master/src/TimeZoneData.
-                       // The file format of the TZ file look like so
-                       //
-                       // [4-byte magic number]
-                       // [4 - byte length of manifest]
-                       // [json manifest]
-                       // [data bytes]
-                       //
-                       // The json manifest is an array that looks like so:
-                       //
-                       // [...["America/Fort_Nelson",2249],["America/Glace_Bay",2206]..]
-                       //
-                       // where the first token in each array is the relative path of the file on disk, and the second is the
-                       // length of the file. The starting offset of a file can be calculated using the lengths of all files
-                       // that appear prior to it.
-                       var zonedata = new Uint8Array(read ("dotnet.timezones.blat", "binary"));
-                       MONO.mono_wasm_load_data (zonedata, "/usr/share/zoneinfo");
-               }
-
 
                config.loaded_cb = function () {
                        App.init ();
index b1be6e6..f47c0f8 100644 (file)
@@ -619,7 +619,6 @@ var MonoSupportLib = {
                                                : virtualName;
                                        if (fileName.startsWith("/"))
                                                fileName = fileName.substr(1);
-
                                        if (parentDirectory) {
                                                if (ctx.tracing)
                                                        console.log ("MONO_WASM: Creating directory '" + parentDirectory + "'");
@@ -634,11 +633,12 @@ var MonoSupportLib = {
                                        if (ctx.tracing)
                                                console.log ("MONO_WASM: Creating file '" + fileName + "' in directory '" + parentDirectory + "'");
 
-                                       var fileRet = ctx.createDataFile (
-                                               parentDirectory, fileName,
-                                               bytes, true /* canRead */, true /* canWrite */, true /* canOwn */
-                                       );
-
+                                       if (!this.mono_wasm_load_data_archive (bytes, parentDirectory)) {
+                                               var fileRet = ctx.createDataFile (
+                                                       parentDirectory, fileName,
+                                                       bytes, true /* canRead */, true /* canWrite */, true /* canOwn */
+                                               );
+                                       }
                                        break;
 
                                default:
@@ -1110,16 +1110,30 @@ var MonoSupportLib = {
                        return className.replace(/\//g, '.').replace(/`\d+/g, '');
                },
 
-               mono_wasm_load_data: function (data, prefix) {
+               mono_wasm_load_data_archive: function (data, prefix) {
+                       if (data.length < 8)
+                               return false;
+
                        var dataview = new DataView(data.buffer);
                        var magic = dataview.getUint32(0, true);
                        //      get magic number
                        if (magic != 0x626c6174) {
-                               throw new Error ("File is of wrong type");
+                               return false;
                        }
                        var manifestSize = dataview.getUint32(4, true);
-                       var manifestContent = Module.UTF8ArrayToString(data, 8, manifestSize);
-                       var manifest = JSON.parse(manifestContent);
+                       if (manifestSize == 0 || data.length < manifestSize + 8)
+                               return false;
+
+                       var manifest;
+                       try {
+                               manifestContent = Module.UTF8ArrayToString(data, 8, manifestSize);
+                               manifest = JSON.parse(manifestContent);
+                               if (!(manifest instanceof Array))
+                                       return false;
+                       } catch (exc) {
+                               return false;
+                       }
+
                        data = data.slice(manifestSize+8);
 
                        // Create the folder structure
@@ -1127,18 +1141,13 @@ var MonoSupportLib = {
                        // /usr/share/zoneinfo/Africa
                        // /usr/share/zoneinfo/Asia
                        // ..
-                       var p = prefix.slice(1).split('/');
-                       p.forEach((v, i) => {
-                               FS.mkdir(v);
-                               Module['FS_createPath']("/" + p.slice(0, i).join('/'), v, true, true);
-                       })
+
                        var folders = new Set()
                        manifest.filter(m => {
-                               m = m[0].split('/')
-                               if (m!= null) {
-                                       if (m.length > 2) folders.add(m.slice(0,m.length-1).join('/'));
-                                       folders.add(m[0]);
-                               }
+                               var file = m[0];
+                               var last = file.lastIndexOf ("/");
+                               var directory = file.slice (0, last);
+                               folders.add(directory);
                        });
                        folders.forEach(folder => {
                                Module['FS_createPath'](prefix, folder, true, true);
@@ -1148,9 +1157,10 @@ var MonoSupportLib = {
                                var name = row[0];
                                var length = row[1];
                                var bytes = data.slice(0, length);
-                               Module['FS_createDataFile'](`${prefix}/${name}`, null, bytes, true, true);
+                               Module['FS_createDataFile'](prefix, name, bytes, true, true);
                                data = data.slice(length);
                        }
+                       return true;
                }
        },
 
index 9a5d51c..668d4ef 100644 (file)
@@ -121,7 +121,7 @@ public class WasmAppBuilder : Task
             var sEnableRemote = enableRemote ? "true" : "false";
 
             sw.WriteLine($"\t\t{{ behavior: \"icu\", name: \"icudt.dat\", load_remote: {sEnableRemote} }},");
-
+            sw.WriteLine($"\t\t{{ behavior: \"vfs\", name: \"dotnet.timezones.blat\", virtual_path: \"/usr/share/zoneinfo/\" }}");
             sw.WriteLine ("\t],");
 
             if (enableRemote) {