代码之家  ›  专栏  ›  技术社区  ›  Vidar S. Ramdal

使用非ASCII字符从wchar_t创建v8::String的安全方法是什么?

  •  2
  • Vidar S. Ramdal  · 技术社区  · 9 年前

    我在写节点。js前端 DAB development board ,最终将在树莓派上运行。我是一名Java和web开发人员,我正在与C++和不同类型字符串之间的转换进行斗争。

    DAB板带有一个C++SDK,具有许多方便的功能。它允许我使用 GetTotalProgram() 。对于我可以调用的每个程序 GetProgramName 获取程序名称:

    GetProgramName(char mode, long dabIndex, char namemode, wchar_t * programName)
    

    哪里 mode 方法 FM DAB , namemode 表示长或短名称。程序名称将在 programName .

    为了转换 wchar_t *programName 进入 v8::String ,我找到了我正在使用的这个片段,并了解了以下内容的基础知识:

      wchar_t buff[300];
      char cbuff[600];
      GetProgramName(0, i, 1, buff);
      wcstombs( cbuff, buff, wcslen(buff) );
      Local<String> str = String::NewFromUtf8(isolate, (const char *) cbuff, v8::String::kNormalString, wcslen(buff));
    

    我遍历可用的程序并建立一个 v8::Array :

    void GetPrograms(const FunctionCallbackInfo<Value>& args) {
      Isolate* isolate = Isolate::GetCurrent();
      HandleScope scope(isolate);
    
      wchar_t buff[300];
      char cbuff[600];
      int numberOfPrograms, i;
    
      numberOfPrograms = GetTotalProgram();
      Local<v8::Array> ARRAY = Array::New(isolate, totalprogram);
    
      for (i = 0; i < numberOfPrograms; i++) {
        if (GetProgramName(0, i, 1, buff)) {
          wcstombs( cbuff, buff, wcslen(buff) );
          Local<String> str = String::NewFromUtf8(isolate, (const char *) cbuff, v8::String::kNormalString, wcslen(buff));
          Local<Object> obj = Object::New(isolate);
          obj->Set(String::NewFromUtf8(isolate, "name"), str);
          ARRAY->Set(i, obj);
        }
      }
      args.GetReturnValue().Set(ARRAY);
    }
    

    我从Node应用程序调用C++方法:

    var programs = ext.getPrograms();
    for (var i = 0; i < programs.length; i++) {
      console.log(programs[i][name]);
    }
    

    这通常有效,但当程序名包含非ASCII字符时,如 Æ , Ø , à 这个 下一个 ARRAY中的元素具有borked名称 .

    下面是Node片段实际输出的内容( console.log ),与预期产量相比:

    | ACTUAL    | EXPECTED   |
    | --------- | ---------- |
    | NRK SUPER | NRK SUPER  |
    | NRK VUPER | NRK VÆR    |
    | NRK P1 ER | NRK P1     |
    

    似乎非ASCII字符导致下一个 wcstombs 提前退出,而不是复制后面的字符。

    为什么会发生这种情况?是否有更好的方法来创建 v8::字符串 从我的 wchar_t ?

    注: 我现在能够将这个问题归结为 wcostobs公司 在Raspberry Pi上运行时使用。以下代码:

    #include <stdio.h>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    
    char cbuff[600];
    wchar_t buff[300] = L"ABCø123abc";
    
    int main( int argc, const char* argv[] ) {
        wcstombs( cbuff, buff, wcslen(buff) );
        wprintf(L"wcslen of wchar_t array: %u - strlen of char array: %u\n", (char) wcslen(buff), strlen(cbuff));
    }
    

    在Mac上运行时,输出
    wcslen of wchar_t array: 10 - strlen of char array: 10 ,
    但当在树莓上运行时,输出
    wcslen of wchar_t array: 10 - strlen of char array: 3 -也就是说,它只计算 ø 性格

    这看起来类似于 this unanswered question .

    3 回复  |  直到 8 年前
        1
  •  3
  •   ANTARA    8 年前
    WCHAR str[256];0
    ... // fill str array here
    Local<String> v8str = String::NewFromTwoByte(isolate, (const uint16_t *) str);
    

    注意 ::NewFromTwoByte 用法而不是 ::NewFromUtf8 (const uint16_t *) 铸造

    ::NewFromTwoByte 从UTF-16数据中分配一个新字符串。

        2
  •  0
  •   Anil8753    9 年前

    我想wcstoms中的最后一个参数是问题的原因。而不是尝试

     wcstombs( cbuff, buff, wcslen(buff) );
    

    尝试

    memset(cbuff, 0, sizeof(cbuff));
    wcstombs( cbuff, buff, sizeof(cbuff) );
    
        3
  •  0
  •   Vidar S. Ramdal    9 年前

    问题出在 wcstombs( cbuff, buff, wcslen(buff) ) 调用,当遇到非ASCII字符时,它将停止复制字符。这个 docs 此函数的行为取决于所选C语言环境的LC_CTYPE类别。

    因此,将区域设置为UTF-8变体解决了问题:

    setlocale(LC_CTYPE, "C.UTF-8");
    

    完成此操作后,我现在可以创建 v8::String 是这样的:

    wchar_t buff[300] = L"Something non-ASCII ÆØÅ here";
    char cbuff[600];
    wcstombs( cbuff, buff, wcslen(buff) );
    Local<String> str = String::NewFromUtf8(isolate, (const char *) cbuff, v8::String::kNormalString, wcslen(buff));