220 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
// 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_
 |