std::ostream interface to an OLE IStream - c++

I have a Visual Studio 2008 C++ application using IStreams. I would like to use the IStream connection in a std::ostream. Something like this:
IStream* stream = /*create valid IStream instance...*/;
IStreamBuf< WIN32_FIND_DATA > sb( stream );
std::ostream os( &sb );
WIN32_FIND_DATA d = { 0 };
// send the structure along the IStream
os << d;
To accomplish this, I've implemented the following code:
template< class _CharT, class _Traits >
inline std::basic_ostream< _CharT, _Traits >&
operator<<( std::basic_ostream< _CharT, _Traits >& os, const WIN32_FIND_DATA& i )
{
const _CharT* c = reinterpret_cast< const _CharT* >( &i );
const _CharT* const end = c + sizeof( WIN32_FIND_DATA ) / sizeof( _CharT );
for( c; c < end; ++c ) os << *c;
return os;
}
template< typename T >
class IStreamBuf : public std::streambuf
{
public:
IStreamBuf( IStream* stream ) : stream_( stream )
{
setp( reinterpret_cast< char* >( &buffer_ ),
reinterpret_cast< char* >( &buffer_ ) + sizeof( buffer_ ) );
};
virtual ~IStreamBuf()
{
sync();
};
protected:
traits_type::int_type FlushBuffer()
{
int bytes = std::min< int >( pptr() - pbase(), sizeof( buffer_ ) );
DWORD written = 0;
HRESULT hr = stream_->Write( &buffer_, bytes, &written );
if( FAILED( hr ) )
{
return traits_type::eof();
}
pbump( -bytes );
return bytes;
};
virtual int sync()
{
if( FlushBuffer() == traits_type::eof() )
return -1;
return 0;
};
traits_type::int_type overflow( traits_type::int_type ch )
{
if( FlushBuffer() == traits_type::eof() )
return traits_type::eof();
if( ch != traits_type::eof() )
{
*pptr() = ch;
pbump( 1 );
}
return ch;
};
private:
/// data queued up to be sent
T buffer_;
/// output stream
IStream* stream_;
}; // class IStreamBuf
Yes, the code compiles and seems to work, but I've not had the pleasure of implementing a std::streambuf before. So, I'd just like to know if it's correct and complete.
Thanks,
PaulH

