kmime_codecs.cpp
00001 /* -*- c++ -*- 00002 kmime_codecs.cpp 00003 00004 This file is part of KMime, the KDE internet mail/usenet news message library. 00005 Copyright (c) 2001-2002 Marc Mutz <mutz@kde.org> 00006 00007 KMime is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License, version 2, as 00009 published by the Free Software Foundation. 00010 00011 KMime is distributed in the hope that it will be useful, but 00012 WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this library; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 00020 In addition, as a special exception, the copyright holders give 00021 permission to link the code of this library with any edition of 00022 the TQt library by Trolltech AS, Norway (or with modified versions 00023 of TQt that use the same license as TQt), and distribute linked 00024 combinations including the two. You must obey the GNU General 00025 Public License in all respects for all of the code used other than 00026 TQt. If you modify this file, you may extend this exception to 00027 your version of the file, but you are not obligated to do so. If 00028 you do not wish to do so, delete this exception statement from 00029 your version. 00030 */ 00031 00032 #include "kmime_codecs.h" 00033 #include "kmime_util.h" 00034 00035 #include "kmime_codec_base64.h" 00036 #include "kmime_codec_qp.h" 00037 #include "kmime_codec_uuencode.h" 00038 #include "kmime_codec_identity.h" 00039 00040 #include <kdebug.h> 00041 00042 #include <tqcstring.h> 00043 #include <kstaticdeleter.h> 00044 00045 #include <cassert> 00046 #include <cstring> 00047 00048 using namespace KMime; 00049 00050 namespace KMime { 00051 00052 // global list of KMime::Codec's 00053 TQAsciiDict<Codec>* Codec::all = 0; 00054 static KStaticDeleter<TQAsciiDict<Codec> > sdAll; 00055 #if defined(QT_THREAD_SUPPORT) 00056 TQMutex* Codec::dictLock = 0; 00057 static KStaticDeleter<TQMutex> sdDictLock; 00058 #endif 00059 00060 void Codec::fillDictionary() { 00061 00062 all->setAutoDelete(true); 00063 00064 //all->insert( "7bit", new SevenBitCodec() ); 00065 //all->insert( "8bit", new EightBitCodec() ); 00066 all->insert( "base64", new Base64Codec() ); 00067 all->insert( "quoted-printable", new QuotedPrintableCodec() ); 00068 all->insert( "b", new Rfc2047BEncodingCodec() ); 00069 all->insert( "q", new Rfc2047TQEncodingCodec() ); 00070 all->insert( "x-kmime-rfc2231", new Rfc2231EncodingCodec() ); 00071 all->insert( "x-uuencode", new UUCodec() ); 00072 //all->insert( "binary", new BinaryCodec() ); 00073 00074 } 00075 00076 Codec * Codec::codecForName( const char * name ) { 00077 #if defined(QT_THREAD_SUPPORT) 00078 if ( !dictLock ) 00079 sdDictLock.setObject( dictLock, new TQMutex ); 00080 dictLock->lock(); // protect "all" 00081 #endif 00082 if ( !all ) { 00083 sdAll.setObject( all, new TQAsciiDict<Codec>( 11, false /* case-insensitive */) ); 00084 fillDictionary(); 00085 } 00086 Codec * codec = (*all)[ name ]; 00087 #if defined(QT_THREAD_SUPPORT) 00088 dictLock->unlock(); 00089 #endif 00090 00091 if ( !codec ) 00092 kdDebug() << "Unknown codec \"" << name << "\" requested!" << endl; 00093 00094 return codec; 00095 } 00096 00097 Codec * Codec::codecForName( const TQCString & name ) { 00098 return codecForName( name.data() ); 00099 } 00100 00101 bool Codec::encode( const char* & scursor, const char * const send, 00102 char* & dcursor, const char * const dend, 00103 bool withCRLF ) const 00104 { 00105 // get an encoder: 00106 Encoder * enc = makeEncoder( withCRLF ); 00107 assert( enc ); 00108 00109 // encode and check for output buffer overflow: 00110 while ( !enc->encode( scursor, send, dcursor, dend ) ) 00111 if ( dcursor == dend ) { 00112 delete enc; 00113 return false; // not enough space in output buffer 00114 } 00115 00116 // finish and check for output buffer overflow: 00117 while ( !enc->finish( dcursor, dend ) ) 00118 if ( dcursor == dend ) { 00119 delete enc; 00120 return false; // not enough space in output buffer 00121 } 00122 00123 // cleanup and return: 00124 delete enc; 00125 return true; // successfully encoded. 00126 } 00127 00128 TQByteArray Codec::encode( const TQByteArray & src, bool withCRLF ) const 00129 { 00130 // allocate buffer for the worst case: 00131 TQByteArray result( maxEncodedSizeFor( src.size(), withCRLF ) ); 00132 00133 // set up iterators: 00134 TQByteArray::ConstIterator iit = src.begin(); 00135 TQByteArray::ConstIterator iend = src.end(); 00136 TQByteArray::Iterator oit = result.begin(); 00137 TQByteArray::ConstIterator oend = result.end(); 00138 00139 // encode 00140 if ( !encode( iit, iend, oit, oend, withCRLF ) ) 00141 kdFatal() << name() << " codec lies about it's mEncodedSizeFor()" 00142 << endl; 00143 00144 // shrink result to actual size: 00145 result.truncate( oit - result.begin() ); 00146 00147 return result; 00148 } 00149 00150 TQCString Codec::encodeToTQCString( const TQByteArray & src, bool withCRLF ) const 00151 { 00152 // allocate buffer for the worst case (remember to add one for the trailing NUL) 00153 TQCString result( maxEncodedSizeFor( src.size(), withCRLF ) + 1 ); 00154 00155 // set up iterators: 00156 TQByteArray::ConstIterator iit = src.begin(); 00157 TQByteArray::ConstIterator iend = src.end(); 00158 TQByteArray::Iterator oit = result.begin(); 00159 TQByteArray::ConstIterator oend = result.end() - 1; 00160 00161 // encode 00162 if ( !encode( iit, iend, oit, oend, withCRLF ) ) 00163 kdFatal() << name() << " codec lies about it's mEncodedSizeFor()" 00164 << endl; 00165 00166 // shrink result to actual size: 00167 result.truncate( oit - result.begin() ); 00168 00169 return result; 00170 } 00171 00172 TQByteArray Codec::decode( const TQByteArray & src, bool withCRLF ) const 00173 { 00174 // allocate buffer for the worst case: 00175 TQByteArray result( maxDecodedSizeFor( src.size(), withCRLF ) ); 00176 00177 // set up iterators: 00178 TQByteArray::ConstIterator iit = src.begin(); 00179 TQByteArray::ConstIterator iend = src.end(); 00180 TQByteArray::Iterator oit = result.begin(); 00181 TQByteArray::ConstIterator oend = result.end(); 00182 00183 // decode 00184 if ( !decode( iit, iend, oit, oend, withCRLF ) ) 00185 kdFatal() << name() << " codec lies about it's maxDecodedSizeFor()" 00186 << endl; 00187 00188 // shrink result to actual size: 00189 result.truncate( oit - result.begin() ); 00190 00191 return result; 00192 } 00193 00194 bool Codec::decode( const char* & scursor, const char * const send, 00195 char* & dcursor, const char * const dend, 00196 bool withCRLF ) const 00197 { 00198 // get a decoder: 00199 Decoder * dec = makeDecoder( withCRLF ); 00200 assert( dec ); 00201 00202 // decode and check for output buffer overflow: 00203 while ( !dec->decode( scursor, send, dcursor, dend ) ) 00204 if ( dcursor == dend ) { 00205 delete dec; 00206 return false; // not enough space in output buffer 00207 } 00208 00209 // finish and check for output buffer overflow: 00210 while ( !dec->finish( dcursor, dend ) ) 00211 if ( dcursor == dend ) { 00212 delete dec; 00213 return false; // not enough space in output buffer 00214 } 00215 00216 // cleanup and return: 00217 delete dec; 00218 return true; // successfully encoded. 00219 } 00220 00221 // write as much as possible off the output buffer. Return true if 00222 // flushing was complete, false if some chars could not be flushed. 00223 bool Encoder::flushOutputBuffer( char* & dcursor, const char * const dend ) { 00224 int i; 00225 // copy output buffer to output stream: 00226 for ( i = 0 ; dcursor != dend && i < mOutputBufferCursor ; ++i ) 00227 *dcursor++ = mOutputBuffer[i]; 00228 00229 // calculate the number of missing chars: 00230 int numCharsLeft = mOutputBufferCursor - i; 00231 // push the remaining chars to the begin of the buffer: 00232 if ( numCharsLeft ) 00233 tqmemmove( mOutputBuffer, mOutputBuffer + i, numCharsLeft ); 00234 // adjust cursor: 00235 mOutputBufferCursor = numCharsLeft; 00236 00237 return !numCharsLeft; 00238 } 00239 00240 00241 } // namespace KMime