Boost.Nowide
filebuf.hpp
1 //
2 // Copyright (c) 2012 Artyom Beilis (Tonkikh)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_NOWIDE_FILEBUF_HPP
9 #define BOOST_NOWIDE_FILEBUF_HPP
10 
11 #include <iosfwd>
12 #include <boost/config.hpp>
13 #include <boost/nowide/stackstring.hpp>
14 #include <fstream>
15 #include <streambuf>
16 #include <stdio.h>
17 
18 #ifdef BOOST_MSVC
19 # pragma warning(push)
20 # pragma warning(disable : 4996 4244 4800)
21 #endif
22 
23 
24 namespace boost {
25 namespace nowide {
26 #if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS) && !defined(BOOST_NOWIDE_DOXYGEN)
27  using std::basic_filebuf;
28  using std::filebuf;
29 #else // Windows
30 
37  template<typename CharType,typename Traits = std::char_traits<CharType> >
39 
46  template<>
47  class basic_filebuf<char> : public std::basic_streambuf<char> {
48  public:
53  buffer_size_(4),
54  buffer_(0),
55  file_(0),
56  own_(true),
57  mode_(std::ios::in | std::ios::out)
58  {
59  setg(0,0,0);
60  setp(0,0);
61  }
62 
63  virtual ~basic_filebuf()
64  {
65  if(file_) {
66  ::fclose(file_);
67  file_ = 0;
68  }
69  if(own_ && buffer_)
70  delete [] buffer_;
71  }
72 
76  basic_filebuf *open(std::string const &s,std::ios_base::openmode mode)
77  {
78  return open(s.c_str(),mode);
79  }
83  basic_filebuf *open(char const *s,std::ios_base::openmode mode)
84  {
85  if(file_) {
86  sync();
87  ::fclose(file_);
88  file_ = 0;
89  }
90  bool ate = bool(mode & std::ios_base::ate);
91  if(ate)
92  mode = mode ^ std::ios_base::ate;
93  wchar_t const *smode = get_mode(mode);
94  if(!smode)
95  return 0;
96  wstackstring name;
97  if(!name.convert(s))
98  return 0;
99  #ifdef BOOST_NOWIDE_FSTREAM_TESTS
100  FILE *f = ::fopen(s,boost::nowide::convert(smode).c_str());
101  #else
102  FILE *f = ::_wfopen(name.c_str(),smode);
103  #endif
104  if(!f)
105  return 0;
106  if(ate && fseek(f,0,SEEK_END)!=0) {
107  fclose(f);
108  return 0;
109  }
110  file_ = f;
111  return this;
112  }
117  {
118  bool res = sync() == 0;
119  if(file_) {
120  if(::fclose(file_)!=0)
121  res = false;
122  file_ = 0;
123  }
124  return res ? this : 0;
125  }
129  bool is_open() const
130  {
131  return file_ != 0;
132  }
133 
134  private:
135  void make_buffer()
136  {
137  if(buffer_)
138  return;
139  if(buffer_size_ > 0) {
140  buffer_ = new char [buffer_size_];
141  own_ = true;
142  }
143  }
144  protected:
145 
146  virtual std::streambuf *setbuf(char *s,std::streamsize n)
147  {
148  if(!buffer_ && n>=0) {
149  buffer_ = s;
150  buffer_size_ = n;
151  own_ = false;
152  }
153  return this;
154  }
155 
156 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
157 
158  void print_buf(char *b,char *p,char *e)
159  {
160  std::cerr << "-- Is Null: " << (b==0) << std::endl;;
161  if(b==0)
162  return;
163  if(e != 0)
164  std::cerr << "-- Total: " << e - b <<" offset from start " << p - b << std::endl;
165  else
166  std::cerr << "-- Total: " << p - b << std::endl;
167 
168  std::cerr << "-- [";
169  for(char *ptr = b;ptr<p;ptr++)
170  std::cerr << *ptr;
171  if(e!=0) {
172  std::cerr << "|";
173  for(char *ptr = p;ptr<e;ptr++)
174  std::cerr << *ptr;
175  }
176  std::cerr << "]" << std::endl;
177 
178  }
179 
180  void print_state()
181  {
182  std::cerr << "- Output:" << std::endl;
183  print_buf(pbase(),pptr(),0);
184  std::cerr << "- Input:" << std::endl;
185  print_buf(eback(),gptr(),egptr());
186  std::cerr << "- fpos: " << (file_ ? ftell(file_) : -1L) << std::endl;
187  }
188 
189  struct print_guard
190  {
191  print_guard(basic_filebuf *p,char const *func)
192  {
193  self = p;
194  f=func;
195  std::cerr << "In: " << f << std::endl;
196  self->print_state();
197  }
198  ~print_guard()
199  {
200  std::cerr << "Out: " << f << std::endl;
201  self->print_state();
202  }
203  basic_filebuf *self;
204  char const *f;
205  };
206 #else
207 #endif
208 
209  int overflow(int c)
210  {
211 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
212  print_guard g(this,__FUNCTION__);
213 #endif
214  if(!file_)
215  return EOF;
216 
217  if(fixg() < 0)
218  return EOF;
219 
220  size_t n = pptr() - pbase();
221  if(n > 0) {
222  if(::fwrite(pbase(),1,n,file_) < n)
223  return -1;
224  fflush(file_);
225  }
226 
227  if(buffer_size_ > 0) {
228  make_buffer();
229  setp(buffer_,buffer_+buffer_size_);
230  if(c!=EOF)
231  sputc(c);
232  }
233  else if(c!=EOF) {
234  if(::fputc(c,file_)==EOF)
235  return EOF;
236  fflush(file_);
237  }
238  return 0;
239  }
240 
241 
242  int sync()
243  {
244  return overflow(EOF);
245  }
246 
247  int underflow()
248  {
249 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
250  print_guard g(this,__FUNCTION__);
251 #endif
252  if(!file_)
253  return EOF;
254  if(fixp() < 0)
255  return EOF;
256  if(buffer_size_ == 0) {
257  int c = ::fgetc(file_);
258  if(c==EOF) {
259  return EOF;
260  }
261  last_char_ = c;
262  setg(&last_char_,&last_char_,&last_char_ + 1);
263  return c;
264  }
265  make_buffer();
266  size_t n = ::fread(buffer_,1,buffer_size_,file_);
267  setg(buffer_,buffer_,buffer_+n);
268  if(n == 0)
269  return EOF;
270  return std::char_traits<char>::to_int_type(*gptr());
271  }
272 
273  int pbackfail(int)
274  {
275  return pubseekoff(-1,std::ios::cur);
276  }
277 
278  std::streampos seekoff(std::streamoff off,
279  std::ios_base::seekdir seekdir,
280  std::ios_base::openmode /*m*/)
281  {
282 #ifdef BOOST_NOWIDE_DEBUG_FILEBUF
283  print_guard g(this,__FUNCTION__);
284 #endif
285  if(!file_)
286  return EOF;
287  if(fixp() < 0 || fixg() < 0)
288  return EOF;
289  if(seekdir == std::ios_base::cur) {
290  if( ::fseek(file_,off,SEEK_CUR) < 0)
291  return EOF;
292  }
293  else if(seekdir == std::ios_base::beg) {
294  if( ::fseek(file_,off,SEEK_SET) < 0)
295  return EOF;
296  }
297  else if(seekdir == std::ios_base::end) {
298  if( ::fseek(file_,off,SEEK_END) < 0)
299  return EOF;
300  }
301  else
302  return -1;
303  return ftell(file_);
304  }
305  std::streampos seekpos(std::streampos off,std::ios_base::openmode m)
306  {
307  return seekoff(std::streamoff(off),std::ios_base::beg,m);
308  }
309  private:
310  int fixg()
311  {
312  if(gptr()!=egptr()) {
313  std::streamsize off = gptr() - egptr();
314  setg(0,0,0);
315  if(fseek(file_,off,SEEK_CUR) != 0)
316  return -1;
317  }
318  setg(0,0,0);
319  return 0;
320  }
321 
322  int fixp()
323  {
324  if(pptr()!=0) {
325  int r = sync();
326  setp(0,0);
327  return r;
328  }
329  return 0;
330  }
331 
332  void reset(FILE *f = 0)
333  {
334  sync();
335  if(file_) {
336  fclose(file_);
337  file_ = 0;
338  }
339  file_ = f;
340  }
341 
342 
343  static wchar_t const *get_mode(std::ios_base::openmode mode)
344  {
345  //
346  // done according to n2914 table 106 27.9.1.4
347  //
348 
349  // note can't use switch case as overload operator can't be used
350  // in constant expression
351  if(mode == (std::ios_base::out))
352  return L"w";
353  if(mode == (std::ios_base::out | std::ios_base::app))
354  return L"a";
355  if(mode == (std::ios_base::app))
356  return L"a";
357  if(mode == (std::ios_base::out | std::ios_base::trunc))
358  return L"w";
359  if(mode == (std::ios_base::in))
360  return L"r";
361  if(mode == (std::ios_base::in | std::ios_base::out))
362  return L"r+";
363  if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
364  return L"w+";
365  if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::app))
366  return L"a+";
367  if(mode == (std::ios_base::in | std::ios_base::app))
368  return L"a+";
369  if(mode == (std::ios_base::binary | std::ios_base::out))
370  return L"wb";
371  if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::app))
372  return L"ab";
373  if(mode == (std::ios_base::binary | std::ios_base::app))
374  return L"ab";
375  if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc))
376  return L"wb";
377  if(mode == (std::ios_base::binary | std::ios_base::in))
378  return L"rb";
379  if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out))
380  return L"r+b";
381  if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
382  return L"w+b";
383  if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app))
384  return L"a+b";
385  if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::app))
386  return L"a+b";
387  return 0;
388  }
389 
390  size_t buffer_size_;
391  char *buffer_;
392  FILE *file_;
393  bool own_;
394  char last_char_;
395  std::ios::openmode mode_;
396  };
397 
402 
403  #endif // windows
404 
405 } // nowide
406 } // namespace boost
407 
408 #ifdef BOOST_MSVC
409 # pragma warning(pop)
410 #endif
411 
412 
413 #endif
414 
415 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Definition: args.hpp:18
basic_filebuf * close()
Definition: filebuf.hpp:116
FILE * fopen(char const *file_name, char const *mode)
Same as fopen but file_name and mode are UTF-8 strings.
Definition: cstdio.hpp:53
basic_filebuf< char > filebuf
Convinience typedef.
Definition: filebuf.hpp:401
bool is_open() const
Definition: filebuf.hpp:129
basic_filebuf * open(char const *s, std::ios_base::openmode mode)
Definition: filebuf.hpp:83
basic_filebuf()
Definition: filebuf.hpp:52
This forward declaration defined the basic_filebuf type.
Definition: filebuf.hpp:38
This is implementation of std::filebuf.
Definition: filebuf.hpp:47
basic_filebuf * open(std::string const &s, std::ios_base::openmode mode)
Definition: filebuf.hpp:76
A class that allows to create a temporary wide or narrow UTF strings from wide or narrow UTF source...
Definition: stackstring.hpp:25