Here's an implementation I wrote a while ago: https://github.com/senderista/UnbufferedOLEStreamBuf
For the most part you just need to mechanically translate between STL and Windows/COM types. This translation is tedious and error-prone, though, so you would probably be best off using the implementation I linked. It's only 150 lines, it was used in a production application, and there are few places for bugs to hide.
Since apparently links in answers are cause for deletion, here's the code in its entirety:
//Copyright (c) 2010 Tobin Baker
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
#include <ios>
#include <streambuf>
#include <windows.h>
// Read-write unbuffered streambuf implementation which uses no
// internal buffers (conventional wisdom says this can't be done
// except for write-only streams, but I adapted Matt Austern's example
// from http://www.drdobbs.com/184401305).
class UnbufferedOLEStreamBuf : public std::streambuf {
public:
UnbufferedOLEStreamBuf(IStream *stream, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
~UnbufferedOLEStreamBuf();
protected:
virtual int overflow(int ch = traits_type::eof());
virtual int underflow();
virtual int uflow();
virtual int pbackfail(int ch = traits_type::eof());
virtual int sync();
virtual std::streampos seekpos(std::streampos sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
virtual std::streamsize xsgetn(char *s, std::streamsize n);
virtual std::streamsize xsputn(const char *s, std::streamsize n);
virtual std::streamsize showmanyc();
private:
IStream *stream_;
bool readOnly_;
bool backup();
};
UnbufferedOLEStreamBuf::UnbufferedOLEStreamBuf(IStream *stream, std::ios_base::openmode which)
: std::streambuf(), stream_(stream), readOnly_(!(which & std::ios_base::out)) {}
UnbufferedOLEStreamBuf::~UnbufferedOLEStreamBuf() { if (!readOnly_) UnbufferedOLEStreamBuf::sync(); }
bool UnbufferedOLEStreamBuf::backup() {
LARGE_INTEGER liMove;
liMove.QuadPart = -1LL;
return SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_CUR, NULL));
}
int UnbufferedOLEStreamBuf::overflow(int ch) {
if (ch != traits_type::eof()) {
if (SUCCEEDED(stream_->Write(&ch, 1, NULL))) {
return ch;
}
}
return traits_type::eof();
}
int UnbufferedOLEStreamBuf::underflow() {
char ch = UnbufferedOLEStreamBuf::uflow();
if (ch != traits_type::eof()) {
ch = backup() ? ch : traits_type::eof();
}
return ch;
}
int UnbufferedOLEStreamBuf::uflow() {
char ch;
ULONG cbRead;
// S_FALSE indicates we've reached end of stream
return (S_OK == stream_->Read(&ch, 1, &cbRead))
? ch : traits_type::eof();
}
int UnbufferedOLEStreamBuf::pbackfail(int ch) {
if (ch != traits_type::eof()) {
ch = backup() ? ch : traits_type::eof();
}
return ch;
}
int UnbufferedOLEStreamBuf::sync() {
return SUCCEEDED(stream_->Commit(STGC_DEFAULT)) ? 0 : -1;
}
std::ios::streampos UnbufferedOLEStreamBuf::seekpos(std::ios::streampos sp, std::ios_base::openmode which) {
LARGE_INTEGER liMove;
liMove.QuadPart = sp;
return SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_SET, NULL)) ? sp : -1;
}
std::streampos UnbufferedOLEStreamBuf::seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) {
STREAM_SEEK sk;
switch (way) {
case std::ios_base::beg: sk = STREAM_SEEK_SET; break;
case std::ios_base::cur: sk = STREAM_SEEK_CUR; break;
case std::ios_base::end: sk = STREAM_SEEK_END; break;
default: return -1;
}
LARGE_INTEGER liMove;
liMove.QuadPart = static_cast<LONGLONG>(off);
ULARGE_INTEGER uliNewPos;
return SUCCEEDED(stream_->Seek(liMove, sk, &uliNewPos))
? static_cast<std::streampos>(uliNewPos.QuadPart) : -1;
}
std::streamsize UnbufferedOLEStreamBuf::xsgetn(char *s, std::streamsize n) {
ULONG cbRead;
return SUCCEEDED(stream_->Read(s, static_cast<ULONG>(n), &cbRead))
? static_cast<std::streamsize>(cbRead) : 0;
}
std::streamsize UnbufferedOLEStreamBuf::xsputn(const char *s, std::streamsize n) {
ULONG cbWritten;
return SUCCEEDED(stream_->Write(s, static_cast<ULONG>(n), &cbWritten))
? static_cast<std::streamsize>(cbWritten) : 0;
}
std::streamsize UnbufferedOLEStreamBuf::showmanyc() {
STATSTG stat;
if (SUCCEEDED(stream_->Stat(&stat, STATFLAG_NONAME))) {
std::streampos lastPos = static_cast<std::streampos>(stat.cbSize.QuadPart - 1);
LARGE_INTEGER liMove;
liMove.QuadPart = 0LL;
ULARGE_INTEGER uliNewPos;
if (SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_CUR, &uliNewPos))) {
return std::max<std::streamsize>(lastPos - static_cast<std::streampos>(uliNewPos.QuadPart), 0);
}
}
return 0;
}
std::streambuf* StdStreamBufFromOLEStream(IStream *pStream, std::ios_base::openmode which)
{
return new (std::nothrow) UnbufferedOLEStreamBuf(pStream, which);
}
Hope this helps.

My suggestion would be to use Boost.IOStreams Device to wrap the IStream. It takes care of all of the C++ IO streams stuff so that you do not have to.

Related

Template for WinAPI functions

