#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 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(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(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& 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