Boost.Nowide
boost/nowide/filebuf.hpp
00001 //
00002 //  Copyright (c) 2012 Artyom Beilis (Tonkikh)
00003 //
00004 //  Distributed under the Boost Software License, Version 1.0. (See
00005 //  accompanying file LICENSE_1_0.txt or copy at
00006 //  http://www.boost.org/LICENSE_1_0.txt)
00007 //
00008 #ifndef BOOST_NOWIDE_FILEBUF_HPP
00009 #define BOOST_NOWIDE_FILEBUF_HPP
00010 
00011 #include <iosfwd>
00012 #include <boost/config.hpp>
00013 #include <boost/nowide/stackstring.hpp>
00014 #include <fstream>
00015 #include <streambuf>
00016 #include <stdio.h>
00017 
00018 #ifdef BOOST_MSVC
00019 #  pragma warning(push)
00020 #  pragma warning(disable : 4996 4244)
00021 #endif
00022 
00023 
00024 namespace boost {
00025 namespace nowide {
00026 #if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS) && !defined(BOOST_NOWIDE_DOXYGEN)
00027     using std::basic_filebuf;
00028     using std::filebuf;
00029 #else // Windows
00030     
00037     template<typename CharType,typename Traits = std::char_traits<CharType> >
00038     class basic_filebuf;
00039     
00046     template<>
00047     class basic_filebuf<char> : public std::basic_streambuf<char> {
00048     public:
00052         basic_filebuf() : 
00053             buffer_size_(4),
00054             buffer_(0),
00055             file_(0),
00056             own_(true),
00057             mode_(std::ios::in | std::ios::out)
00058         {
00059             setg(0,0,0);
00060             setp(0,0);
00061         }
00062         
00063         virtual ~basic_filebuf()
00064         {
00065             if(file_) {
00066                 ::fclose(file_);
00067                 file_ = 0;
00068             }
00069             if(own_ && buffer_)
00070                 delete [] buffer_;
00071         }
00072         
00076         basic_filebuf *open(std::string const &s,std::ios_base::openmode mode)
00077         {
00078             return open(s.c_str(),mode);
00079         }
00083         basic_filebuf *open(char const *s,std::ios_base::openmode mode)
00084         {
00085             if(file_) {
00086                 sync();
00087                 ::fclose(file_);
00088                 file_ = 0;
00089             }
00090             wchar_t const *smode = get_mode(mode);
00091             if(!smode)
00092                 return 0;
00093             wstackstring name;
00094             if(!name.convert(s)) 
00095                 return 0;
00096             #ifdef BOOST_NOWIDE_FSTREAM_TESTS
00097             FILE *f = ::fopen(s,boost::nowide::convert(smode).c_str());
00098             #else
00099             FILE *f = ::_wfopen(name.c_str(),smode);
00100             #endif
00101             if(!f)
00102                 return 0;
00103             file_ = f;
00104             return this;
00105         }
00109         basic_filebuf *close()
00110         {
00111             bool res = sync() == 0;
00112             if(file_) {
00113                 if(::fclose(file_)!=0)
00114                     res = false;
00115                 file_ = 0;
00116             }
00117             return res ? this : 0;
00118         }
00122         bool is_open() const
00123         {
00124             return file_ != 0;
00125         }
00126 
00127     private:
00128         void make_buffer()
00129         {
00130             if(buffer_)
00131                 return;
00132             if(buffer_size_ > 0) {
00133                 buffer_ = new char [buffer_size_];
00134                 own_ = true;
00135             }
00136         }
00137     protected:
00138         
00139         virtual std::streambuf *setbuf(char *s,std::streamsize n)
00140         {
00141             if(!buffer_ && n>=0) {
00142                 buffer_ = s;
00143                 buffer_size_ = n;
00144                 own_ = false;
00145             }
00146             return this;
00147         }
00148         
00149 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
00150 
00151         void print_buf(char *b,char *p,char *e)
00152         {
00153             std::cerr << "-- Is Null: " << (b==0) << std::endl;; 
00154             if(b==0)
00155                 return;
00156             if(e != 0)
00157                 std::cerr << "-- Total: " << e - b <<" offset from start " << p - b << std::endl;
00158             else
00159                 std::cerr << "-- Total: " << p - b << std::endl;
00160                 
00161             std::cerr << "-- [";
00162             for(char *ptr = b;ptr<p;ptr++)
00163                 std::cerr << *ptr;
00164             if(e!=0) {
00165                 std::cerr << "|";
00166                 for(char *ptr = p;ptr<e;ptr++)
00167                     std::cerr << *ptr;
00168             }
00169             std::cerr << "]" << std::endl;
00170            
00171         }
00172         
00173         void print_state()
00174         {
00175             std::cerr << "- Output:" << std::endl;
00176             print_buf(pbase(),pptr(),0);
00177             std::cerr << "- Input:" << std::endl;
00178             print_buf(eback(),gptr(),egptr());
00179             std::cerr << "- fpos: " << (file_ ? ftell(file_) : -1L) << std::endl;
00180         }
00181         
00182         struct print_guard
00183         {
00184             print_guard(basic_filebuf *p,char const *func)
00185             {
00186                 self = p;
00187                 f=func;
00188                 std::cerr << "In: " << f << std::endl;
00189                 self->print_state();
00190             }
00191             ~print_guard()
00192             {
00193                 std::cerr << "Out: " << f << std::endl;
00194                 self->print_state();
00195             }
00196             basic_filebuf *self;
00197             char const *f;
00198         };
00199 #else
00200 #endif        
00201         
00202         int overflow(int c)
00203         {
00204 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
00205             print_guard g(this,__FUNCTION__);
00206 #endif            
00207             if(!file_)
00208                 return EOF;
00209             
00210             if(fixg() < 0)
00211                 return EOF;
00212 
00213             size_t n = pptr() - pbase();
00214             if(n > 0) {
00215                 if(::fwrite(pbase(),1,n,file_) < n)
00216                     return -1;
00217                 fflush(file_);
00218             }
00219 
00220             if(buffer_size_ > 0) {
00221                 make_buffer();
00222                 setp(buffer_,buffer_+buffer_size_);
00223                 if(c!=EOF)
00224                     sputc(c);
00225             }
00226             else if(c!=EOF) {
00227                 if(::fputc(c,file_)==EOF)
00228                     return EOF;
00229                 fflush(file_);
00230             }
00231             return 0;
00232         }
00233         
00234         
00235         int sync()
00236         {
00237             return overflow(EOF);
00238         }
00239 
00240         int underflow()
00241         {
00242 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
00243             print_guard g(this,__FUNCTION__);
00244 #endif            
00245             if(!file_)
00246                 return EOF;
00247             if(fixp() < 0)
00248                 return EOF;
00249             if(buffer_size_ == 0) {
00250                 int c = ::fgetc(file_);
00251                 if(c==EOF) {
00252                     return EOF;
00253                 }
00254                 last_char_ = c;
00255                 setg(&last_char_,&last_char_,&last_char_ + 1);
00256                 return c;
00257             }
00258             make_buffer();
00259             size_t n = ::fread(buffer_,1,buffer_size_,file_);
00260             setg(buffer_,buffer_,buffer_+n);
00261             if(n == 0)
00262                 return EOF;
00263             return std::char_traits<char>::to_int_type(*gptr());
00264         }
00265 
00266         int pbackfail(int)
00267         {
00268             return pubseekoff(-1,std::ios::cur);
00269         }
00270 
00271         std::streampos seekoff(std::streamoff off,
00272                             std::ios_base::seekdir seekdir,
00273                             std::ios_base::openmode /*m*/)
00274         {
00275 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
00276             print_guard g(this,__FUNCTION__);
00277 #endif            
00278             if(!file_)
00279                 return EOF;
00280             if(fixp() < 0 || fixg() < 0)
00281                 return EOF;
00282             if(seekdir == std::ios_base::cur) {
00283                 if( ::fseek(file_,off,SEEK_CUR) < 0)
00284                     return EOF;
00285             }
00286             else if(seekdir == std::ios_base::beg) {
00287                 if( ::fseek(file_,off,SEEK_SET) < 0)
00288                     return EOF;
00289             }
00290             else if(seekdir == std::ios_base::end) {
00291                 if( ::fseek(file_,off,SEEK_END) < 0)
00292                     return EOF;
00293             }
00294             else
00295                 return -1;
00296             return ftell(file_);
00297         }
00298         std::streampos seekpos(std::streampos off,std::ios_base::openmode m)
00299         {
00300             return seekoff(std::streamoff(off),std::ios_base::beg,m);
00301         }
00302     private:
00303         int fixg()
00304         {
00305             if(gptr()!=egptr()) {
00306                 std::streamsize off = gptr() - egptr();
00307                 setg(0,0,0);
00308                 if(fseek(file_,off,SEEK_CUR) != 0)
00309                     return -1;
00310             }
00311             setg(0,0,0);
00312             return 0;
00313         }
00314         
00315         int fixp()
00316         {
00317             if(pptr()!=0) {
00318                 int r = sync();
00319                 setp(0,0);
00320                 return r;
00321             }
00322             return 0;
00323         }
00324 
00325         void reset(FILE *f = 0)
00326         {
00327             sync();
00328             if(file_) {
00329                 fclose(file_);
00330                 file_ = 0;
00331             }
00332             file_ = f;
00333         }
00334         
00335         
00336         static wchar_t const *get_mode(std::ios_base::openmode mode)
00337         {
00338             //
00339             // done according to n2914 table 106 27.9.1.4
00340             //
00341 
00342             // note can't use switch case as overload operator can't be used
00343             // in constant expression
00344             if(mode == (std::ios_base::out))
00345                 return L"w";
00346             if(mode == (std::ios_base::out | std::ios_base::app))
00347                 return L"a";
00348             if(mode == (std::ios_base::app))
00349                 return L"a";
00350             if(mode == (std::ios_base::out | std::ios_base::trunc))
00351                 return L"w";
00352             if(mode == (std::ios_base::in))
00353                 return L"r";
00354             if(mode == (std::ios_base::in | std::ios_base::out))
00355                 return L"r+";
00356             if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
00357                 return L"w+";
00358             if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::app))
00359                 return L"a+";
00360             if(mode == (std::ios_base::in | std::ios_base::app))
00361                 return L"a+";
00362             if(mode == (std::ios_base::binary | std::ios_base::out))
00363                 return L"wb";
00364             if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::app))
00365                 return L"ab";
00366             if(mode == (std::ios_base::binary | std::ios_base::app))
00367                 return L"ab";
00368             if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc))
00369                 return L"wb";
00370             if(mode == (std::ios_base::binary | std::ios_base::in))
00371                 return L"rb";
00372             if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out))
00373                 return L"r+b";
00374             if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
00375                 return L"w+b";
00376             if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app))
00377                 return L"a+b";
00378             if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::app))
00379                 return L"a+b";
00380             return 0;    
00381         }
00382         
00383         size_t buffer_size_;
00384         char *buffer_;
00385         FILE *file_;
00386         bool own_;
00387         char last_char_;
00388         std::ios::openmode mode_;
00389     };
00390     
00394     typedef basic_filebuf<char> filebuf;
00395     
00396     #endif // windows
00397     
00398 } // nowide
00399 } // namespace boost
00400 
00401 #ifdef BOOST_MSVC
00402 #  pragma warning(pop)
00403 #endif
00404 
00405 
00406 #endif
00407 
00408 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4