transcode_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_TRANSCODE_STREAM_API_H
18 #define ZORBA_TRANSCODE_STREAM_API_H
19 
20 #include <zorba/config.h>
23 
24 namespace zorba {
25 namespace transcode {
26 
27 ///////////////////////////////////////////////////////////////////////////////
28 
29 /**
30  * A %transcode::streambuf is-a std::streambuf for transcoding character
31  * encodings from/to UTF-8 on-the-fly.
32  *
33  * To use it, replace a stream's streambuf:
34  * \code
35  * istream is;
36  * // ...
37  * transcode::streambuf tbuf( "ISO-8859-1", is.rdbuf() );
38  * is.ios::rdbuf( &tbuf );
39  * \endcode
40  * Note that the %transcode::streambuf must exist for as long as it's being used
41  * by the stream. If you are replacing the streabuf for a stream you did not
42  * create, you should set it back to the original streambuf:
43  * \code
44  * void f( ostream &os ) {
45  * transcode::streambuf tbuf( "ISO-8859-1", os.rdbuf() );
46  * try {
47  * os.ios::rdbuf( &tbuf );
48  * // ...
49  * }
50  * catch ( ... ) {
51  * os.ios::rdbuf( tbuf.orig_streambuf() );
52  * throw;
53  * }
54  * os.ios::rdbuf( tbuf.orig_streambuf() );
55  * }
56  * \endcode
57  * Alternatively, you may wish to use either \c attach(), \c auto_attach, or
58  * \c transcode::stream instead.
59  *
60  * While %transcode::streambuf does support seeking, the positions are relative
61  * to the original byte stream.
62  */
63 class ZORBA_DLL_PUBLIC streambuf : public std::streambuf {
64 public:
65  /**
66  * Constructs a %transcode::streambuf.
67  *
68  * @param charset The name of the character encoding to convert from/to.
69  * @param orig The original streambuf to read/write from/to.
70  * @throws std::invalid_argument if either \a charset is not supported or
71  * \a orig is null.
72  */
73  streambuf( char const *charset, std::streambuf *orig );
74 
75  /**
76  * Destructs a %transcode::streambuf.
77  */
78  ~streambuf();
79 
80  /**
81  * Gets the original streambuf.
82  *
83  * @return said streambuf.
84  */
85  std::streambuf* orig_streambuf() const {
86  return proxy_buf_->original();
87  }
88 
89 protected:
90  void imbue( std::locale const& );
91  pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode );
92  pos_type seekpos( pos_type, std::ios_base::openmode );
93  std::streambuf* setbuf( char_type*, std::streamsize );
94  std::streamsize showmanyc();
95  int sync();
96  int_type overflow( int_type );
97  int_type pbackfail( int_type );
98  int_type uflow();
99  int_type underflow();
100  std::streamsize xsgetn( char_type*, std::streamsize );
101  std::streamsize xsputn( char_type const*, std::streamsize );
102 
103 private:
105 
106  // forbid
107  streambuf( streambuf const& );
108  streambuf& operator=( streambuf const& );
109 };
110 
111 ///////////////////////////////////////////////////////////////////////////////
112 
113 } // namespace transcode
114 
115 namespace internal {
116 namespace transcode {
117 
118 ZORBA_DLL_PUBLIC
119 std::streambuf* alloc_streambuf( char const *charset, std::streambuf *orig );
120 
121 ZORBA_DLL_PUBLIC
122 int get_streambuf_index();
123 
124 } // transcode
125 } // namespace internal
126 
127 namespace transcode {
128 
129 ///////////////////////////////////////////////////////////////////////////////
130 
131 /**
132  * Attaches a transcode::streambuf to a stream. Unlike using a
133  * transcode::streambuf directly, this function will create the streambuf,
134  * attach it to the stream, and manage it for the lifetime of the stream
135  * automatically.
136  *
137  * @param ios The stream to attach the transcode::streambuf to. If the stream
138  * already has a transcode::streambuf attached to it, this function does
139  * nothing.
140  * @param charset The name of the character encoding to convert from/to.
141  */
142 template<typename charT,class Traits> inline
143 void attach( std::basic_ios<charT,Traits> &ios, char const *charset ) {
144  int const index = internal::transcode::get_streambuf_index();
145  void *&pword = ios.pword( index );
146  if ( !pword ) {
147  std::streambuf *const buf =
148  internal::transcode::alloc_streambuf( charset, ios.rdbuf() );
149  ios.rdbuf( buf );
150  pword = buf;
151  ios.register_callback( internal::stream_callback, index );
152  }
153 }
154 
155 /**
156  * Detaches a previously attached transcode::streambuf from a stream. The
157  * streambuf is destroyed and the stream's original streambuf is restored.
158  *
159  * @param ios The stream to detach the transcode::streambuf from. If the
160  * stream doesn't have a transcode::streambuf attached to it, this function
161  * does nothing.
162  */
163 template<typename charT,class Traits> inline
164 void detach( std::basic_ios<charT,Traits> &ios ) {
165  int const index = internal::transcode::get_streambuf_index();
166  if ( streambuf *const buf = static_cast<streambuf*>( ios.pword( index ) ) ) {
167  ios.pword( index ) = 0;
168  ios.rdbuf( buf->orig_streambuf() );
170  }
171 }
172 
173 /**
174  * Checks whether the given stream has a transcode::streambuf attached.
175  *
176  * @param ios The stream to check.
177  * @return \c true only if a transcode::streambuf is attached.
178  */
179 template<typename charT,class Traits> inline
180 bool is_attached( std::basic_ios<charT,Traits> &ios ) {
181  return !!ios.pword( internal::transcode::get_streambuf_index() );
182 }
183 
184 /**
185  * Gets the original streambuf of the given iostream.
186  *
187  * @param ios The stream to get the original streambuf of.
188  * @return the original streambuf.
189  */
190 template<typename charT,class Traits> inline
191 std::streambuf* orig_streambuf( std::basic_ios<charT,Traits> &ios ) {
192  std::streambuf *const buf = ios.rdbuf();
193  if ( streambuf *const tbuf = dynamic_cast<streambuf*>( buf ) )
194  return tbuf->orig_streambuf();
195  return buf;
196 }
197 
198 /**
199  * A %transcode::auto_attach is a class that attaches a transcode::streambuf to
200  * a stream and automatically detaches it when the %auto_attach object is
201  * destroyed.
202  * \code
203  * void f( ostream &os ) {
204  * transcode::auto_attach<ostream> const raii( os, "ISO-8859-1" );
205  * // ...
206  * }
207  * \endcode
208  * A %transcode::auto_attach is useful for streams not created by you.
209  *
210  * @see http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
211  */
212 template<class StreamType>
213 class auto_attach {
214 public:
215  /**
216  * Constructs an %auto_attach object calling attach() on the given stream.
217  *
218  * @param stream The stream to attach the transcode::streambuf to. If the
219  * stream already has a transcode::streambuf attached to it, this contructor
220  * does nothing.
221  * @param charset The name of the character encoding to convert from/to.
222  */
223  auto_attach( StreamType &stream, char const *charset ) : stream_( stream ) {
224  attach( stream, charset );
225  }
226 
227  /**
228  * Destroys this %auto_attach object calling detach() on the previously
229  * attached stream.
230  */
232  detach( stream_ );
233  }
234 
235 private:
236  StreamType &stream_;
237 };
238 
239 ///////////////////////////////////////////////////////////////////////////////
240 
241 /**
242  * A %transcode::stream is used to wrap a C++ standard I/O stream with a
243  * transcode::streambuf so that transcoding and the management of the streambuf
244  * happens automatically.
245  *
246  * A %transcode::stream is useful for streams created by you.
247  *
248  * @tparam StreamType The I/O stream class type to wrap. It must be a concrete
249  * stream class.
250  */
251 template<class StreamType>
252 class stream : public StreamType {
253 public:
254  /**
255  * Constructs a %transcode::stream.
256  *
257  * @param charset The name of the character encoding to convert from/to.
258  * @throws std::invalid_argument if \a charset is not supported.
259  */
260  stream( char const *charset ) :
261 #ifdef WIN32
262 # pragma warning( push )
263 # pragma warning( disable : 4355 )
264 #endif /* WIN32 */
265  tbuf_( charset, this->rdbuf() )
266 #ifdef WIN32
267 # pragma warning( pop )
268 #endif /* WIN32 */
269  {
270  init();
271  }
272 
273  /**
274  * Constructs a %stream.
275  *
276  * @tparam StreamArgType The type of the first argument of \a StreamType's
277  * constructor.
278  * @param charset The name of the character encoding to convert from/to.
279  * @param stream_arg The argument to pass as the first argument to
280  * \a StreamType's constructor.
281  * @throws std::invalid_argument if \a charset is not supported.
282  */
283  template<typename StreamArgType>
284  stream( char const *charset, StreamArgType stream_arg ) :
285  StreamType( stream_arg ),
286 #ifdef WIN32
287 # pragma warning( push )
288 # pragma warning( disable : 4355 )
289 #endif /* WIN32 */
290  tbuf_( charset, this->rdbuf() )
291 #ifdef WIN32
292 # pragma warning( pop )
293 #endif /* WIN32 */
294  {
295  init();
296  }
297 
298  /**
299  * Constructs a %transcode::stream.
300  *
301  * @tparam StreamArgType The type of the first argument of \a StreamType's
302  * constructor.
303  * @param charset The name of the character encoding to convert from/to.
304  * @param stream_arg The argument to pass as the first argument to
305  * \a StreamType's constructor.
306  * @param mode The open-mode to pass to \a StreamType's constructor.
307  * @throws std::invalid_argument if \a charset is not supported.
308  */
309  template<typename StreamArgType>
310  stream( char const *charset, StreamArgType stream_arg,
311  std::ios_base::openmode mode ) :
312  StreamType( stream_arg, mode ),
313 #ifdef WIN32
314 # pragma warning( push )
315 # pragma warning( disable : 4355 )
316 #endif /* WIN32 */
317  tbuf_( charset, this->rdbuf() )
318 #ifdef WIN32
319 # pragma warning( pop )
320 #endif /* WIN32 */
321  {
322  init();
323  }
324 
325 private:
326  streambuf tbuf_;
327 
328  void init() {
329  this->std::ios::rdbuf( &tbuf_ );
330  }
331 };
332 
333 ///////////////////////////////////////////////////////////////////////////////
334 
335 /**
336  * Checks whether it would be necessary to transcode from the given character
337  * encoding to UTF-8.
338  *
339  * @param charset The name of the character encoding to check.
340  * @return \c true only if it would be necessary to transcode from the given
341  * character encoding to UTF-8.
342  */
343 ZORBA_DLL_PUBLIC
344 bool is_necessary( char const *charset );
345 
346 /**
347  * Checks whether the given character set is supported for transcoding.
348  *
349  * @param charset The name of the character encoding to check.
350  * @return \c true only if the character encoding is supported.
351  */
352 ZORBA_DLL_PUBLIC
353 bool is_supported( char const *charset );
354 
355 ///////////////////////////////////////////////////////////////////////////////
356 
357 } // namespace transcode
358 } // namespace zorba
359 #endif /* ZORBA_TRANSCODE_STREAM_API_H */
360 /* vim:set et sw=2 ts=2: */