00001 #ifndef BOOSTER_NOWIDE_FSTREAM_H
00002 #define BOOSTER_NOWIDE_FSTREAM_H
00003
00004 #include <booster/config.h>
00005 #include <booster/nowide/convert.h>
00006 #include <fstream>
00007 #include <memory>
00008
00009 #if defined BOOSTER_WIN_NATIVE || defined BOOSTER_WORKAROUND_BROKEN_GCC_ON_DARWIN
00010 #include <booster/streambuf.h>
00011 #include <booster/nowide/cstdio.h>
00012 #endif
00013
00014 namespace booster {
00020 namespace nowide {
00021 #if !defined BOOSTER_WIN_NATIVE && !defined(BOOSTER_WORKAROUND_BROKEN_GCC_ON_DARWIN)
00022
00023 using std::basic_ifstream;
00024 using std::basic_ofstream;
00025 using std::basic_fstream;
00026 using std::basic_filebuf;
00027 using std::filebuf;
00028 using std::ifstream;
00029 using std::ofstream;
00030 using std::fstream;
00031
00032 #endif
00033 #if defined(BOOSTER_WIN_NATIVE) || defined(BOOSTER_DOXYGEN_DOCS) || defined(BOOSTER_WORKAROUND_BROKEN_GCC_ON_DARWIN)
00034
00035 #if defined BOOSTER_MSVC
00036
00037 template<typename CharType,typename Traits = std::char_traits<CharType> >
00038 class basic_filebuf : public std::basic_filebuf<CharType,Traits> {
00039 public:
00040 typedef std::basic_filebuf<CharType,Traits> my_base_type;
00041 basic_filebuf *open(char const *s,std::ios_base::openmode mode)
00042 {
00043 try {
00044 if(my_base_type::open(convert(s).c_str(),mode)) {
00045 return this;
00046 }
00047 return 0;
00048 }
00049 catch(bad_utf const &e) {
00050 return 0;
00051 }
00052 }
00053 };
00054
00055 #else // not msvc
00056
00058
00059 namespace details {
00060 class stdio_iodev : public booster::io_device {
00061 stdio_iodev(stdio_iodev const &);
00062 void operator=(stdio_iodev const &);
00063 public:
00064 stdio_iodev(FILE *f) :
00065 file_(f)
00066 {
00067
00068 }
00069 size_t read(char *p,size_t n)
00070 {
00071 return fread(p,1,n,file_);
00072 }
00073 size_t write(char const *p,size_t n)
00074 {
00075 size_t res = fwrite(p,1,n,file_);
00076 fflush(file_);
00077 return res;
00078 }
00079 long long seek(long long pos,io_device::pos_type t=set)
00080 {
00081 switch(t) {
00082 case cur:
00083 fseek(file_,pos,SEEK_CUR);
00084 break;
00085 case set:
00086 fseek(file_,pos,SEEK_SET);
00087 break;
00088 case end:
00089 fseek(file_,pos,SEEK_END);
00090 break;
00091 default:
00092 return -1;
00093 }
00094 return ftell(file_);
00095 }
00096 ~stdio_iodev()
00097 {
00098 fclose(file_);
00099 }
00100 private:
00101 FILE *file_;
00102 };
00103 }
00104
00106
00107 template<typename CharType,typename Traits = std::char_traits<CharType> >
00108 class basic_filebuf;
00109
00113
00114 template<>
00115 class basic_filebuf<char> : public booster::streambuf {
00116 public:
00117
00118 basic_filebuf() : opened_(false)
00119 {
00120 }
00121 ~basic_filebuf()
00122 {
00123 }
00124 basic_filebuf *open(char const *s,std::ios_base::openmode mode)
00125 {
00126 reset_device();
00127 wchar_t const *smode = get_mode(mode);
00128 if(!smode)
00129 return 0;
00130 std::wstring name;
00131 try {
00132 name = convert(s);
00133 }
00134 catch(bad_utf const &) {
00135 return 0;
00136 }
00137 FILE *f = _wfopen(name.c_str(),smode);
00138 if(!f)
00139 return 0;
00140 std::auto_ptr<io_device> dev(new details::stdio_iodev(f));
00141 device(dev);
00142 opened_ = true;
00143 return this;
00144 }
00145 basic_filebuf *close()
00146 {
00147
00148 bool res = sync();
00149 reset_device();
00150 opened_ = false;
00151 return res ? this : 0;
00152 }
00153 bool is_open() const
00154 {
00155 return opened_;
00156 }
00157 private:
00158 static wchar_t const *get_mode(std::ios_base::openmode mode)
00159 {
00160
00161
00162
00163
00164
00165
00166 if(mode == (std::ios_base::out))
00167 return L"w";
00168 if(mode == (std::ios_base::out | std::ios_base::app))
00169 return L"a";
00170 if(mode == (std::ios_base::app))
00171 return L"a";
00172 if(mode == (std::ios_base::out | std::ios_base::trunc))
00173 return L"w";
00174 if(mode == (std::ios_base::in))
00175 return L"r";
00176 if(mode == (std::ios_base::in | std::ios_base::out))
00177 return L"r+";
00178 if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
00179 return L"w+";
00180 if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::app))
00181 return L"a+";
00182 if(mode == (std::ios_base::in | std::ios_base::app))
00183 return L"a+";
00184 if(mode == (std::ios_base::binary | std::ios_base::out))
00185 return L"wb";
00186 if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::app))
00187 return L"ab";
00188 if(mode == (std::ios_base::binary | std::ios_base::app))
00189 return L"ab";
00190 if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc))
00191 return L"wb";
00192 if(mode == (std::ios_base::binary | std::ios_base::in))
00193 return L"rb";
00194 if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out))
00195 return L"r+b";
00196 if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
00197 return L"w+b";
00198 if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app))
00199 return L"a+b";
00200 if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::app))
00201 return L"a+b";
00202 return 0;
00203 }
00204
00205 bool opened_;
00206 };
00207
00208 #endif
00209
00213 template<typename CharType,typename Traits = std::char_traits<CharType> >
00214 class basic_ifstream : public std::basic_istream<CharType,Traits>
00215 {
00216 public:
00217 typedef basic_filebuf<CharType,Traits> internal_buffer_type;
00218 typedef std::basic_istream<CharType,Traits> internal_stream_type;
00219
00220 basic_ifstream() :
00221 internal_stream_type(new internal_buffer_type())
00222 {
00223 buf_.reset(static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()));
00224 }
00225 explicit basic_ifstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::in) :
00226 internal_stream_type(new internal_buffer_type())
00227 {
00228 buf_.reset(static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()));
00229 open(file_name,mode);
00230 }
00231 void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::in)
00232 {
00233 if(!buf_->open(file_name,mode | std::ios_base::in)) {
00234 this->setstate(std::ios_base::failbit);
00235 }
00236 else {
00237 this->clear();
00238 }
00239 }
00240 bool is_open()
00241 {
00242 return buf_->is_open();
00243 }
00244 bool is_open() const
00245 {
00246 return buf_->is_open();
00247 }
00248 void close()
00249 {
00250 if(!buf_->close())
00251 this->setstate(std::ios_base::failbit);
00252 else
00253 this->clear();
00254 }
00255
00256 internal_buffer_type *rdbuf() const
00257 {
00258 return buf_.get();
00259 }
00260 ~basic_ifstream()
00261 {
00262 buf_->close();
00263 }
00264
00265 private:
00266 std::auto_ptr<internal_buffer_type> buf_;
00267 };
00268
00272
00273 template<typename CharType,typename Traits = std::char_traits<CharType> >
00274 class basic_ofstream : public std::basic_ostream<CharType,Traits>
00275 {
00276 public:
00277 typedef basic_filebuf<CharType,Traits> internal_buffer_type;
00278 typedef std::basic_ostream<CharType,Traits> internal_stream_type;
00279
00280 basic_ofstream() :
00281 internal_stream_type(new internal_buffer_type())
00282 {
00283 buf_.reset(static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()));
00284 }
00285 explicit basic_ofstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::out) :
00286 internal_stream_type(new internal_buffer_type())
00287 {
00288 buf_.reset(static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()));
00289 open(file_name,mode);
00290 }
00291 void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out)
00292 {
00293 if(!buf_->open(file_name,mode | std::ios_base::out)) {
00294 this->setstate(std::ios_base::failbit);
00295 }
00296 else {
00297 this->clear();
00298 }
00299 }
00300 bool is_open()
00301 {
00302 return buf_->is_open();
00303 }
00304 bool is_open() const
00305 {
00306 return buf_->is_open();
00307 }
00308 void close()
00309 {
00310 if(!buf_->close())
00311 this->setstate(std::ios_base::failbit);
00312 else
00313 this->clear();
00314 }
00315
00316 internal_buffer_type *rdbuf() const
00317 {
00318 return buf_.get();
00319 }
00320 ~basic_ofstream()
00321 {
00322 buf_->close();
00323 }
00324
00325 private:
00326 std::auto_ptr<internal_buffer_type> buf_;
00327 };
00328
00332
00333 template<typename CharType,typename Traits = std::char_traits<CharType> >
00334 class basic_fstream : public std::basic_iostream<CharType,Traits>
00335 {
00336 public:
00337 typedef basic_filebuf<CharType,Traits> internal_buffer_type;
00338 typedef std::basic_iostream<CharType,Traits> internal_stream_type;
00339
00340 basic_fstream() :
00341 internal_stream_type(new internal_buffer_type())
00342 {
00343 buf_.reset(static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()));
00344 }
00345 explicit basic_fstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::out | std::ios_base::in) :
00346 internal_stream_type(new internal_buffer_type())
00347 {
00348 buf_.reset(static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()));
00349 open(file_name,mode);
00350 }
00351 void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out | std::ios_base::out)
00352 {
00353 if(!buf_->open(file_name,mode)) {
00354 this->setstate(std::ios_base::failbit);
00355 }
00356 else {
00357 this->clear();
00358 }
00359 }
00360 bool is_open()
00361 {
00362 return buf_->is_open();
00363 }
00364 bool is_open() const
00365 {
00366 return buf_->is_open();
00367 }
00368 void close()
00369 {
00370 if(!buf_->close())
00371 this->setstate(std::ios_base::failbit);
00372 else
00373 this->clear();
00374 }
00375
00376 internal_buffer_type *rdbuf() const
00377 {
00378 return buf_.get();
00379 }
00380 ~basic_fstream()
00381 {
00382 buf_->close();
00383 }
00384
00385 private:
00386 std::auto_ptr<internal_buffer_type> buf_;
00387 };
00388
00389
00393 typedef basic_filebuf<char> filebuf;
00397 typedef basic_ifstream<char> ifstream;
00401 typedef basic_ofstream<char> ofstream;
00405 typedef basic_fstream<char> fstream;
00406
00407 #endif
00408 }
00409 }
00410
00411
00412
00413 #endif