1// Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT 2// Copyright (c) 2016 Google, Inc. 3// 4// Permission is hereby granted, free of charge, to any person obtaining a copy 5// of this software and associated documentation files (the "Software"), to deal 6// in the Software without restriction, including without limitation the rights 7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8// copies of the Software, and to permit persons to whom the Software is 9// furnished to do so, subject to the following conditions: 10// 11// The above copyright notice and this permission notice shall be included in 12// all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20// THE SOFTWARE. 21 22#ifndef ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_ 23#define ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_ 24 25#include <cstdio> 26#include <istream> 27#include <locale> 28#include <streambuf> 29 30namespace android { 31namespace dvr { 32 33// An implementation of std::basic_streambuf backed by a FILE pointer. This is 34// ported from the internal llvm-libc++ support for std::cin. It's really 35// unfortunate that we have to do this, but the C++11 standard is too pendantic 36// to support creating streams from file descriptors or FILE pointers. This 37// implementation uses all standard interfaces, except for the call to 38// std::__throw_runtime_error(), which is only needed to deal with exceeding 39// locale encoding limits. This class is meant to be used for reading system 40// files, which don't require exotic locale support, so this call could be 41// removed in the future, if necessary. 42// 43// Original source file: llvm-libcxx/llvm-libc++/include/__std_stream 44// Original class name: __stdinbuf 45// 46template <class _CharT> 47class stdio_filebuf 48 : public std::basic_streambuf<_CharT, std::char_traits<_CharT> > { 49 public: 50 typedef _CharT char_type; 51 typedef std::char_traits<char_type> traits_type; 52 typedef typename traits_type::int_type int_type; 53 typedef typename traits_type::pos_type pos_type; 54 typedef typename traits_type::off_type off_type; 55 typedef typename traits_type::state_type state_type; 56 57 explicit stdio_filebuf(FILE* __fp); 58 ~stdio_filebuf() override; 59 60 protected: 61 virtual int_type underflow() override; 62 virtual int_type uflow() override; 63 virtual int_type pbackfail(int_type __c = traits_type::eof()) override; 64 virtual void imbue(const std::locale& __loc) override; 65 66 private: 67 FILE* __file_; 68 const std::codecvt<char_type, char, state_type>* __cv_; 69 state_type __st_; 70 int __encoding_; 71 int_type __last_consumed_; 72 bool __last_consumed_is_next_; 73 bool __always_noconv_; 74 75 stdio_filebuf(const stdio_filebuf&); 76 stdio_filebuf& operator=(const stdio_filebuf&); 77 78 int_type __getchar(bool __consume); 79 80 static const int __limit = 8; 81}; 82 83template <class _CharT> 84stdio_filebuf<_CharT>::stdio_filebuf(FILE* __fp) 85 : __file_(__fp), 86 __last_consumed_(traits_type::eof()), 87 __last_consumed_is_next_(false) { 88 imbue(this->getloc()); 89} 90 91template <class _CharT> 92stdio_filebuf<_CharT>::~stdio_filebuf() { 93 if (__file_) 94 fclose(__file_); 95} 96 97template <class _CharT> 98void stdio_filebuf<_CharT>::imbue(const std::locale& __loc) { 99 __cv_ = &std::use_facet<std::codecvt<char_type, char, state_type> >(__loc); 100 __encoding_ = __cv_->encoding(); 101 __always_noconv_ = __cv_->always_noconv(); 102 if (__encoding_ > __limit) 103 std::__throw_runtime_error("unsupported locale for standard io"); 104} 105 106template <class _CharT> 107typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::underflow() { 108 return __getchar(false); 109} 110 111template <class _CharT> 112typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::uflow() { 113 return __getchar(true); 114} 115 116template <class _CharT> 117typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::__getchar( 118 bool __consume) { 119 if (__last_consumed_is_next_) { 120 int_type __result = __last_consumed_; 121 if (__consume) { 122 __last_consumed_ = traits_type::eof(); 123 __last_consumed_is_next_ = false; 124 } 125 return __result; 126 } 127 char __extbuf[__limit]; 128 int __nread = std::max(1, __encoding_); 129 for (int __i = 0; __i < __nread; ++__i) { 130 int __c = getc(__file_); 131 if (__c == EOF) 132 return traits_type::eof(); 133 __extbuf[__i] = static_cast<char>(__c); 134 } 135 char_type __1buf; 136 if (__always_noconv_) 137 __1buf = static_cast<char_type>(__extbuf[0]); 138 else { 139 const char* __enxt; 140 char_type* __inxt; 141 std::codecvt_base::result __r; 142 do { 143 state_type __sv_st = __st_; 144 __r = __cv_->in(__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf, 145 &__1buf + 1, __inxt); 146 switch (__r) { 147 case std::codecvt_base::ok: 148 break; 149 case std::codecvt_base::partial: 150 __st_ = __sv_st; 151 if (__nread == sizeof(__extbuf)) 152 return traits_type::eof(); 153 { 154 int __c = getc(__file_); 155 if (__c == EOF) 156 return traits_type::eof(); 157 __extbuf[__nread] = static_cast<char>(__c); 158 } 159 ++__nread; 160 break; 161 case std::codecvt_base::error: 162 return traits_type::eof(); 163 case std::codecvt_base::noconv: 164 __1buf = static_cast<char_type>(__extbuf[0]); 165 break; 166 } 167 } while (__r == std::codecvt_base::partial); 168 } 169 if (!__consume) { 170 for (int __i = __nread; __i > 0;) { 171 if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF) 172 return traits_type::eof(); 173 } 174 } else 175 __last_consumed_ = traits_type::to_int_type(__1buf); 176 return traits_type::to_int_type(__1buf); 177} 178 179template <class _CharT> 180typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::pbackfail( 181 int_type __c) { 182 if (traits_type::eq_int_type(__c, traits_type::eof())) { 183 if (!__last_consumed_is_next_) { 184 __c = __last_consumed_; 185 __last_consumed_is_next_ = 186 !traits_type::eq_int_type(__last_consumed_, traits_type::eof()); 187 } 188 return __c; 189 } 190 if (__last_consumed_is_next_) { 191 char __extbuf[__limit]; 192 char* __enxt; 193 const char_type __ci = traits_type::to_char_type(__last_consumed_); 194 const char_type* __inxt; 195 switch (__cv_->out(__st_, &__ci, &__ci + 1, __inxt, __extbuf, 196 __extbuf + sizeof(__extbuf), __enxt)) { 197 case std::codecvt_base::ok: 198 break; 199 case std::codecvt_base::noconv: 200 __extbuf[0] = static_cast<char>(__last_consumed_); 201 __enxt = __extbuf + 1; 202 break; 203 case std::codecvt_base::partial: 204 case std::codecvt_base::error: 205 return traits_type::eof(); 206 } 207 while (__enxt > __extbuf) 208 if (ungetc(*--__enxt, __file_) == EOF) 209 return traits_type::eof(); 210 } 211 __last_consumed_ = __c; 212 __last_consumed_is_next_ = true; 213 return __c; 214} 215 216} // namespace dvr 217} // namespace android 218 219#endif // ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_ 220