-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathUtils.cs
More file actions
164 lines (152 loc) · 4.89 KB
/
Utils.cs
File metadata and controls
164 lines (152 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using QuickJS.Native;
namespace QuickJS
{
/// <summary>
/// Contains utilities that the QuickJS.NET uses.
/// </summary>
public static class Utils
{
internal unsafe static IntPtr CreateArgv(Encoding encoding, string[] args)
{
int arraySize = IntPtr.Size * (args.Length + 1);
int memorySize = arraySize + args.Length;
foreach (string arg in args)
{
memorySize += encoding.GetByteCount(arg);
}
byte** argv = (byte**)Marshal.AllocHGlobal(memorySize);
byte* data = (byte*)argv + arraySize;
byte* bufferEnd = (byte*)argv + memorySize;
for (var i = 0; i < args.Length; i++)
{
argv[i] = data;
string arg = args[i];
fixed (char* arg_ptr = arg)
{
data += encoding.GetBytes(arg_ptr, arg.Length, data, (int)(bufferEnd - data));
}
data[0] = 0;
data++;
}
argv[args.Length] = null;
return new IntPtr(argv);
}
internal static void ReleaseArgv(IntPtr argv)
{
Marshal.FreeHGlobal(argv);
}
/// <summary>
/// Copies the contents of a managed <see cref="string"/> into a byte
/// array that represents a store for null terminated string.
/// </summary>
/// <param name="s">A managed string to be copied.</param>
/// <returns>
/// A byte array allocated for the null terminated UTF-8 string, or null
/// if <paramref name="s"/> is null.
/// </returns>
public static byte[] StringToManagedUTF8(string s)
{
return StringToManagedUTF8(s, out int _);
}
/// <summary>
/// Copies the contents of a managed <see cref="string"/> into a byte
/// array that represents a store for null terminated string.
/// </summary>
/// <param name="s">A managed string to be copied.</param>
/// <param name="length">When the method returns, a value containing the length of the UTF-8 string in bytes.</param>
/// <returns>
/// A byte array allocated for the null terminated UTF-8 string, or null
/// if <paramref name="s"/> is null.
/// </returns>
public static unsafe byte[] StringToManagedUTF8(string s, out int length)
{
if (s is null)
{
length = 0;
return null;
}
Encoding utf8 = Encoding.UTF8;
fixed (char* s0 = s)
{
length = utf8.GetByteCount(s0, s.Length);
byte[] buffer = new byte[length + 1];
fixed (byte* buf = buffer)
{
utf8.GetBytes(s0, s.Length, buf, length);
buf[length] = 0;
}
return buffer;
}
}
/// <summary>
/// Allocates a managed <see cref="string"/> and copies a specified
/// number of bytes from an unmanaged UTF8 string into it.
/// </summary>
/// <param name="ptr">
/// The address of the first character of the unmanaged string.
/// </param>
/// <param name="length">The number of bytes to copy.</param>
/// <returns>
/// A managed string that holds a copy of the unmanaged string if the
/// value of the <paramref name="ptr"/> parameter is not null;
/// otherwise, this method returns null.
/// </returns>
public static unsafe string PtrToStringUTF8(IntPtr ptr, int length)
{
if (ptr == IntPtr.Zero)
return null;
#if NETSTANDARD
return Encoding.UTF8.GetString((byte*)ptr, length);
#else
var buffer = new byte[length];
Marshal.Copy(ptr, buffer, 0, length);
return Encoding.UTF8.GetString(buffer);
#endif
}
/// <summary>
/// Allocates a managed String and copies all characters up to the
/// first null character from an unmanaged UTF-8 string into it.
/// </summary>
/// <param name="ptr">The address of the first character of the unmanaged string.</param>
/// <returns>
/// A managed string that holds a copy of the unmanaged string if the value of
/// the <paramref name="ptr"/> parameter is not null; otherwise, this method
/// returns null.
/// </returns>
public static unsafe string PtrToStringUTF8(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
byte* str = (byte*)ptr;
while (*str++ != 0) ;
#if NETSTANDARD
return Encoding.UTF8.GetString((byte*)ptr, (int)(--str - (byte*)ptr));
#else
var buffer = new byte[(int)(--str - (byte*)ptr)];
Marshal.Copy(ptr, buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer);
#endif
}
internal unsafe static JSValue ReportException(JSContext ctx, Exception ex)
{
IntPtr opaque = QuickJSNativeApi.JS_GetContextOpaque(ctx);
if (opaque != IntPtr.Zero)
((QuickJSContext)GCHandle.FromIntPtr(opaque).Target).SetClrException(ex);
fixed (byte* msg = Utils.StringToManagedUTF8((ex.Message ?? string.Empty).Replace("%", "%%")))
{
if (ex is QuickJSInterruptedException)
{
QuickJSNativeApi.JS_ThrowInternalError(ctx, msg, __arglist());
JSValue exception = QuickJSNativeApi.JS_GetException(ctx);
QuickJSNativeApi.JS_SetUncatchableError(ctx, exception, true);
return QuickJSNativeApi.JS_Throw(ctx, exception);
}
return QuickJSNativeApi.JS_ThrowInternalError(ctx, msg, __arglist());
}
}
}
}