1

I am trying to create a native nodejs module, using NAN and c ++, I want to transform an existing program that uses std::ifstream stream (filename, std :: ifstream :: in | std :: ifstream :: binary); to load a file into a javascript module that can load a buffer and send it to c ++

The original c ++ code was made to work via command line, I don't want to have to write a file to disk, I would like to send this file using a nodejs buffer.

index.js

const fs = require('fs')
const addon = require('./build/Release/image_edit');

fs.readFile('image.png', function read(err, buffer) {
    if (err) {
        throw err;
    }

    var result = addon.edit(buffer, buffer.length);
    //console.log(result)

});

main.cpp

#include <node.h>
#include <node_buffer.h>
#include <iostream>
#include <nan.h>
#include <sstream>
#include <string>
#include <fstream>
#include <streambuf>
#include <istream>

using namespace Nan;
using namespace v8;

uint32_t read(std::istream& in)
{
    uint32_t v;
    in.read(reinterpret_cast<char*>(&v), sizeof(v));
    return v;
}

NAN_METHOD(edit) {

    unsigned char*buffer = (unsigned char*) node::Buffer::Data(info[0]->ToObject());
    unsigned int size = info[1]->Uint32Value();

    //the closest I could to manipulating the data was using a vector
    std::vector<uint32_t> png_data(buffer, buffer + size);

    //The main core of the program uses the in.read function to parse the file, tb uses in.clear () and in.seekg ();
    //here an example of how this is done
    uint32_t count = readU32(stream);


}

NAN_MODULE_INIT(Init) {
   Nan::Set(target, New<String>("edit").ToLocalChecked(),
        GetFunction(New<FunctionTemplate>(edit)).ToLocalChecked());
}

NODE_MODULE(image_edit, Init)

I tried using the following code to verify that the data received is valid and if the recorded file is the same as the original, everything looks fine.

std::ofstream FILE("test.png", std::ios::out | std::ofstream::binary);
        std::copy(png_data.begin(), png_data.end(), std::ostreambuf_iterator<char>(FILE));

The question is, how do I make this buffer received from nodejs into something read the same way an ifstream does, without having to drastically change the c ++ program?

The main methods called by the program in c ++ are: .seekg (), .push_back, .clear (),

Stan
  • 191
  • 7

2 Answers2

2

This kind of thing is usually done by implementing a custom subclass of std::streambuf, and then using it to construct a std::istream.

std::istream has a constructor that takes a pointer to a std::streambuf as a parameter, so the basic outline is something like this

class my_streambuf : public std::streambuf {

      // ... Your implementation of your subclass
};

my_streambuf msb{ /* Parameters to your class's constructor */ }

std::istream i{&msb};

At this point, i is an ordinary input stream and does everything that any other input stream does. You can seek it. You can read from it.

Of course, the hard part is implementing your custom subclass of std::streambuf. This is not something that can be fully described in one or two paragraphs on stackoverflow.com. You should read std::streambuf's documentation, specifically the descriptions of its virtual methods. Your custom subclass will need to reimplement std::streambuf's virtual methods and make them work with your buffer. It's likely you will not need to reimplement all the virtual methods. For some of them their default implementation will be sufficient. Some of them won't be needed, for what you end up doing with std::istream.

You will have to determine, based on you specific needs to what extent you need to reimplement which std::streambuf's virtual methods, and how.

Of course, another, easy alternative is to use your buffer to construct a std::string, and then using it to construct a std::istringstream, and call it a day. Of course, that'll be somewhat wasteful and require effectively doubling the memory used for the data, with a second copy that's owned by a throw-away std::string, and copying it. If this is a small amount of data that's probably fine, but if your buffer is very big that may not be practical, and a custom std::streambuf subclass that uses the buffer directly is your only option.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Sorry, I'm new to c ++, I can't build a custom subclass, can you help me? or at least help with an example of how I do it using "istringstream" – Stan Aug 03 '19 at 12:13
  • What you need to do [is find a good C++ book and start reading it](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). C++ is the most complicated general purpose programming language in use today. It takes time to learn C++, and the best help you can get is pointers to good resources which one can use to learn C++, see above. There are no shortcuts to learning C++, no magic buttons to push and C++ code pops out. It takes time. You need to start learning C++ basics first, instead of going heads first into a complex library of its own, like node. That comes later. – Sam Varshavchik Aug 03 '19 at 12:21
  • I'm not interested in learning c ++ right now, I'm just trying to reuse a legacy program, I didn't want to completely rewrite it. Can you help me with an example using std :: istringstream? – Stan Aug 03 '19 at 12:28
  • learning c ++ in 2019 only in specific cases, but not my case, I'm just wanting to port a legacy system for fun. – Stan Aug 03 '19 at 19:19
1

Like the other answer mentioned, you can use an std::stringstream if you don't want to go the std::streambuf route:

std::stringstream ss;
std::copy(png_data.begin(), png_data.end(), std::ostreambuf_iterator<uint32_t>(ss));

Then you just use it like an input stream.

David G
  • 94,763
  • 41
  • 167
  • 253
  • I have the following runtime error: terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc – Stan Aug 03 '19 at 17:04
  • only the: char* buffer = node::Buffer::Data(info[0]->ToObject()); size_t size = node::Buffer::Length(info[0]); – Stan Aug 03 '19 at 17:09
  • @Stan Try `ostreambuf_iterator` instead of `ostream_iterator`. If that doesn't work, try stepping through the code with a debugger and finding where the exception is thrown. Is `size` small or large? – David G Aug 03 '19 at 17:16
  • @Stan Glad I could help. – David G Aug 03 '19 at 17:23