some of buffer

This commit is contained in:
Jarred Sumner
2022-04-25 07:09:18 -07:00
parent 4b4df5095e
commit 2c6e5c3fc4
43 changed files with 3645 additions and 87 deletions

View File

@@ -0,0 +1,52 @@
// ----- THIS IS NOT WEBCORE ----
// It reuses the namespace.
// ----- THIS IS NOT WEBCORE ----
// Node.js buffer
#include "root.h"
#include "Buffer.h"
#include "JavaScriptCore/JSArrayBufferViewInlines.h"
namespace WebCore {
Ref<Buffer> Buffer::create(JSC::JSGlobalObject* globalObject, RefPtr<ArrayBuffer>&& arrayBuffer, size_t byteOffset, size_t length)
{
return adoptRef(*new Buffer(globalObject, WTFMove(arrayBuffer), byteOffset, length));
}
Ref<Buffer> Buffer::create(JSC::JSGlobalObject* globalObject, RefPtr<ArrayBuffer>&& arrayBuffer)
{
return create(globalObject, WTFMove(arrayBuffer), 0, arrayBuffer->byteLength());
}
int32_t static write(WTF::StringView view, size_t offset, size_t length, BufferEncodingType encodingType)
{
}
Buffer::~Buffer()
{
m_arrayBuffer->deref();
}
Ref<Buffer> Buffer::createEmpty(JSC::JSGlobalObject* globalObject)
{
return adoptRef(*new Buffer(globalObject, nullptr, 0, 0));
}
Ref<Buffer> Buffer::create(JSC::JSGlobalObject* globalObject, UChar* ptr, size_t len, BufferEncodingType encoding)
{
}
Ref<Buffer> Buffer::create(JSC::JSGlobalObject* globalObject, LChar* ptr, size_t len, BufferEncodingType encoding)
{
}
Ref<Buffer> Buffer::create(JSC::JSGlobalObject* globalObject, WTF::StringView& str, BufferEncodingType encoding)
{
if (str.is8Bit()) {
}
}
Ref<Buffer> Buffer::create(JSC::JSGlobalObject* globalObject, WTF::String& str, BufferEncodingType encoding)
{
}
}

View File

@@ -0,0 +1,42 @@
#pragma once
// ----- THIS IS NOT WEBCORE ----
// It reuses the namespace.
// ----- THIS IS NOT WEBCORE ----
// Node.js buffer
#include "root.h"
#include "BufferEncodingType.h"
#include "JavaScriptCore/GenericTypedArrayView.h"
namespace WebCore {
class Buffer final : public RefCounted<Buffer> {
public:
using Adaptor = JSC::JSUint8Array::Adaptor;
~Buffer();
static int32_t write(WTF::StringView view, size_t offset, size_t length, BufferEncodingType encodingType);
static Ref<Buffer> create(JSC::JSGlobalObject* globalObject, RefPtr<ArrayBuffer>&&, size_t byteOffset, size_t length);
static Ref<Buffer> create(JSC::JSGlobalObject* globalObject, RefPtr<ArrayBuffer>&&);
static Ref<Buffer> createEmpty(JSC::JSGlobalObject* globalObject);
static Ref<Buffer> create(JSC::JSGlobalObject* globalObject, UChar* ptr, size_t len, BufferEncodingType encoding);
static Ref<Buffer> create(JSC::JSGlobalObject* globalObject, LChar* ptr, size_t len, BufferEncodingType encoding);
static Ref<Buffer> create(JSC::JSGlobalObject* globalObject, WTF::StringView&, BufferEncodingType encoding);
static Ref<Buffer> create(JSC::JSGlobalObject* globalObject, WTF::String&, BufferEncodingType encoding);
Buffer(JSC::JSGlobalObject* globalObject, RefPtr<ArrayBuffer>&& arrayBuffer, size_t byteOffset,
size_t length)
: m_arrayBuffer(WTFMove(arrayBuffer))
{
}
RefPtr<JSC::ArrayBuffer> m_arrayBuffer;
};
}

View File

