Pass Node.js Buffer to C++ addon - c++

test.js
buf = new Buffer(100);
for (var i = 0; i < 100; i++) buf[i] = i
addon.myFync(buf);
addon.cpp
Handle<Value> set(const Arguments& args) {
char *buf = SOMETHING(args[0]);
return Undefined();
}
How to get the pointer to a data of the buffer inside the C++ function?
What should I write in place of SOMETHING(args[0])?
I have node_buffer.h opened in my editor, but I cannot figure out.
Node version = v0.10.29

You can do:
char* buf = node::Buffer::Data(args[0]);
to directly access the bytes of a Buffer.

According to the node.js node binding documentation the 'arg[0]' value argument can be accessed as:
String::AsciiValue v(args[0]->ToString());

Related

Creating Vulkan instance causes access violation

I am trying to initialize the Vulkan API.
The problem I am having is that I get an access violation error after I call vkCreateInstance and I think the problem comes from the extension and layer lists.
I am using a char buff[20][256] to transfer them from strings to the structure for the API call, and the layer and extension names I see in the debugger(3 extensions and 15 layers) are all a lot shorter than 256 characters and are all null terminated.
There is no buffer overflow with the extension or layer names, yet it crashes.
The layer and extension lists of strings I received trough using vkEnumerateInstanceExtensionProperties and vkEnumerateInstanceLayerProperties beforehand and are all valid null-terminated strings like "VK_KHR_surface", etc.
Is it possible that even tho it says I support some extensions, that I don't really support them and the API is crashing when it's trying to initialize an extension I don't support?
void InitializeInstance(void** instance, const vector<string>& layers, const vector<string>& extensions)
{
VkApplicationInfo applicationInfo;
VkInstanceCreateInfo instanceInfo;
VkInstance* instanceOut = (VkInstance*)instance;
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pNext = nullptr;
applicationInfo.pApplicationName = "MyApp";
applicationInfo.pEngineName = "MyEngine";
applicationInfo.engineVersion = 1;
applicationInfo.apiVersion = VK_API_VERSION_1_0;
instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceInfo.pNext = null;
instanceInfo.flags = 0;
instanceInfo.pApplicationInfo = &applicationInfo;
char buffLayer[20][256];
char buffExt[20][256];
if(!layers.empty())
{
instanceInfo.enabledLayerCount = layers.size();
for(int i = 0; i < layers.size(); i++)
{
strcpy(buffLayer[i], layers[i].c_str());
}
instanceInfo.ppEnabledLayerNames = (char**)buffLayer;
}
else
{
instanceInfo.enabledLayerCount = 0;
instanceInfo.ppEnabledLayerNames = nullptr;
}
if(!extensions.empty())
{
instanceInfo.enabledExtensionCount = extensions.size();
for(int i = 0; i < extensions.size(); i++)
{
strcpy(buffExt[i], extensions[i].c_str());
}
instanceInfo.ppEnabledExtensionNames = (char**)buffExt;
}
else
{
instanceInfo.enabledExtensionCount = 0;
instanceInfo.ppEnabledExtensionNames = nullptr;
}
vkCreateInstance(&instanceInfo, nullptr, instanceOut);
}
When I have only 0 extensions AND 0 layers, it creates successfully. If any of them is not 0, it crashes.
char buffLayer[20][256];
instanceInfo.ppEnabledLayerNames = (char**)buffLayer;
ppEnabledLayerNames is supposed to be an array of pointers to character arrays. But you're passing it a 2D array of characters, which is effectively just an array of 20*256 characters.
If you're on a machine with 32-bit pointers, the driver is going to take the first four bytes in buffLayer and treat them as a pointer to a character array. But you've just stored the first four characters of a layer name there, and 'VK_K' is probably not going to be a valid pointer value :). So the loader will crash when trying to dereference that invalid pointer.
Probably the simplest change would be to add:
char* layerNames[20];
for (int i = 0; i < 20; i++)
layerNames[i] = &buffLayer[i][0];
and pass layerNames as ppEnabledLayerNames.

