#include "xstream.h"
#if defined(HAVE_CONFIG_H)
#include "config.h"
#else
#define HAVE_LIBTIRPC 1
#endif
#if defined(HAVE_LIBTIRPC)
namespace xdr
{
// xbyte
xbyte::xbyte() {}
xbyte::xbyte(unsigned char c0): c(c0) {}
xbyte::xbyte(int c0): c((unsigned char) c0) {}
xbyte::xbyte(unsigned c0): c((unsigned char) c0) {}
int xbyte::byte() const
{
return c;
}
xbyte::operator unsigned char() const
{
return c;
}
// xios
int xios::good() const { return _state == 0; }
int xios::eof() const { return _state & eofbit; }
int xios::fail() const { return !good();}
int xios::bad() const { return _state & badbit; }
void xios::clear(int state) {_state=state;}
void xios::set(int flag) {_state |= flag;}
xios::operator void*() const { return fail() ? (void*)0 : (void*)(-1); }
int xios::operator!() const { return fail(); }
// xstream
xstream::~xstream() {}
xstream::xstream(): xios(), buf(nullptr) {}
void xstream::precision(int) {}
xstream& xstream::seek(OffsetType pos, seekdir dir) {
if(buf) {
clear();
if(fseeko(buf,pos,dir) != 0) set(failbit);
}
return *this;
}
OffsetType xstream::tell() {
return ftello(buf);
}
// ixstream
ixstream::ixstream(bool singleprecision)
: singleprecision(singleprecision)
{
}
void ixstream::open(const char* filename, open_mode)
{
clear();
buf=fopen(filename,"rb");
if(buf) xdrstdio_create(&xdri,buf,XDR_DECODE);
else set(badbit);
}
void ixstream::close()
{
closeFile();
}
void ixstream::closeFile()
{
if(buf) {
#ifndef _CRAY
xdr_destroy(&xdri);
#endif
fclose(buf);
buf=nullptr;
}
}
ixstream::ixstream(const char* filename, bool singleprecision)
: singleprecision(singleprecision)
{
ixstream::open(filename);
}
ixstream::ixstream(const char* filename, open_mode mode, bool singleprecision)
: singleprecision(singleprecision)
{
ixstream::open(filename,mode);
}
ixstream::~ixstream()
{
ixstream::close();
}
ixstream& ixstream::operator>>(imanip func)
{
return (*func)(*this);
}
ixstream& ixstream::operator>>(double& x)
{
if(singleprecision)
{
float f;
*this >> f;
x=(double) f;
} else
if(!xdr_double(&xdri, &x)) set(eofbit);
return *this;
}
ixstream& ixstream::operator>>(xbyte& x)
{
int c=fgetc(buf);
if(c != EOF) x=c;
else set(eofbit);
return *this;
}
// oxstream
oxstream::oxstream(bool singleprecision): singleprecision(singleprecision)
{
}
void oxstream::open(const char* filename, open_mode mode)
{
clear();
buf=fopen(filename,(mode & app) ? "ab" : "wb");
if(buf) xdrstdio_create(&xdro,buf,XDR_ENCODE);
else set(badbit);
}
void oxstream::close()
{
closefile();
}
void oxstream::closefile()
{
if(buf) {
#ifndef _CRAY
xdr_destroy(&xdro);
#endif
fclose(buf);
buf=NULL;
}
}
oxstream::oxstream(const char* filename, bool singleprecision)
: singleprecision(singleprecision)
{
oxstream::open(filename);
}
oxstream::oxstream(const char* filename, open_mode mode, bool singleprecision)
: singleprecision(singleprecision)
{
oxstream::open(filename,mode);
}
oxstream::~oxstream()
{
closefile();
}
oxstream& oxstream::flush() {if(buf) fflush(buf); return *this;}
oxstream& oxstream::operator<<(omanip func) { return (*func)(*this); }
oxstream& oxstream::operator<<(double x)
{
if(singleprecision)
*this << (float) x;
else
if(!xdr_double(&xdro, &x)) set(badbit);
return *this;
}
oxstream& oxstream::operator<<(xbyte x) {
if(fputc(x.byte(),buf) == EOF) set(badbit);
return *this;
}
memoxstream::memoxstream(bool singleprecision)
: oxstream(singleprecision)
#if defined(_WIN32)
,fmInstance()
#endif
{
clear();
#if defined(_WIN32)
fmem_init(&fmInstance);
buf=fmem_open(&fmInstance, "w+");
#else
buf=open_memstream(&buffer,&size);
#endif
if(buf)
xdrstdio_create(&xdro,buf,XDR_ENCODE);
else
set(badbit);
}
memoxstream::~memoxstream()
{
closefile();
#if defined(_WIN32)
fmem_term(&fmInstance);
#else
free(buffer);
#endif
}
std::vector<uint8_t> memoxstream::createCopyOfCurrentData() {
auto flushResult = fflush(buf);
if (flushResult != 0)
{
std::cerr << "cannot flush memory xstream";
exit(EXIT_FAILURE);
}
#if defined(_WIN32)
size_t retSize=0;
void* streamPtr=nullptr;
// DANGER: There's a severe but rare issue with certain systems
// involving a potential memory leak.
// See
https://github.com/Kreijstal/fmem/issues/6
// Right now, we have no reasonable way to determine if a tmpfile
// implementation is being used, so we cannot have a way to
// conditionally free the memory.
// On most systems, we have the open_memstream and Windows tmpfile API,
// where the allocation/mapping is handled by the system; hence
// there is no need to free the pointer ourselves.
// But the tmpfile implementation uses malloc that doesn't
// get freed, so it is our job to manually free it.
fmem_mem(&fmInstance, &streamPtr, &retSize);
if (streamPtr == nullptr)
{
return {};
}
auto* bytePtr = static_cast<uint8_t*>(streamPtr);
std::vector ret(bytePtr, bytePtr + retSize);
return ret;
#else
// for sanity check, always ensure that we have a vector of bytes
static_assert(sizeof(char) == sizeof(uint8_t));
if (buffer == nullptr)
{
return {};
}
auto* retPtr = reinterpret_cast<uint8_t*>(buffer);
return {retPtr, retPtr + size};
#endif
}
// memixstream
memixstream::memixstream(char* data, size_t length, bool singleprecision)
: ixstream(singleprecision)
{
xdrmem_create(&xdri,data,length,XDR_DECODE);
}
memixstream::memixstream(std::vector<char>& data, bool singleprecision)
: memixstream(data.data(), data.size(), singleprecision)
{
}
memixstream::~memixstream()
{
xdr_destroy(&xdri);
}
void memixstream::close()
{
xdr_destroy(&xdri);
}
void memixstream::open(const char* filename, open_mode openMode)
{
}
// ioxstream
void ioxstream::open(const char* filename, open_mode mode)
{
clear();
if(mode & app)
buf=fopen(filename,"ab+");
else if(mode & trunc)
buf=fopen(filename,"wb+");
else if(mode & out) {
buf=fopen(filename,"rb+");
if(!buf)
buf=fopen(filename,"wb+");
} else
buf=fopen(filename,"rb");
if(buf) {
xdrstdio_create(&xdri,buf,XDR_DECODE);
xdrstdio_create(&xdro,buf,XDR_ENCODE);
} else set(badbit);
}
void ioxstream::close() {
if(buf) {
#ifndef _CRAY
xdr_destroy(&xdri);
xdr_destroy(&xdro);
#endif
fclose(buf);
buf=NULL;
}
}
ioxstream::ioxstream()
{
}
ioxstream::ioxstream(const char* filename)
{
ioxstream::open(filename);
}
ioxstream::ioxstream(const char* filename, open_mode mode)
{
ioxstream::open(filename,mode);
}
ioxstream::~ioxstream()
{
ioxstream::close();
}
oxstream& endl(oxstream& s) { s.flush(); return s; }
oxstream& flush(oxstream& s) {s.flush(); return s;}
}
#endif