@@ -0,0 +1,20 @@
#pragma once
namespace WebCore {
enum class BufferEncodingType {
utf8 = 0,
ucs2 = 1,
utf16le = 2,
latin1 = 3,
ascii = 4,
base64 = 5,
base64url = 6,
hex = 7,
/// Refer to the buffer's encoding
buffer = 8,
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
/*
This file is part of the WebKit open source project.
This file has been generated by generate-bindings.pl. DO NOT MODIFY!
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#pragma once
#include "root.h"
#include "JSDOMWrapper.h"
#include "wtf/NeverDestroyed.h"
#include "BufferEncodingType.h"
#include "Buffer.h"
extern "C" bool JSBuffer__isBuffer(JSC::JSGlobalObject*, JSC::EncodedJSValue);
namespace WebCore {
class WEBCORE_EXPORT JSBuffer final : public JSDOMWrapper<Buffer> {
public:
using Base = JSDOMWrapper<Buffer>;
static constexpr JSC::TypedArrayType TypedArrayStorageType = JSC::JSUint8Array::Adaptor::typeValue;
static JSBuffer* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<Buffer>&& impl)
{
JSBuffer* ptr = new (NotNull, JSC::allocateCell<JSBuffer>(globalObject->vm())) JSBuffer(structure, *globalObject, WTFMove(impl));
ptr->finishCreation(globalObject->vm());
return ptr;
}
static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);
static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
static Buffer* toWrapped(JSC::VM&, JSC::JSValue);
static void destroy(JSC::JSCell*);
using Adaptor = JSC::JSUint8Array::Adaptor;
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), JSC::NonArray);
}
static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
mutable JSC::WriteBarrier<JSC::Unknown> m_searchParams;
template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return subspaceForImpl(vm);
}
static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
// DECLARE_VISIT_CHILDREN;
// template<typename Visitor> void visitAdditionalChildren(Visitor&);
// template<typename Visitor> static void visitOutputConstraints(JSCell*, Visitor&);
// static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
protected:
JSBuffer(JSC::Structure*, JSDOMGlobalObject&, Ref<Buffer>&&);
void finishCreation(JSC::VM&);
};
class JSBufferOwner final : public JSC::WeakHandleOwner {
public:
~JSBufferOwner() final;
bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::AbstractSlotVisitor&, const char**) final;
void finalize(JSC::Handle<JSC::Unknown>, void* context) final;
};
inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, Buffer*)
{
static NeverDestroyed<JSBufferOwner> owner;
return &owner.get();
}
inline void* wrapperKey(Buffer* wrappableObject)
{
return wrappableObject;
}
WEBCORE_EXPORT JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, Buffer&);
inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, Buffer* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); }
JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref<Buffer>&&);
inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr<Buffer>&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }
template<> struct JSDOMWrapperConverterTraits<Buffer> {
using WrapperClass = JSBuffer;
using ToWrappedReturnType = Buffer*;
};
} // namespace WebCore

View File

@@ -0,0 +1,164 @@
/*
This file is part of the WebKit open source project.
This file has been generated by generate-bindings.pl. DO NOT MODIFY!
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#pragma once
#include "config.h"
#include "JSBufferEncodingType.h"
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSString.h>
#include <wtf/NeverDestroyed.h>
namespace WebCore {
using namespace JSC;
String convertEnumerationToString(BufferEncodingType enumerationValue)
{
static const NeverDestroyed<String> values[] = {
MAKE_STATIC_STRING_IMPL("utf8"),
MAKE_STATIC_STRING_IMPL("ucs2"),
MAKE_STATIC_STRING_IMPL("utf16le"),
MAKE_STATIC_STRING_IMPL("latin1"),
MAKE_STATIC_STRING_IMPL("ascii"),
MAKE_STATIC_STRING_IMPL("base64"),
MAKE_STATIC_STRING_IMPL("base64url"),
MAKE_STATIC_STRING_IMPL("hex"),
MAKE_STATIC_STRING_IMPL("buffer"),
};
ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));
return values[static_cast<size_t>(enumerationValue)];
}
template<> JSString* convertEnumerationToJS(JSGlobalObject& lexicalGlobalObject, BufferEncodingType enumerationValue)
{
return jsStringWithCache(lexicalGlobalObject.vm(), convertEnumerationToString(enumerationValue));
}
// this function is mostly copied from node
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSGlobalObject& lexicalGlobalObject, JSValue value)
{
JSC::JSString* str = value.toStringOrNull(&lexicalGlobalObject);
if (!str)
return std::nullopt;
auto encoding = str->value(&lexicalGlobalObject);
if (encoding.length() < 3)
return std::nullopt;
switch (encoding[0]) {
case 'u':
case 'U':
// utf8, utf16le
if (encoding[1] == 't' && encoding[2] == 'f') {
// Skip `-`
const size_t skip = encoding[3] == '-' ? 4 : 3;
if (encoding[skip] == '8' && encoding[skip + 1] == '\0')
return BufferEncodingType::utf8;
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(skip, 5), "16le"))
return BufferEncodingType::ucs2;
// ucs2
} else if (encoding[1] == 'c' && encoding[2] == 's') {
const size_t skip = encoding[3] == '-' ? 4 : 3;
if (encoding[skip] == '2' && encoding[skip + 1] == '\0')
return BufferEncodingType::ucs2;
}
if (WTF::equalIgnoringASCIICase(encoding, "utf8"))
return BufferEncodingType::utf8;
if (WTF::equalIgnoringASCIICase(encoding, "utf-8"))
return BufferEncodingType::utf8;
if (WTF::equalIgnoringASCIICase(encoding, "ucs2"))
return BufferEncodingType::ucs2;
if (WTF::equalIgnoringASCIICase(encoding, "ucs-2"))
return BufferEncodingType::ucs2;
if (WTF::equalIgnoringASCIICase(encoding, "utf16le"))
return BufferEncodingType::ucs2;
if (WTF::equalIgnoringASCIICase(encoding, "utf-16le"))
return BufferEncodingType::ucs2;
break;
case 'l':
case 'L':
// latin1
if (encoding[1] == 'a') {
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(2, 4), "tin1"))
return BufferEncodingType::latin1;
}
if (WTF::equalIgnoringASCIICase(encoding, "latin1"))
return BufferEncodingType::latin1;
break;
case 'b':
case 'B':
// binary is a deprecated alias of latin1
if (encoding[1] == 'i') {
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(2, 5), "nary"))
return BufferEncodingType::latin1;
// buffer
} else if (encoding[1] == 'u') {
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(2, 5), "ffer"))
return BufferEncodingType::buffer;
// base64
} else if (encoding[1] == 'a') {
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(2, 5), "se64"))
return BufferEncodingType::base64;
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(2, 8), "se64url"))
return BufferEncodingType::base64url;
}
if (WTF::equalIgnoringASCIICase(encoding, "binary"))
return BufferEncodingType::latin1; // BINARY is a deprecated alias of LATIN1.
if (WTF::equalIgnoringASCIICase(encoding, "buffer"))
return BufferEncodingType::buffer;
if (WTF::equalIgnoringASCIICase(encoding, "base64"))
return BufferEncodingType::base64;
if (WTF::equalIgnoringASCIICase(encoding, "base64url"))
return BufferEncodingType::base64url;
break;
case 'a':
case 'A':
// ascii
if (encoding[1] == 's') {
if (WTF::equalIgnoringASCIICase(encoding.substringSharingImpl(2, 3), "cii"))
return BufferEncodingType::ascii;
}
if (WTF::equalIgnoringASCIICase(encoding, "ascii"))
return BufferEncodingType::ascii;
break;
case 'h':
case 'H':
// hex
if (encoding[1] == 'e')
if (encoding[2] == 'x' && encoding[3] == '\0')
return BufferEncodingType::hex;
if (WTF::equalIgnoringASCIICase(encoding, "hex"))
return BufferEncodingType::hex;
break;
}
return std::nullopt;
}
template<> const char* expectedEnumerationValues<BufferEncodingType>()
{
return "\"utf8\", \"ucs2\", \"utf16le\", \"latin1\", \"ascii\", \"base64\", \"base64url\", \"hex\", \"buffer\"";
}
} // namespace WebCore

View File

@@ -0,0 +1,13 @@
#include "root.h"
#include "BufferEncodingType.h"
#include "JSDOMConvertEnumeration.h"
namespace WebCore {
String convertEnumerationToString(BufferEncodingType);
template<> JSC::JSString* convertEnumerationToJS(JSC::JSGlobalObject&, BufferEncodingType);
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSC::JSGlobalObject&, JSC::JSValue);
template<> const char* expectedEnumerationValues<BufferEncodingType>();
} // namespace WebCore

View File

@@ -0,0 +1,31 @@
#pragma once
#include "BufferSource.h"
#include "IDLTypes.h"
#include "JSDOMConvertBase.h"
#include "JSDOMWrapperCache.h"
#include "JSBuffer.h"
namespace WebCore {
struct IDLJSBuffer : IDLTypedArray<WebCore::JSBuffer> {
};
template<> struct JSConverter<IDLJSBuffer> {
static constexpr bool needsState = true;
static constexpr bool needsGlobalObject = true;
template<typename U>
static JSC::JSValue convert(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, const U& value)
{
return toJS(&lexicalGlobalObject, &globalObject, Detail::getPtrOrRef(value));
}
template<typename U>
static JSC::JSValue convertNewlyCreated(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, U&& value)
{
return convert(lexicalGlobalObject, globalObject, std::forward<U>(value));
}
};
}

View File

@@ -88,6 +88,8 @@
#include "JavaScriptCore/RemoteInspectorServer.h"
#include "JSBuffer.h"
using JSGlobalObject = JSC::JSGlobalObject;
using Exception = JSC::Exception;
using JSValue = JSC::JSValue;
@@ -99,6 +101,7 @@ using SourceOrigin = JSC::SourceOrigin;
using JSObject = JSC::JSObject;
using JSNonFinalObject = JSC::JSNonFinalObject;
namespace JSCastingHelpers = JSC::JSCastingHelpers;
using JSBuffer = WebCore::JSBuffer;
static bool has_loaded_jsc = false;
@@ -325,6 +328,17 @@ void GlobalObject::setConsole(void* console)
#pragma mark - Globals
JSC_DECLARE_CUSTOM_GETTER(JSBuffer_getter);
JSC_DEFINE_CUSTOM_GETTER(JSBuffer_getter,
(JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue,
JSC::PropertyName))
{
Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
return JSC::JSValue::encode(
WebCore::JSBuffer::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject));
}
JSC_DECLARE_CUSTOM_GETTER(JSDOMURL_getter);
JSC_DEFINE_CUSTOM_GETTER(JSDOMURL_getter,
@@ -874,6 +888,9 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "ErrorEvent"_s), JSC::CustomGetterSetter::create(vm, JSErrorEvent_getter, nullptr),
JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Buffer"_s), JSC::CustomGetterSetter::create(vm, JSBuffer_getter, nullptr),
JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
extraStaticGlobals.releaseBuffer();
this->setRemoteDebuggingEnabled(true);

View File

@@ -3461,6 +3461,19 @@ pub const StringView = extern struct {
};
};
pub const WTF = struct {
extern fn WTF__copyLCharsFromUCharSource(dest: [*]u8, source: *const anyopaque, len: usize) void;
/// This uses SSE2 instructions and/or ARM NEON to copy 16-bit characters efficiently
/// See wtf/Text/ASCIIFastPath.h for details
pub fn copyLCharsFromUCharSource(destination: [*]u8, comptime Source: type, source: Source) void {
if (comptime JSC.is_bindgen) unreachable;
// This is any alignment
WTF__copyLCharsFromUCharSource(destination, source.ptr, source.len);
}
};
pub const Callback = struct {
// zig: Value,
};

View File

@@ -1,4 +1,4 @@
//-- AUTOGENERATED FILE -- 1650708320
//-- AUTOGENERATED FILE -- 1650803913
// clang-format off
#pragma once

View File

@@ -205,4 +205,16 @@ extern "C" const char* Bun__versions_zig;
extern "C" void ZigString__free_global(const unsigned char* ptr, size_t len);
extern "C" int64_t Bun__encoding__writeLatin1AsHex(const unsigned char* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeUTF16AsHex(const UChar* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeLatin1AsURLSafeBase64(const unsigned char* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeUTF16AsURLSafeBase64(const UChar* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeLatin1AsBase64(const unsigned char* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeUTF16AsBase64(const UChar* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeLatin1AsUTF16(const unsigned char* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeUTF16AsUTF16(const UChar* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeLatin1AsUTF8(const unsigned char* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeUTF16AsUTF8(const UChar* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeLatin1AsASCII(const unsigned char* ptr, size_t len, unsigned char* to, size_t other_len);
extern "C" int64_t Bun__encoding__writeUTF16AsASCII(const UChar* ptr, size_t len, unsigned char* to, size_t other_len);
#endif

View File

@@ -1,5 +1,5 @@
// clang-format: off
//-- AUTOGENERATED FILE -- 1650708320
//-- AUTOGENERATED FILE -- 1650803913
#pragma once
#include <stddef.h>

View File

@@ -15,6 +15,10 @@ class DOMClientIsoSubspaces {
public:
DOMClientIsoSubspaces() = default;
/* --- bun --- */
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBuffer;
/* --- bun --- */
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForGlobalObject;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForDOMException;

View File

@@ -843,9 +843,14 @@ enum class DOMConstructorID : uint16_t {
XPathNSResolver,
XPathResult,
XSLTProcessor,
// Bun extras
Buffer
};
static constexpr unsigned numberOfDOMConstructors = 836;
static constexpr unsigned bunExtraConstructors = 1;
static constexpr unsigned numberOfDOMConstructors = 836 + bunExtraConstructors;
class DOMConstructors {
WTF_MAKE_NONCOPYABLE(DOMConstructors);

View File

@@ -15,6 +15,10 @@ class DOMIsoSubspaces {
public:
DOMIsoSubspaces() = default;
/*-- BUN --*/
std::unique_ptr<IsoSubspace> m_subspaceForBuffer;
/*-- BUN --*/
// std::unique_ptr<IsoSubspace> m_subspaceForTouch;
// std::unique_ptr<IsoSubspace> m_subspaceForTouchEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForTouchList;

View File

@@ -45,3 +45,5 @@
#include "JSDOMConvertStrings.h"
#include "JSDOMConvertUnion.h"
#include "JSDOMConvertWebGL.h"
#include "JSDOMConvertBufferSource+JSBuffer.h"

View File

@@ -29,6 +29,7 @@
#include "JSDOMBinding.h"
#include "JSDOMConvertBase.h"
#include "JSDOMConvertBufferSource.h"
#include "JSDOMConvertBufferSource+JSBuffer.h"
#include "JSDOMConvertInterface.h"
#include "JSDOMConvertNull.h"
#include "JavaScriptCore/IteratorOperations.h"

View File

@@ -0,0 +1,6 @@
#include "wtf-bindings.h"
extern "C" void WTF__copyLCharsFromUCharSource(LChar* destination, const UChar* source, size_t length)
{
WTF::copyLCharsFromUCharSource(destination, source, length);
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "root.h"
#include "wtf/text/ASCIIFastPath.h"
extern "C" void WTF__copyLCharsFromUCharSource(LChar* destination, const UChar* source, size_t length);

View File

@@ -187,6 +187,13 @@ pub const Encoding = enum(u8) {
/// Refer to the buffer's encoding
buffer,
pub fn isBinaryToText(this: Encoding) bool {
return switch (this) {
.hex, .base64, .base64url => true,
else => false,
};
}
const Eight = strings.ExactSizeMatcher(8);
/// Caller must verify the value is a string
pub fn fromStringValue(value: JSC.JSValue, global: *JSC.JSGlobalObject) ?Encoding {

View File

@@ -0,0 +1,445 @@
// this is ripped from zig's stdlib
const std = @import("std");
const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem;
pub const Error = error{
InvalidCharacter,
InvalidPadding,
NoSpaceLeft,
};
/// Base64 codecs
pub const Codecs = struct {
alphabet_chars: [64]u8,
pad_char: ?u8,
decoderWithIgnore: fn (ignore: []const u8) Base64DecoderWithIgnore,
Encoder: Base64Encoder,
Decoder: Base64Decoder,
};
pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".*;
fn standardBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore {
return Base64DecoderWithIgnore.init(standard_alphabet_chars, '=', ignore);
}
/// Standard Base64 codecs, with padding
pub const standard = Codecs{
.alphabet_chars = standard_alphabet_chars,
.pad_char = '=',
.decoderWithIgnore = standardBase64DecoderWithIgnore,
.Encoder = Base64Encoder.init(standard_alphabet_chars, '='),
.Decoder = Base64Decoder.init(standard_alphabet_chars, '='),
};
/// Standard Base64 codecs, without padding
pub const standard_no_pad = Codecs{
.alphabet_chars = standard_alphabet_chars,
.pad_char = null,
.decoderWithIgnore = standardBase64DecoderWithIgnore,
.Encoder = Base64Encoder.init(standard_alphabet_chars, null),
.Decoder = Base64Decoder.init(standard_alphabet_chars, null),
};
pub const url_safe_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
fn urlSafeBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore {
return Base64DecoderWithIgnore.init(url_safe_alphabet_chars, null, ignore);
}
/// URL-safe Base64 codecs, with padding
pub const url_safe = Codecs{
.alphabet_chars = url_safe_alphabet_chars,
.pad_char = '=',
.decoderWithIgnore = urlSafeBase64DecoderWithIgnore,
.Encoder = Base64Encoder.init(url_safe_alphabet_chars, '='),
.Decoder = Base64Decoder.init(url_safe_alphabet_chars, '='),
};
/// URL-safe Base64 codecs, without padding
pub const url_safe_no_pad = Codecs{
.alphabet_chars = url_safe_alphabet_chars,
.pad_char = null,
.decoderWithIgnore = urlSafeBase64DecoderWithIgnore,
.Encoder = Base64Encoder.init(url_safe_alphabet_chars, null),
.Decoder = Base64Decoder.init(url_safe_alphabet_chars, null),
};
pub const standard_pad_char = @compileError("deprecated; use standard.pad_char");
pub const standard_encoder = @compileError("deprecated; use standard.Encoder");
pub const standard_decoder = @compileError("deprecated; use standard.Decoder");
pub const Base64Encoder = struct {
alphabet_chars: [64]u8,
pad_char: ?u8,
/// A bunch of assertions, then simply pass the data right through.
pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Encoder {
assert(alphabet_chars.len == 64);
var char_in_alphabet = [_]bool{false} ** 256;
for (alphabet_chars) |c| {
assert(!char_in_alphabet[c]);
assert(pad_char == null or c != pad_char.?);
char_in_alphabet[c] = true;
}
return Base64Encoder{
.alphabet_chars = alphabet_chars,
.pad_char = pad_char,
};
}
/// Compute the encoded length
pub fn calcSize(encoder: *const Base64Encoder, source_len: usize) usize {
if (encoder.pad_char != null) {
return @divTrunc(source_len + 2, 3) * 4;
} else {
const leftover = source_len % 3;
return @divTrunc(source_len, 3) * 4 + @divTrunc(leftover * 4 + 2, 3);
}
}
/// dest.len must at least be what you get from ::calcSize.
pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) []const u8 {
const out_len = encoder.calcSize(source.len);
assert(dest.len >= out_len);
var acc: u12 = 0;
var acc_len: u4 = 0;
var out_idx: usize = 0;
for (source) |v| {
acc = (acc << 8) + v;
acc_len += 8;
while (acc_len >= 6) {
acc_len -= 6;
dest[out_idx] = encoder.alphabet_chars[@truncate(u6, (acc >> acc_len))];
out_idx += 1;
}
}
if (acc_len > 0) {
dest[out_idx] = encoder.alphabet_chars[@truncate(u6, (acc << 6 - acc_len))];
out_idx += 1;
}
if (encoder.pad_char) |pad_char| {
for (dest[out_idx..]) |*pad| {
pad.* = pad_char;
}
}
return dest[0..out_len];
}
};
pub const Base64Decoder = struct {
const invalid_char: u8 = 0xff;
/// e.g. 'A' => 0.
/// `invalid_char` for any value not in the 64 alphabet chars.
char_to_index: [256]u8,
pad_char: ?u8,
pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Decoder {
var result = Base64Decoder{
.char_to_index = [_]u8{invalid_char} ** 256,
.pad_char = pad_char,
};
var char_in_alphabet = [_]bool{false} ** 256;
for (alphabet_chars) |c, i| {
assert(!char_in_alphabet[c]);
assert(pad_char == null or c != pad_char.?);
result.char_to_index[c] = @intCast(u8, i);
char_in_alphabet[c] = true;
}
return result;
}
/// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding.
/// `InvalidPadding` is returned if the input length is not valid.
pub fn calcSizeUpperBound(decoder: *const Base64Decoder, source_len: usize) Error!usize {
var result = source_len / 4 * 3;
const leftover = source_len % 4;
if (decoder.pad_char != null) {
if (leftover % 4 != 0) return error.InvalidPadding;
} else {
if (leftover % 4 == 1) return error.InvalidPadding;
result += leftover * 3 / 4;
}
return result;
}
/// Return the exact decoded size for a slice.
/// `InvalidPadding` is returned if the input length is not valid.
pub fn calcSizeForSlice(decoder: *const Base64Decoder, source: []const u8) Error!usize {
const source_len = source.len;
var result = try decoder.calcSizeUpperBound(source_len);
if (decoder.pad_char) |pad_char| {
if (source_len >= 1 and source[source_len - 1] == pad_char) result -= 1;
if (source_len >= 2 and source[source_len - 2] == pad_char) result -= 1;
}
return result;
}
/// dest.len must be what you get from ::calcSize.
/// invalid characters result in error.InvalidCharacter.
/// invalid padding results in error.InvalidPadding.
pub fn decode(decoder: *const Base64Decoder, dest: []u8, source: []const u8) Error!void {
if (decoder.pad_char != null and source.len % 4 != 0) return error.InvalidPadding;
var acc: u12 = 0;
var acc_len: u4 = 0;
var dest_idx: usize = 0;
var leftover_idx: ?usize = null;
for (source) |c, src_idx| {
const d = decoder.char_to_index[c];
if (d == invalid_char) {
if (decoder.pad_char == null or c != decoder.pad_char.?) return error.InvalidCharacter;
leftover_idx = src_idx;
break;
}
acc = (acc << 6) + d;
acc_len += 6;
if (acc_len >= 8) {
acc_len -= 8;
dest[dest_idx] = @truncate(u8, acc >> acc_len);
dest_idx += 1;
}
}
if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) {
return error.InvalidPadding;
}
if (leftover_idx == null) return;
var leftover = source[leftover_idx.?..];
if (decoder.pad_char) |pad_char| {
const padding_len = acc_len / 2;
var padding_chars: usize = 0;
for (leftover) |c| {
if (c != pad_char) {
return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding;
}
padding_chars += 1;
}
if (padding_chars != padding_len) return error.InvalidPadding;
}
}
};
pub const Base64DecoderWithIgnore = struct {
decoder: Base64Decoder,
char_is_ignored: [256]bool,
pub fn init(alphabet_chars: [64]u8, pad_char: ?u8, ignore_chars: []const u8) Base64DecoderWithIgnore {
var result = Base64DecoderWithIgnore{
.decoder = Base64Decoder.init(alphabet_chars, pad_char),
.char_is_ignored = [_]bool{false} ** 256,
};
for (ignore_chars) |c| {
assert(result.decoder.char_to_index[c] == Base64Decoder.invalid_char);
assert(!result.char_is_ignored[c]);
assert(result.decoder.pad_char != c);
result.char_is_ignored[c] = true;
}
return result;
}
/// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding
/// `InvalidPadding` is returned if the input length is not valid.
pub fn calcSizeUpperBound(decoder_with_ignore: *const Base64DecoderWithIgnore, source_len: usize) Error!usize {
var result = source_len / 4 * 3;
if (decoder_with_ignore.decoder.pad_char == null) {
const leftover = source_len % 4;
result += leftover * 3 / 4;
}
return result;
}
/// Invalid characters that are not ignored result in error.InvalidCharacter.
/// Invalid padding results in error.InvalidPadding.
/// Decoding more data than can fit in dest results in error.NoSpaceLeft. See also ::calcSizeUpperBound.
/// Returns the number of bytes written to dest.
pub fn decode(decoder_with_ignore: *const Base64DecoderWithIgnore, dest: []u8, source: []const u8) Error!usize {
const decoder = &decoder_with_ignore.decoder;
var acc: u12 = 0;
var acc_len: u4 = 0;
var dest_idx: usize = 0;
var leftover_idx: ?usize = null;
for (source) |c, src_idx| {
if (decoder_with_ignore.char_is_ignored[c]) continue;
const d = decoder.char_to_index[c];
if (d == Base64Decoder.invalid_char) {
if (decoder.pad_char == null or c != decoder.pad_char.?) return error.InvalidCharacter;
leftover_idx = src_idx;
break;
}
acc = (acc << 6) + d;
acc_len += 6;
if (acc_len >= 8) {
if (dest_idx == dest.len) return error.NoSpaceLeft;
acc_len -= 8;
dest[dest_idx] = @truncate(u8, acc >> acc_len);
dest_idx += 1;
}
}
if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) {
return error.InvalidPadding;
}
const padding_len = acc_len / 2;
if (leftover_idx == null) {
if (decoder.pad_char != null and padding_len != 0) return error.InvalidPadding;
return dest_idx;
}
var leftover = source[leftover_idx.?..];
if (decoder.pad_char) |pad_char| {
var padding_chars: usize = 0;
for (leftover) |c| {
if (decoder_with_ignore.char_is_ignored[c]) continue;
if (c != pad_char) {
return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding;
}
padding_chars += 1;
}
if (padding_chars != padding_len) return error.InvalidPadding;
}
return dest_idx;
}
};
test "base64" {
@setEvalBranchQuota(8000);
try testBase64();
comptime try testAllApis(standard, "comptime", "Y29tcHRpbWU=");
}
test "base64 url_safe_no_pad" {
@setEvalBranchQuota(8000);
try testBase64UrlSafeNoPad();
comptime try testAllApis(url_safe_no_pad, "comptime", "Y29tcHRpbWU");
}
fn testBase64() !void {
const codecs = standard;
try testAllApis(codecs, "", "");
try testAllApis(codecs, "f", "Zg==");
try testAllApis(codecs, "fo", "Zm8=");
try testAllApis(codecs, "foo", "Zm9v");
try testAllApis(codecs, "foob", "Zm9vYg==");
try testAllApis(codecs, "fooba", "Zm9vYmE=");
try testAllApis(codecs, "foobar", "Zm9vYmFy");
try testDecodeIgnoreSpace(codecs, "", " ");
try testDecodeIgnoreSpace(codecs, "f", "Z g= =");
try testDecodeIgnoreSpace(codecs, "fo", " Zm8=");
try testDecodeIgnoreSpace(codecs, "foo", "Zm9v ");
try testDecodeIgnoreSpace(codecs, "foob", "Zm9vYg = = ");
try testDecodeIgnoreSpace(codecs, "fooba", "Zm9v YmE=");
try testDecodeIgnoreSpace(codecs, "foobar", " Z m 9 v Y m F y ");
// test getting some api errors
try testError(codecs, "A", error.InvalidPadding);
try testError(codecs, "AA", error.InvalidPadding);
try testError(codecs, "AAA", error.InvalidPadding);
try testError(codecs, "A..A", error.InvalidCharacter);
try testError(codecs, "AA=A", error.InvalidPadding);
try testError(codecs, "AA/=", error.InvalidPadding);
try testError(codecs, "A/==", error.InvalidPadding);
try testError(codecs, "A===", error.InvalidPadding);
try testError(codecs, "====", error.InvalidPadding);
try testNoSpaceLeftError(codecs, "AA==");
try testNoSpaceLeftError(codecs, "AAA=");
try testNoSpaceLeftError(codecs, "AAAA");
try testNoSpaceLeftError(codecs, "AAAAAA==");
}
fn testBase64UrlSafeNoPad() !void {
const codecs = url_safe_no_pad;
try testAllApis(codecs, "", "");
try testAllApis(codecs, "f", "Zg");
try testAllApis(codecs, "fo", "Zm8");
try testAllApis(codecs, "foo", "Zm9v");
try testAllApis(codecs, "foob", "Zm9vYg");
try testAllApis(codecs, "fooba", "Zm9vYmE");
try testAllApis(codecs, "foobar", "Zm9vYmFy");
try testDecodeIgnoreSpace(codecs, "", " ");
try testDecodeIgnoreSpace(codecs, "f", "Z g ");
try testDecodeIgnoreSpace(codecs, "fo", " Zm8");
try testDecodeIgnoreSpace(codecs, "foo", "Zm9v ");
try testDecodeIgnoreSpace(codecs, "foob", "Zm9vYg ");
try testDecodeIgnoreSpace(codecs, "fooba", "Zm9v YmE");
try testDecodeIgnoreSpace(codecs, "foobar", " Z m 9 v Y m F y ");
// test getting some api errors
try testError(codecs, "A", error.InvalidPadding);
try testError(codecs, "AAA=", error.InvalidCharacter);
try testError(codecs, "A..A", error.InvalidCharacter);
try testError(codecs, "AA=A", error.InvalidCharacter);
try testError(codecs, "AA/=", error.InvalidCharacter);
try testError(codecs, "A/==", error.InvalidCharacter);
try testError(codecs, "A===", error.InvalidCharacter);
try testError(codecs, "====", error.InvalidCharacter);
try testNoSpaceLeftError(codecs, "AA");
try testNoSpaceLeftError(codecs, "AAA");
try testNoSpaceLeftError(codecs, "AAAA");
try testNoSpaceLeftError(codecs, "AAAAAA");
}
fn testAllApis(codecs: Codecs, expected_decoded: []const u8, expected_encoded: []const u8) !void {
// Base64Encoder
{
var buffer: [0x100]u8 = undefined;
const encoded = codecs.Encoder.encode(&buffer, expected_decoded);
try testing.expectEqualSlices(u8, expected_encoded, encoded);
}
// Base64Decoder
{
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0..try codecs.Decoder.calcSizeForSlice(expected_encoded)];
try codecs.Decoder.decode(decoded, expected_encoded);
try testing.expectEqualSlices(u8, expected_decoded, decoded);
}
// Base64DecoderWithIgnore
{
const decoder_ignore_nothing = codecs.decoderWithIgnore("");
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0..try decoder_ignore_nothing.calcSizeUpperBound(expected_encoded.len)];
var written = try decoder_ignore_nothing.decode(decoded, expected_encoded);
try testing.expect(written <= decoded.len);
try testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]);
}
}
fn testDecodeIgnoreSpace(codecs: Codecs, expected_decoded: []const u8, encoded: []const u8) !void {
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0..try decoder_ignore_space.calcSizeUpperBound(encoded.len)];
var written = try decoder_ignore_space.decode(decoded, encoded);
try testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]);
}
fn testError(codecs: Codecs, encoded: []const u8, expected_err: anyerror) !void {
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
var buffer: [0x100]u8 = undefined;
if (codecs.Decoder.calcSizeForSlice(encoded)) |decoded_size| {
var decoded = buffer[0..decoded_size];
if (codecs.Decoder.decode(decoded, encoded)) |_| {
return error.ExpectedError;
} else |err| if (err != expected_err) return err;
} else |err| if (err != expected_err) return err;
if (decoder_ignore_space.decode(buffer[0..], encoded)) |_| {
return error.ExpectedError;
} else |err| if (err != expected_err) return err;
}
fn testNoSpaceLeftError(codecs: Codecs, encoded: []const u8) !void {
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
var buffer: [0x100]u8 = undefined;
var decoded = buffer[0 .. (try codecs.Decoder.calcSizeForSlice(encoded)) - 1];
if (decoder_ignore_space.decode(decoded, encoded)) |_| {
return error.ExpectedError;
} else |err| if (err != error.NoSpaceLeft) return err;
}

