kmime_codecs.cpp
Go to the documentation of this file.
00001 /* -*- c++ -*- 00002 00003 KMime, the KDE Internet mail/usenet news message library. 00004 00005 Copyright (c) 2001-2002 Marc Mutz <mutz@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00033 #include "kmime_codecs.h" 00034 #include "kmime_util.h" 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 "kautodeletehash.h" 00041 00042 #include <kascii.h> 00043 #include <kdebug.h> 00044 #include <kglobal.h> 00045 00046 #include <QtCore/QCoreApplication> 00047 #include <QtCore/QMutex> 00048 00049 #include <cassert> 00050 #include <cstring> 00051 #include <string.h> 00052 00053 using namespace KMime; 00054 00055 namespace KMime { 00056 00057 // global list of KMime::Codec's 00058 //@cond PRIVATE 00059 KAutoDeleteHash<QByteArray, Codec> *Codec::all = 0; 00060 K_GLOBAL_STATIC(QMutex, dictLock) 00061 //@endcond 00062 00063 void Codec::cleanupCodec() 00064 { 00065 delete all; 00066 all = 0; 00067 } 00068 00069 void Codec::fillDictionary() 00070 { 00071 //all->insert( "7bit", new SevenBitCodec() ); 00072 //all->insert( "8bit", new EightBitCodec() ); 00073 all->insert( "base64", new Base64Codec() ); 00074 all->insert( "quoted-printable", new QuotedPrintableCodec() ); 00075 all->insert( "b", new Rfc2047BEncodingCodec() ); 00076 all->insert( "q", new Rfc2047QEncodingCodec() ); 00077 all->insert( "x-kmime-rfc2231", new Rfc2231EncodingCodec() ); 00078 all->insert( "x-uuencode", new UUCodec() ); 00079 //all->insert( "binary", new BinaryCodec() ); 00080 } 00081 00082 Codec *Codec::codecForName( const char *name ) 00083 { 00084 const QByteArray ba( name ); 00085 return codecForName( ba ); 00086 } 00087 00088 Codec *Codec::codecForName( const QByteArray &name ) 00089 { 00090 dictLock->lock(); // protect "all" 00091 if ( !all ) { 00092 all = new KAutoDeleteHash<QByteArray, Codec>(); 00093 qAddPostRoutine(cleanupCodec); 00094 fillDictionary(); 00095 } 00096 QByteArray lowerName = name; 00097 kAsciiToLower( lowerName.data() ); 00098 Codec *codec = (*all)[ lowerName ]; // FIXME: operator[] adds an entry into the hash 00099 dictLock->unlock(); 00100 00101 if ( !codec ) { 00102 kDebug() << "Unknown codec \"" << name << "\" requested!"; 00103 } 00104 00105 return codec; 00106 } 00107 00108 bool Codec::encode( const char* &scursor, const char * const send, 00109 char* &dcursor, const char * const dend, 00110 bool withCRLF ) const 00111 { 00112 // get an encoder: 00113 Encoder *enc = makeEncoder( withCRLF ); 00114 assert( enc ); 00115 00116 // encode and check for output buffer overflow: 00117 while ( !enc->encode( scursor, send, dcursor, dend ) ) { 00118 if ( dcursor == dend ) { 00119 delete enc; 00120 return false; // not enough space in output buffer 00121 } 00122 } 00123 00124 // finish and check for output buffer overflow: 00125 while ( !enc->finish( dcursor, dend ) ) { 00126 if ( dcursor == dend ) { 00127 delete enc; 00128 return false; // not enough space in output buffer 00129 } 00130 } 00131 00132 // cleanup and return: 00133 delete enc; 00134 return true; // successfully encoded. 00135 } 00136 00137 QByteArray Codec::encode( const QByteArray &src, bool withCRLF ) const 00138 { 00139 // allocate buffer for the worst case: 00140 QByteArray result; 00141 result.resize( maxEncodedSizeFor( src.size(), withCRLF ) ); 00142 00143 // set up iterators: 00144 QByteArray::ConstIterator iit = src.begin(); 00145 QByteArray::ConstIterator iend = src.end(); 00146 QByteArray::Iterator oit = result.begin(); 00147 QByteArray::ConstIterator oend = result.end(); 00148 00149 // encode 00150 if ( !encode( iit, iend, oit, oend, withCRLF ) ) { 00151 kFatal() << name() << "codec lies about it's mEncodedSizeFor()"; 00152 } 00153 00154 // shrink result to actual size: 00155 result.truncate( oit - result.begin() ); 00156 00157 return result; 00158 } 00159 00160 QByteArray Codec::decode( const QByteArray &src, bool withCRLF ) const 00161 { 00162 // allocate buffer for the worst case: 00163 QByteArray result; 00164 result.resize( maxDecodedSizeFor( src.size(), withCRLF ) ); 00165 00166 // set up iterators: 00167 QByteArray::ConstIterator iit = src.begin(); 00168 QByteArray::ConstIterator iend = src.end(); 00169 QByteArray::Iterator oit = result.begin(); 00170 QByteArray::ConstIterator oend = result.end(); 00171 00172 // decode 00173 if ( !decode( iit, iend, oit, oend, withCRLF ) ) { 00174 kFatal() << name() << "codec lies about it's maxDecodedSizeFor()"; 00175 } 00176 00177 // shrink result to actual size: 00178 result.truncate( oit - result.begin() ); 00179 00180 return result; 00181 } 00182 00183 bool Codec::decode( const char* &scursor, const char * const send, 00184 char* &dcursor, const char * const dend, 00185 bool withCRLF ) const 00186 { 00187 // get a decoder: 00188 Decoder *dec = makeDecoder( withCRLF ); 00189 assert( dec ); 00190 00191 // decode and check for output buffer overflow: 00192 while ( !dec->decode( scursor, send, dcursor, dend ) ) { 00193 if ( dcursor == dend ) { 00194 delete dec; 00195 return false; // not enough space in output buffer 00196 } 00197 } 00198 00199 // finish and check for output buffer overflow: 00200 while ( !dec->finish( dcursor, dend ) ) { 00201 if ( dcursor == dend ) { 00202 delete dec; 00203 return false; // not enough space in output buffer 00204 } 00205 } 00206 00207 // cleanup and return: 00208 delete dec; 00209 return true; // successfully encoded. 00210 } 00211 00212 // write as much as possible off the output buffer. Return true if 00213 // flushing was complete, false if some chars could not be flushed. 00214 bool Encoder::flushOutputBuffer( char* &dcursor, const char * const dend ) 00215 { 00216 int i; 00217 // copy output buffer to output stream: 00218 for ( i = 0 ; dcursor != dend && i < mOutputBufferCursor ; ++i ) { 00219 *dcursor++ = mOutputBuffer[i]; 00220 } 00221 00222 // calculate the number of missing chars: 00223 int numCharsLeft = mOutputBufferCursor - i; 00224 // push the remaining chars to the begin of the buffer: 00225 if ( numCharsLeft ) { 00226 ::memmove( mOutputBuffer, mOutputBuffer + i, numCharsLeft ); 00227 } 00228 // adjust cursor: 00229 mOutputBufferCursor = numCharsLeft; 00230 00231 return !numCharsLeft; 00232 } 00233 00234 } // namespace KMime