summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/lldictionary.h2
-rw-r--r--indra/llcommon/llfile.cpp705
-rw-r--r--indra/llcommon/llfile.h423
3 files changed, 945 insertions, 185 deletions
diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h
index bc3bc3e74a..c752859a36 100644
--- a/indra/llcommon/lldictionary.h
+++ b/indra/llcommon/lldictionary.h
@@ -30,6 +30,8 @@
#include <map>
#include <string>
+#include "llerror.h"
+
struct LL_COMMON_API LLDictionaryEntry
{
LLDictionaryEntry(const std::string &name);
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index c51d042a3d..38b0dfdaf1 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -56,6 +56,8 @@ std::string strerr(int errn)
return buffer;
}
+typedef std::basic_ios<char,std::char_traits < char > > _Myios;
+
#else
// On Posix we want to call strerror_r(), but alarmingly, there are two
// different variants. The one that returns int always populates the passed
@@ -324,9 +326,10 @@ const char *LLFile::tmpdir()
/***************** Modified file stream created to overcome the incorrect behaviour of posix fopen in windows *******************/
-#if USE_LLFILESTREAMS
+#if LL_WINDOWS
-LLFILE * LLFile::_Fiopen(const std::string& filename, std::ios::openmode mode,int) // protection currently unused
+LLFILE * LLFile::_Fiopen(const std::string& filename,
+ std::ios::openmode mode,int) // protection currently unused
{ // open a file
static const char *mods[] =
{ // fopen mode strings corresponding to valid[i]
@@ -385,117 +388,677 @@ LLFILE * LLFile::_Fiopen(const std::string& filename, std::ios::openmode mode,in
return (0);
}
-/************** input file stream ********************************/
+#endif /* LL_WINDOWS */
-void llifstream::close()
-{ // close the C stream
- if (_Filebuffer && _Filebuffer->close() == 0)
+/************** llstdio file buffer ********************************/
+
+
+//llstdio_filebuf* llstdio_filebuf::open(const char *_Filename,
+// ios_base::openmode _Mode)
+//{
+//#if LL_WINDOWS
+// _Filet *_File;
+// if (is_open() || (_File = LLFILE::_Fiopen(_Filename, _Mode)) == 0)
+// return (0); // open failed
+//
+// _Init(_File, _Openfl);
+// _Initcvt(&_USE(_Mysb::getloc(), _Cvt));
+// return (this); // open succeeded
+//#else
+// std::filebuf* _file = std::filebuf::open(_Filename, _Mode);
+// if (NULL == _file) return NULL;
+// return this;
+//#endif
+//}
+
+llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __c)
+{
+ int_type __ret = traits_type::eof();
+ const bool __testeof = traits_type::eq_int_type(__c, __ret);
+ const bool __testout = _M_mode & ios_base::out;
+ if (__testout && !_M_reading)
{
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
+ if (this->pbase() < this->pptr())
+ {
+ // If appropriate, append the overflow char.
+ if (!__testeof)
+ {
+ *this->pptr() = traits_type::to_char_type(__c);
+ this->pbump(1);
+ }
+
+ // Convert pending sequence to external representation,
+ // and output.
+ if (_convert_to_external(this->pbase(),
+ this->pptr() - this->pbase()))
+ {
+ _M_set_buffer(0);
+ __ret = traits_type::not_eof(__c);
+ }
+ }
+ else if (_M_buf_size > 1)
+ {
+ // Overflow in 'uncommitted' mode: set _M_writing, set
+ // the buffer to the initial 'write' mode, and put __c
+ // into the buffer.
+ _M_set_buffer(0);
+ _M_writing = true;
+ if (!__testeof)
+ {
+ *this->pptr() = traits_type::to_char_type(__c);
+ this->pbump(1);
+ }
+ __ret = traits_type::not_eof(__c);
+ }
+ else
+ {
+ // Unbuffered.
+ char_type __conv = traits_type::to_char_type(__c);
+ if (__testeof || _convert_to_external(&__conv, 1))
+ {
+ _M_writing = true;
+ __ret = traits_type::not_eof(__c);
+ }
+ }
}
+ return __ret;
}
-void llifstream::open(const std::string& _Filename, /* Flawfinder: ignore */
- ios_base::openmode _Mode,
- int _Prot)
-{ // open a C stream with specified mode
+bool llstdio_filebuf::_convert_to_external(char_type* __ibuf,
+ std::streamsize __ilen)
+{
+ // Sizes of external and pending output.
+ streamsize __elen;
+ streamsize __plen;
+ if (__check_facet(_M_codecvt).always_noconv())
+ {
+ //__elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
+ __elen = fwrite(reinterpret_cast<void*>(__ibuf), 1,
+ __ilen, _M_file.file());
+ __plen = __ilen;
+ }
+ else
+ {
+ // Worst-case number of external bytes needed.
+ // XXX Not done encoding() == -1.
+ streamsize __blen = __ilen * _M_codecvt->max_length();
+ char* __buf = static_cast<char*>(__builtin_alloca(__blen));
+
+ char* __bend;
+ const char_type* __iend;
+ codecvt_base::result __r;
+ __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
+ __iend, __buf, __buf + __blen, __bend);
- LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot);
- if(filep == NULL)
+ if (__r == codecvt_base::ok || __r == codecvt_base::partial)
+ __blen = __bend - __buf;
+ else if (__r == codecvt_base::noconv)
+ {
+ // Same as the always_noconv case above.
+ __buf = reinterpret_cast<char*>(__ibuf);
+ __blen = __ilen;
+ }
+ else
+ __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external "
+ "conversion error"));
+
+ //__elen = _M_file.xsputn(__buf, __blen);
+ __elen = fwrite(__buf, 1, __blen, _M_file.file());
+ __plen = __blen;
+
+ // Try once more for partial conversions.
+ if (__r == codecvt_base::partial && __elen == __plen)
+ {
+ const char_type* __iresume = __iend;
+ streamsize __rlen = this->pptr() - __iend;
+ __r = _M_codecvt->out(_M_state_cur, __iresume,
+ __iresume + __rlen, __iend, __buf,
+ __buf + __blen, __bend);
+ if (__r != codecvt_base::error)
+ {
+ __rlen = __bend - __buf;
+ //__elen = _M_file.xsputn(__buf, __rlen);
+ __elen = fwrite(__buf, 1, __rlen, _M_file.file());
+ __plen = __rlen;
+ }
+ else
+ {
+ __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external "
+ "conversion error"));
+ }
+ }
+ }
+ return __elen == __plen;
+}
+
+llstdio_filebuf::int_type llstdio_filebuf::underflow()
+{
+ int_type __ret = traits_type::eof();
+ const bool __testin = _M_mode & ios_base::in;
+ if (__testin)
{
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
- return;
+ if (_M_writing)
+ {
+ if (overflow() == traits_type::eof())
+ return __ret;
+ //_M_set_buffer(-1);
+ //_M_writing = false;
+ }
+ // Check for pback madness, and if so switch back to the
+ // normal buffers and jet outta here before expensive
+ // fileops happen...
+ _M_destroy_pback();
+
+ if (this->gptr() < this->egptr())
+ return traits_type::to_int_type(*this->gptr());
+
+ // Get and convert input sequence.
+ const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
+
+ // Will be set to true if ::fread() returns 0 indicating EOF.
+ bool __got_eof = false;
+ // Number of internal characters produced.
+ streamsize __ilen = 0;
+ codecvt_base::result __r = codecvt_base::ok;
+ if (__check_facet(_M_codecvt).always_noconv())
+ {
+ //__ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
+ // __buflen);
+ __ilen = fread(reinterpret_cast<void*>(this->eback()), 1,
+ __buflen, _M_file.file());
+ if (__ilen == 0)
+ __got_eof = true;
+ }
+ else
+ {
+ // Worst-case number of external bytes.
+ // XXX Not done encoding() == -1.
+ const int __enc = _M_codecvt->encoding();
+ streamsize __blen; // Minimum buffer size.
+ streamsize __rlen; // Number of chars to read.
+ if (__enc > 0)
+ __blen = __rlen = __buflen * __enc;
+ else
+ {
+ __blen = __buflen + _M_codecvt->max_length() - 1;
+ __rlen = __buflen;
+ }
+ const streamsize __remainder = _M_ext_end - _M_ext_next;
+ __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
+
+ // An imbue in 'read' mode implies first converting the external
+ // chars already present.
+ if (_M_reading && this->egptr() == this->eback() && __remainder)
+ __rlen = 0;
+
+ // Allocate buffer if necessary and move unconverted
+ // bytes to front.
+ if (_M_ext_buf_size < __blen)
+ {
+ char* __buf = new char[__blen];
+ if (__remainder)
+ __builtin_memcpy(__buf, _M_ext_next, __remainder);
+
+ delete [] _M_ext_buf;
+ _M_ext_buf = __buf;
+ _M_ext_buf_size = __blen;
+ }
+ else if (__remainder)
+ __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
+
+ _M_ext_next = _M_ext_buf;
+ _M_ext_end = _M_ext_buf + __remainder;
+ _M_state_last = _M_state_cur;
+
+ do
+ {
+ if (__rlen > 0)
+ {
+ // Sanity check!
+ // This may fail if the return value of
+ // codecvt::max_length() is bogus.
+ if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
+ {
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "codecvt::max_length() "
+ "is not valid"));
+ }
+ //streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
+ streamsize __elen = fread(_M_ext_end, 1,
+ __rlen, _M_file.file());
+ if (__elen == 0)
+ __got_eof = true;
+ else if (__elen == -1)
+ break;
+ //_M_ext_end += __elen;
+ }
+
+ char_type* __iend = this->eback();
+ if (_M_ext_next < _M_ext_end)
+ {
+ __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
+ _M_ext_end, _M_ext_next,
+ this->eback(),
+ this->eback() + __buflen, __iend);
+ }
+ if (__r == codecvt_base::noconv)
+ {
+ size_t __avail = _M_ext_end - _M_ext_buf;
+ __ilen = std::min(__avail, __buflen);
+ traits_type::copy(this->eback(),
+ reinterpret_cast<char_type*>
+ (_M_ext_buf), __ilen);
+ _M_ext_next = _M_ext_buf + __ilen;
+ }
+ else
+ __ilen = __iend - this->eback();
+
+ // _M_codecvt->in may return error while __ilen > 0: this is
+ // ok, and actually occurs in case of mixed encodings (e.g.,
+ // XML files).
+ if (__r == codecvt_base::error)
+ break;
+
+ __rlen = 1;
+ } while (__ilen == 0 && !__got_eof);
+ }
+
+ if (__ilen > 0)
+ {
+ _M_set_buffer(__ilen);
+ _M_reading = true;
+ __ret = traits_type::to_int_type(*this->gptr());
+ }
+ else if (__got_eof)
+ {
+ // If the actual end of file is reached, set 'uncommitted'
+ // mode, thus allowing an immediate write without an
+ // intervening seek.
+ _M_set_buffer(-1);
+ _M_reading = false;
+ // However, reaching it while looping on partial means that
+ // the file has got an incomplete character.
+ if (__r == codecvt_base::partial)
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "incomplete character in file"));
+ }
+ else if (__r == codecvt_base::error)
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "invalid byte sequence in file"));
+ else
+ __throw_ios_failure(__N("llstdio_filebuf::underflow "
+ "error reading the file"));
}
- llassert(_Filebuffer == NULL);
- _Filebuffer = new _Myfb(filep);
- _ShouldClose = true;
- _Myios::init(_Filebuffer);
+ return __ret;
}
-bool llifstream::is_open() const
-{ // test if C stream has been opened
- if(_Filebuffer)
- return (_Filebuffer->is_open());
- return false;
+std::streamsize llstdio_filebuf::xsgetn(char_type* __s, std::streamsize __n)
+{
+ // Clear out pback buffer before going on to the real deal...
+ streamsize __ret = 0;
+ if (_M_pback_init)
+ {
+ if (__n > 0 && this->gptr() == this->eback())
+ {
+ *__s++ = *this->gptr();
+ this->gbump(1);
+ __ret = 1;
+ --__n;
+ }
+ _M_destroy_pback();
+ }
+
+ // Optimization in the always_noconv() case, to be generalized in the
+ // future: when __n > __buflen we read directly instead of using the
+ // buffer repeatedly.
+ const bool __testin = _M_mode & ios_base::in;
+ const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
+
+ if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
+ && __testin && !_M_writing)
+ {
+ // First, copy the chars already present in the buffer.
+ const streamsize __avail = this->egptr() - this->gptr();
+ if (__avail != 0)
+ {
+ if (__avail == 1)
+ *__s = *this->gptr();
+ else
+ traits_type::copy(__s, this->gptr(), __avail);
+ __s += __avail;
+ this->gbump(__avail);
+ __ret += __avail;
+ __n -= __avail;
+ }
+
+ // Need to loop in case of short reads (relatively common
+ // with pipes).
+ streamsize __len;
+ for (;;)
+ {
+ //__len = _M_file.xsgetn(reinterpret_cast<char*>(__s), __n);
+ __len = fread(reinterpret_cast<void*>(__s), 1,
+ __n, _M_file.file());
+ if (__len == -1)
+ __throw_ios_failure(__N("llstdio_filebuf::xsgetn "
+ "error reading the file"));
+ if (__len == 0)
+ break;
+
+ __n -= __len;
+ __ret += __len;
+ if (__n == 0)
+ break;
+
+ __s += __len;
+ }
+
+ if (__n == 0)
+ {
+ _M_set_buffer(0);
+ _M_reading = true;
+ }
+ else if (__len == 0)
+ {
+ // If end of file is reached, set 'uncommitted'
+ // mode, thus allowing an immediate write without
+ // an intervening seek.
+ _M_set_buffer(-1);
+ _M_reading = false;
+ }
+ }
+ else
+ __ret += __streambuf_type::xsgetn(__s, __n);
+
+ return __ret;
}
-llifstream::~llifstream()
+
+std::streamsize llstdio_filebuf::xsputn(char_type* __s, std::streamsize __n)
{
- if (_ShouldClose)
+ // Optimization in the always_noconv() case, to be generalized in the
+ // future: when __n is sufficiently large we write directly instead of
+ // using the buffer.
+ streamsize __ret = 0;
+ const bool __testout = _M_mode & ios_base::out;
+ if (__check_facet(_M_codecvt).always_noconv()
+ && __testout && !_M_reading)
{
- close();
+ // Measurement would reveal the best choice.
+ const streamsize __chunk = 1ul << 10;
+ streamsize __bufavail = this->epptr() - this->pptr();
+
+ // Don't mistake 'uncommitted' mode buffered with unbuffered.
+ if (!_M_writing && _M_buf_size > 1)
+ __bufavail = _M_buf_size - 1;
+
+ const streamsize __limit = std::min(__chunk, __bufavail);
+ if (__n >= __limit)
+ {
+ const streamsize __buffill = this->pptr() - this->pbase();
+ const char* __buf = reinterpret_cast<const char*>(this->pbase());
+ //__ret = _M_file.xsputn_2(__buf, __buffill,
+ // reinterpret_cast<const char*>(__s), __n);
+ if (__buffill)
+ {
+ __ret = fwrite(__buf, 1, __buffill, _M_file.file());
+ }
+ if (__ret == __buffill)
+ {
+ __ret += fwrite(reinterpret_cast<const char*>(__s), 1,
+ __n, _M_file.file());
+ }
+ if (__ret == __buffill + __n)
+ {
+ _M_set_buffer(0);
+ _M_writing = true;
+ }
+ if (__ret > __buffill)
+ __ret -= __buffill;
+ else
+ __ret = 0;
+ }
+ else
+ __ret = __streambuf_type::xsputn(__s, __n);
}
- delete _Filebuffer;
+ else
+ __ret = __streambuf_type::xsputn(__s, __n);
+ return __ret;
}
-llifstream::llifstream(const std::string& _Filename,
- ios_base::openmode _Mode,
- int _Prot)
- : std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
+int llstdio_filebuf::sync()
+{
+ return (_M_file.sync() == 0 ? 0 : -1);
+}
-{ // construct with named file and specified mode
- open(_Filename, _Mode | ios_base::in, _Prot); /* Flawfinder: ignore */
+/************** input file stream ********************************/
+
+
+llifstream::llifstream() : _M_filebuf(),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf) {}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+// explicit
+llifstream::llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename.c_str(), _Mode | ios_base::in) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename.c_str(), _Mode | ios_base::in);
}
+#endif
+// explicit
+llifstream::llifstream(const char* _Filename,
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::in) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename, _Mode | ios_base::in);
+}
+#endif
-/************** output file stream ********************************/
-bool llofstream::is_open() const
+// explicit
+llifstream::llifstream(_Filet *_File,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(_File, _Mode, _Size),
+#if LL_WINDOWS
+ std::istream(&_M_filebuf) {}
+#else
+ std::istream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+#if LL_WINDOWS
+// explicit
+llifstream::llifstream(int __fd,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(__fd, _Mode, _Size),
+ std::istream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+bool llifstream::is_open() const
{ // test if C stream has been opened
- if(_Filebuffer)
- return (_Filebuffer->is_open());
- return false;
+ return _M_filebuf.is_open();
}
-void llofstream::open(const std::string& _Filename, /* Flawfinder: ignore */
- ios_base::openmode _Mode,
- int _Prot)
+void llifstream::open(const char* _Filename, ios_base::openmode _Mode)
{ // open a C stream with specified mode
-
- LLFILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot);
- if(filep == NULL)
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::in) == 0)
+#if LL_WINDOWS
{
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
- return;
+ _Myios::setstate(ios_base::failbit);
}
- llassert(_Filebuffer==NULL);
- _Filebuffer = new _Myfb(filep);
- _ShouldClose = true;
- _Myios::init(_Filebuffer);
+ else
+ {
+ _Myios::clear();
+ }
+#else
+ {
+ this->setstate(ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+#endif
}
-void llofstream::close()
+void llifstream::close()
{ // close the C stream
- if(is_open())
+ if (_M_filebuf.close() == 0)
{
- if (_Filebuffer->close() == 0)
- {
- _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
- }
- delete _Filebuffer;
- _Filebuffer = NULL;
- _ShouldClose = false;
+#if LL_WINDOWS
+ _Myios::setstate(ios_base::failbit);
+#else
+ this->setstate(ios_base::failbit);
+#endif
}
}
+
+/************** output file stream ********************************/
+
+
+llofstream::llofstream() : _M_filebuf(),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf) {}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
+}
+#endif
+
+// explicit
llofstream::llofstream(const std::string& _Filename,
- std::ios_base::openmode _Mode,
- int _Prot)
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
-{ // construct with named file and specified mode
- open(_Filename, _Mode , _Prot); /* Flawfinder: ignore */
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename.c_str(), _Mode | ios_base::out) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename.c_str(), _Mode | ios_base::out);
+}
+#endif
+
+// explicit
+llofstream::llofstream(const char* _Filename,
+ ios_base::openmode _Mode) : _M_filebuf(),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf)
+{
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::out) == 0)
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
+ this->open(_Filename, _Mode | ios_base::out);
+}
+#endif
+
+// explicit
+llofstream::llofstream(_Filet *_File,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(_File, _Mode, _Size),
+#if LL_WINDOWS
+ std::ostream(&_M_filebuf) {}
+#else
+ std::ostream()
+{
+ this->init(&_M_filebuf);
}
+#endif
-llofstream::~llofstream()
+#if LL_WINDOWS
+// explicit
+llofstream::llofstream(int __fd,
+ ios_base::openmode _Mode, size_t _Size) :
+ _M_filebuf(__fd, _Mode, _Size),
+ std::ostream()
{
- // destroy the object
- if (_ShouldClose)
+ this->init(&_M_filebuf);
+}
+#endif
+
+bool llofstream::is_open() const
+{ // test if C stream has been opened
+ return _M_filebuf.is_open();
+}
+
+void llofstream::open(const char* _Filename, ios_base::openmode _Mode)
+{ // open a C stream with specified mode
+ if (_M_filebuf.open(_Filename, _Mode | ios_base::out) == 0)
+#if LL_WINDOWS
+ {
+ _Myios::setstate(ios_base::failbit);
+ }
+ else
{
- close();
+ _Myios::clear();
}
- delete _Filebuffer;
+#else
+ {
+ this->setstate(ios_base::failbit);
+ }
+ else
+ {
+ this->clear();
+ }
+#endif
}
-#endif // #if USE_LLFILESTREAMS
+void llofstream::close()
+{ // close the C stream
+ if (_M_filebuf.close() == 0)
+ {
+#if LL_WINDOWS
+ _Myios::setstate(ios_base::failbit);
+#else
+ this->setstate(ios_base::failbit);
+#endif
+ }
+}
/************** helper functions ********************************/
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index dd7d36513a..7049ab1396 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -35,16 +35,10 @@
* Attempts to mostly mirror the POSIX style IO functions.
*/
-typedef FILE LLFILE;
+typedef FILE LLFILE;
#include <fstream>
-
-#ifdef LL_WINDOWS
-#define USE_LLFILESTREAMS 1
-#else
-#define USE_LLFILESTREAMS 0
-#endif
-
+#include <bits/postypes.h>
#include <sys/stat.h>
#if LL_WINDOWS
@@ -52,6 +46,7 @@ typedef FILE LLFILE;
typedef struct _stat llstat;
#else
typedef struct stat llstat;
+#include <ext/stdio_filebuf.h>
#endif
#ifndef S_ISREG
@@ -83,142 +78,342 @@ public:
static int stat(const std::string& filename,llstat* file_status);
static bool isdir(const std::string& filename);
static bool isfile(const std::string& filename);
- static LLFILE * _Fiopen(const std::string& filename, std::ios::openmode mode,int); // protection currently unused
+ static LLFILE * _Fiopen(const std::string& filename,
+ std::ios::openmode mode);
static const char * tmpdir();
};
+/**
+ * @brief Provides a layer of compatibility for C/POSIX.
+ *
+ * This is taken from both the GNU __gnu_cxx::stdio_filebuf extension and
+ * VC's basic_filebuf implementation.
+ * This file buffer provides extensions for working with standard C FILE*'s
+ * and POSIX file descriptors for platforms that support this.
+*/
+namespace
+{
+#if LL_WINDOWS
+typedef std::filebuf _Myfb;
+#else
+typedef __gnu_cxx::stdio_filebuf< char > _Myfb;
+typedef std::__c_file _Filet;
+#endif /* LL_WINDOWS */
+}
-#if USE_LLFILESTREAMS
-
-class LL_COMMON_API llifstream : public std::basic_istream < char , std::char_traits < char > >
+class LL_COMMON_API llstdio_filebuf : public _Myfb
{
- // input stream associated with a C stream
public:
- typedef std::basic_ifstream<char,std::char_traits < char > > _Myt;
- typedef std::basic_filebuf<char,std::char_traits< char > > _Myfb;
- typedef std::basic_ios<char,std::char_traits< char > > _Myios;
-
- llifstream()
- : std::basic_istream<char,std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
- { // construct unopened
- }
+ /**
+ * deferred initialization / destruction
+ */
+ llstdio_filebuf() : _Myfb() {}
+ virtual ~llstdio_filebuf() {}
+
+ /**
+ * @param f An open @c FILE*.
+ * @param mode Same meaning as in a standard filebuf.
+ * @param size Optimal or preferred size of internal buffer, in chars.
+ * Defaults to system's @c BUFSIZ.
+ *
+ * This constructor associates a file stream buffer with an open
+ * C @c FILE*. The @c FILE* will not be automatically closed when the
+ * stdio_filebuf is closed/destroyed.
+ */
+ llstdio_filebuf(_Filet* __f, std::ios_base::openmode __mode,
+ //size_t __size = static_cast<size_t>(BUFSIZ)) :
+ size_t __size = static_cast<size_t>(1)) :
+#if LL_WINDOWS
+ _Myfb(__f) {}
+#else
+ _Myfb(__f, __mode, __size) {}
+#endif
- explicit llifstream(const std::string& _Filename,
- ios_base::openmode _Mode = ios_base::in,
- int _Prot = (int)ios_base::_Openprot);
-
- explicit llifstream(_Filet *_File)
- : std::basic_istream<char,std::char_traits< char > >(NULL,true),
- _Filebuffer(new _Myfb(_File)),
- _ShouldClose(false)
- { // construct with specified C stream
- }
- virtual ~llifstream();
-
- _Myfb *rdbuf() const
- { // return pointer to file buffer
- return _Filebuffer;
- }
- bool is_open() const;
- void open(const std::string& _Filename, /* Flawfinder: ignore */
- ios_base::openmode _Mode = ios_base::in,
- int _Prot = (int)ios_base::_Openprot);
- void close();
+ /**
+ * @brief Opens an external file.
+ * @param s The name of the file.
+ * @param mode The open mode flags.
+ * @return @c this on success, NULL on failure
+ *
+ * If a file is already open, this function immediately fails.
+ * Otherwise it tries to open the file named @a s using the flags
+ * given in @a mode.
+ */
+ //llstdio_filebuf* open(const char *_Filename,
+ // std::ios_base::openmode _Mode);
+
+ /**
+ * @param fd An open file descriptor.
+ * @param mode Same meaning as in a standard filebuf.
+ * @param size Optimal or preferred size of internal buffer, in chars.
+ *
+ * This constructor associates a file stream buffer with an open
+ * POSIX file descriptor. The file descriptor will be automatically
+ * closed when the stdio_filebuf is closed/destroyed.
+ */
+#if !LL_WINDOWS
+ llstdio_filebuf(int __fd, std::ios_base::openmode __mode,
+ //size_t __size = static_cast<size_t>(BUFSIZ)) :
+ size_t __size = static_cast<size_t>(1)) :
+ _Myfb(__fd, __mode, __size) {}
+#endif
-private:
- _Myfb* _Filebuffer; // the file buffer
- bool _ShouldClose;
+// *TODO: Seek the underlying c stream for better cross-platform compatibility?
+#if !LL_WINDOWS
+protected:
+ /** underflow() and uflow() functions are called to get the next
+ * character from the real input source when the buffer is empty.
+ * Buffered input uses underflow()
+ */
+ /*virtual*/ int_type underflow();
+
+ /* Convert internal byte sequence to external, char-based
+ * sequence via codecvt.
+ */
+ bool _convert_to_external(char_type*, std::streamsize);
+
+ /** The overflow() function is called to transfer characters to the
+ * real output destination when the buffer is full. A call to
+ * overflow(c) outputs the contents of the buffer plus the
+ * character c.
+ * Consume some sequence of the characters in the pending sequence.
+ */
+ /*virtual*/ int_type overflow(int_type __c = traits_type::eof());
+
+ /** sync() flushes the underlying @c FILE* stream.
+ */
+ /*virtual*/ int sync();
+
+ std::streamsize xsgetn(char_type*, std::streamsize);
+ std::streamsize xsputn(char_type*, std::streamsize);
+#endif
};
-class LL_COMMON_API llofstream : public std::basic_ostream< char , std::char_traits < char > >
+/**
+ * @brief Controlling input for files.
+ *
+ * This class supports reading from named files, using the inherited
+ * functions from std::basic_istream. To control the associated
+ * sequence, an instance of std::basic_filebuf (or a platform-specific derivative)
+ * which allows construction using a pre-exisintg file stream buffer.
+ * We refer to this std::basic_filebuf (or derivative) as @c sb.
+*/
+class LL_COMMON_API llifstream : public std::istream
{
+ // input stream associated with a C stream
public:
- typedef std::basic_ostream< char , std::char_traits < char > > _Myt;
- typedef std::basic_filebuf< char , std::char_traits < char > > _Myfb;
- typedef std::basic_ios<char,std::char_traits < char > > _Myios;
-
- llofstream()
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
- { // construct unopened
- }
-
- explicit llofstream(const std::string& _Filename,
- std::ios_base::openmode _Mode = ios_base::out,
- int _Prot = (int)std::ios_base::_Openprot);
-
-
- explicit llofstream(_Filet *_File)
- : std::basic_ostream<char,std::char_traits < char > >(NULL,true),
- _Filebuffer(new _Myfb(_File)),//_File)
- _ShouldClose(false)
- { // construct with specified C stream
- }
-
- virtual ~llofstream();
-
- _Myfb *rdbuf() const
- { // return pointer to file buffer
- return _Filebuffer;
- }
+ // Constructors:
+ /**
+ * @brief Default constructor.
+ *
+ * Initializes @c sb using its default constructor, and passes
+ * @c &sb to the base class initializer. Does not open any files
+ * (you haven't given it a filename to open).
+ */
+ llifstream();
+
+ /**
+ * @brief Create an input file stream.
+ * @param Filename String specifying the filename.
+ * @param Mode Open file in specified mode (see std::ios_base).
+ *
+ * @c ios_base::in is automatically included in @a mode.
+ */
+ explicit llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::in);
+ explicit llifstream(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::in);
+
+ /**
+ * @brief Create a stream using an open c file stream.
+ * @param File An open @c FILE*.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+ explicit llifstream(_Filet *_File,
+ ios_base::openmode _Mode = ios_base::in,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+
+ /**
+ * @brief Create a stream using an open file descriptor.
+ * @param fd An open file descriptor.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+#if !LL_WINDOWS
+ explicit llifstream(int __fd,
+ ios_base::openmode _Mode = ios_base::in,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+#endif
+ /**
+ * @brief The destructor does nothing.
+ *
+ * The file is closed by the filebuf object, not the formatting
+ * stream.
+ */
+ virtual ~llifstream() {}
+
+ // Members:
+ /**
+ * @brief Accessing the underlying buffer.
+ * @return The current basic_filebuf buffer.
+ *
+ * This hides both signatures of std::basic_ios::rdbuf().
+ */
+ llstdio_filebuf* rdbuf() const
+ { return const_cast<llstdio_filebuf*>(&_M_filebuf); }
+
+ /**
+ * @brief Wrapper to test for an open file.
+ * @return @c rdbuf()->is_open()
+ */
bool is_open() const;
- void open(const std::string& _Filename,ios_base::openmode _Mode = ios_base::out,int _Prot = (int)ios_base::_Openprot); /* Flawfinder: ignore */
-
+ /**
+ * @brief Opens an external file.
+ * @param Filename The name of the file.
+ * @param Node The open mode flags.
+ *
+ * Calls @c llstdio_filebuf::open(s,mode|in). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
+ void open(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::in)
+ { open(_Filename.c_str(), _Mode); }
+ void open(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::in);
+
+ /**
+ * @brief Close the file.
+ *
+ * Calls @c llstdio_filebuf::close(). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
void close();
private:
- _Myfb *_Filebuffer; // the file buffer
- bool _ShouldClose;
-};
-
-
-
-#else
-//Use standard file streams on non windows platforms
-//#define llifstream std::ifstream
-//#define llofstream std::ofstream
-
-class LL_COMMON_API llifstream : public std::ifstream
-{
-public:
- llifstream() : std::ifstream()
- {
- }
-
- explicit llifstream(const std::string& _Filename, std::_Ios_Openmode _Mode = in)
- : std::ifstream(_Filename.c_str(), _Mode)
- {
- }
- void open(const std::string& _Filename, std::_Ios_Openmode _Mode = in) /* Flawfinder: ignore */
- {
- std::ifstream::open(_Filename.c_str(), _Mode);
- }
+ llstdio_filebuf _M_filebuf;
};
-class LL_COMMON_API llofstream : public std::ofstream
+/**
+ * @brief Controlling output for files.
+ *
+ * This class supports writing to named files, using the inherited
+ * functions from std::basic_ostream. To control the associated
+ * sequence, an instance of std::basic_filebuf (or a platform-specific derivative)
+ * which allows construction using a pre-exisintg file stream buffer.
+ * We refer to this std::basic_filebuf (or derivative) as @c sb.
+*/
+class LL_COMMON_API llofstream : public std::ostream
{
public:
- llofstream() : std::ofstream()
- {
- }
+ // Constructors:
+ /**
+ * @brief Default constructor.
+ *
+ * Initializes @c sb using its default constructor, and passes
+ * @c &sb to the base class initializer. Does not open any files
+ * (you haven't given it a filename to open).
+ */
+ llofstream();
+
+ /**
+ * @brief Create an output file stream.
+ * @param Filename String specifying the filename.
+ * @param Mode Open file in specified mode (see std::ios_base).
+ *
+ * @c ios_base::out|ios_base::trunc is automatically included in
+ * @a mode.
+ */
+ explicit llofstream(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc);
+ explicit llofstream(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc);
+
+ /**
+ * @brief Create a stream using an open c file stream.
+ * @param File An open @c FILE*.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+ explicit llofstream(_Filet *_File,
+ ios_base::openmode _Mode = ios_base::out,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+
+ /**
+ * @brief Create a stream using an open file descriptor.
+ * @param fd An open file descriptor.
+ @param Mode Same meaning as in a standard filebuf.
+ @param Size Optimal or preferred size of internal buffer, in chars.
+ Defaults to system's @c BUFSIZ.
+ */
+#if !LL_WINDOWS
+ explicit llofstream(int __fd,
+ ios_base::openmode _Mode = ios_base::out,
+ //size_t _Size = static_cast<size_t>(BUFSIZ));
+ size_t _Size = static_cast<size_t>(1));
+#endif
- explicit llofstream(const std::string& _Filename, std::_Ios_Openmode _Mode = out)
- : std::ofstream(_Filename.c_str(), _Mode)
- {
- }
+ /**
+ * @brief The destructor does nothing.
+ *
+ * The file is closed by the filebuf object, not the formatting
+ * stream.
+ */
+ virtual ~llofstream() {}
+
+ // Members:
+ /**
+ * @brief Accessing the underlying buffer.
+ * @return The current basic_filebuf buffer.
+ *
+ * This hides both signatures of std::basic_ios::rdbuf().
+ */
+ llstdio_filebuf* rdbuf() const
+ { return const_cast<llstdio_filebuf*>(&_M_filebuf); }
+
+ /**
+ * @brief Wrapper to test for an open file.
+ * @return @c rdbuf()->is_open()
+ */
+ bool is_open() const;
- void open(const std::string& _Filename, std::_Ios_Openmode _Mode = out) /* Flawfinder: ignore */
- {
- std::ofstream::open(_Filename.c_str(), _Mode);
- }
+ /**
+ * @brief Opens an external file.
+ * @param Filename The name of the file.
+ * @param Node The open mode flags.
+ *
+ * Calls @c llstdio_filebuf::open(s,mode|out). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
+ void open(const std::string& _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc)
+ { open(_Filename.c_str(), _Mode); }
+ void open(const char* _Filename,
+ ios_base::openmode _Mode = ios_base::out|ios_base::trunc);
+
+ /**
+ * @brief Close the file.
+ *
+ * Calls @c llstdio_filebuf::close(). If that function
+ * fails, @c failbit is set in the stream's error state.
+ */
+ void close();
+private:
+ llstdio_filebuf _M_filebuf;
};
-#endif
/**
* @breif filesize helpers.