Is it possible to somehow create a template for WinAPI functions? For example, there are two similar functions (LookupPrivilegeName and LookupPrivilegeDisplayName), but with different set of parameters. I call both functions like this: the first call retrieves required buffer size, the second call returns desired value. If this is not possible, are there any alternative ways to make the code more compact?
You likely want something like:
template<typename CharT>
bool LookupPriviledgeDisplayName(CharT const *, CharT const *, DWORD *, std::basic_string<CharT> & strDisplayName);
template<>
bool LookupPriviledgeDisplayName<char>(char const * pszSystem, char const * pszName, DWORD * pdwLangID, std::basic_string <char> & strDisplayName)
{
DWORD dwLength = 0;
if(!LookupPrivilegeDisplayNameA(pszSystem, pszName, nullptr, &dwLength, pdwLangID))
return false;
std::vector<char> buffer(dwLength + 1);
if(!LookupPrivilegeDisplayNameA(pszSystem, pszName, &buffer[0], &dwLength, pdwLangID))
return false;
strDisplayName.assign(&buffer[0], &buffer[0] + dwLength);
return true;
}
template<>
bool LookupPriviledgeDisplayName<wchar_t>(wchar_t const * pszSystem, wchar_t const * pszName, DWORD * pdwLangID, std::basic_string <wchar_t> & strDisplayName)
{
DWORD dwLength = 0;
if(!LookupPrivilegeDisplayNameW(pszSystem, pszName, nullptr, &dwLength, pdwLangID))
return false;
std::vector<wchar_t> buffer(dwLength + 1);
if(!LookupPrivilegeDisplayNameW(pszSystem, pszName, &buffer[0], &dwLength, pdwLangID))
return false;
strDisplayName.assign(&buffer[0], &buffer[0] + dwLength);
return true;
}
Something like this. The main idea is to separate code by functionality avoiding duplication.
#include <memory>
#include <string>
#include <iostream>
#include <system_error>
#include <cassert>
// Error handler.
void
On_Error(const ::DWORD error_code)
{
throw ::std::system_error{static_cast<int>(error_code), ::std::system_category()};
}
// Error check.
void
Validate_LookupPrivilegeNameSuccess(const ::BOOL result, const bool expect_insufficient_buffer)
{
if(FALSE == result)
{
auto const error_code{::GetLastError()};
if((ERROR_INSUFFICIENT_BUFFER == error_code) && (!expect_insufficient_buffer))
{
On_Error(error_code);
}
}
}
enum class
t_PrivilegeNameCategoryId
{
name
, display_name
};
// Helper class calling WinAPI methods, checking input and output.
template<t_PrivilegeNameCategoryId> class
t_LookupPrivilegeNameImpl;
template<> class
t_LookupPrivilegeNameImpl<t_PrivilegeNameCategoryId::name> final
{
public: static ::std::size_t
Lookup(const ::LPCWSTR psz_system_name, ::LUID & luid, const ::LPWSTR p_buffer, ::DWORD buffer_capacity_items_count)
{
assert((0 == buffer_capacity_items_count) || (nullptr != p_buffer));
Validate_LookupPrivilegeNameSuccess
(
::LookupPrivilegeNameW
(
psz_system_name
, ::std::addressof(luid)
, p_buffer
, ::std::addressof(buffer_capacity_items_count)
)
, nullptr == p_buffer
);
return(buffer_capacity_items_count);
}
};
template<> class
t_LookupPrivilegeNameImpl<t_PrivilegeNameCategoryId::display_name> final
{
public: static ::std::size_t
Lookup(const ::LPCWSTR psz_system_name, const ::LPCWSTR psz_display_name, const ::LPWSTR p_buffer, ::DWORD buffer_capacity_items_count)
{
assert(psz_display_name);
assert(L'\0' != psz_display_name[0]);
assert((0 == buffer_capacity_items_count) || (nullptr != p_buffer));
::DWORD language_id{};
Validate_LookupPrivilegeNameSuccess
(
::LookupPrivilegeDisplayNameW
(
psz_system_name
, psz_display_name
, p_buffer
, ::std::addressof(buffer_capacity_items_count)
, ::std::addressof(language_id)
)
, nullptr == p_buffer
);
return(buffer_capacity_items_count);
}
};
// Lookup function implementing get size -> resize buffer -> get data algorithm.
template<t_PrivilegeNameCategoryId name_category_id, typename... TArgs> void
Lookup_PrivilegeName(::std::wstring & name, TArgs &&... args)
{
try
{
name.resize(t_LookupPrivilegeNameImpl<name_category_id>::Lookup(::std::forward<TArgs>(args)..., ::LPWSTR{}, ::DWORD{}));
t_LookupPrivilegeNameImpl<name_category_id>::Lookup(::std::forward<TArgs>(args)..., name.data(), static_cast<::DWORD>(name.size()));
if(name.empty() || (L'\0' != name.back()))
{
On_Error(ERROR_UNIDENTIFIED_ERROR);
}
name.pop_back();
}
catch(...)
{
name.clear();
throw;
}
}
int main()
{
::LPCWSTR psz_system_name{};
::LUID privilege_luid{5}; // a wild guess
::std::wstring privilege_name{};
Lookup_PrivilegeName<t_PrivilegeNameCategoryId::name>(privilege_name, psz_system_name, privilege_luid);
::std::wstring privilege_display_name{};
Lookup_PrivilegeName<t_PrivilegeNameCategoryId::display_name>(privilege_display_name, psz_system_name, privilege_name.c_str());
::std::wcout << privilege_name << L"\n" << privilege_display_name << ::std::endl;
return(0);
}
My Russian friend explained to me the limitations of templates. Instead of them, he suggested using functions with context switching. In my situation it will be something like this:
BOOL LookupData(DWORD context, PLUID luid, wstring input, wstring & output) {
BOOL status = TRUE;
DWORD buflen = 0, lang = 0;
switch (context) {
case 0: status = LookupPrivilegeName(NULL, luid, NULL, &buflen); break;
case 1: status = LookupPrivilegeDisplayName(NULL, input.c_str(), NULL, &buflen, &lang); break;
default: return FALSE;
}
if (!status && ERROR_INSUFFICIENT_BUFFER != GetLastError()) return status;
auto buffer = make_unique<wchar_t[]>(buflen);
switch (context) {
case 0: status = LookupPrivilegeName(NULL, luid, buffer.get(), &buflen); break;
case 1: status = LookupPrivilegeDispayName(NULL, input.c_str(), buffer.get(), &buflen, &lang); break;
}
if (!status) {
buf.release();
return status;
}
output = buf.get();
buf.release();
return status;
}
Now I can write in cycle after getting TOKEN_PRIVILEGES structures:
std::wstring name, desription;
if (!LookupData(0, tp->Privipeges[i].Luid, L"", name)) break;
if (!LookupData(1, NULL, name, description)) break;
std::wcout << name << L" - " << std::endl;
Of course, it's dirty trick but it works.

