vector-of-bool / cmrc

A Resource Compiler in a Single CMake Script
MIT License
672 stars 74 forks source link

Using CMakeRC file objects with std::istream #51

Closed prosilio closed 10 months ago

prosilio commented 10 months ago

I am trying to pass a cmrc resource file to a function that takes a std::istream object as input. In order to do that, I create a std::streambuf object from the cmrc data, which I can then pass to std::istream. There are two issues I've encountered:

Is there some way to make this work? I could probably create a string from the data and then pass it to a std:istringstream, but I am trying to avoid the copy, as my data files could be very large. This is all rather new territory for me, so I wouldn't be surprised if I just overlooked something obvious.

include <cmrc/cmrc.hpp>

#include <cstddef>
#include <iostream>
#include <streambuf>

CMRC_DECLARE(simple);

struct membuf : std::streambuf {
    membuf(char *begin, char *end) { this->setg(begin, begin, end); }
};

int main() {
    auto fs = cmrc::simple::get_filesystem();
    auto data = fs.open("hello.txt");
    // Instead of const_cast, Krzysztof Tomaszewski at The Art of Code provides 
    // a solution to use const char* with streambuf.
    // https://artofcode.wordpress.com/2010/12/12/deriving-from-stdstreambuf/
    // However, I wanted to keep things simple for this example.
    membuf data_buf(const_cast<char*>(data.begin()),
                    const_cast<char*>(data.end()));
    std::istream data_stream(&data_buf);
    data_stream.seekg(0, data_stream.end);
    size_t data_size = data_stream.tellg();
    std::cout << data_size << '\n'; // This prints 18446744073709551615 on my computer.
}
prosilio commented 10 months ago

Based on this info:

I think my problem is that I need to implement my own seekoff and seekpos. While the root problem is not CMakeRC, I'll post my solution here (if I figure it out) in the hope that those with similar use cases may find it helpful.

prosilio commented 10 months ago

It turns out that strstream does what exactly what I need (see example below). Unfortunately, strstream has been deprecated for a very long time. Fortunately, spanstream in C++23 is a near drop-in replacement for strstream.

#include <cmrc/cmrc.hpp>

#include <iostream>
#include <strstream>

CMRC_DECLARE(simple);

int main()
{
    auto fs = cmrc::simple::get_filesystem();
    auto data = fs.open("hello.txt");
    std::istrstream data_stream(data.begin(), data.size());
    data_stream.seekg(0, data_stream.end);
    size_t data_size = data_stream.tellg();
    std::cout << std::string(data.begin(), data.end()) << '\n';
    std::cout << "String length: " << data_size << '\n';
}

/*
Hello, world!
String length: 13
*/