2

I have a legacy library that takes data from hardware and writes it to ostream. The method looks like following :

int sensors(ostream*) const;

I am not skilled enough in Ancient Ways. How to convert this data to QByteArray? Or, at least, to char array of known size? I would have solved it myself, but there is an additional problem: the data in ostream seem to be arbitrary length and have several arbitrary '\0' symbols, so you can't count on it being null-terminated.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283

3 Answers3

2

I have not tried it, but you need something like this :

ostream s (ios::out | ios::binary);
//..Populate the stream

//Convert it to string. string can hold \0 values too.
string str = s.str ();

QByteArray ba (str.data (),str.size ());
O.C.
  • 6,711
  • 1
  • 25
  • 26
  • If you declare `s` as `std::stringstream` instead of `ostream`, this is much better than mine (no need to copy to a vector first)! – Björn Pollex Jun 27 '11 at 15:26
2

I think this is what OrcunC was getting at:

std::stringstream s;
sensors( &s );
QByteArray( s.str().data(), (int) s.str().size() );

... but hopefully more clear :). See also std::stringstream and std::string for information on the classes/member functions used here. By the way, note that I am using str().data(), not str().c_str() -- I'm being really careful to handle those \0 characters, and I'm not assuming NULL termination.

AHelps
  • 1,782
  • 11
  • 17
  • This copies the data twice. Once to the std::string s.str() and then again to the QByteArray. That is a shame. – Anthony Hayward Jan 22 '18 at 10:39
  • 1
    std::stringstream does not guarantee that the data is stored sequentially, and the QByteArray absolutely requires construction with sequential data. You could get around that extra copy if you had an ostream-derived class which guaranteed sequential storage, but that's a *much* longer answer. I agree, however, that it's a shame. – AHelps Feb 02 '18 at 04:35
  • See my non-stringstream suggestion below. – Anthony Hayward Feb 05 '18 at 12:31
1

You can subclass std::ostream and use an object of the subclass to collect the bytes into your QByteArray.

/**
 * This helper class collects bytes that are passed to it
 * into a QByteArray.
 *
 * After https://stackoverflow.com/a/19933011/316578
 */
class QByteArrayAppender : public std::ostream, public std::streambuf {
private:
    QByteArray &m_byteArray;
public:
    QByteArrayAppender(QByteArray &byteArray)
        : std::ostream(this),
          std::streambuf(),
          m_byteArray(byteArray) {
    }

    int overflow(int c) {
        m_byteArray.append(static_cast<char>(c));
        return 0;
    }
};

This avoids going via an std::string, which is an extra copy of the byte array.

Anthony Hayward
  • 2,164
  • 21
  • 17