diff --git a/Jint/Extensions/WebEncoders.cs b/Jint/Extensions/WebEncoders.cs
index 80bb40b429..45d0b2188f 100644
--- a/Jint/Extensions/WebEncoders.cs
+++ b/Jint/Extensions/WebEncoders.cs
@@ -106,15 +106,16 @@ private static int GetArraySizeRequiredToDecode(int count)
/// Encodes using base64url encoding.
///
/// The binary input to encode.
+ ///
/// The base64url-encoded form of .
- public static string Base64UrlEncode(byte[] input)
+ public static string Base64UrlEncode(byte[] input, bool omitPadding)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
- return Base64UrlEncode(input, offset: 0, count: input.Length);
+ return Base64UrlEncode(input, offset: 0, count: input.Length, omitPadding);
}
///
@@ -123,8 +124,9 @@ public static string Base64UrlEncode(byte[] input)
/// The binary input to encode.
/// The offset into at which to begin encoding.
/// The number of bytes from to encode.
+ ///
/// The base64url-encoded form of .
- public static string Base64UrlEncode(byte[] input, int offset, int count)
+ public static string Base64UrlEncode(byte[] input, int offset, int count, bool omitPadding)
{
if (input == null)
{
@@ -132,7 +134,7 @@ public static string Base64UrlEncode(byte[] input, int offset, int count)
}
#if NETCOREAPP
- return Base64UrlEncode(input.AsSpan(offset, count));
+ return Base64UrlEncode(input.AsSpan(offset, count), omitPadding);
#else
// Special-case empty input
if (count == 0)
@@ -141,7 +143,7 @@ public static string Base64UrlEncode(byte[] input, int offset, int count)
}
var buffer = new char[GetArraySizeRequiredToEncode(count)];
- var numBase64Chars = Base64UrlEncode(input, offset, buffer, outputOffset: 0, count: count);
+ var numBase64Chars = Base64UrlEncode(input, offset, buffer, outputOffset: 0, count: count, omitPadding);
return new string(buffer, startIndex: 0, length: numBase64Chars);
#endif
@@ -162,10 +164,11 @@ public static string Base64UrlEncode(byte[] input, int offset, int count)
/// .
///
/// The number of bytes from to encode.
+ ///
///
/// The number of characters written to , less any padding characters.
///
- public static int Base64UrlEncode(byte[] input, int offset, char[] output, int outputOffset, int count)
+ public static int Base64UrlEncode(byte[] input, int offset, char[] output, int outputOffset, int count, bool omitPadding)
{
if (input == null)
{
@@ -188,7 +191,7 @@ public static int Base64UrlEncode(byte[] input, int offset, char[] output, int o
}
#if NETCOREAPP
- return Base64UrlEncode(input.AsSpan(offset, count), output.AsSpan(outputOffset));
+ return Base64UrlEncode(input.AsSpan(offset, count), output.AsSpan(outputOffset), omitPadding);
#else
// Special-case empty input.
if (count == 0)
@@ -213,7 +216,7 @@ public static int Base64UrlEncode(byte[] input, int offset, char[] output, int o
{
output[i] = '_';
}
- else if (ch == '=')
+ else if (omitPadding && ch == '=')
{
// We've reached a padding character; truncate the remainder.
return i - outputOffset;
@@ -226,7 +229,7 @@ public static int Base64UrlEncode(byte[] input, int offset, char[] output, int o
///
/// Get the minimum output char[] size required for encoding
- /// s with the method.
+ /// s with the method.
///
/// The number of characters to encode.
///
@@ -243,8 +246,9 @@ public static int GetArraySizeRequiredToEncode(int count)
/// Encodes using base64url encoding.
///
/// The binary input to encode.
+ ///
/// The base64url-encoded form of .
- public static string Base64UrlEncode(ReadOnlySpan input)
+ public static string Base64UrlEncode(ReadOnlySpan input, bool omitPadding)
{
if (input.IsEmpty)
{
@@ -258,7 +262,7 @@ public static string Base64UrlEncode(ReadOnlySpan input)
? stackalloc char[bufferSize]
: bufferToReturnToPool = ArrayPool.Shared.Rent(bufferSize);
- var numBase64Chars = Base64UrlEncode(input, buffer);
+ var numBase64Chars = Base64UrlEncode(input, buffer, omitPadding);
var base64Url = new string(buffer.Slice(0, numBase64Chars));
if (bufferToReturnToPool != null)
@@ -269,7 +273,7 @@ public static string Base64UrlEncode(ReadOnlySpan input)
return base64Url;
}
- private static int Base64UrlEncode(ReadOnlySpan input, Span output)
+ private static int Base64UrlEncode(ReadOnlySpan input, Span output, bool omitPadding)
{
Debug.Assert(output.Length >= GetArraySizeRequiredToEncode(input.Length));
@@ -294,7 +298,7 @@ private static int Base64UrlEncode(ReadOnlySpan input, Span output)
{
output[i] = '_';
}
- else if (ch == '=')
+ else if (omitPadding && ch == '=')
{
// We've reached a padding character; truncate the remainder.
return i;
diff --git a/Jint/Native/Array/ArrayPrototype.cs b/Jint/Native/Array/ArrayPrototype.cs
index 7b7d711594..d04494c84a 100644
--- a/Jint/Native/Array/ArrayPrototype.cs
+++ b/Jint/Native/Array/ArrayPrototype.cs
@@ -1267,7 +1267,7 @@ static string StringFromJsValue(JsValue value)
return s;
}
- using var sb = new ValueStringBuilder(stackalloc char[256]);
+ using var sb = new ValueStringBuilder();
sb.Append(s);
for (uint k = 1; k < len; k++)
{
diff --git a/Jint/Native/JsTypedArray.cs b/Jint/Native/JsTypedArray.cs
index 592133d375..82e38907eb 100644
--- a/Jint/Native/JsTypedArray.cs
+++ b/Jint/Native/JsTypedArray.cs
@@ -52,7 +52,11 @@ public JsValue this[uint index]
public uint Length => GetLength();
- internal override uint GetLength() => IntrinsicTypedArrayPrototype.MakeTypedArrayWithBufferWitnessRecord(this, ArrayBufferOrder.Unordered).TypedArrayLength;
+ internal override uint GetLength()
+ {
+ var record = IntrinsicTypedArrayPrototype.MakeTypedArrayWithBufferWitnessRecord(this, ArrayBufferOrder.Unordered);
+ return record.IsTypedArrayOutOfBounds ? 0 : record.TypedArrayLength;
+ }
internal override bool IsArrayLike => true;
diff --git a/Jint/Native/TypedArray/TypedArrayConstructor.Uint8Array.cs b/Jint/Native/TypedArray/TypedArrayConstructor.Uint8Array.cs
index 6f4b0e68ea..08ad54437d 100644
--- a/Jint/Native/TypedArray/TypedArrayConstructor.Uint8Array.cs
+++ b/Jint/Native/TypedArray/TypedArrayConstructor.Uint8Array.cs
@@ -129,14 +129,14 @@ internal static FromEncodingResult FromBase64(Engine engine, string input, strin
{
if (chunkLength == 1)
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 chunk length."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 chunk length."), read);
}
DecodeBase64Chunk(engine, bytes, chunk, chunkLength, throwOnExtraBits: false);
}
else // strict
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 chunk length in strict mode."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 chunk length in strict mode."), read);
}
}
@@ -150,7 +150,7 @@ internal static FromEncodingResult FromBase64(Engine engine, string input, strin
{
if (chunkLength < 2)
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid '=' placement in base64 string."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid '=' placement in base64 string."), read);
}
index = SkipAsciiWhitespace(input, index);
@@ -163,13 +163,13 @@ internal static FromEncodingResult FromBase64(Engine engine, string input, strin
return new FromEncodingResult(bytes.ToArray(), Error: null, read);
}
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 string termination."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 string termination."), read);
}
currentChar = input[index];
if (currentChar != '=')
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Expected '=' in base64 string."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Expected '=' in base64 string."), read);
}
index = SkipAsciiWhitespace(input, index + 1);
@@ -177,7 +177,7 @@ internal static FromEncodingResult FromBase64(Engine engine, string input, strin
if (index < length)
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Extra characters after base64 string."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Extra characters after base64 string."), read);
}
DecodeBase64Chunk(engine, bytes, chunk, chunkLength, throwOnExtraBits);
@@ -188,7 +188,7 @@ internal static FromEncodingResult FromBase64(Engine engine, string input, strin
{
if (currentChar is '+' or '/')
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid character in base64url string."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid character in base64url string."), read);
}
if (currentChar == '-')
@@ -204,7 +204,7 @@ internal static FromEncodingResult FromBase64(Engine engine, string input, strin
if (!Base64Alphabet.Contains(currentChar))
{
- return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 character."), read);
+ return new FromEncodingResult(bytes.ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid base64 character."), read);
}
ulong remaining = maxLength - (ulong) bytes.Count;
@@ -318,7 +318,7 @@ internal static FromEncodingResult FromHex(Engine engine, string s, uint maxLeng
if (length % 2 != 0)
{
- return new FromEncodingResult(bytes, ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid hex string"), read);
+ return new FromEncodingResult([], ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid hex string"), read);
}
var byteIndex = 0;
@@ -327,7 +327,7 @@ internal static FromEncodingResult FromHex(Engine engine, string s, uint maxLeng
var hexits = s.AsSpan(read, 2);
if (!HexAlphabet.Contains(hexits[0]) || !HexAlphabet.Contains(hexits[1]))
{
- return new FromEncodingResult(bytes, ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid hex value"), read);
+ return new FromEncodingResult(bytes.AsSpan(0, byteIndex).ToArray(), ExceptionHelper.CreateSyntaxError(engine.Realm, "Invalid hex value"), read);
}
#if SUPPORTS_SPAN_PARSE
diff --git a/Jint/Native/TypedArray/Uint8ArrayPrototype.cs b/Jint/Native/TypedArray/Uint8ArrayPrototype.cs
index 295f48d7da..2dea5a4d91 100644
--- a/Jint/Native/TypedArray/Uint8ArrayPrototype.cs
+++ b/Jint/Native/TypedArray/Uint8ArrayPrototype.cs
@@ -60,13 +60,13 @@ private JsObject SetFromBase64(JsValue thisObject, JsValue[] arguments)
var byteLength = taRecord.TypedArrayLength;
var result = Uint8ArrayConstructor.FromBase64(_engine, s.ToString(), alphabet.ToString(), lastChunkHandling.ToString(), byteLength);
+ SetUint8ArrayBytes(into, result.Bytes);
+
if (result.Error is not null)
{
throw result.Error;
}
- SetUint8ArrayBytes(into, result.Bytes);
-
var resultObject = OrdinaryObjectCreate(_engine, _engine.Intrinsics.Object);
resultObject.CreateDataPropertyOrThrow("read", result.Read);
resultObject.CreateDataPropertyOrThrow("written", result.Bytes.Length);
@@ -105,13 +105,13 @@ private JsObject SetFromHex(JsValue thisObject, JsValue[] arguments)
var byteLength = taRecord.TypedArrayLength;
var result = Uint8ArrayConstructor.FromHex(_engine, s.ToString(), byteLength);
+ SetUint8ArrayBytes(into, result.Bytes);
+
if (result.Error is not null)
{
throw result.Error;
}
- SetUint8ArrayBytes(into, result.Bytes);
-
var resultObject = OrdinaryObjectCreate(_engine, _engine.Intrinsics.Object);
resultObject.CreateDataPropertyOrThrow("read", result.Read);
resultObject.CreateDataPropertyOrThrow("written", result.Bytes.Length);
@@ -136,10 +136,14 @@ private JsValue ToBase64(JsValue thisObject, JsValue[] arguments)
if (alphabet == "base64")
{
outAscii = Convert.ToBase64String(toEncode);
+ if (omitPadding)
+ {
+ outAscii = outAscii.TrimEnd('=');
+ }
}
else
{
- outAscii = WebEncoders.Base64UrlEncode(toEncode);
+ outAscii = WebEncoders.Base64UrlEncode(toEncode, omitPadding);
}
return outAscii;