// Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT // Copyright (c) 2016 Google, Inc. // // 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. #ifndef ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_ #define ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_ #include <cstdio> #include <istream> #include <locale> #include <streambuf> namespace android { namespace dvr { // An implementation of std::basic_streambuf backed by a FILE pointer. This is // ported from the internal llvm-libc++ support for std::cin. It's really // unfortunate that we have to do this, but the C++11 standard is too pendantic // to support creating streams from file descriptors or FILE pointers. This // implementation uses all standard interfaces, except for the call to // std::__throw_runtime_error(), which is only needed to deal with exceeding // locale encoding limits. This class is meant to be used for reading system // files, which don't require exotic locale support, so this call could be // removed in the future, if necessary. // // Original source file: llvm-libcxx/llvm-libc++/include/__std_stream // Original class name: __stdinbuf // template <class _CharT> class stdio_filebuf : public std::basic_streambuf<_CharT, std::char_traits<_CharT> > { public: typedef _CharT char_type; typedef std::char_traits<char_type> traits_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::pos_type pos_type; typedef typename traits_type::off_type off_type; typedef typename traits_type::state_type state_type; explicit stdio_filebuf(FILE* __fp); ~stdio_filebuf() override; protected: virtual int_type underflow() override; virtual int_type uflow() override; virtual int_type pbackfail(int_type __c = traits_type::eof()) override; virtual void imbue(const std::locale& __loc) override; private: FILE* __file_; const std::codecvt<char_type, char, state_type>* __cv_; state_type __st_; int __encoding_; int_type __last_consumed_; bool __last_consumed_is_next_; bool __always_noconv_; stdio_filebuf(const stdio_filebuf&); stdio_filebuf& operator=(const stdio_filebuf&); int_type __getchar(bool __consume); static const int __limit = 8; }; template <class _CharT> stdio_filebuf<_CharT>::stdio_filebuf(FILE* __fp) : __file_(__fp), __last_consumed_(traits_type::eof()), __last_consumed_is_next_(false) { imbue(this->getloc()); } template <class _CharT> stdio_filebuf<_CharT>::~stdio_filebuf() { if (__file_) fclose(__file_); } template <class _CharT> void stdio_filebuf<_CharT>::imbue(const std::locale& __loc) { __cv_ = &std::use_facet<std::codecvt<char_type, char, state_type> >(__loc); __encoding_ = __cv_->encoding(); __always_noconv_ = __cv_->always_noconv(); if (__encoding_ > __limit) std::__throw_runtime_error("unsupported locale for standard io"); } template <class _CharT> typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::underflow() { return __getchar(false); } template <class _CharT> typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::uflow() { return __getchar(true); } template <class _CharT> typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::__getchar( bool __consume) { if (__last_consumed_is_next_) { int_type __result = __last_consumed_; if (__consume) { __last_consumed_ = traits_type::eof(); __last_consumed_is_next_ = false; } return __result; } char __extbuf[__limit]; int __nread = std::max(1, __encoding_); for (int __i = 0; __i < __nread; ++__i) { int __c = getc(__file_); if (__c == EOF) return traits_type::eof(); __extbuf[__i] = static_cast<char>(__c); } char_type __1buf; if (__always_noconv_) __1buf = static_cast<char_type>(__extbuf[0]); else { const char* __enxt; char_type* __inxt; std::codecvt_base::result __r; do { state_type __sv_st = __st_; __r = __cv_->in(__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf, &__1buf + 1, __inxt); switch (__r) { case std::codecvt_base::ok: break; case std::codecvt_base::partial: __st_ = __sv_st; if (__nread == sizeof(__extbuf)) return traits_type::eof(); { int __c = getc(__file_); if (__c == EOF) return traits_type::eof(); __extbuf[__nread] = static_cast<char>(__c); } ++__nread; break; case std::codecvt_base::error: return traits_type::eof(); case std::codecvt_base::noconv: __1buf = static_cast<char_type>(__extbuf[0]); break; } } while (__r == std::codecvt_base::partial); } if (!__consume) { for (int __i = __nread; __i > 0;) { if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF) return traits_type::eof(); } } else __last_consumed_ = traits_type::to_int_type(__1buf); return traits_type::to_int_type(__1buf); } template <class _CharT> typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::pbackfail( int_type __c) { if (traits_type::eq_int_type(__c, traits_type::eof())) { if (!__last_consumed_is_next_) { __c = __last_consumed_; __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_, traits_type::eof()); } return __c; } if (__last_consumed_is_next_) { char __extbuf[__limit]; char* __enxt; const char_type __ci = traits_type::to_char_type(__last_consumed_); const char_type* __inxt; switch (__cv_->out(__st_, &__ci, &__ci + 1, __inxt, __extbuf, __extbuf + sizeof(__extbuf), __enxt)) { case std::codecvt_base::ok: break; case std::codecvt_base::noconv: __extbuf[0] = static_cast<char>(__last_consumed_); __enxt = __extbuf + 1; break; case std::codecvt_base::partial: case std::codecvt_base::error: return traits_type::eof(); } while (__enxt > __extbuf) if (ungetc(*--__enxt, __file_) == EOF) return traits_type::eof(); } __last_consumed_ = __c; __last_consumed_is_next_ = true; return __c; } } // namespace dvr } // namespace android #endif // ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_