C++ Implementing SFML InputStream

I'm trying to implement a custom InputStream but I'm having trouble doing so.
I seem to be opening the zip file just fine, and the library I'm using (https://bitbucket.org/wbenny/ziplib/wiki/Home) automatically gives me an istream* to the
data.
Yet I keep failing when I try to load the image file texture with the stream through:
sf::Texture::loadFromStream(sf::InputStream)
Any ideas as to what I'm doing incorrectly?
sf::InputStream
sf::Texture::loadFromStream
Here's my implementation:
Header)
#include <ZipFile.h>
namespace lvn
{
class NStream : public sf::InputStream
{
private:
ZipArchiveEntry::Ptr m_entry;
std::shared_ptr<std::istream> m_File = nullptr;
std::string m_filename;
//bool m_file_is_open = false;
public:
static bool ReadTxtFile( std::string filepath, tstring& textbuffer );
NStream( std::string pathName="" );
virtual ~NStream();
bool isOpen() const;
bool open( std::string pathName );
void close();
virtual sf::Int64 read( void* data, sf::Int64 size );
virtual sf::Int64 seek( sf::Int64 position );
virtual sf::Int64 tell();
virtual sf::Int64 getSize();
};
}
CPP)
#include <ZipFile.h>
#include "NStream.h"
namespace lvn
{
NStream::NStream( std::string pathName )
//: m_File( 0x00 )
{
using namespace std;
open( pathName );
}
NStream::~NStream( )
{
close( );
}
bool NStream::isOpen( ) const
{
//return (m_File != 0x0);
return ( m_File != nullptr );
}
//Ex. Images//albert.png
bool NStream::open( std::string pathName )
{
using namespace std;
close( );
auto archive_name = pathName.substr( 0, pathName.find( "/" ) ) + (".vndat"); //need to add the archive extension to the name
ZipArchive::Ptr archive = ZipFile::Open( archive_name );
m_entry = archive->GetEntry( pathName );
if ( m_entry == nullptr )
return false;
m_File = make_shared<istream>( nullptr );
m_File->rdbuf( m_entry->GetDecompressionStream()->rdbuf() );
m_filename = pathName;
return isOpen( );
}
void NStream::close( )
{
m_File.reset( );
}
sf::Int64 NStream::read( void* data, sf::Int64 size )
{
if ( !isOpen( ) )
return -1;
auto posPrev = tell();
m_File->read( static_cast<char *>( data ), size );
auto cur = tell();
return tell() - posPrev;
}
sf::Int64 NStream::seek( sf::Int64 position )
{
if ( !isOpen( ) )
return -1;
m_File->seekg( position );
return tell( );
}
sf::Int64 NStream::tell( )
{
if ( !isOpen( ) )
return -1;
// istream returns the offset in bytes or -1 on error just like SFML wants.
return m_File->tellg( );
}
sf::Int64 NStream::getSize( )
{
if ( !isOpen( ) )
return -1;
//get length of file (by seeking to end), then restore original offset
const auto originalIdx = tell( );
m_File->seekg( 0, m_File->end );
const sf::Int64 length = tell( );
seek( originalIdx );
// tell returns length of file or -1 on error just like SFML wants.
return length;
}
}
Example usage (should work but doesn't: loadFromStream fails):
auto pTextureStream = make_shared<NStream>();
pTextureStream->open( "Images/image.png" );
auto pTexture = make_shared<sf::Texture>();
pTexture->loadFromStream( *pTextureStream );
This is my implementation, I hope you find it useful
class StreamSFML : public sf::InputStream
{
std::shared_ptr<std::istream> m_source;
public:
explicit StreamSFML(std::shared_ptr<std::istream> stream) : m_source(stream) {}
sf::Int64 read(void* data, sf::Int64 size) override
{
m_source->read(static_cast<char*>(data), size);
return m_source->gcount();
}
sf::Int64 seek(sf::Int64 position) override
{
m_source->seekg(position, m_source->beg);
return m_source->gcount();
}
sf::Int64 tell() override
{
return m_source->tellg();
}
sf::Int64 getSize() override
{
auto curr = m_source->tellg();
m_source->seekg(0, m_source->end);
sf::Int64 pos = static_cast<sf::Int64>(m_source->tellg());
m_source->seekg(curr, m_source->beg);
return pos;
}
};

how can I design a RAII file descriptor without creating a new int

I want to create a RAII wrapper around a file descriptor. As the object might be passed around threads, it really is a shared resource: this is why I made a first implementation by using a shared_ptr with a custom destructor.
struct file_descriptor
{
file_descriptor( const std::string & pathname, int flags )
:m_fd( initialize( pathname, flags ) )
{
}
file_descriptor( const int opened_fd )
:m_fd( initialize( opened_fd ) )
{
}
operator int() const { return *m_fd; }
private:
std::shared_ptr<int> initialize( const int opened_fd )
{
std::shared_ptr<int> ptr_to_fd;
try
{
int * shared_fd = new int;
ptr_to_fd = std::shared_ptr<int>( shared_fd, file_descriptor_closer() );
*shared_fd = opened_fd;
}
catch( std::bad_alloc & )
{
close( opened_fd );
throw;
}
return ptr_to_fd;
}
std::shared_ptr<int> initialize( const std::string & pathname, int flags )
{
const int fd = open( pathname.c_str(), flags );
if (fd < 0)
throw std::system_error( std::error_code(errno, std::system_category() ), "cannot create file descriptor" );
return initialize( fd );
}
std::shared_ptr<int> m_fd;
};
The custom destructor, is pretty simple:
struct file_descriptor_closer
{
void operator()(int * const fd) noexcept { if (fd) close(*fd); delete fd; }
};
Now I find the design horrible, namely because of the "new int". I thought about making a custom allocator to point to an already-allocated block, but that seems overkill. Do you guys have suggestion to simplify this?
IMHO, you're mixing responsibilities. Let your RAII class deal with the opening and closing of the file descriptor. Let some other class deal with the lifetime question of your RAII class. As you have it now, the user of your file_descriptor class would need to know that it is using a shared_ptr internally. On first glance, if I were to share a file_descriptor between threads, I'd be making a shared_ptr<file_descriptor> of my own to counter the problem that I don't really know that internally it's already doing one.
use some gentle violence:
struct file_descriptor_closer
{
void operator()(void* fd) noexcept { if (fd) close(reinterpret_cast< int >(fd)); }
};
struct file_descriptor
{
file_descriptor( const std::string & pathname, int flags )
:m_fd( initialize( pathname, flags ) )
{
}
file_descriptor( const int opened_fd )
:m_fd( initialize( opened_fd ) )
{
}
operator int() const { return reinterpret_cast< int >(m_fd.get()); }
private:
std::shared_ptr<void> initialize( const int opened_fd )
{
try
{
return std::shared_ptr< void >( reinterpret_cast< void* >( opened_fd ), file_descriptor_closer() );
}
catch( std::bad_alloc & )
{
close( opened_fd );
throw;
}
}
std::shared_ptr<void> initialize( const std::string & pathname, int flags )
{
const int fd = open( pathname.c_str(), flags );
if (fd < 0)
throw std::system_error( std::error_code(errno, std::system_category() ), "cannot create file descriptor" );
return initialize( fd );
}
std::shared_ptr<void> m_fd;
};
Why not create your own container? What about something like: http://ideone.com/m3kmaJ or with static counter: http://ideone.com/Gs4Kb7
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <thread>
#include <memory>
#include <unistd.h>
#include <atomic>
class FD
{
private:
int fd;
static int count;
public:
FD(const char* FilePath, int flags) : fd(open(FilePath, flags)) {++FD::count;}
FD(const FD& other) : fd(other.fd) {++FD::count;}
FD(FD&& other) : fd(other.fd) { other.fd = -1; }
~FD()
{
FD::count -= 1;
if (FD::count == 0)
{
std::cout<<"Destroyed\n";
if (is_open())
close(fd);
}
}
bool is_open() {return fd != -1;}
FD* operator &() {return nullptr;}
operator int() {return fd;}
FD& operator = (FD other)
{
fd = other.fd;
FD::count += 1;
return *this;
}
FD& operator = (FD&& other)
{
fd = other.fd;
other.fd = -1;
return *this;
}
};
int FD::count = 0;
int main()
{
FD fd = FD("Unicode.cpp", O_RDONLY);
FD copy = fd;
FD cpy = FD(copy);
return 0;
}

Handle socket descriptors like file descriptor (fstream)? C++/Linux

By accident I found out that I can use read and write on socket descriptors. Can I somehow (ab)use the fstream mechanism to output data into the socket descriptor?
The standard file stream doesn't support use of a file descriptor. However, the I/O stream classes make it reasonably easy to create your own abstraction which allows creating your own sources of or destination for characters. The magic class is std::streambuf whose responsibility is to buffer characters and read or write characters at appropriate times. Nicolai Josuttis's "The C++ Standard Library" has a detailed description of how to do so (the basis of which I contributed to Nico many years ago). A simple implementation of a stream buffer using a socket for reading and writing would look something like this:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <streambuf>
#include <cstddef>
#include <unistd.h>
class fdbuf
: public std::streambuf
{
private:
enum { bufsize = 1024 };
char outbuf_[bufsize];
char inbuf_[bufsize + 16 - sizeof(int)];
int fd_;
public:
typedef std::streambuf::traits_type traits_type;
fdbuf(int fd);
~fdbuf();
void open(int fd);
void close();
protected:
int overflow(int c);
int underflow();
int sync();
};
fdbuf::fdbuf(int fd)
: fd_(-1) {
this->open(fd);
}
fdbuf::~fdbuf() {
this->close();
}
void fdbuf::open(int fd) {
this->close();
this->fd_ = fd;
this->setg(this->inbuf_, this->inbuf_, this->inbuf_);
this->setp(this->outbuf_, this->outbuf_ + bufsize - 1);
}
void fdbuf::close() {
if (!(this->fd_ < 0)) {
this->sync();
::close(this->fd_);
}
}
int fdbuf::overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
*this->pptr() = traits_type::to_char_type(c);
this->pbump(1);
}
return this->sync() == -1
? traits_type::eof()
: traits_type::not_eof(c);
}
int fdbuf::sync() {
if (this->pbase() != this->pptr()) {
std::streamsize size(this->pptr() - this->pbase());
std::streamsize done(::write(this->fd_, this->outbuf_, size));
// The code below assumes that it is success if the stream made
// some progress. Depending on the needs it may be more
// reasonable to consider it a success only if it managed to
// write the entire buffer and, e.g., loop a couple of times
// to try achieving this success.
if (0 < done) {
std::copy(this->pbase() + done, this->pptr(), this->pbase());
this->setp(this->pbase(), this->epptr());
this->pbump(size - done);
}
}
return this->pptr() != this->epptr()? 0: -1;
}
int fdbuf::underflow()
{
if (this->gptr() == this->egptr()) {
std::streamsize pback(std::min(this->gptr() - this->eback(),
std::ptrdiff_t(16 - sizeof(int))));
std::copy(this->egptr() - pback, this->egptr(), this->eback());
int done(::read(this->fd_, this->eback() + pback, bufsize));
this->setg(this->eback(),
this->eback() + pback,
this->eback() + pback + std::max(0, done));
}
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*this->gptr());
}
int main()
{
fdbuf inbuf(0);
std::istream in(&inbuf);
fdbuf outbuf(1);
std::ostream out(&outbuf);
std::copy(std::istreambuf_iterator<char>(in),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(out));
}

