// This comes from llvm's libcxx project. I've copied the code from there (with heavy modifications) for use with MinGW to support opening Windows "Unicode" filenames. #if defined(_WIN32) && !defined(_MSC_VER) #pragma once #include #include #include #include class filebuf_wfopen : public std::filebuf { public: typedef typename traits_type::state_type state_type; // 27.9.1.2 Constructors/destructor: filebuf_wfopen() : __extbuf_(nullptr), __extbufnext_(nullptr), __extbufend_(nullptr), __ebs_(0), __intbuf_(nullptr), __ibs_(0), __file_(nullptr), __cv_(nullptr), __st_(), __st_last_(), __om_(static_cast(0)), __cm_(static_cast(0)), __owns_eb_(false), __owns_ib_(false), __always_noconv_(false) { if (std::has_facet>(this->getloc())) { this->__cv_ = &std::use_facet>(this->getloc()); this->__always_noconv_ = this->__cv_->always_noconv(); } this->setbuf(nullptr, 4096); } virtual ~filebuf_wfopen() { try { this->close(); } catch (...) { } if (this->__owns_eb_) delete[] this->__extbuf_; if (this->__owns_ib_) delete[] this->__intbuf_; } // 27.9.1.4 Members: bool is_open() const { return !!this->__file_; } filebuf_wfopen *open(const char *__s, std::ios_base::openmode __mode) { filebuf_wfopen *__rt = nullptr; if (!this->__file_) { __rt = this; const char *__mdstr = nullptr; switch (__mode & ~std::ios_base::ate) { case std::ios_base::out: case std::ios_base::out | std::ios_base::trunc: __mdstr = "w"; break; case std::ios_base::out | std::ios_base::app: case std::ios_base::app: __mdstr = "a"; break; case std::ios_base::in: __mdstr = "r"; break; case std::ios_base::in | std::ios_base::out: __mdstr = "r+"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::trunc: __mdstr = "w+"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::app: case std::ios_base::in | std::ios_base::app: __mdstr = "a+"; break; case std::ios_base::out | std::ios_base::binary: case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: __mdstr = "wb"; break; case std::ios_base::out | std::ios_base::app | std::ios_base::binary: case std::ios_base::app | std::ios_base::binary: __mdstr = "ab"; break; case std::ios_base::in | std::ios_base::binary: __mdstr = "rb"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::binary: __mdstr = "r+b"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: __mdstr = "w+b"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary: case std::ios_base::in | std::ios_base::app | std::ios_base::binary: __mdstr = "a+b"; break; default: __rt = nullptr; } if (__rt) { this->__file_ = fopen(__s, __mdstr); if (this->__file_) { this->__om_ = __mode; if ((__mode & std::ios_base::ate) && fseek(this->__file_, 0, SEEK_END)) { fclose(this->__file_); this->__file_ = nullptr; __rt = nullptr; } } else __rt = nullptr; } } return __rt; } filebuf_wfopen *open(const std::string &__s, std::ios_base::openmode __mode) { return this->open(__s.c_str(), __mode); } filebuf_wfopen *open(const wchar_t *__s, std::ios_base::openmode __mode) { filebuf_wfopen *__rt = nullptr; if (!this->__file_) { __rt = this; const wchar_t *__mdstr = nullptr; switch (__mode & ~std::ios_base::ate) { case std::ios_base::out: case std::ios_base::out | std::ios_base::trunc: __mdstr = L"w"; break; case std::ios_base::out | std::ios_base::app: case std::ios_base::app: __mdstr = L"a"; break; case std::ios_base::in: __mdstr = L"r"; break; case std::ios_base::in | std::ios_base::out: __mdstr = L"r+"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::trunc: __mdstr = L"w+"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::app: case std::ios_base::in | std::ios_base::app: __mdstr = L"a+"; break; case std::ios_base::out | std::ios_base::binary: case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: __mdstr = L"wb"; break; case std::ios_base::out | std::ios_base::app | std::ios_base::binary: case std::ios_base::app | std::ios_base::binary: __mdstr = L"ab"; break; case std::ios_base::in | std::ios_base::binary: __mdstr = L"rb"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::binary: __mdstr = L"r+b"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: __mdstr = L"w+b"; break; case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary: case std::ios_base::in | std::ios_base::app | std::ios_base::binary: __mdstr = L"a+b"; break; default: __rt = nullptr; } if (__rt) { this->__file_ = _wfopen(__s, __mdstr); if (this->__file_) { this->__om_ = __mode; if ((__mode & std::ios_base::ate) && fseek(this->__file_, 0, SEEK_END)) { fclose(this->__file_); this->__file_ = nullptr; __rt = nullptr; } } else __rt = nullptr; } } return __rt; } filebuf_wfopen *open(const std::wstring &__s, std::ios_base::openmode __mode) { return this->open(__s.c_str(), __mode); } filebuf_wfopen *close() { filebuf_wfopen *__rt = nullptr; if (this->__file_) { __rt = this; std::unique_ptr __h(this->__file_, fclose); if (this->sync()) __rt = nullptr; if (!fclose(__h.release())) this->__file_ = nullptr; else __rt = nullptr; } return __rt; } protected: // 27.9.1.5 Overridden virtual functions: virtual int_type underflow() { if (!this->__file_) return traits_type::eof(); bool __initial = this->__read_mode(); char __1buf; if (!this->gptr()) this->setg(&__1buf, &__1buf + 1, &__1buf + 1); const size_t __unget_sz = __initial ? 0 : std::min((this->egptr() - this->eback()) / 2, 4); int_type __c = traits_type::eof(); if (this->gptr() == this->egptr()) { memmove(this->eback(), this->egptr() - __unget_sz, __unget_sz); if (this->__always_noconv_) { size_t __nmemb = static_cast(this->egptr() - this->eback() - __unget_sz); __nmemb = fread(this->eback() + __unget_sz, 1, __nmemb, this->__file_); if (__nmemb) { this->setg(this->eback(), this->eback() + __unget_sz, this->eback() + __unget_sz + __nmemb); __c = traits_type::to_int_type(*this->gptr()); } } else { memmove(this->__extbuf_, this->__extbufnext_, this->__extbufend_ - this->__extbufnext_); this->__extbufnext_ = this->__extbuf_ + (this->__extbufend_ - this->__extbufnext_); this->__extbufend_ = this->__extbuf_ + (this->__extbuf_ == this->__extbuf_min_ ? sizeof(this->__extbuf_min_) : this->__ebs_); size_t __nmemb = std::min(this->__ibs_ - __unget_sz, this->__extbufend_ - this->__extbufnext_); std::codecvt_base::result __r; this->__st_last_ = this->__st_; size_t __nr = fread(const_cast(this->__extbufnext_), 1, __nmemb, this->__file_); if (__nr) { if (!this->__cv_) throw std::bad_cast(); this->__extbufend_ = this->__extbufnext_ + __nr; char *__inext; __r = this->__cv_->in(this->__st_, this->__extbuf_, this->__extbufend_, this->__extbufnext_, this->eback() + __unget_sz, this->eback() + this->__ibs_, __inext); if (__r == std::codecvt_base::noconv) { this->setg(this->__extbuf_, this->__extbuf_, const_cast(this->__extbufend_)); __c = traits_type::to_int_type(*this->gptr()); } else if (__inext != this->eback() + __unget_sz) { this->setg(this->eback(), this->eback() + __unget_sz, __inext); __c = traits_type::to_int_type(*this->gptr()); } } } } else __c = traits_type::to_int_type(*this->gptr()); if (this->eback() == &__1buf) this->setg(nullptr, nullptr, nullptr); return __c; } virtual int_type pbackfail(int_type __c = traits_type::eof()) { if (this->__file_ && this->eback() < this->gptr()) { if (traits_type::eq_int_type(__c, traits_type::eof())) { this->gbump(-1); return traits_type::not_eof(__c); } if ((this->__om_ & std::ios_base::out) || traits_type::eq(traits_type::to_char_type(__c), this->gptr()[-1])) { this->gbump(-1); *this->gptr() = traits_type::to_char_type(__c); return __c; } } return traits_type::eof(); } virtual int_type overflow (int_type __c = traits_type::eof()) { if (!this->__file_) return traits_type::eof(); this->__write_mode(); char __1buf; char *__pb_save = this->pbase(); char *__epb_save = this->epptr(); if (!traits_type::eq_int_type(__c, traits_type::eof())) { if (!this->pptr()) this->setp(&__1buf, &__1buf + 1); *this->pptr() = traits_type::to_char_type(__c); this->pbump(1); } if (this->pptr() != this->pbase()) { if (this->__always_noconv_) { size_t __nmemb = static_cast(this->pptr() - this->pbase()); if (fwrite(this->pbase(), 1, __nmemb, __file_) != __nmemb) return traits_type::eof(); } else { char *__extbe = this->__extbuf_; std::codecvt_base::result __r; do { if (!this->__cv_) throw std::bad_cast(); const char *__e; __r = this->__cv_->out(this->__st_, this->pbase(), this->pptr(), __e, this->__extbuf_, this->__extbuf_ + this->__ebs_, __extbe); if (__e == this->pbase()) return traits_type::eof(); if (__r == std::codecvt_base::noconv) { size_t __nmemb = static_cast(this->pptr() - this->pbase()); if (fwrite(this->pbase(), 1, __nmemb, this->__file_) != __nmemb) return traits_type::eof(); } else if (__r == std::codecvt_base::ok || __r == std::codecvt_base::partial) { size_t __nmemb = static_cast(__extbe - this->__extbuf_); if (fwrite(this->__extbuf_, 1, __nmemb, this->__file_) != __nmemb) return traits_type::eof(); if (__r == std::codecvt_base::partial) { this->setp(const_cast(__e), this->pptr()); this->pbump(this->epptr() - this->pbase()); } } else return traits_type::eof(); } while (__r == std::codecvt_base::partial); } this->setp(__pb_save, __epb_save); } return traits_type::not_eof(__c); } virtual std::streambuf *setbuf(char *__s, std::streamsize __n) { this->setg(nullptr, nullptr, nullptr); this->setp(nullptr, nullptr); if (this->__owns_eb_) delete[] this->__extbuf_; if (this->__owns_ib_) delete[] this->__intbuf_; this->__ebs_ = __n; if (this->__ebs_ > sizeof(this->__extbuf_min_)) { if (this->__always_noconv_ && __s) { this->__extbuf_ = __s; this->__owns_eb_ = false; } else { this->__extbuf_ = new char[this->__ebs_]; this->__owns_eb_ = true; } } else { this->__extbuf_ = this->__extbuf_min_; this->__ebs_ = sizeof(this->__extbuf_min_); this->__owns_eb_ = false; } if (!this->__always_noconv_) { this->__ibs_ = std::max(__n, sizeof(this->__extbuf_min_)); if (__s && this->__ibs_ >= sizeof(this->__extbuf_min_)) { this->__intbuf_ = __s; this->__owns_ib_ = false; } else { this->__intbuf_ = new char[this->__ibs_]; this->__owns_ib_ = true; } } else { this->__ibs_ = 0; this->__intbuf_ = nullptr; this->__owns_ib_ = false; } return this; } virtual pos_type seekoff(off_type __off, std::ios_base::seekdir __way, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { if (!this->__cv_) throw std::bad_cast(); int __width = this->__cv_->encoding(); if (!this->__file_ || (__width <= 0 && __off) || this->sync()) return pos_type(off_type(-1)); // __width > 0 || __off == 0 int __whence; switch (__way) { case std::ios_base::beg: __whence = SEEK_SET; break; case std::ios_base::cur: __whence = SEEK_CUR; break; case std::ios_base::end: __whence = SEEK_END; break; default: return pos_type(off_type(-1)); } if (fseek(this->__file_, __width > 0 ? __width * __off : 0, __whence)) return pos_type(off_type(-1)); pos_type __r = ftell(this->__file_); __r.state(this->__st_); return __r; } virtual pos_type seekpos(pos_type __sp, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { if (!this->__file_ || this->sync()) return pos_type(off_type(-1)); if (fseek(this->__file_, __sp, SEEK_SET)) return pos_type(off_type(-1)); this->__st_ = __sp.state(); return __sp; } virtual int sync() { if (!this->__file_) return 0; if (!this->__cv_) throw std::bad_cast(); if (this->__cm_ & std::ios_base::out) { if (this->pptr() != this->pbase() && this->overflow() == traits_type::eof()) return -1; std::codecvt_base::result __r; do { char *__extbe; __r = this->__cv_->unshift(this->__st_, this->__extbuf_, this->__extbuf_ + this->__ebs_, __extbe); size_t __nmemb = static_cast(__extbe - this->__extbuf_); if (fwrite(this->__extbuf_, 1, __nmemb, this->__file_) != __nmemb) return -1; } while (__r == std::codecvt_base::partial); if (__r == std::codecvt_base::error) return -1; if (fflush(this->__file_)) return -1; } else if (this->__cm_ & std::ios_base::in) { off_type __c; state_type __state = this->__st_last_; bool __update_st = false; if (this->__always_noconv_) __c = this->egptr() - this->gptr(); else { int __width = this->__cv_->encoding(); __c = this->__extbufend_ - this->__extbufnext_; if (__width > 0) __c += __width * (this->egptr() - this->gptr()); else if (this->gptr() != this->egptr()) { int __off = this->__cv_->length(__state, this->__extbuf_, this->__extbufnext_, this->gptr() - this->eback()); __c += this->__extbufnext_ - this->__extbuf_ - __off; __update_st = true; } } if (fseek(this->__file_, -__c, SEEK_CUR)) return -1; if (__update_st) this->__st_ = __state; this->__extbufnext_ = this->__extbufend_ = this->__extbuf_; this->setg(nullptr, nullptr, nullptr); this->__cm_ = static_cast(0); } return 0; } virtual void imbue(const std::locale &__loc) { this->sync(); this->__cv_ = &std::use_facet>(__loc); bool __old_anc = this->__always_noconv_; this->__always_noconv_ = this->__cv_->always_noconv(); if (__old_anc != this->__always_noconv_) { this->setg(nullptr, nullptr, nullptr); this->setp(nullptr, nullptr); // invariant, char_type is char, else we couldn't get here if (this->__always_noconv_) // need to dump __intbuf_ { if (this->__owns_eb_) delete[] this->__extbuf_; this->__owns_eb_ = this->__owns_ib_; this->__ebs_ = this->__ibs_; this->__extbuf_ = this->__intbuf_; this->__ibs_ = 0; this->__intbuf_ = nullptr; this->__owns_ib_ = false; } // need to obtain an __intbuf_. else if (!this->__owns_eb_ && this->__extbuf_ != this->__extbuf_min_) // If __extbuf_ is user-supplied, use it, else new __intbuf_ { this->__ibs_ = this->__ebs_; this->__intbuf_ = this->__extbuf_; this->__owns_ib_ = false; this->__extbuf_ = new char[this->__ebs_]; this->__owns_eb_ = true; } else { this->__ibs_ = this->__ebs_; this->__intbuf_ = new char[this->__ibs_]; this->__owns_ib_ = true; } } } private: char *__extbuf_; const char *__extbufnext_; const char *__extbufend_; char __extbuf_min_[8]; size_t __ebs_; char *__intbuf_; size_t __ibs_; FILE *__file_; const std::codecvt *__cv_; state_type __st_; state_type __st_last_; std::ios_base::openmode __om_; std::ios_base::openmode __cm_; bool __owns_eb_; bool __owns_ib_; bool __always_noconv_; bool __read_mode() { if (!(this->__cm_ & std::ios_base::in)) { this->setp(nullptr, nullptr); if (this->__always_noconv_) this->setg(this->__extbuf_, this->__extbuf_ + this->__ebs_, this->__extbuf_ + this->__ebs_); else this->setg(this->__intbuf_, this->__intbuf_ + this->__ibs_, this->__intbuf_ + this->__ibs_); this->__cm_ = std::ios_base::in; return true; } return false; } void __write_mode() { if (!(this->__cm_ & std::ios_base::out)) { this->setg(nullptr, nullptr, nullptr); if (this->__ebs_ > sizeof(this->__extbuf_min_)) { if (this->__always_noconv_) this->setp(this->__extbuf_, this->__extbuf_ + (this->__ebs_ - 1)); else this->setp(this->__intbuf_, this->__intbuf_ + (this->__ibs_ - 1)); } else this->setp(nullptr, nullptr); this->__cm_ = std::ios_base::out; } } }; // basic_ifstream class ifstream_wfopen : public std::ifstream { public: ifstream_wfopen() { std::ios::rdbuf(&this->__sb_); } explicit ifstream_wfopen(const char *__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } explicit ifstream_wfopen(const std::string &__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } explicit ifstream_wfopen(const wchar_t *__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } explicit ifstream_wfopen(const std::wstring &__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } std::filebuf *rdbuf() const { return const_cast(static_cast(&this->__sb_)); } bool is_open() const { return this->__sb_.is_open(); } void open(const char *__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) this->clear(); else this->setstate(std::ios_base::failbit); } void open(const std::string &__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) this->clear(); else this->setstate(std::ios_base::failbit); } void open(const wchar_t *__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) this->clear(); else this->setstate(std::ios_base::failbit); } void open(const std::wstring &__s, std::ios_base::openmode __mode = std::ios_base::in) { if (this->__sb_.open(__s, __mode | std::ios_base::in)) this->clear(); else this->setstate(std::ios_base::failbit); } void close() { if (!this->__sb_.close()) this->setstate(std::ios_base::failbit); } private: filebuf_wfopen __sb_; }; // basic_ofstream class ofstream_wfopen : public std::ofstream { public: ofstream_wfopen() { std::ios::rdbuf(&this->__sb_); } explicit ofstream_wfopen(const char *__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } explicit ofstream_wfopen(const std::string &__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } explicit ofstream_wfopen(const wchar_t *__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } explicit ofstream_wfopen(const std::wstring &__s, std::ios_base::openmode __mode = std::ios_base::out) { if (!this->__sb_.open(__s, __mode | std::ios_base::out)) std::ios::rdbuf(&this->__sb_); else this->setstate(std::ios_base::failbit); } std::filebuf *rdbuf() const { return const_cast(static_cast(&this->__sb_)); } bool is_open() const { return this->__sb_.is_open(); } void open(const char *__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) this->clear(); else this->setstate(std::ios_base::failbit); } void open(const std::string &__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) this->clear(); else this->setstate(std::ios_base::failbit); } void open(const wchar_t *__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) this->clear(); else this->setstate(std::ios_base::failbit); } void open(const std::wstring &__s, std::ios_base::openmode __mode = std::ios_base::out) { if (this->__sb_.open(__s, __mode | std::ios_base::out)) this->clear(); else this->setstate(std::ios_base::failbit); } void close() { if (!this->__sb_.close()) this->setstate(std::ios_base::failbit); } private: filebuf_wfopen __sb_; }; #endif