00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00033 #include "kmime_codec_base64.h"
00034
00035 #include <kdebug.h>
00036
00037 #include <cassert>
00038
00039 using namespace KMime;
00040
00041 namespace KMime {
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 static const uchar base64DecodeMap[128] = {
00055 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
00056 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
00057
00058 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
00059 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
00060
00061 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
00062 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
00063
00064 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
00065 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64
00066 };
00067
00068 static const char base64EncodeMap[64] = {
00069 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00070 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
00071 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
00072 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
00073 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00074 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
00075 'w', 'x', 'y', 'z', '0', '1', '2', '3',
00076 '4', '5', '6', '7', '8', '9', '+', '/'
00077 };
00078
00079
00080 class Base64Decoder : public Decoder
00081 {
00082 uint mStepNo;
00083 uchar mOutbits;
00084 bool mSawPadding : 1;
00085
00086 protected:
00087 friend class Base64Codec;
00088 Base64Decoder( bool withCRLF=false )
00089 : Decoder( withCRLF ), mStepNo( 0 ), mOutbits( 0 ),
00090 mSawPadding( false ) {}
00091
00092 public:
00093 virtual ~Base64Decoder() {}
00094
00095 bool decode( const char* &scursor, const char * const send,
00096 char* &dcursor, const char * const dend );
00097
00098 bool finish( char* &dcursor, const char * const dend )
00099 {
00100 Q_UNUSED( dcursor ); Q_UNUSED( dend );
00101 return true;
00102 }
00103 };
00104
00105 class Base64Encoder : public Encoder
00106 {
00107 uint mStepNo;
00109 uint mWrittenPacketsOnThisLine;
00110 uchar mNextbits;
00111 bool mInsideFinishing : 1;
00112
00113 protected:
00114 friend class Rfc2047BEncodingCodec;
00115 friend class Rfc2047BEncodingEncoder;
00116 friend class Base64Codec;
00117 Base64Encoder( bool withCRLF=false )
00118 : Encoder( withCRLF ), mStepNo( 0 ), mWrittenPacketsOnThisLine( 0 ),
00119 mNextbits( 0 ), mInsideFinishing( false ) {}
00120
00121 bool generic_finish( char* &dcursor, const char * const dend,
00122 bool withLFatEnd );
00123
00124 public:
00125 virtual ~Base64Encoder() {}
00126
00127 bool encode( const char* &scursor, const char * const send,
00128 char* &dcursor, const char * const dend );
00129
00130 bool finish( char* &dcursor, const char * const dend );
00131
00132 protected:
00133 bool writeBase64( uchar ch, char* &dcursor, const char * const dend )
00134 { return write( base64EncodeMap[ ch ], dcursor, dend ); }
00135 };
00136
00137 class Rfc2047BEncodingEncoder : public Base64Encoder
00138 {
00139 protected:
00140 friend class Rfc2047BEncodingCodec;
00141 Rfc2047BEncodingEncoder( bool withCRLF=false )
00142 : Base64Encoder( withCRLF ) {}
00143
00144 public:
00145 bool encode( const char* &scursor, const char * const send,
00146 char* &dcursor, const char * const dend );
00147 bool finish( char* &dcursor, const char * const dend );
00148 };
00149
00150 Encoder *Base64Codec::makeEncoder( bool withCRLF ) const
00151 {
00152 return new Base64Encoder( withCRLF );
00153 }
00154
00155 Decoder *Base64Codec::makeDecoder( bool withCRLF ) const
00156 {
00157 return new Base64Decoder( withCRLF );
00158 }
00159
00160 Encoder *Rfc2047BEncodingCodec::makeEncoder( bool withCRLF ) const
00161 {
00162 return new Rfc2047BEncodingEncoder( withCRLF );
00163 }
00164
00165
00166
00167
00168
00169 bool Base64Decoder::decode( const char* &scursor, const char * const send,
00170 char* &dcursor, const char * const dend )
00171 {
00172 while ( dcursor != dend && scursor != send ) {
00173 uchar ch = *scursor++;
00174 uchar value;
00175
00176
00177 if ( ch < 128 ) {
00178 value = base64DecodeMap[ ch ];
00179 } else {
00180 value = 64;
00181 }
00182
00183
00184 if ( value >= 64 ) {
00185 if ( ch == '=' ) {
00186
00187 if ( mStepNo == 0 || mStepNo == 1 ) {
00188 if ( !mSawPadding ) {
00189
00190 kWarning() << "Base64Decoder: unexpected padding"
00191 "character in input stream";
00192 }
00193 mSawPadding = true;
00194 break;
00195 } else if ( mStepNo == 2 ) {
00196
00197 } else if ( mStepNo == 3 ) {
00198
00199 mSawPadding = true;
00200 break;
00201 }
00202 mSawPadding = true;
00203 mStepNo = (mStepNo + 1) % 4;
00204 continue;
00205 } else {
00206
00207 continue;
00208 }
00209 }
00210
00211 if ( mSawPadding ) {
00212 kWarning() << "Base64Decoder: Embedded padding character"
00213 "encountered!";
00214 return true;
00215 }
00216
00217
00218 switch ( mStepNo ) {
00219 case 0:
00220 mOutbits = value << 2;
00221 break;
00222 case 1:
00223 *dcursor++ = (char)(mOutbits | value >> 4);
00224 mOutbits = value << 4;
00225 break;
00226 case 2:
00227 *dcursor++ = (char)(mOutbits | value >> 2);
00228 mOutbits = value << 6;
00229 break;
00230 case 3:
00231 *dcursor++ = (char)(mOutbits | value);
00232 mOutbits = 0;
00233 break;
00234 default:
00235 assert( 0 );
00236 }
00237 mStepNo = (mStepNo + 1) % 4;
00238 }
00239
00240
00241 return scursor == send;
00242 }
00243
00244 bool Base64Encoder::encode( const char* &scursor, const char * const send,
00245 char* &dcursor, const char * const dend )
00246 {
00247 const uint maxPacketsPerLine = 76 / 4;
00248
00249
00250 if ( mInsideFinishing ) {
00251 return true;
00252 }
00253
00254 while ( scursor != send && dcursor != dend ) {
00255
00256
00257
00258 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) {
00259 return scursor == send;
00260 }
00261
00262 uchar ch = *scursor++;
00263
00264
00265
00266 if ( mStepNo == 0 && mWrittenPacketsOnThisLine >= maxPacketsPerLine ) {
00267 writeCRLF( dcursor, dend );
00268 mWrittenPacketsOnThisLine = 0;
00269 }
00270
00271
00272
00273 switch ( mStepNo ) {
00274 case 0:
00275 assert( mNextbits == 0 );
00276 writeBase64( ch >> 2, dcursor, dend );
00277 mNextbits = (ch & 0x3) << 4;
00278 break;
00279 case 1:
00280 assert( (mNextbits & ~0x30) == 0 );
00281 writeBase64( mNextbits | ch >> 4, dcursor, dend );
00282 mNextbits = (ch & 0xf) << 2;
00283 break;
00284 case 2:
00285 assert( (mNextbits & ~0x3C) == 0 );
00286 writeBase64( mNextbits | ch >> 6, dcursor, dend );
00287 writeBase64( ch & 0x3F, dcursor, dend );
00288 mNextbits = 0;
00289 mWrittenPacketsOnThisLine++;
00290 break;
00291 default:
00292 assert( 0 );
00293 }
00294 mStepNo = ( mStepNo + 1 ) % 3;
00295 }
00296
00297 if ( mOutputBufferCursor ) {
00298 flushOutputBuffer( dcursor, dend );
00299 }
00300
00301 return scursor == send;
00302 }
00303
00304 bool Rfc2047BEncodingEncoder::encode( const char* &scursor,
00305 const char * const send,
00306 char* &dcursor,
00307 const char * const dend )
00308 {
00309
00310 if ( mInsideFinishing ) {
00311 return true;
00312 }
00313
00314 while ( scursor != send && dcursor != dend ) {
00315
00316
00317
00318 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) {
00319 return scursor == send;
00320 }
00321
00322 uchar ch = *scursor++;
00323
00324
00325
00326
00327 switch ( mStepNo ) {
00328 case 0:
00329 assert( mNextbits == 0 );
00330 writeBase64( ch >> 2, dcursor, dend );
00331 mNextbits = (ch & 0x3) << 4;
00332 break;
00333 case 1:
00334 assert( (mNextbits & ~0x30) == 0 );
00335 writeBase64( mNextbits | ch >> 4, dcursor, dend );
00336 mNextbits = (ch & 0xf) << 2;
00337 break;
00338 case 2:
00339 assert( (mNextbits & ~0x3C) == 0 );
00340 writeBase64( mNextbits | ch >> 6, dcursor, dend );
00341 writeBase64( ch & 0x3F, dcursor, dend );
00342 mNextbits = 0;
00343 break;
00344 default:
00345 assert( 0 );
00346 }
00347 mStepNo = ( mStepNo + 1 ) % 3;
00348 }
00349
00350 if ( mOutputBufferCursor ) {
00351 flushOutputBuffer( dcursor, dend );
00352 }
00353
00354 return scursor == send;
00355 }
00356
00357 bool Base64Encoder::finish( char* &dcursor, const char * const dend )
00358 {
00359 return generic_finish( dcursor, dend, true );
00360 }
00361
00362 bool Rfc2047BEncodingEncoder::finish( char* & dcursor,
00363 const char * const dend )
00364 {
00365 return generic_finish( dcursor, dend, false );
00366 }
00367
00368 bool Base64Encoder::generic_finish( char* &dcursor, const char * const dend,
00369 bool withLFatEnd )
00370 {
00371 if ( mInsideFinishing ) {
00372 return flushOutputBuffer( dcursor, dend );
00373 }
00374
00375 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) {
00376 return false;
00377 }
00378
00379 mInsideFinishing = true;
00380
00381
00382
00383
00384 switch ( mStepNo ) {
00385 case 1:
00386 case 2:
00387 writeBase64( mNextbits, dcursor, dend );
00388 mNextbits = 0;
00389 break;
00390 case 0:
00391 assert( mNextbits == 0 );
00392 break;
00393 default:
00394 assert( 0 );
00395 }
00396
00397
00398
00399
00400 switch( mStepNo ) {
00401 case 1:
00402 write( '=', dcursor, dend );
00403
00404 case 2:
00405 write( '=', dcursor, dend );
00406
00407 case 0:
00408 if ( withLFatEnd ) {
00409 writeCRLF( dcursor, dend );
00410 }
00411 return flushOutputBuffer( dcursor, dend );
00412 default:
00413 assert( 0 );
00414 }
00415 return true;
00416 }
00417
00418 }