使用非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
意味着FM
或DAB
, namemode
意味着长名或短名。 该程序的名称将在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));