libkmime

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 Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), 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     Qt.  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 <qcstring.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 QAsciiDict<Codec>* Codec::all = 0;
00054 static KStaticDeleter<QAsciiDict<Codec> > sdAll;
00055 #if defined(QT_THREAD_SUPPORT)
00056 QMutex* Codec::dictLock = 0;
00057 static KStaticDeleter<QMutex> 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 Rfc2047QEncodingCodec() );
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 QMutex );
00080   dictLock->lock(); // protect "all"
00081 #endif
00082   if ( !all ) {
00083     sdAll.setObject( all, new QAsciiDict<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 QCString & 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 QByteArray Codec::encode( const QByteArray & src, bool withCRLF ) const
00129 {
00130   // allocate buffer for the worst case:
00131   QByteArray result( maxEncodedSizeFor( src.size(), withCRLF ) );
00132 
00133   // set up iterators:
00134   QByteArray::ConstIterator iit = src.begin();
00135   QByteArray::ConstIterator iend = src.end();
00136   QByteArray::Iterator oit = result.begin();
00137   QByteArray::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 QCString Codec::encodeToQCString( const QByteArray & src, bool withCRLF ) const
00151 {
00152   // allocate buffer for the worst case (remember to add one for the trailing NUL)
00153   QCString result( maxEncodedSizeFor( src.size(), withCRLF ) + 1 );
00154 
00155   // set up iterators:
00156   QByteArray::ConstIterator iit = src.begin();
00157   QByteArray::ConstIterator iend = src.end();
00158   QByteArray::Iterator oit = result.begin();
00159   QByteArray::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 QByteArray Codec::decode( const QByteArray & src, bool withCRLF ) const
00173 {
00174   // allocate buffer for the worst case:
00175   QByteArray result( maxDecodedSizeFor( src.size(), withCRLF ) );
00176 
00177   // set up iterators:
00178   QByteArray::ConstIterator iit = src.begin();
00179   QByteArray::ConstIterator iend = src.end();
00180   QByteArray::Iterator oit = result.begin();
00181   QByteArray::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     qmemmove( mOutputBuffer, mOutputBuffer + i, numCharsLeft );
00234   // adjust cursor:
00235   mOutputBufferCursor = numCharsLeft;
00236 
00237   return !numCharsLeft;
00238 }
00239 
00240 
00241 } // namespace KMime
KDE Home | KDE Accessibility Home | Description of Access Keys