C++ from linux to windows: 'does not evaluate to a constant'

I am trying to port this function from Linux to windows:
template<class TDescriptor, class F>
bool TemplatedVocabulary<TDescriptor,F>::loadFromBinaryFile(const std::string &filename) {
fstream f;
f.open(filename.c_str(), ios_base::in|ios::binary);
unsigned int nb_nodes, size_node;
f.read((char*)&nb_nodes, sizeof(nb_nodes));
f.read((char*)&size_node, sizeof(size_node));
f.read((char*)&m_k, sizeof(m_k));
f.read((char*)&m_L, sizeof(m_L));
f.read((char*)&m_scoring, sizeof(m_scoring));
f.read((char*)&m_weighting, sizeof(m_weighting));
createScoringObject();
m_words.clear();
m_words.reserve(pow((double)m_k, (double)m_L + 1));
m_nodes.clear();
m_nodes.resize(nb_nodes+1);
m_nodes[0].id = 0;
char buf[size_node];// fails
int nid = 1;
while (!f.eof()) {
f.read(buf, size_node);
m_nodes[nid].id = nid;
// FIXME
const int* ptr=(int*)buf;
m_nodes[nid].parent = *ptr;
//m_nodes[nid].parent = *(const int*)buf;
m_nodes[m_nodes[nid].parent].children.push_back(nid);
m_nodes[nid].descriptor = cv::Mat(1, F::L, CV_8U);
memcpy(m_nodes[nid].descriptor.data, buf+4, F::L);
m_nodes[nid].weight = *(float*)(buf+4+F::L);
if (buf[8+F::L]) { // is leaf
int wid = m_words.size();
m_words.resize(wid+1);
m_nodes[nid].word_id = wid;
m_words[wid] = &m_nodes[nid];
}
else
m_nodes[nid].children.reserve(m_k);
nid+=1;
}
f.close();
return true;
}
This line:
char buf[size_node];
will not compile, giving the error:
expression did not evaluate to a constant.
I have tried using:
std::vector<char> buf(size_node)
and:
char buf[size_node] = new char[];
but I see the same error. It seems like this is related to a run time constant vs compile time constant, as stated in the answer here:
Tuple std::get() Not Working for Variable-Defined Constant
But I am not sure how to get around it in this case. Thank you.
It should be
char *buf = new char[size_node];
Remember to delete the memory after use.
Or, just use std::vector. It's much safer.
std::vector<char> buf(size_node);
Then you'd have to change how buf is used. For example:
f.read(buf, size_node);
should become
f.read(buf.data(), size_node); //Only C++11

How to export array data through node addon

I'm using node 0.12.x, I want to return some array data from node addon written by c++
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
This is a sample for returning Number data.
using namespace v8;
Create an array:
Local<Array> myArray = Array::New(isolate);
You can then create objects with properties (or just integers) and push them into the array:
for (int i = 0; i < n; i++) {
Local<Object> obj = Object::New(isolate);
obj->Set(String::NewFromUtf8(isolate, "tag1"), "test");
myArray->Set(i, obj);
}
args.GetReturnValue().Set(myArray);
If you're writing native code for node.js I highly recommend using nan:
https://github.com/nodejs/nan

Strange symbols when i'm trying to get char array from structure

I'm working with libuv (https://github.com/joyent/libuv) and nodejs v12. I I write native module, in this module i have struct:
struct Work_req
{
const char *data;
size_t data_length;
Isolate* isolate;
unsigned int callback_id;
Persistent<Function> callback;
};
Then i try to pass this structure to work:
Work_req* request = new Work_req;
request->data = buf->base;
request->data_length = (size_t)nread;
request->isolate = env->isolate();
request->callback_id = callback_id->ToNumber()->Value();
uv_work_t *req = new uv_work_t;
req->data = request;
uv_queue_work(env->event_loop(), req, findCallback, after_findCallback);
In the end of this code i passed work to loop and all is ok.
But when i'm trying to read data from uv_work_t *req in findCallback function, i get strange symbols there:
Work_req *s = ((struct Work_req*)req->data);
printf(s>data); //print char array from structure here
I see something like this:
����g�Kack_id":1,"error":null,"response":{"type":"test"}}�����
How i can fix it?
Thanks a lot.

