CppCMS
booster/nowide/fstream.h
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         } // details
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                         // done according to n2914 table 106 27.9.1.4
00162                         //
00163 
00164                         // note can't use switch case as overload operator can't be used
00165                         // in constant expression
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 } // nowide
00409 } // booster
00410 
00411 
00412 
00413 #endif