Use of memcpy() function with file_buffer or fstream::istream

Jul 15, 2014 at 10:03 AM
Edited Jul 15, 2014 at 11:11 AM
Here is a sample of my code :

auto filebuffer = std::make_shared<streambuf<uint8_t>>();

file_buffer<uint8_t>::open(L"d:\myfile.txt", std::ios::out)
.then([=](streambuf<uint8_t> output) -> task < http_response >
{
*filebuffer = output;
..
..
})
.then([=](http_response response)
{
response.body().read_to_end(*filebuffer);
DWORD length = filebuffer->buffer_size();
IStream *m_istream;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, length);
LPVOID pData = NULL;
pData = GlobalLock(hMem);
memcpy(hMem,filebuffer , length); //do something here, copy the data from stream into block allocated by hMem

}


How should i use memcpy??

i want to copy the data retrieved from the file_buffer or fstream::istream to the block allocated by "hMem" using memcpy() function

This is the error i am getting:
IntelliSense: no suitable conversion function from "const std::shared_ptr<Concurrency::streams::streambuf<uint8_t>>" to "const void *" exists

if there is another way around to use memcpy function, please let me know.
Jul 15, 2014 at 7:08 PM
Hi utsav_popli,

It is a little confusing what you have going on here. You are opening a file for output, then reading the response body into that file. Then it looks like you are trying to read the file for input through a raw pointer. First off you didn't open the file for input, second you can't get a raw pointer to a file stream.

I think what you are trying to do is get a raw pointer to the memory containing the response stream. Here is one way the code could look:
    http_client client(U("address"));
    http_request request(methods::GET);
    
    // set a stream backed by a vector that the entire response body should be written to
    container_buffer<std::vector<uint8_t>> responseBody; // container_buffer is in cpprest/containerstream.h
    request.set_response_stream(responseBody.create_ostream());

    client.request(request).then([](http_response response)
    {
        // headers have arrived...
        // inspect the status code...

        // return a task that will be completed once entire response body has arrived
        return response.content_ready();
    }).then([responseBody](::pplx::task<http_response> bodyArrivedTask)
    {
        try
        {
            bodyArrivedTask.wait();

            // response body has completely arrived, extract the backing vectory containing the data
            std::vector<uint8_t> body = std::move(responseBody.collection());

            // TODO you now have the response body in a std::vector and do whatever...
        }
        catch (const http_exception &e)
        {
            // handle any exceptions
        }
    });
In this snippet I'm have the response body be directly written into a std::vector. Once completed you have access to the raw memory and can do whatever. This is probably the most efficient because it avoids any additional copies. Here is another similar way, but waits until the response body has arrived and then copies into a vector.
    http_client client(U("address"));
    client.request(methods::GET).then([](http_response response)
    {
        // headers have arrived...
        // inspect the status code...

        // return a task that will be completed once entire response body has arrived
        return response.content_ready();
    }).then([](::pplx::task<http_response> bodyArrivedTask)
    {
        try
        {
            http_response response = bodyArrivedTask.get();

            // read the entire response body into a buffer backed by a vector
            container_buffer<std::vector<uint8_t>> responseBody;
            response.body().read_to_end(responseBody).wait();
            std::vector<uint8_t> body = std::move(responseBody.collection());

            // TODO you now have the response body in a std::vector and do whatever...
        }
        catch (const http_exception &e)
        {
            // handle any exceptions
        }
    });
Hope that helps.

Steve
Jul 15, 2014 at 8:50 PM
Edited Jul 15, 2014 at 8:51 PM
Thank you steve,

.then([=](pplx::task<http_response> response)
{
try{
        http_response response1 = response.get();
        std::cout << "\n" << "statuscode:";
        std::cout << response1.status_code();
        std::cout << "\n" << "response body: ";
        ucout << response1.to_string();
        container_buffer<std::vector<uint8_t>> container;
        response1.body().read_to_end(container);
        std::vector<uint8_t> body = std::move(container.collection());
        std::cout << "\n ***************";
        std::cout<<container.size();
        DWORD length = container.size();
        IStream *m_pStream;
        HGLOBAL hMem;
        LPVOID pData = NULL;
        hMem = GlobalAlloc(GMEM_MOVEABLE, length);

        pData = GlobalLock(hMem);
        memmove(pData, &body, length);    //application crash here with memmove or memcpy
        GlobalUnlock(hMem);
        std::cout << "done";
        HRESULT hr = CreateStreamOnHGlobal(hMem, TRUE, &m_pStream);
        if (hr == S_OK)
        {
            std::cout << "done";
        }
    }
    catch (const http_exception &e)
    {
        std::cout << "error";
    }
}).wait();

I tried the code you provided me, but my application just crash at memcpy or memmove !
Jul 15, 2014 at 9:08 PM
Hi utsav_popli,

Looking at your code I see two potential issues.
  1. The read_to_end operation is asynchronous you aren't actually waiting for it to complete. You need to do response1.body().read_to_end(container).wait(); Please note in general I would recommend avoiding waiting on potentially blocking I/O.
  2. In your call to memmove you are not accessing the actual memory in the vector. Instead you are treating the vector as if it is a raw pointer to the data. What you shold be doing is getting a pointer to the first element in the vector, since the data is stored contiguously. You should be doing something like this:
memmove(pData, &body[0], length);
Steve
Jul 15, 2014 at 9:14 PM
Edited Jul 15, 2014 at 9:18 PM
Yes, thank you so much. It works !!!
The problem was with the asynchronous wait operation.

response1.body().read_to_end(container).wait();


This work very fine.