Trouble with byte array marshaling in ObjC/C++ to C# in IOS

** This is still unsolved **
I'm trying to call an ObjC/C++ function code from C#. I've done my best to follow different example code, the latest being mostly from:
http://msdn.microsoft.com/en-us/library/ms146631(v=VS.80).aspx
This is for an iPhone/MonoTouch environment, so I'm not sure I've done everything I should. The bytes appear to be ok in the ObjC/C++ function, but the byte array I get back into C# ends up containing 0 0 0 0 0 0 etc.
** Update **
Corrected for loop initializer, and now its giving a EXC_BAD_ACCESS signal on the *returnbytes[i] = bytes[i]; line.
C# code:
[DllImport ("__Internal")]
private static extern int _getjpeg(string url,ref IntPtr thebytes);
void somefunction(string image_id) {
int maxsize = 50000;
byte[] thebytes = new byte[maxsize];
IntPtr byteptr = Marshal.AllocHGlobal(maxsize);
int imagesize = _getjpeg(image_id,ref byteptr);
Debug.Log("Getting _picturesize()... "+ image_id);
int picsize = _picturesize();
Marshal.Copy(byteptr,thebytes,0,picsize);
var texture = new Texture2D(1,1);
string bytedebug = "";
for (int i=5000 ; i < 5020 ; i++)
bytedebug+=thebytes[i] + " ";
Debug.Log("Bytes length is "+imagesize);
Debug.Log("Bytes content is "+bytedebug);
}
C++/ObjC code:
int _getjpeg(const char* url,unsigned char** returnbytes) {
ALAsset* asset = [_pictures objectForKey:[NSString stringWithUTF8String:url]];
if(asset != NULL)
NSLog(#"_getjpeg() found URL: %#",[NSString stringWithUTF8String: url]);
else {
NSLog(#"_getjpeg() could not find URL: %#",[NSString stringWithUTF8String: url]);
return NULL;
}
UIImage *image = [UIImage imageWithCGImage: [asset thumbnail]];
NSData* pictureData = UIImageJPEGRepresentation (image, 1.0);
picturesize = (int)[pictureData length];
unsigned char* bytes = (unsigned char*)[pictureData bytes];
// This test does not give EXC_BAD_ACCESS
*returnbytes[5] = (unsigned int)3;
// updated below initializer in below for loop according to Eikos suggestion
for(int i=0 ; i < picturesize ; i++) {
// below lines gives EXC_BAD_ACCESS
*returnbytes[i] = bytes[i];
}
NSString* debugstr = [NSString string];
for(int i=5000; i < 5020 ; i++) {
unsigned char byteint = bytes[i];
debugstr = [debugstr stringByAppendingString:[NSString stringWithFormat:#"%i ",byteint]];
}
NSLog(#"bytes %s",[debugstr UTF8String]);
return picturesize;
}
Thanks
Keep in mind that the JPGRepresentation is probably not exactly the same as you put into it, so the length may differ.
In
for(int i;i < picturesize;i++) {
// *** Not sure I'm doing this correctly ***
*returnbytes[i] = bytes[i];
}
you forget to initialize i, so it might start with a random value which is bigger than picturesize, so the loop won't run at all.
You want unsigned char*, not **. You are passing a pointer in that is already allocated. A ** is for when you are passing in a pointer to variable that is itself a pointer to data: i.e. when the callee will allocate the memory and the caller wants to know about it.
Just pass in unsigned char* and then use
returnbytes[i] = bytes[i];
Alternatively, allocate in the calee and use an out, not a ref.