base64_stream.h
Go to the documentation of this file.
1 /*
2  * Copyright 2006-2008 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ZORBA_BASE64_STREAM_API_H
18 #define ZORBA_BASE64_STREAM_API_H
19 
20 #include <streambuf>
21 
22 #include <zorba/config.h>
24 
25 namespace zorba {
26 namespace base64 {
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 
30 /**
31  * A %base64::streambuf is-a std::streambuf for encoding to and decoding from
32  * Base64 on-the-fly.
33  *
34  * To use it, replace a stream's streambuf:
35  * \code
36  * istream is;
37  * // ...
38  * base64::streambuf b64buf( is.rdbuf() );
39  * is.ios::rdbuf( &b64buf );
40  * \endcode
41  * Note that the %base64::streambuf must exist for as long as it's being used
42  * by the stream. If you are replacing the streabuf for a stream you did not
43  * create, you should set it back to the original streambuf:
44  * \code
45  * void f( ostream &os ) {
46  * base64::streambuf b64buf( os.rdbuf() );
47  * try {
48  * os.ios::rdbuf( &b64buf );
49  * // ...
50  * }
51  * catch ( ... ) {
52  * os.ios::rdbuf( b64buf.orig_streambuf() );
53  * throw;
54  * }
55  * os.ios::rdbuf( b64buf.orig_streambuf() );
56  * }
57  * \endcode
58  * Alternatively, you may wish to use either \c attach(), \c auto_attach, or
59  * \c base64::stream instead.
60  *
61  * \b Note: due to the nature of Base64-encoding, when writing, you \e must
62  * ensure that the streambuf is flushed (by calling either \c pubsync() on the
63  * streambuf or \c flush() on the owning stream) when done.
64  *
65  * While %base64::streambuf does support seeking, the positions are relative
66  * to the original byte stream.
67  */
68 class ZORBA_DLL_PUBLIC streambuf : public std::streambuf {
69 public:
70  /**
71  * Constructs a %base64::streambuf.
72  *
73  * @param orig The original streambuf to read/write from/to.
74  * @throws std::invalid_argument if is not supported or \a orig is null.
75  */
76  streambuf( std::streambuf *orig );
77 
78  /**
79  * Destructs a %base64::streambuf.
80  */
81  ~streambuf();
82 
83  /**
84  * Gets the original streambuf.
85  *
86  * @return said streambuf.
87  */
88  std::streambuf* orig_streambuf() const {
89  return orig_buf_;
90  }
91 
92 protected:
93  void imbue( std::locale const& );
94  pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode );
95  pos_type seekpos( pos_type, std::ios_base::openmode );
96  std::streambuf* setbuf( char_type*, std::streamsize );
97  std::streamsize showmanyc();
98  int sync();
99  int_type overflow( int_type );
100  int_type pbackfail( int_type );
101  int_type underflow();
102  std::streamsize xsgetn( char_type*, std::streamsize );
103  std::streamsize xsputn( char_type const*, std::streamsize );
104 
105 private:
106  std::streambuf *orig_buf_;
107 
108  char gbuf_[3];
109  char pbuf_[3];
110  int plen_;
111 
112  void clear();
113  void resetg();
114  void resetp();
115  void writep();
116 
117  // forbid
118  streambuf( streambuf const& );
119  streambuf& operator=( streambuf const& );
120 };
121 
122 ///////////////////////////////////////////////////////////////////////////////
123 
124 } // namespace base64
125 
126 namespace internal {
127 namespace base64 {
128 
129 ZORBA_DLL_PUBLIC
130 std::streambuf* alloc_streambuf( std::streambuf *orig );
131 
132 ZORBA_DLL_PUBLIC
133 int get_streambuf_index();
134 
135 } // namespace base64
136 } // namespace internal
137 
138 namespace base64 {
139 
140 ///////////////////////////////////////////////////////////////////////////////
141 
142 /**
143  * Attaches a base64::streambuf to a stream. Unlike using a
144  * base64::streambuf directly, this function will create the streambuf,
145  * attach it to the stream, and manage it for the lifetime of the stream
146  * automatically.
147  *
148  * @param ios The stream to attach the base64::streambuf to. If the stream
149  * already has a base64::streambuf attached to it, this function does
150  * nothing.
151  */
152 template<typename charT,class Traits> inline
153 void attach( std::basic_ios<charT,Traits> &ios ) {
154  int const index = internal::base64::get_streambuf_index();
155  void *&pword = ios.pword( index );
156  if ( !pword ) {
157  std::streambuf *const buf =
158  internal::base64::alloc_streambuf( ios.rdbuf() );
159  ios.rdbuf( buf );
160  pword = buf;
161  ios.register_callback( internal::stream_callback, index );
162  }
163 }
164 
165 /**
166  * Detaches a previously attached base64::streambuf from a stream. The
167  * streambuf is destroyed and the stream's original streambuf is restored.
168  *
169  * @param ios The stream to detach the base64::streambuf from. If the
170  * stream doesn't have a base64::streambuf attached to it, this function
171  * does nothing.
172  */
173 template<typename charT,class Traits> inline
174 void detach( std::basic_ios<charT,Traits> &ios ) {
175  int const index = internal::base64::get_streambuf_index();
176  if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {
177  ios.pword( index ) = 0;
178  ios.rdbuf( buf->orig_streambuf() );
180  }
181 }
182 
183 /**
184  * Checks whether the given stream has a base64::streambuf attached.
185  *
186  * @param ios The stream to check.
187  * @return \c true only if a base64::streambuf is attached.
188  */
189 template<typename charT,class Traits> inline
190 bool is_attached( std::basic_ios<charT,Traits> &ios ) {
191  return !!ios.pword( internal::base64::get_streambuf_index() );
192 }
193 
194 /**
195  * A %base64::auto_attach is a class that attaches a base64::streambuf to
196  * a stream and automatically detaches it when the %auto_attach object is
197  * destroyed.
198  * \code
199  * void f( ostream &os ) {
200  * base64::auto_attach<ostream> const raii( os, "ISO-8859-1" );
201  * // ...
202  * }
203  * \endcode
204  * A %base64::auto_attach is useful for streams not created by you.
205  *
206  * @see http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
207  */
208 template<class StreamType>
209 class auto_attach {
210 public:
211  /**
212  * Constructs an %auto_attach object calling attach() on the given stream.
213  *
214  * @param stream The stream to attach the base64::streambuf to. If the
215  * stream already has a base64::streambuf attached to it, this contructor
216  * does nothing.
217  */
218  auto_attach( StreamType &stream ) : stream_( stream ) {
219  attach( stream );
220  }
221 
222  /**
223  * Destroys this %auto_attach object calling detach() on the previously
224  * attached stream.
225  */
227  detach( stream_ );
228  }
229 
230 private:
231  StreamType &stream_;
232 };
233 
234 ///////////////////////////////////////////////////////////////////////////////
235 
236 /**
237  * A %base64::stream is used to wrap a C++ standard I/O stream with a
238  * base64::streambuf so that encoding/decoding and the management of the
239  * streambuf happens automatically.
240  *
241  * A %base64::stream is useful for streams created by you.
242  *
243  * @tparam StreamType The I/O stream class type to wrap. It must be a concrete
244  * stream class.
245  */
246 template<class StreamType>
247 class stream : public StreamType {
248 public:
249  /**
250  * Constructs a %base64::stream.
251  */
252  stream() :
253 #ifdef WIN32
254 # pragma warning( push )
255 # pragma warning( disable : 4355 )
256 #endif /* WIN32 */
257  b64buf_( this->rdbuf() )
258 #ifdef WIN32
259 # pragma warning( pop )
260 #endif /* WIN32 */
261  {
262  init();
263  }
264 
265  /**
266  * Constructs a %stream.
267  *
268  * @tparam StreamArgType The type of the first argument of \a StreamType's
269  * constructor.
270  * @param stream_arg The argument to pass as the first argument to
271  * \a StreamType's constructor.
272  */
273  template<typename StreamArgType>
274  stream( StreamArgType stream_arg ) :
275  StreamType( stream_arg ),
276 #ifdef WIN32
277 # pragma warning( push )
278 # pragma warning( disable : 4355 )
279 #endif /* WIN32 */
280  b64buf_( this->rdbuf() )
281 #ifdef WIN32
282 # pragma warning( pop )
283 #endif /* WIN32 */
284  {
285  init();
286  }
287 
288  /**
289  * Constructs a %base64::stream.
290  *
291  * @tparam StreamArgType The type of the first argument of \a StreamType's
292  * constructor.
293  * @param stream_arg The argument to pass as the first argument to
294  * \a StreamType's constructor.
295  * @param mode The open-mode to pass to \a StreamType's constructor.
296  */
297  template<typename StreamArgType>
298  stream( StreamArgType stream_arg, std::ios_base::openmode mode ) :
299  StreamType( stream_arg, mode ),
300 #ifdef WIN32
301 # pragma warning( push )
302 # pragma warning( disable : 4355 )
303 #endif /* WIN32 */
304  b64buf_( this->rdbuf() )
305 #ifdef WIN32
306 # pragma warning( pop )
307 #endif /* WIN32 */
308  {
309  init();
310  }
311 
312 private:
313  streambuf b64buf_;
314 
315  void init() {
316  this->std::ios::rdbuf( &b64buf_ );
317  }
318 };
319 
320 ///////////////////////////////////////////////////////////////////////////////
321 
322 } // namespace base64
323 } // namespace zorba
324 #endif /* ZORBA_BASE64_STREAM_API_H */
325 /* vim:set et sw=2 ts=2: */