Boost.Nowide
|
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