Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelsavara committed Feb 22, 2023
1 parent 16d8126 commit 89d4f74
Show file tree
Hide file tree
Showing 31 changed files with 670 additions and 652 deletions.
1 change: 0 additions & 1 deletion eng/liveBuilds.targets
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@
$(LibrariesNativeArtifactsPath)package.json;
$(LibrariesNativeArtifactsPath)dotnet.wasm;
$(LibrariesNativeArtifactsPath)dotnet.js.symbols;
$(LibrariesNativeArtifactsPath)dotnet.timezones.blat;
$(LibrariesNativeArtifactsPath)*.dat;"
IsNative="true" />
<!-- for threaded wasm -->
Expand Down
5 changes: 3 additions & 2 deletions eng/native/configurecompiler.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,9 @@ if(CLR_CMAKE_TARGET_UNIX)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_ANDROID>)
elseif(CLR_CMAKE_TARGET_LINUX)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_LINUX>)
if(CLR_CMAKE_TARGET_BROWSER)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_BROWSER>)
endif()
if(CLR_CMAKE_TARGET_LINUX_MUSL)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_LINUX_MUSL>)
endif()
Expand All @@ -597,8 +600,6 @@ if(CLR_CMAKE_TARGET_UNIX)
endif()
elseif(CLR_CMAKE_TARGET_WASI)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_WASI>)
elseif(CLR_CMAKE_TARGET_BROWSER)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_BROWSER>)
else(CLR_CMAKE_TARGET_UNIX)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_OS>>>:TARGET_WINDOWS>)
endif(CLR_CMAKE_TARGET_UNIX)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,13 @@
<PlatformManifestFileEntry Include="libmono-profiler-browser.a" IsNative="true" />
<PlatformManifestFileEntry Include="libmono-wasm-eh-js.a" IsNative="true" />
<PlatformManifestFileEntry Include="libmono-wasm-eh-wasm.a" IsNative="true" />
<PlatformManifestFileEntry Include="wasm-bundled-timezones.a" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.worker.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.js.symbols" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.d.ts" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet-legacy.d.ts" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.wasm" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.timezones.blat" IsNative="true" />
<PlatformManifestFileEntry Include="icudt.dat" IsNative="true" />
<PlatformManifestFileEntry Include="icudt_no_CJK.dat" IsNative="true" />
<PlatformManifestFileEntry Include="icudt_CJK.dat" IsNative="true" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[LibraryImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetTimeZoneData", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)]
internal static partial IntPtr GetTimeZoneData(string fileName, out int length);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2143,6 +2143,9 @@
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetDefaultTimeZone.AnyMobile.cs" Condition="'$(TargetsAndroid)' == 'true' or '$(TargetsLinuxBionic)' == 'true' or '$(IsiOSLike)' == 'true'">
<Link>Common\Interop\Unix\System.Native\Interop.GetDefaultTimeZone.AnyMobile.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetTimeZoneData.Wasm.cs" Condition="'$(TargetsWasi)' == 'true' or '$(TargetsBrowser)' == 'true'">
<Link>Common\src\Interop\Unix\System.Native\Interop.GetTimeZoneData.Wasm.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetEnv.cs">
<Link>Common\Interop\Unix\System.Native\Interop.GetEnv.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public sealed partial class TimeZoneInfo
private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR";
private const string TimeZoneEnvironmentVariable = "TZ";

#if TARGET_WASI || TARGET_BROWSER
// if TZDIR is set, then the embedded TZ data will be ignored and normal unix behavior will be used
private static readonly bool UseEmbeddedTzDatabase = Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable) == null;
#endif

private static TimeZoneInfo GetLocalTimeZoneCore()
{
// Without Registry support, create the TimeZoneInfo from a TZ file
Expand All @@ -29,9 +34,30 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachineCore(string id,
value = null;
e = null;

byte[]? rawData=null;
#if TARGET_WASI || TARGET_BROWSER
if (UseEmbeddedTzDatabase)
{
if(!TryLoadEmbeddedTzFile(id, ref rawData))
{
e = new FileNotFoundException(id, "Embedded TZ data not found");
return TimeZoneInfoResult.TimeZoneNotFoundException;
}

value = GetTimeZoneFromTzData(rawData, id);

if (value == null)
{
e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, id));
return TimeZoneInfoResult.InvalidTimeZoneException;
}

return TimeZoneInfoResult.Success;
}
#endif