FILE * and istream: connect the two?

Suppose I "popen" an executable, I get a FILE* in return. Furthermore, suppose I'd like to "connect" this file to an istream object for easier processing, is there a way to do this?
You can get away by deriving std::basic_streambuf or std::streambuf classes.
Something along these lines:
#include <stdio.h>
#include <iostream>
#define BUFFER_SIZE 1024
class popen_streambuf : public std::streambuf {
public:
popen_streambuf() : fp(NULL) {
}
~popen_streambuf() {
close();
}
popen_streambuf *open(const char *command, const char *mode) {
fp = popen(command, mode);
if (fp == NULL)
return NULL;
buffer = new char_type[BUFFER_SIZE];
// It's good to check because exceptions can be disabled
if (buffer == NULL) {
close();
return NULL;
}
setg(buffer, buffer, buffer);
return this;
}
void close() {
if (fp != NULL) {
pclose(fp);
fp = NULL;
}
}
std::streamsize xsgetn(char_type *ptr, std::streamsize n) {
std::streamsize got = showmanyc();
if (n <= got) {
memcpy(ptr, gptr(), n * sizeof(char_type));
gbump(n);
return n;
}
memcpy(ptr, gptr(), got * sizeof(char_type));
gbump(got);
if (traits_type::eof() == underflow()) {
return got;
}
return (got + xsgetn(ptr + got, n - got));
}
int_type underflow() {
if (gptr() == 0) {
return traits_type::eof();
}
if (gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
size_t len = fread(eback(), sizeof(char_type), BUFFER_SIZE, fp);
setg(eback(), eback(), eback() + (sizeof(char_type) * len));
if (0 == len) {
return traits_type::eof();
}
return traits_type::to_int_type(*gptr());
}
std::streamsize showmanyc() {
if (gptr() == 0) {
return 0;
}
if (gptr() < egptr()) {
return egptr() - gptr();
}
return 0;
}
private:
FILE *fp;
char_type *buffer;
};
int main(int argc, char *argv)
{
char c;
popen_streambuf sb;
std::istream is(&sb);
if (NULL == sb.open("ls -la", "r")) {
return 1;
}
while (is.read(&c, 1)) {
std::cout << c;
}
return 0;
}
There is no standard way but if you want a quick solution you can get the file descriptor with fileno() and then use Josuttis' fdstream. There may be similar efforts around but I used this in the distant past and it worked fine. If nothing else it should be a very good map to implementing your own.
Sure there's a way, implement your own istream that can be constructed from a FILE*.
If you're asking whether there is a standard way to do this, then no.