在Unix下用jsc运行本地JS文件时替代window.btoa()的方法
window.btoa() in JavaScriptCore (jsc) Without Node.js Got it, let's work through this problem since you're stuck with window.btoa() missing in JSC (JavaScriptCore) and can't use Node.js because you need to integrate this into a C++ program. Here are three practical solutions that fit your use case perfectly:
1. Implement btoa() Purely in JavaScript
Since btoa() is just Base64 encoding for ASCII strings, you can write a standalone JS implementation that doesn't rely on any host environment objects like window. This is the quickest fix if you want to keep everything in your .js file.
function btoa(str) { const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; let result = ''; let i = 0; // Handle Unicode by first encoding to UTF-8 str = unescape(encodeURIComponent(str)); while (i < str.length) { const c1 = str.charCodeAt(i++) & 0xff; const c2 = i < str.length ? str.charCodeAt(i++) & 0xff : 0; const c3 = i < str.length ? str.charCodeAt(i++) & 0xff : 0; const enc1 = c1 >> 2; const enc2 = ((c1 & 0x3) << 4) | (c2 >> 4); const enc3 = ((c2 & 0xf) << 2) | (c3 >> 6); const enc4 = c3 & 0x3f; result += base64Chars[enc1] + base64Chars[enc2]; result += i > str.length + 1 ? base64Chars[64] : base64Chars[enc3]; result += i > str.length ? base64Chars[64] : base64Chars[enc4]; } return result; }
Just drop this function into your script, and you can call btoa() exactly like you would in a browser—no window required.
2. Extend JSC's Global Object via C++ API
Since you're going to run this script inside a C++ program, you can use JSC's C API to add the btoa function directly to the global scope. This approach is more robust, especially if you want to leverage system-level Base64 utilities (like OpenSSL on Unix) for better performance.
Here's a simplified example of how to do this:
#include <JavaScriptCore/JavaScriptCore.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <cstdlib> // C implementation of btoa that uses OpenSSL for Base64 encoding JSValueRef JSBtoa(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { if (argumentCount < 1) { return JSValueMakeUndefined(ctx); } // Convert JS string to UTF-8 C string JSStringRef inputStr = JSValueToStringCopy(ctx, arguments[0], exception); size_t strLen = JSStringGetLength(inputStr); char* inputBuffer = (char*)malloc(strLen + 1); JSStringGetUTF8CString(inputStr, inputBuffer, strLen + 1); // Use OpenSSL to encode to Base64 BIO* base64Filter = BIO_new(BIO_f_base64()); BIO_set_flags(base64Filter, BIO_FLAGS_BASE64_NO_NL); // No newline characters BIO* memoryBuffer = BIO_new(BIO_s_mem()); base64Filter = BIO_push(base64Filter, memoryBuffer); BIO_write(base64Filter, inputBuffer, strLen); BIO_flush(base64Filter); char* encodedData; long encodedLen = BIO_get_mem_data(memoryBuffer, &encodedData); JSStringRef encodedStr = JSStringCreateWithUTF8CString(encodedData); JSValueRef result = JSValueMakeString(ctx, encodedStr); // Clean up resources BIO_free_all(base64Filter); free(inputBuffer); JSStringRelease(inputStr); JSStringRelease(encodedStr); return result; } // Attach the btoa function to JSC's global object void setupJSCGlobalContext(JSContextRef ctx) { JSObjectRef globalObj = JSContextGetGlobalObject(ctx); JSStringRef btoaName = JSStringCreateWithUTF8CString("btoa"); JSObjectRef btoaFunction = JSObjectMakeFunctionWithCallback(ctx, btoaName, JSBtoa); // Set the function as a global property JSObjectSetProperty(ctx, globalObj, btoaName, btoaFunction, kJSPropertyAttributeNone, NULL); JSStringRelease(btoaName); }
Once you set up the context like this, your JS script can call btoa() directly—no need for window, and you get the reliability of a system-level encoding library.
3. Use JSC's Built-in Text Encoding (If Available)
Some newer versions of JavaScriptCore include the TextEncoder API, which you can use to roll your own Base64 encoder. Note that this isn't guaranteed to work on all JSC versions, but it's worth testing if you want a more modern approach:
function btoa(str) { const encoder = new TextEncoder(); const utf8Bytes = encoder.encode(str); const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; let result = ''; for (let i = 0; i < utf8Bytes.length; i += 3) { const triplet = (utf8Bytes[i] << 16) | ((utf8Bytes[i+1] || 0) << 8) | (utf8Bytes[i+2] || 0); result += base64Chars[(triplet >> 18) & 0x3F]; result += base64Chars[(triplet >> 12) & 0x3F]; result += base64Chars[(triplet >> 6) & 0x3F]; result += base64Chars[triplet & 0x3F]; } // Fix padding for incomplete triplets const padding = utf8Bytes.length % 3; if (padding > 0) { result = result.slice(0, result.length - (3 - padding)) + '='.repeat(3 - padding); } return result; }
This avoids manual UTF-8 handling since TextEncoder does it for you, but double-check compatibility with your JSC version first.
内容的提问来源于stack exchange,提问作者levaa

