Search code examples
c++c++11visual-c++iostreambuf

Writing char* into a basic_streambuf and assign it to a ifstream


I have a problem, mostly because I can't really understand how to handle the situation.

I have a char* buffer of X size, it's the content of an encrypted file who's got decrypted and will be then parsed by the ifstream handler class that i can't edit.

So my idea was to create an fstream object in which, with rdbuf() assign the buffer with sputn.

fstream _handle2; _handle2.rdbuf()->sputn(_buffer, _size); _handle2.flush();

But of course, it's not working and buffer does not get written into the fstream object, do you have any idea of how to make it so?

I tried different methods but I clearly can't figure out what to do.


Solution

  • I'm trying to create a buffer type that can be parsed similarly to a ifstream.

    You might try something like this (adopted from the link I provided in the comment already):

    std::ifstream ifs("test.txt", std::ifstream::binary);
    if (ifs)
    {
        ifs.seekg (0, ifs.end);
        int length = ifs.tellg();
        ifs.seekg (0, ifs.beg);
    
        std::string buffer;
        buffer.resize(length);
        ifs.read(const_cast<char*>(buffer.data()), length);
        if (ifs)
        {
            // de-crypt the buffer here!
            // something like:
            // buffer[i] = decryptChar(buffer[i]);
    
            std::istringstream iss(buffer);
    
            // now you can use iss just the same way as ifs,
            // if the file was not encrypted...
    
        }
        else
        {
            std::cout << "error: only " << ifs.gcount() << " bytes could be read";
        }
        ifs.close();
    }
    

    Edit in response to your comment:

    std::istringstream is used to convert text into binary data, e. g. int n; iss >> n; would convert the string "20102012", represented by ascii sequence 0x32, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x32 into the corresponding four-byte integer value of 0x0132bb7c). But if data is already binary, std::istringstream is not suitable. Then you might rather try to write your own stream class similar to this example:

    class DecryptionStream
    {
        std::unique_ptr<char> mBuffer;
        char* mEnd;
        char* mPos;
        unsigned int flags;
    
        unsigned int const eofbit  = 1 << 0;
        unsigned int const failbit = 1 << 1;
        // other flag bits as needed
    
    public:
        // fail/eof bits as needed
        DecryptionStream(char const* fileName) : mPos(nullptr)
        {
            std::ifstream ifs(fileName, std::ifstream::binary);
            if (ifs)
            {
                ifs.seekg (0, ifs.end);
                int length = ifs.tellg();
                ifs.seekg (0, ifs.beg);
    
                mBuffer.reset(new char[length]);
                ifs.read(mBuffer.get(), length);
                if (ifs)
                {
                    // de-crypt the buffer here!
                    // something like:
                    // buffer[i] = decryptChar(buffer[i]);
                    mPos = mBuffer.get();
                    mEnd = mBuffer.get() + length;
                }
                else
                {
                    flags |= failbit;
                }
                ifs.close();
            }
        }
    
        template<typename T>
        DecryptionStream& operator >>(T& t)
        {
            // fail, if any fail bit set already
            size_t avail = mPos - mEnd;
            if (avail < sizeof(t))
            {
                flags |= eofbit | failbit;
            }
            else
            {
                if(avail == sizeof(t))
                {
                    flags |= eofbit;
                }
                memcpy(&t, mPos, sizeof(t));
                mPos += sizeof(t);
            }
            return *this;
        }
    
        operator bool()
        {
            return flags == 0;
        }
    };
    

    You could even use this class with complex data types - then make sure, though, that you control byte alignment of these appropriately, otherwise you might fail badly!