// 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 <streambuf>
#include <locale>
#include <memory>
#include <fstream>
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<std::ios_base::openmode>(0)), __cm_(static_cast<std::ios_base::openmode>(0)),
__owns_eb_(false), __owns_ib_(false), __always_noconv_(false)
{
if (std::has_facet<std::codecvt<char, char, state_type>>(this->getloc()))
{
this->__cv_ = &std::use_facet<std::codecvt<char, char, state_type>>(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<FILE, int (*)(FILE *)> __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<size_t>((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<size_t>(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<size_t>(this->__ibs_ - __unget_sz,
this->__extbufend_ - this->__extbufnext_);
std::codecvt_base::result __r;
this->__st_last_ = this->__st_;
size_t __nr = fread(const_cast<char *>(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<char *>(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<size_t>(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<size_t>(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<size_t>(__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<char *>(__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<std::streamsize>(__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<size_t>(__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<std::ios_base::openmode>(0);
}
return 0;
}
virtual void imbue(const std::locale &__loc)
{
this->sync();
this->__cv_ = &std::use_facet<std::codecvt<char, char, state_type>>(__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<char, char, state_type> *__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<std::filebuf *>(static_cast<const std::filebuf *>(&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<std::filebuf *>(static_cast<const std::filebuf *>(&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