View File

@@ -12,7 +12,7 @@ const js = JSC.C;
const Method = @import("../../../http/method.zig").Method;
const ObjectPool = @import("../../../pool.zig").ObjectPool;
const bun = @import("../../../global.zig");
const Output = @import("../../../global.zig").Output;
const MutableString = @import("../../../global.zig").MutableString;
const strings = @import("../../../global.zig").strings;
@@ -457,23 +457,16 @@ pub const TextDecoder = struct {
}
var buffer = std.ArrayListAlignedUnmanaged(u16, @alignOf(@TypeOf(slice.ptr))){};
buffer.ensureTotalCapacity(default_allocator, slice.len) catch unreachable;
// copy the allocator to reduce the number of threadlocal accesses
const allocator = VirtualMachine.vm.allocator;
buffer.ensureTotalCapacity(allocator, slice.len) catch unreachable;
buffer.items.len = i;
defer buffer.deinit(
default_allocator,
);
if (comptime Slice == []u16) {
@memcpy(
std.mem.sliceAsBytes(buffer.items).ptr,
std.mem.sliceAsBytes(slice).ptr,
std.mem.sliceAsBytes(slice[0..i]).len,
);
} else {
for (slice[0..i]) |ch, j| {
buffer.items[j] = ch;
}
}
@memcpy(
std.mem.sliceAsBytes(buffer.items).ptr,
std.mem.sliceAsBytes(slice).ptr,
std.mem.sliceAsBytes(slice[0..i]).len,
);
const first_high_surrogate = 0xD800;
const last_high_surrogate = 0xDBFF;
@@ -484,20 +477,24 @@ pub const TextDecoder = struct {
while (remainder.len > 0) {
switch (remainder[0]) {
0...127 => {
var count: usize = 1;
while (remainder.len > count and remainder[count] <= 127) : (count += 1) {}
buffer.ensureUnusedCapacity(default_allocator, count) catch unreachable;
const count: usize = if (strings.firstNonASCII16CheckMin(Slice, remainder, false)) |index| index + 1 else remainder.len;
buffer.ensureUnusedCapacity(allocator, count) catch unreachable;
const prev = buffer.items.len;
buffer.items.len += count;
for (remainder[0..count]) |char, j| {
buffer.items[prev + j] = char;
}
// Since this string is freshly allocated, we know it's not going to overlap
@memcpy(
std.mem.sliceAsBytes(buffer.items[prev..]).ptr,
std.mem.sliceAsBytes(remainder).ptr,
std.mem.sliceAsBytes(remainder[0..count]).len,
);
remainder = remainder[count..];
},
first_high_surrogate...last_high_surrogate => |first| {
if (remainder.len > 1) {
if (remainder[1] >= first_low_surrogate and remainder[1] <= last_low_surrogate) {
buffer.ensureUnusedCapacity(default_allocator, 2) catch unreachable;
buffer.ensureUnusedCapacity(allocator, 2) catch unreachable;
buffer.items.ptr[buffer.items.len] = first;
buffer.items.ptr[buffer.items.len + 1] = remainder[1];
buffer.items.len += 2;
@@ -505,7 +502,7 @@ pub const TextDecoder = struct {
continue;
}
}
buffer.ensureUnusedCapacity(default_allocator, 1) catch unreachable;
buffer.ensureUnusedCapacity(allocator, 1) catch unreachable;
buffer.items.ptr[buffer.items.len] = strings.unicode_replacement;
buffer.items.len += 1;
remainder = remainder[1..];
@@ -514,7 +511,7 @@ pub const TextDecoder = struct {
// Is this an unpaired low surrogate or four-digit hex escape?
else => {
buffer.ensureUnusedCapacity(default_allocator, 1) catch unreachable;
buffer.ensureUnusedCapacity(allocator, 1) catch unreachable;
buffer.items.ptr[buffer.items.len] = strings.unicode_replacement;
buffer.items.len += 1;
remainder = remainder[1..];
@@ -522,9 +519,11 @@ pub const TextDecoder = struct {
}
}
var full = buffer.toOwnedSlice(allocator);
var out = ZigString.init("");
out.ptr = @ptrCast([*]u8, buffer.items.ptr);
out.len = buffer.items.len;
out.ptr = @ptrCast([*]u8, full.ptr);
out.len = full.len;
out.markUTF16();
return out.toValueGC(ctx.ptr()).asObjectRef();
}
@@ -651,4 +650,232 @@ pub const TextDecoder = struct {
}
};
pub const Encoder = struct {
export fn Bun__encoding__writeLatin1AsHex(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, .hex);
}
export fn Bun__encoding__writeLatin1AsASCII(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, .ascii);
}
export fn Bun__encoding__writeLatin1AsURLSafeBase64(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, .base64url);
}
export fn Bun__encoding__writeLatin1AsUTF16(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, .utf16le);
}
export fn Bun__encoding__writeLatin1AsUTF8(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, JSC.Node.Encoding.utf8);
}
export fn Bun__encoding__writeLatin1AsBase64(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, .base64);
}
export fn Bun__encoding__writeUTF16AsBase64(input: [*]const u16, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU16(input, len, to, to_len, .base64);
}
export fn Bun__encoding__writeUTF16AsHex(input: [*]const u16, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU16(input, len, to, to_len, .hex);
}
export fn Bun__encoding__writeUTF16AsURLSafeBase64(input: [*]const u16, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU16(input, len, to, to_len, .base64url);
}
export fn Bun__encoding__writeUTF16AsUTF16(input: [*]const u16, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU16(input, len, to, to_len, JSC.Node.Encoding.utf16le);
}
export fn Bun__encoding__writeUTF16AsUTF8(input: [*]const u16, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU16(input, len, to, to_len, .utf8);
}
export fn Bun__encoding__writeUTF16AsASCII(input: [*]const u8, len: usize, to: [*]u8, to_len: usize) i64 {
return writeU8(input, len, to, to_len, .ascii);
}
// pub fn writeUTF16AsUTF8(utf16: [*]const u16, len: usize, to: [*]u8, to_len: usize) callconv(.C) i32 {
// return @intCast(i32, strings.copyUTF16IntoUTF8(to[0..to_len], []const u16, utf16[0..len]).written);
// }
// pub fn toString(input: [*]const u8, len: usize, zig_str: *ZigString, comptime encoding: JSC.Node.Encoding) callconv(.C) i64 {}
pub fn writeU8(input: [*]const u8, len: usize, to: [*]u8, to_len: usize, comptime encoding: JSC.Node.Encoding) i64 {
if (len == 0 or to_len == 0)
return 0;
// TODO: increase temporary buffer size for larger amounts of data
// defer {
// if (comptime encoding.isBinaryToText()) {}
// }
// if (comptime encoding.isBinaryToText()) {}
switch (comptime encoding) {
JSC.Node.Encoding.ascii => {
const written = @truncate(u32, @minimum(len, to_len));
@memcpy(to, input, written);
return @intCast(i32, written);
},
.utf8 => {
// need to encode
return @intCast(i32, strings.copyLatin1IntoUTF8(to[0..to_len], []const u8, input[0..len]).written);
},
// encode latin1 into UTF16
JSC.Node.Encoding.ucs2, JSC.Node.Encoding.utf16le => {
if (to_len < 2)
return 0;
if (std.mem.isAligned(@ptrToInt(to), @alignOf([*]u16))) {
var buf = input[0..len];
var output = @ptrCast([*]u16, @alignCast(@alignOf(u16), to))[0 .. to_len / 2];
return strings.copyLatin1IntoUTF16([]u16, output, []const u8, buf).written;
} else {
var buf = input[0..len];
var output = @ptrCast([*]align(1) u16, to)[0 .. to_len / 2];
return strings.copyLatin1IntoUTF16([]align(1) u16, output, []const u8, buf).written;
}
},
JSC.Node.Encoding.hex => {
return @intCast(i64, strings.decodeHexToBytes(to[0..to_len], u8, input[0..len]));
},
JSC.Node.Encoding.base64url => {
var slice = strings.trim(input[0..len], "\r\n\t " ++ [_]u8{std.ascii.control_code.VT});
if (slice.len == 0)
return 0;
if (strings.eqlComptime(slice[slice.len - 2 ..][0..2], "==")) {
slice = slice[0 .. slice.len - 2];
} else if (slice[slice.len - 1] == '=') {
slice = slice[0 .. slice.len - 1];
}
const wrote = bun.base64.urlsafe.decode(to[0..to_len], slice) catch |err| brk: {
if (err == error.NoSpaceLeft) {
break :brk to_len;
}
return -1;
};
return @intCast(i64, wrote);
},
JSC.Node.Encoding.base64 => {
var slice = strings.trim(input[0..len], "\r\n\t " ++ [_]u8{std.ascii.control_code.VT});
var outlen = bun.base64.decodeLen(slice);
return @intCast(i64, bun.base64.decode(to[0..outlen], slice).written);
},
else => return 0,
}
}
pub fn writeU16(input: [*]const u16, len: usize, to: [*]u8, to_len: usize, comptime encoding: JSC.Node.Encoding) i64 {
// TODO: increase temporary buffer size for larger amounts of data
// defer {
// if (comptime encoding.isBinaryToText()) {}
// }
// if (comptime encoding.isBinaryToText()) {}
switch (comptime encoding) {
.utf8 => {
return @intCast(i32, strings.copyUTF16IntoUTF8(to[0..to_len], []const u16, input[0..len]).written);
},
// string is already encoded, just need to copy the data
JSC.Node.Encoding.ucs2, JSC.Node.Encoding.ascii, JSC.Node.Encoding.utf16le => {
strings.copyU16IntoU8(to[0..to_len], []const u16, input[0..len]);
return @intCast(i64, @minimum(len, to_len));
},
JSC.Node.Encoding.hex => {
return @intCast(i64, strings.decodeHexToBytes(to[0..to_len], u16, input[0..len]));
},
JSC.Node.Encoding.base64, JSC.Node.Encoding.base64url => {
if (to_len < 2 or len == 0)
return 0;
// very very slow case!
// shouldn't really happen though
var transcoded = strings.toUTF8Alloc(bun.default_allocator, input[0..len]) catch return 0;
defer bun.default_allocator.free(transcoded);
return writeU8(transcoded.ptr, transcoded.len, to, to_len, encoding);
},
else => return 0,
}
}
// pub fn writeU8(input: [*]const u8, len: usize, to: [*]u8, to_len: usize, comptime encoding: JSC.Node.Encoding) callconv(.C) i32 {}
// pub fn toUTF8FromU16(comptime Slice: type, slice: Slice, out_ptr: *[*]u8) i32 {
// var out = strings.toUTF8AllocWithType(
// default_allocator,
// Slice,
// slice,
// ) catch {
// return -1;
// };
// out_ptr.* = out.ptr;
// return @intCast(isize, out.len);
// }
// pub fn toUTF8FromLatin1(comptime Slice: type, slice: Slice, out_ptr: *[*]u8) i32 {
// var latin1 = strings.allocateLatin1IntoUTF8(default_allocator, Slice, slice) catch return -1;
// out_ptr.* = latin1.ptr;
// return @intCast(isize, latin1.len);
// }
// pub fn toUTF16FromLatin1(comptime Slice: type, slice: Slice, out_ptr: *[*]u8) i32 {
// var latin1 = strings.toUTF(default_allocator, Slice, slice) catch return -1;
// out_ptr.* = latin1.ptr;
// return @intCast(isize, latin1.len);
// }
// pub fn toUTF16FromU8(slice: []const u8, out_ptr: *[*]u16) i32 {
// if (strings.toUTF16Alloc(default_allocator, slice, true)) |result_| {
// if (result_) |result| {
// out_ptr.* = result.ptr;
// return @intCast(isize, result.len);
// }
// } else |err| {
// switch (err) {
// error.InvalidByteSequence => {
// return -2;
// },
// error.OutOfMemory => {
// return -1;
// },
// else => {
// return -3;
// },
// }
// }
// var out = default_allocator.alloc(u16, slice.len) catch return -1;
// strings.copyU8IntoU16(out, slice);
// out_ptr.* = out.ptr;
// return @intCast(isize, out.len);
// }
comptime {
if (!JSC.is_bindgen) {
_ = Bun__encoding__writeLatin1AsHex;
_ = Bun__encoding__writeLatin1AsURLSafeBase64;
_ = Bun__encoding__writeLatin1AsUTF16;
_ = Bun__encoding__writeLatin1AsUTF8;
_ = Bun__encoding__writeLatin1AsBase64;
_ = Bun__encoding__writeUTF16AsBase64;
_ = Bun__encoding__writeUTF16AsHex;
_ = Bun__encoding__writeUTF16AsURLSafeBase64;
_ = Bun__encoding__writeUTF16AsUTF16;
_ = Bun__encoding__writeUTF16AsUTF8;
_ = Bun__encoding__writeLatin1AsASCII;
_ = Bun__encoding__writeUTF16AsASCII;
}
}
};
comptime {
if (!JSC.is_bindgen) {
std.testing.refAllDecls(Encoder);
}
}
test "Vec" {}