8

Disclaimers: I am not a c++ programmer, please save me from myself.

I'm trying to create a PutObjectRequest in c++ using the AWS SDK.

I have a 'uint8_t*' (in Java-land from whence I hail we call this a byte[], I believe on planet c++ this is a buffer), and I need to get it into an Aws::IOStream somehow.

All of the examples show the data coming directly from the filesystem.

I've seen a couple of similar-ish (but not really) questions with answers that point to another third party library called Boost, but surely this is a common usecase? Why would I need a third party library to do something that should just be possible using the AWS SDK?:

"I have data, I want to put it up on S3. No it's not in the filesystem, yes I created it in memory."

uint8_t* buf; //<-- How do I get this...
...
Aws::S3::Model::PutObjectRequest object_request;
object_request.WithBucket(output_bucket).WithKey(key_name);

object_request.SetBody(data); //<-- ...into here

I really appreciate any help or pointers (no pun intended) here.

Update
I've tried everything in the comments, and this:

std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>("PutObjectInputStream");        
*objectStream << data;
objectStream->flush();
object_request.SetBody(objectStream);

and this:

std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>("PutObjectInputStream");        
std::istringstream is((char*) data);
*objectStream << is.rdbuf();
objectStream->flush();
object_request.SetBody(objectStream);

which compile, but each only uploads 2 bytes of data.

Other thing I've tried that don't compile are:

auto input_data = Aws::MakeShared<Aws::IOStream>("PutObjectInputStream", std::istringstream((char*) data), std::ios_base::in | std::ios_base::binary);
object_request.SetBody(input_data);

and

object_request.SetBody(std::make_shared<std::istringstream>( std::istringstream( (char*) spn ) ));

and these ones creates the object on S3, but with 0 bytes:

    std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>("PutObjectInputStream");
    objectStream->rdbuf()->pubsetbuf(static_cast<char*>(reinterpret_cast<char*>(data)), length);
    objectStream->rdbuf()->pubseekpos(length);
    objectStream->seekg(0);
    object_request.SetBody(objectStream);


    std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>("PutObjectInputStream");
    objectStream->rdbuf()->pubsetbuf(reinterpret_cast<char*>(data), length);
    objectStream->rdbuf()->pubseekpos(length);
    objectStream->seekg(0);
    object_request.SetBody(objectStream);
ndtreviv
  • 3,473
  • 1
  • 31
  • 45
  • Please provide a reference to `SetBody` method. [First link in google](https://sdk.amazonaws.com/cpp/api/0.12.9/df/da6/class_aws_1_1_s3_1_1_model_1_1_put_object_request.html) does not contain it. – Denis Sheremet Feb 07 '18 at 15:30
  • It's in the AWS SDK documentation, right here: https://sdk.amazonaws.com/cpp/api/0.12.9/dd/dd8/class_aws_1_1_amazon_streaming_web_service_request.html Sorry, I thought I made it clear that this was an AWS S3 PutObjectRequest. – ndtreviv Feb 07 '18 at 15:35
  • It seems you can use something like `object_request.SetBody( std::istringstream( (char*) data ) );`, but I'm unable to test it myself and not sure this is the best solution. – Denis Sheremet Feb 07 '18 at 15:40
  • Thank you for checking it. Unfortunately it doesn't compile: `error: no viable conversion from 'std::istringstream' (aka 'basic_istringstream') to 'const std::shared_ptr' (aka 'const shared_ptr > >')` – ndtreviv Feb 07 '18 at 19:22
  • What if you replace `std::istringstream` with `std::make_shared`? – Denis Sheremet Feb 08 '18 at 04:02
  • That results in this: `address of overloaded function 'make_shared' does not match required type 'std::__1::shared_ptr >'` – ndtreviv Feb 09 '18 at 14:13
  • You need to actually call `make_shared` – Ben Voigt Feb 09 '18 at 15:34
  • @BenVoigt like this: `object_request.SetBody(std::make_shared( std::istringstream( (char*) data ) )>);` ? – ndtreviv Feb 21 '18 at 12:11
  • 1
    @ndtreviv: No, `make_shared` doesn't take a parameter of type `T`, but those needed to create a `T` (the parameters for `T`'s constructor). – Ben Voigt Feb 21 '18 at 15:44

1 Answers1

14

And after hours of hacking, here is the answer:

    Aws::S3::Model::PutObjectRequest object_request;
    object_request.WithBucket(output_bucket).WithKey(key_name);
    auto data = Aws::MakeShared<Aws::StringStream>("PutObjectInputStream", std::stringstream::in | std::stringstream::out | std::stringstream::binary);
    data->write(reinterpret_cast<char*>(buffer), length);
    object_request.SetBody(data);

Thanks to Ben Voigt for pointing out that when you make_shared (or MakeShared in my case), you're not actually passing it the data at that point. You're just telling it what T you're making shared.

Also helped by nbubis' answer to this question: const char * to std::basic_iostream

ndtreviv
  • 3,473
  • 1
  • 31
  • 45
  • If you have a vector of user define struct/lass then the following works: auto data = Aws::MakeShared("PutObjectInputStream", std::stringstream::in | std::stringstream::out | std::stringstream::binary); data->write((char*)&vec[0], vec.size() * sizeof(MyData)); object_request.SetBody(data); – user1978816 Sep 23 '19 at 08:50