const char * to std::basic_iostream
Asked Answered
H

3

1

I have a pointer to a const *char buffer as well as it's length, and am trying to use an API (in this case, the AWS S3 C++ upload request) that accepts an object of type:

std::basic_iostream <char, std::char_traits <char>>

Is there a simple standard C++11 way to convert my buffer into a compatible stream, preferably without actually copying over the memory?

Hyponasty answered 3/1, 2017 at 17:1 Comment(5)
When you say I have a pointer to a const *char buffer do you really mean that you have a pointer to a const char* buffer[N], or did you intend to say that you have a pointer to a (zero terminated?) buffer of characters?Yardman
@user2079303 - The latter. It's a binary data buffer so it's not necessarily zero terminated.Hyponasty
This question looks related to meTelles
@Telles - Indeed, however, one solution involves boost which I can't currently use, and the second (pubsetbuf) doesn't work for const char.Hyponasty
std::strstream can do that, but it's deprecated. The non-deprecated counterpart is std::stringstream, but it can't work off a client-provided buffer - it always makes a copy.Fides
H
4

Thanks to Igor's comment, this seems to work:

func(const * char buffer, std::size_t buffersize)
{     
    auto sstream = std::make_shared<std::stringstream>();
    sstream->write(buffer, buffersize);
    ...
    uploadRequest.SetBody(sstream);     
    ....
Hyponasty answered 3/1, 2017 at 17:40 Comment(5)
@MarkR - Probably best to add this as an answer.Hyponasty
I thought this was the answer I, too, was looking for. But it doesn't compile: no member named 'write' in 'std::__1::basic_istringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >'Woods
Actually, it does compile if you use the std::stringstream::out flag when calling make_shared.Woods
FYI It helped me answer my question: #48667049Woods
Doesn't ->write do a copy of the data, though? I'm still looking for a copyless solution, will post if I succeed.Overdue
B
2

As a fairly obvious corollary to your solution, you can create an empty basic_iostream with code like this. This example creates a 0-byte pseudo-directory S3 key:

Aws::S3::Model::PutObjectRequest object_request; 
// dirName ends in /.             
object_request.WithBucket(bucketName).WithKey(dirName); 
// Create an empty input stream to create the 0-byte directory file. 
auto empty_sstream = std::make_shared<std::stringstream>();    
object_request.SetBody(empty_sstream); 
auto put_object_outcome = s3_client->PutObject(object_request);
Bryna answered 9/9, 2017 at 22:33 Comment(0)
S
1

If you do not want to make a copy of your data, and assuming using boost is an option, you can use basic_bufferstream from boost:

#include <boost/interprocess/streams/bufferstream.hpp>
char* buf = nullptr; // get your buffer
size_t length = 0; 
auto input = Aws::MakeShared<boost::interprocess::basic_bufferstream<char>> (
             "PutObjectInputStream",                                         
             buf,                                                            
             length); 

Then your s3 client can use it:

 Aws::S3::Model::PutObjectRequest req;
 req.WithBucket(bucket).WithKey(key);
 req.SetBody(input);
 s3.PutObject(req);
Silurian answered 3/10, 2018 at 16:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.