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

我正在为DAB开发板编写Node.js前端,后者最终将运行在Raspberry Pi上。 我是一个Java和Web开发人员,我正在努力与C ++和不同types的string之间转换。

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

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

mode意味着FMDABnamemode意味着长名或短名。 该程序的名称将在programName中返回。

为了将wchar_t *programName转换为v8::String ,我find了我正在使用的这个片段,并且理解了以下基本知识:

  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)); 

我遍历可用的程序,并build立一个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提前退出,而不是复制后面的字符。

为什么会这样呢? 有没有更好的方法来创build一个v8::String从我的wchar_t

注意:在Raspberry Pi上运行时,我现在已经能够将这个问题分解到wcstombs方法。 以下代码:

 #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
但是在Raspberry上运行时,输出
wcslen of wchar_t array: 10 - strlen of char array: 3 – 也就是说,它只计算字符之前的字符

这看起来类似于这个没有答案的问题 。

 WCHAR str[256];0 ... // fill str array here Local<String> v8str = String::NewFromTwoByte(isolate, (const uint16_t *) str); 

注意::NewFromTwoByte用法代替::NewFromUtf8(const uint16_t *) ::NewFromUtf8

::NewFromTwoByte从UTF-16数据分配一个新的string。

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

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

尝试

 memset(cbuff, 0, sizeof(cbuff)); wcstombs( cbuff, buff, sizeof(cbuff) ); 

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

所以将locale设置为UTF-8变体解决了这个问题:

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

完成这个之后,我现在可以这样创buildv8::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));