string timeZoneDirectory = GetTimeZoneDirectory();
string timeZoneFilePath = Path.Combine(timeZoneDirectory, id);
byte[] rawData;
try
{
rawData = File.ReadAllBytes(timeZoneFilePath);
Expand Down Expand Up @@ -74,52 +100,68 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachineCore(string id,
/// <remarks>
/// Lines that start with # are comments and are skipped.
/// </remarks>
private static List<string> GetTimeZoneIds()
private static IEnumerable<string> GetTimeZoneIds()
{
#if TARGET_WASI || TARGET_BROWSER
byte[]? rawData = null;
if (UseEmbeddedTzDatabase)
{
if(!TryLoadEmbeddedTzFile(TimeZoneFileName, ref rawData))
{
return Array.Empty<string>();
}
using var reader = new StreamReader(new MemoryStream(rawData), Encoding.UTF8);
return ParseTimeZoneIds(reader);
}
#endif
try
{
using var reader = new StreamReader(Path.Combine(GetTimeZoneDirectory(), TimeZoneFileName), Encoding.UTF8);
return ParseTimeZoneIds(reader);
}
catch (IOException) { }
catch (UnauthorizedAccessException) { }
return Array.Empty<string>();
}

private static List<string> ParseTimeZoneIds(StreamReader reader)
{
List<string> timeZoneIds = new List<string>();

try
string? zoneTabFileLine;
while ((zoneTabFileLine = reader.ReadLine()) != null)
{
using (StreamReader sr = new StreamReader(Path.Combine(GetTimeZoneDirectory(), TimeZoneFileName), Encoding.UTF8))
if (!string.IsNullOrEmpty(zoneTabFileLine) && zoneTabFileLine[0] != '#')
{
string? zoneTabFileLine;
while ((zoneTabFileLine = sr.ReadLine()) != null)
// the format of the line is "country-code \t coordinates \t TimeZone Id \t comments"

int firstTabIndex = zoneTabFileLine.IndexOf('\t');
if (firstTabIndex >= 0)
{
if (!string.IsNullOrEmpty(zoneTabFileLine) && zoneTabFileLine[0] != '#')
int secondTabIndex = zoneTabFileLine.IndexOf('\t', firstTabIndex + 1);
if (secondTabIndex >= 0)
{
// the format of the line is "country-code \t coordinates \t TimeZone Id \t comments"

int firstTabIndex = zoneTabFileLine.IndexOf('\t');
if (firstTabIndex >= 0)
string timeZoneId;
int startIndex = secondTabIndex + 1;
int thirdTabIndex = zoneTabFileLine.IndexOf('\t', startIndex);
if (thirdTabIndex >= 0)
{
int secondTabIndex = zoneTabFileLine.IndexOf('\t', firstTabIndex + 1);
if (secondTabIndex >= 0)
{
string timeZoneId;
int startIndex = secondTabIndex + 1;
int thirdTabIndex = zoneTabFileLine.IndexOf('\t', startIndex);
if (thirdTabIndex >= 0)
{
int length = thirdTabIndex - startIndex;
timeZoneId = zoneTabFileLine.Substring(startIndex, length);
}
else
{
timeZoneId = zoneTabFileLine.Substring(startIndex);
}
int length = thirdTabIndex - startIndex;
timeZoneId = zoneTabFileLine.Substring(startIndex, length);
}
else
{
timeZoneId = zoneTabFileLine.Substring(startIndex);
}

if (!string.IsNullOrEmpty(timeZoneId))
{
timeZoneIds.Add(timeZoneId);
}
}
if (!string.IsNullOrEmpty(timeZoneId))
{
timeZoneIds.Add(timeZoneId);
}
}
}
}
}
catch (IOException) { }
catch (UnauthorizedAccessException) { }

return timeZoneIds;
}
Expand Down Expand Up @@ -379,6 +421,22 @@ private static bool TryLoadTzFile(string tzFilePath, [NotNullWhen(true)] ref byt
return false;
}

#if TARGET_WASI || TARGET_BROWSER
private static bool TryLoadEmbeddedTzFile(string name, [NotNullWhen(true)] ref byte[]? rawData)
{
IntPtr bytes = Interop.Sys.GetTimeZoneData(name, out int length);
if(bytes == IntPtr.Zero)
{
rawData = null;
return false;
}

rawData = new byte[length];
Marshal.Copy(bytes, rawData, 0, length);
return true;
}
#endif

/// <summary>
/// Gets the tzfile raw data for the current 'local' time zone using the following rules.
///
Expand All @@ -387,6 +445,10 @@ private static bool TryLoadTzFile(string tzFilePath, [NotNullWhen(true)] ref byt
/// 2. Get the default TZ from the device
/// 3. Use UTC if all else fails.
///
/// On WASI / Browser
/// 0. if TZDIR is not set, use TZ variable as id to embedded database.
/// 1. fall back to unix behavior if TZDIR is set.
///
/// On all other platforms
/// 1. Read the TZ environment variable. If it is set, use it.
/// 2. Look for the data in /etc/localtime.
Expand All @@ -406,6 +468,11 @@ private static bool TryGetLocalTzFile([NotNullWhen(true)] out byte[]? rawData, [
{
#if TARGET_IOS || TARGET_TVOS
tzVariable = Interop.Sys.GetDefaultTimeZone();
#elif TARGET_WASI || TARGET_BROWSER
if (UseEmbeddedTzDatabase)
{
return false; // use UTC
}
#else
return
TryLoadTzFile("/etc/localtime", ref rawData, ref id) ||
Expand All @@ -419,6 +486,17 @@ private static bool TryGetLocalTzFile([NotNullWhen(true)] out byte[]? rawData, [
{
return false;
}
#if TARGET_WASI || TARGET_BROWSER
if (UseEmbeddedTzDatabase)
{
if(!TryLoadEmbeddedTzFile(tzVariable, ref rawData))
{
return false;
}
id = tzVariable;
return true;
}
#endif

// Otherwise, use the path from the env var. If it's not absolute, make it relative
// to the system timezone directory
Expand Down
43 changes: 43 additions & 0 deletions src/mono/mono/utils/mono-dl-wasm.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <config.h>
#include <mono/utils/mono-compiler.h>
#include <mono/eglib/glib.h>

#if defined (HOST_WASM)

Expand Down Expand Up @@ -93,3 +94,45 @@ mono_dl_close_handle (MonoDl *module, MonoError *error)
MONO_EMPTY_SOURCE_FILE (mono_dl_wasm);

#endif

#if defined (HOST_WASM)

static GHashTable *name_to_blob = NULL;

typedef struct {
const unsigned char *data;
unsigned int size;
} FileBlob;

int
mono_wasm_add_bundled_file (const char *name, const unsigned char *data, unsigned int size)
{
// printf("mono_wasm_add_bundled_file: %s %p %d\n", name, data, size);
if(name_to_blob == NULL)
{
name_to_blob = g_hash_table_new (g_str_hash, g_str_equal);
}
FileBlob *blob = g_new0 (FileBlob, 1);
blob->data = data;
blob->size = size;
g_hash_table_insert (name_to_blob, (gpointer) name, blob);
return 0;
}

const unsigned char*
mono_wasm_get_bundled_file (const char *name, int* out_length)
{
FileBlob *blob = (FileBlob *)g_hash_table_lookup (name_to_blob, name);
if (blob != NULL)
{
// printf("mono_wasm_get_bundled_file: %s %p %d \n", name, blob->data, blob->size);
*out_length = blob->size;
return blob->data;
}

// printf("mono_wasm_get_bundled_file: %s not found \n", name);
*out_length = 0;
return NULL;
}

#endif /* HOST_WASM */
5 changes: 5 additions & 0 deletions src/mono/mono/utils/mono-dl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,10 @@ int mono_dl_convert_flags (int mono_flags, int native_flags);
char* mono_dl_current_error_string (void);
const char* mono_dl_get_system_dir (void);

#if defined (HOST_WASM)
int mono_wasm_add_bundled_file (const char *name, const unsigned char *data, unsigned int size);
const unsigned char* mono_wasm_get_bundled_file (const char *name, int* out_length);
#endif /* HOST_WASM */

#endif /* __MONO_UTILS_DL_H__ */

Loading

0 comments on commit 89d4f74

Please sign in to comment.