libkdenetwork Library API Documentation

kmime_codec_base64.cpp

00001 /* -*- c++ -*- 00002 kmime_codec_base64.cpp 00003 00004 This file is part of KMime, the KDE internet mail/usenet news message library. 00005 Copyright (c) 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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_codec_base64.h" 00033 00034 #include <kdebug.h> 00035 00036 #include <cassert> 00037 00038 using namespace KMime; 00039 00040 namespace KMime { 00041 00042 // codec for base64 as specified in RFC 2045 00043 //class Base64Codec; 00044 //class Base64Decoder; 00045 //class Base64Encoder; 00046 00047 // codec for the B encoding as specified in RFC 2047 00048 //class Rfc2047BEncodingCodec; 00049 //class Rfc2047BEncodingEncoder; 00050 //class Rfc2047BEncodingDecoder; 00051 00052 00053 static const uchar base64DecodeMap[128] = { 00054 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 00055 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 00056 00057 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 00058 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 00059 00060 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 00061 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 00062 00063 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 00064 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64 00065 }; 00066 00067 static const char base64EncodeMap[64] = { 00068 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 00069 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 00070 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 00071 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 00072 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 00073 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 00074 'w', 'x', 'y', 'z', '0', '1', '2', '3', 00075 '4', '5', '6', '7', '8', '9', '+', '/' 00076 }; 00077 00078 00079 class Base64Decoder : public Decoder { 00080 uint mStepNo; 00081 uchar mOutbits; 00082 bool mSawPadding : 1; 00083 00084 protected: 00085 friend class Base64Codec; 00086 Base64Decoder( bool withCRLF=false ) 00087 : Decoder( withCRLF ), mStepNo(0), mOutbits(0), 00088 mSawPadding(false) {} 00089 00090 public: 00091 virtual ~Base64Decoder() {} 00092 00093 bool decode( const char* & scursor, const char * const send, 00094 char* & dcursor, const char * const dend ); 00095 // ### really needs no finishing??? 00096 bool finish( char* & /*dcursor*/, const char * const /*dend*/ ) { return true; } 00097 }; 00098 00099 00100 00101 class Base64Encoder : public Encoder { 00102 uint mStepNo; 00104 uint mWrittenPacketsOnThisLine; 00105 uchar mNextbits; 00106 bool mInsideFinishing : 1; 00107 00108 protected: 00109 friend class Rfc2047BEncodingCodec; 00110 friend class Rfc2047BEncodingEncoder; 00111 friend class Base64Codec; 00112 Base64Encoder( bool withCRLF=false ) 00113 : Encoder( withCRLF ), mStepNo(0), mWrittenPacketsOnThisLine(0), 00114 mNextbits(0), mInsideFinishing(false) {} 00115 00116 bool generic_finish( char* & dcursor, const char * const dend, 00117 bool withLFatEnd ); 00118 00119 public: 00120 virtual ~Base64Encoder() {} 00121 00122 bool encode( const char* & scursor, const char * const send, 00123 char* & dcursor, const char * const dend ); 00124 00125 bool finish( char* & dcursor, const char * const dend ); 00126 00127 protected: 00128 bool writeBase64( uchar ch, char* & dcursor, const char * const dend ) { 00129 return write( base64EncodeMap[ ch ], dcursor, dend ); 00130 } 00131 }; 00132 00133 00134 00135 class Rfc2047BEncodingEncoder : public Base64Encoder { 00136 protected: 00137 friend class Rfc2047BEncodingCodec; 00138 Rfc2047BEncodingEncoder( bool withCRLF=false ) 00139 : Base64Encoder( withCRLF ) {}; 00140 public: 00141 bool encode( const char* & scursor, const char * const send, 00142 char* & dcursor, const char * const dend ); 00143 bool finish( char* & dcursor, const char * const dend ); 00144 }; 00145 00146 00147 Encoder * Base64Codec::makeEncoder( bool withCRLF ) const { 00148 return new Base64Encoder( withCRLF ); 00149 } 00150 00151 Decoder * Base64Codec::makeDecoder( bool withCRLF ) const { 00152 return new Base64Decoder( withCRLF ); 00153 } 00154 00155 Encoder * Rfc2047BEncodingCodec::makeEncoder( bool withCRLF ) const { 00156 return new Rfc2047BEncodingEncoder( withCRLF ); 00157 } 00158 00159 /********************************************************/ 00160 /********************************************************/ 00161 /********************************************************/ 00162 00163 00164 bool Base64Decoder::decode( const char* & scursor, const char * const send, 00165 char* & dcursor, const char * const dend ) 00166 { 00167 while ( dcursor != dend && scursor != send ) { 00168 uchar ch = *scursor++; 00169 uchar value; 00170 00171 // try converting ch to a 6-bit value: 00172 if ( ch < 128 ) 00173 value = base64DecodeMap[ ch ]; 00174 else 00175 value = 64; 00176 00177 // ch isn't of the base64 alphabet, check for other significant chars: 00178 if ( value >= 64 ) { 00179 if ( ch == '=' ) { 00180 // padding: 00181 if ( mStepNo == 0 || mStepNo == 1) { 00182 if (!mSawPadding) { 00183 // malformed 00184 kdWarning() << "Base64Decoder: unexpected padding " 00185 "character in input stream" << endl; 00186 } 00187 mSawPadding = true; 00188 break; 00189 } else if ( mStepNo == 2 ) { 00190 // ok, there should be another one 00191 } else if ( mStepNo == 3 ) { 00192 // ok, end of encoded stream 00193 mSawPadding = true; 00194 break; 00195 } 00196 mSawPadding = true; 00197 mStepNo = (mStepNo + 1) % 4; 00198 continue; 00199 } else { 00200 // non-base64 alphabet 00201 continue; 00202 } 00203 } 00204 00205 if ( mSawPadding ) { 00206 kdWarning() << "Base64Decoder: Embedded padding character " 00207 "encountered!" << endl; 00208 return true; 00209 } 00210 00211 // add the new bits to the output stream and flush full octets: 00212 switch ( mStepNo ) { 00213 case 0: 00214 mOutbits = value << 2; 00215 break; 00216 case 1: 00217 *dcursor++ = (char)(mOutbits | value >> 4); 00218 mOutbits = value << 4; 00219 break; 00220 case 2: 00221 *dcursor++ = (char)(mOutbits | value >> 2); 00222 mOutbits = value << 6; 00223 break; 00224 case 3: 00225 *dcursor++ = (char)(mOutbits | value); 00226 mOutbits = 0; 00227 break; 00228 default: 00229 assert( 0 ); 00230 } 00231 mStepNo = (mStepNo + 1) % 4; 00232 } 00233 00234 // return false when caller should call us again: 00235 return (scursor == send); 00236 } // Base64Decoder::decode() 00237 00238 00239 00240 bool Base64Encoder::encode( const char* & scursor, const char * const send, 00241 char* & dcursor, const char * const dend ) { 00242 const uint maxPacketsPerLine = 76 / 4; 00243 00244 // detect when the caller doesn't adhere to our rules: 00245 if ( mInsideFinishing ) return true; 00246 00247 while ( scursor != send && dcursor != dend ) { 00248 // properly empty the output buffer before starting something new: 00249 // ### fixme: we can optimize this away, since the buffer isn't 00250 // written to anyway (most of the time) 00251 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) 00252 return (scursor == send); 00253 00254 uchar ch = *scursor++; 00255 // mNextbits // (part of) value of next sextet 00256 00257 // check for line length; 00258 if ( mStepNo == 0 && mWrittenPacketsOnThisLine >= maxPacketsPerLine ) { 00259 writeCRLF( dcursor, dend ); 00260 mWrittenPacketsOnThisLine = 0; 00261 } 00262 00263 // depending on mStepNo, extract value and mNextbits from the 00264 // octet stream: 00265 switch ( mStepNo ) { 00266 case 0: 00267 assert( mNextbits == 0 ); 00268 writeBase64( ch >> 2, dcursor, dend ); // top-most 6 bits -> output 00269 mNextbits = (ch & 0x3) << 4; // 0..1 bits -> 4..5 in mNextbits 00270 break; 00271 case 1: 00272 assert( (mNextbits & ~0x30) == 0 ); 00273 writeBase64( mNextbits | ch >> 4, dcursor, dend ); // 4..7 bits -> 0..3 in value 00274 mNextbits = (ch & 0xf) << 2; // 0..3 bits -> 2..5 in mNextbits 00275 break; 00276 case 2: 00277 assert( (mNextbits & ~0x3C) == 0 ); 00278 writeBase64( mNextbits | ch >> 6, dcursor, dend ); // 6..7 bits -> 0..1 in value 00279 writeBase64( ch & 0x3F, dcursor, dend ); // 0..5 bits -> output 00280 mNextbits = 0; 00281 mWrittenPacketsOnThisLine++; 00282 break; 00283 default: 00284 assert( 0 ); 00285 } 00286 mStepNo = ( mStepNo + 1 ) % 3; 00287 } 00288 00289 if ( mOutputBufferCursor ) flushOutputBuffer( dcursor, dend ); 00290 00291 return (scursor == send); 00292 } 00293 00294 00295 bool Rfc2047BEncodingEncoder::encode( const char* & scursor, 00296 const char * const send, 00297 char* & dcursor, 00298 const char * const dend ) 00299 { 00300 // detect when the caller doesn't adhere to our rules: 00301 if ( mInsideFinishing ) return true; 00302 00303 while ( scursor != send && dcursor != dend ) { 00304 // properly empty the output buffer before starting something new: 00305 // ### fixme: we can optimize this away, since the buffer isn't 00306 // written to anyway (most of the time) 00307 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) 00308 return (scursor == send); 00309 00310 uchar ch = *scursor++; 00311 // mNextbits // (part of) value of next sextet 00312 00313 // depending on mStepNo, extract value and mNextbits from the 00314 // octet stream: 00315 switch ( mStepNo ) { 00316 case 0: 00317 assert( mNextbits == 0 ); 00318 writeBase64( ch >> 2, dcursor, dend ); // top-most 6 bits -> output 00319 mNextbits = (ch & 0x3) << 4; // 0..1 bits -> 4..5 in mNextbits 00320 break; 00321 case 1: 00322 assert( (mNextbits & ~0x30) == 0 ); 00323 writeBase64( mNextbits | ch >> 4, dcursor, dend ); // 4..7 bits -> 0..3 in value 00324 mNextbits = (ch & 0xf) << 2; // 0..3 bits -> 2..5 in mNextbits 00325 break; 00326 case 2: 00327 assert( (mNextbits & ~0x3C) == 0 ); 00328 writeBase64( mNextbits | ch >> 6, dcursor, dend ); // 6..7 bits -> 0..1 in value 00329 writeBase64( ch & 0x3F, dcursor, dend ); // 0..5 bits -> output 00330 mNextbits = 0; 00331 break; 00332 default: 00333 assert( 0 ); 00334 } 00335 mStepNo = ( mStepNo + 1 ) % 3; 00336 } 00337 00338 if ( mOutputBufferCursor ) flushOutputBuffer( dcursor, dend ); 00339 00340 return (scursor == send); 00341 } 00342 00343 00344 bool Base64Encoder::finish( char* & dcursor, const char * const dend ) { 00345 return generic_finish( dcursor, dend, true ); 00346 } 00347 00348 bool Rfc2047BEncodingEncoder::finish( char* & dcursor, 00349 const char * const dend ) { 00350 return generic_finish( dcursor, dend, false ); 00351 } 00352 00353 bool Base64Encoder::generic_finish( char* & dcursor, const char * const dend, 00354 bool withLFatEnd ) 00355 { 00356 if ( mInsideFinishing ) 00357 return flushOutputBuffer( dcursor, dend ); 00358 00359 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) 00360 return false; 00361 00362 mInsideFinishing = true; 00363 00364 // 00365 // writing out the last mNextbits... 00366 // 00367 switch ( mStepNo ) { 00368 case 1: // 2 mNextbits waiting to be written. Needs two padding chars: 00369 case 2: // 4 or 6 mNextbits waiting to be written. Completes a block 00370 writeBase64( mNextbits, dcursor, dend ); 00371 mNextbits = 0; 00372 break; 00373 case 0: // no padding, nothing to be written, except possibly the CRLF 00374 assert( mNextbits == 0 ); 00375 break; 00376 default: 00377 assert( 0 ); 00378 } 00379 00380 // 00381 // adding padding... 00382 // 00383 switch( mStepNo ) { 00384 case 1: 00385 write( '=', dcursor, dend ); 00386 // fall through: 00387 case 2: 00388 write( '=', dcursor, dend ); 00389 // fall through: 00390 case 0: // completed an quartet - add CRLF 00391 if ( withLFatEnd ) 00392 writeCRLF( dcursor, dend ); 00393 return flushOutputBuffer( dcursor, dend ); 00394 default: 00395 assert( 0 ); 00396 } 00397 return true; // asserts get compiled out 00398 } 00399 00400 00401 00402 00403 00404 00405 } // namespace KMime
KDE Logo
This file is part of the documentation for libkdenetwork Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:48:41 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003