Shuyang
Shuyang

Reputation: 519

C++ std::istringstream how to not terminate at '\0'

There is a function Foo that takes in an input stream of char. I want to call Foo from my function Bar, which takes in a C-style array with size. char is used to represent a byte (not using std::byte because it's difficult to get it working with streams).

void Foo(std::basic_istream<char>& stream) { /* ... */ }

// absl::Span<const char> in my code, using char pointer
// and size here for simplicity.
void Bar(const char * const arr, const size_t size) {
  std::basic_istream<char> stream = ArrToStream(arr, size);
  foo(stream);
}

I'm struggling to implement ArrToStream.

If I pass an instance of std::ifstream to Foo, everything works as expected. When it comes to ArrToStream, seems like the most recommended approach is just to use std::istringstream like the following:

std::basic_istream<char> ArrToStream(
  const char * const arr,
  const size_t size
) {
  return std::istringstream(arr, size);
}

However, this only works if there is no '\0' character in the array. There are many 0 bytes in my data, so the input string stream treats them as null terminators and stops reading the stream. I tried calling stream.clear() and stream.seekg(...) but no luck so far, the string stream simply refuse to read past 0's.

Is there a way to read or ignore '\0'? If not, what's the best way to represent byte streams in C++20?

Upvotes: -1

Views: 228

Answers (1)

Jerry Coffin
Jerry Coffin

Reputation: 490178

It's not clear (at least to me) what problem you're encountering. It's pretty easy to initialize a stringstream with a string that contains NUL characters:

#include <sstream>
#include <cassert>
#include <string>
#include <iostream>

int main() { 
    // a string of 100 NUL characters
    std::string data(100, '\0');

    // initialize the stream from that string
    std::istringstream input (data);

    // initialize a string with other characters:
    std::string data_read(20, '1');

    // read data from stream:
    if (input.read(data_read.data(), 20))
        for (int i=0; i<20; i++) {
            // and assure that we read the NULs that we expected:
            assert(data_read[i] == '\0');
        }
    else
        std::cerr << "Read failed\n";
}

At least when I run this, it succeeds, indicating that the NULs were place in the stream, and that we successfully read them back out afterwards.

Upvotes: 2

Related Questions