00001 /* 00002 * Copyright 2006-2008 The FLWOR Foundation. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifndef ZORBA_TRANSCODE_STREAM_API_H 00018 #define ZORBA_TRANSCODE_STREAM_API_H 00019 00020 #include <stdexcept> 00021 #include <streambuf> 00022 #include <string> 00023 00024 #include <zorba/config.h> 00025 #include <zorba/internal/proxy.h> 00026 #include <zorba/internal/unique_ptr.h> 00027 00028 namespace zorba { 00029 00030 typedef internal::ztd::proxy<std::streambuf> proxy_streambuf; 00031 00032 namespace transcode { 00033 00034 /////////////////////////////////////////////////////////////////////////////// 00035 00036 /** 00037 * A %transcode::streambuf is-a std::streambuf for transcoding character 00038 * encodings from/to UTF-8 on-the-fly. 00039 * 00040 * To use it, replace a stream's streambuf: 00041 * \code 00042 * istream is; 00043 * // ... 00044 * transcode::streambuf tbuf( "ISO-8859-1", is.rdbuf() ); 00045 * is.ios::rdbuf( &tbuf ); 00046 * \endcode 00047 * Note that the %transcode::streambuf must exist for as long as it's being used 00048 * by the stream. If you are replacing the streabuf for a stream you did not 00049 * create, you should set it back to the original streambuf: 00050 * \code 00051 * void f( ostream &os ) { 00052 * transcode::streambuf tbuf( "ISO-8859-1", os.rdbuf() ); 00053 * try { 00054 * os.ios::rdbuf( &tbuf ); 00055 * // ... 00056 * } 00057 * catch ( ... ) { 00058 * os.ios::rdbuf( tbuf.orig_streambuf() ); 00059 * throw; 00060 * } 00061 * } 00062 * \endcode 00063 * 00064 * While %transcode::streambuf does support seeking, the positions are relative 00065 * to the original byte stream. 00066 */ 00067 class ZORBA_DLL_PUBLIC streambuf : public std::streambuf { 00068 public: 00069 /** 00070 * Constructs a %transcode::streambuf. 00071 * 00072 * @param charset The name of the character encoding to convert from/to. 00073 * @param orig The original streambuf to read/write from/to. 00074 * @throws std::invalid_argument if either \a charset is not supported or 00075 * \a orig is null. 00076 */ 00077 streambuf( char const *charset, std::streambuf *orig ); 00078 00079 /** 00080 * Destructs a %transcode::streambuf. 00081 */ 00082 ~streambuf(); 00083 00084 /** 00085 * Gets the original streambuf. 00086 * 00087 * @return said streambuf. 00088 */ 00089 std::streambuf* orig_streambuf() const { 00090 return proxy_buf_->original(); 00091 } 00092 00093 protected: 00094 void imbue( std::locale const& ); 00095 pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode ); 00096 pos_type seekpos( pos_type, std::ios_base::openmode ); 00097 std::streambuf* setbuf( char_type*, std::streamsize ); 00098 std::streamsize showmanyc(); 00099 int sync(); 00100 int_type overflow( int_type ); 00101 int_type pbackfail( int_type ); 00102 int_type uflow(); 00103 int_type underflow(); 00104 std::streamsize xsgetn( char_type*, std::streamsize ); 00105 std::streamsize xsputn( char_type const*, std::streamsize ); 00106 00107 private: 00108 std::unique_ptr<proxy_streambuf> proxy_buf_; 00109 00110 // forbid 00111 streambuf( streambuf const& ); 00112 streambuf& operator=( streambuf const& ); 00113 }; 00114 00115 /////////////////////////////////////////////////////////////////////////////// 00116 00117 /** 00118 * A %transcode::stream is used to wrap a C++ standard I/O stream with a 00119 * transcode::streambuf so that transcoding and the management of the streambuf 00120 * happens automatically. 00121 * 00122 * @tparam StreamType The I/O stream class type to wrap. It must be a concrete 00123 * stream class. 00124 */ 00125 template<class StreamType> 00126 class stream : public StreamType { 00127 public: 00128 /** 00129 * Constructs a %transcode::stream. 00130 * 00131 * @param charset The name of the character encoding to convert from/to. 00132 * @throws std::invalid_argument if \a charset is not supported. 00133 */ 00134 stream( char const *charset ) : 00135 tbuf_( charset, this->rdbuf() ) 00136 { 00137 init(); 00138 } 00139 00140 /** 00141 * Constructs a %stream. 00142 * 00143 * @tparam StreamArgType The type of the first argument of \a StreamType's 00144 * constructor. 00145 * @param charset The name of the character encoding to convert from/to. 00146 * @param stream_arg The argument to pass as the first argument to 00147 * \a StreamType's constructor. 00148 * @throws std::invalid_argument if \a charset is not supported. 00149 */ 00150 template<typename StreamArgType> 00151 stream( char const *charset, StreamArgType stream_arg ) : 00152 StreamType( stream_arg ), 00153 tbuf_( charset, this->rdbuf() ) 00154 { 00155 init(); 00156 } 00157 00158 /** 00159 * Constructs a %transcode::stream. 00160 * 00161 * @tparam StreamArgType The type of the first argument of \a StreamType's 00162 * constructor. 00163 * @param charset The name of the character encoding to convert from/to. 00164 * @param stream_arg The argument to pass as the first argument to 00165 * \a StreamType's constructor. 00166 * @param mode The open-mode to pass to \a StreamType's constructor. 00167 * @throws std::invalid_argument if \a charset is not supported. 00168 */ 00169 template<typename StreamArgType> 00170 stream( char const *charset, StreamArgType stream_arg, 00171 std::ios_base::openmode mode ) : 00172 StreamType( stream_arg, mode ), 00173 tbuf_( charset, this->rdbuf() ) 00174 { 00175 init(); 00176 } 00177 00178 private: 00179 streambuf tbuf_; 00180 00181 void init() { 00182 this->std::ios::rdbuf( &tbuf_ ); 00183 } 00184 }; 00185 00186 /////////////////////////////////////////////////////////////////////////////// 00187 00188 /** 00189 * Checks whether it would be necessary to transcode from the given character 00190 * encoding to UTF-8. 00191 * 00192 * @param charset The name of the character encoding to check. 00193 * @return \c true only if it would be necessary to transcode from the given 00194 * character encoding to UTF-8. 00195 */ 00196 ZORBA_DLL_PUBLIC 00197 bool is_necessary( char const *charset ); 00198 00199 /** 00200 * Checks whether the given character set is supported for transcoding. 00201 * 00202 * @param charset The name of the character encoding to check. 00203 * @return \c true only if the character encoding is supported. 00204 */ 00205 ZORBA_DLL_PUBLIC 00206 bool is_supported( char const *charset ); 00207 00208 /////////////////////////////////////////////////////////////////////////////// 00209 00210 } // namespace transcode 00211 } // namespace zorba 00212 #endif /* ZORBA_TRANSCODE_STREAM_API_H */ 00213 /* vim:set et sw=2 ts=2: */