You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Unix下用jsc运行本地JS文件时替代window.btoa()的方法

Solutions for 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:21:32