36 #include "kmime_util.h"
42 using namespace KMime;
54 static inline char binToHex( uchar value )
57 return value +
'A' - 10;
67 static inline uchar highNibble( uchar ch )
76 static inline uchar lowNibble( uchar ch )
86 static inline bool keep( uchar ch )
89 return !( ( ch <
' ' && ch !=
'\t' ) || ch ==
'?' );
96 class QuotedPrintableEncoder :
public Encoder
98 char mInputBuffer[16];
99 uchar mCurrentLineLength;
101 uint mInputBufferReadCursor : 4;
102 uint mInputBufferWriteCursor : 4;
104 Never, AtBOL, Definitely
105 } mAccuNeedsEncoding : 2;
106 bool mSawLineEnd : 1;
112 QuotedPrintableEncoder(
bool withCRLF=
false )
113 :
Encoder( withCRLF ), mCurrentLineLength( 0 ), mAccu( 0 ),
114 mInputBufferReadCursor( 0 ), mInputBufferWriteCursor( 0 ),
115 mAccuNeedsEncoding( Never ),
116 mSawLineEnd( false ), mSawCR( false ), mFinishing( false ),
117 mFinished( false ) {}
119 bool needsEncoding( uchar ch )
120 {
return ch >
'~' || ( ch <
' ' && ch !=
'\t' ) || ch ==
'='; }
121 bool needsEncodingAtEOL( uchar ch )
122 {
return ch ==
' ' || ch ==
'\t'; }
123 bool needsEncodingAtBOL( uchar ch )
124 {
return ch ==
'F' || ch ==
'.' || ch ==
'-'; }
125 bool fillInputBuffer(
const char* &scursor,
const char *
const send );
126 bool processNextChar();
127 void createOutputBuffer(
char* &dcursor,
const char *
const dend );
129 virtual ~QuotedPrintableEncoder() {}
131 bool encode(
const char* &scursor,
const char *
const send,
132 char* &dcursor,
const char *
const dend );
134 bool finish(
char* &dcursor,
const char *
const dend );
137 class QuotedPrintableDecoder :
public Decoder
139 const char mEscapeChar;
152 const bool mQEncoding;
164 QuotedPrintableDecoder(
bool withCRLF=
false,
165 bool aQEncoding=
false,
char aEscapeChar=
'=' )
167 mEscapeChar( aEscapeChar ),
170 mQEncoding( aQEncoding ),
171 mInsideHexChar( false ),
177 virtual ~QuotedPrintableDecoder() {}
179 bool decode(
const char* &scursor,
const char *
const send,
180 char* &dcursor,
const char *
const dend );
181 bool finish(
char* & dcursor,
const char *
const dend );
184 class Rfc2047QEncodingEncoder :
public Encoder
188 const char mEscapeChar;
189 bool mInsideFinishing : 1;
193 Rfc2047QEncodingEncoder(
bool withCRLF=
false,
char aEscapeChar=
'=' )
195 mAccu( 0 ), mStepNo( 0 ), mEscapeChar( aEscapeChar ),
196 mInsideFinishing( false )
199 assert( aEscapeChar ==
'=' || aEscapeChar ==
'%' );
203 bool needsEncoding( uchar ch )
208 if ( !isEText( ch ) ) {
211 if ( mEscapeChar ==
'%' && ( ch ==
'*' || ch ==
'/' ) ) {
218 virtual ~Rfc2047QEncodingEncoder() {}
220 bool encode(
const char* & scursor,
const char *
const send,
221 char* & dcursor,
const char *
const dend );
222 bool finish(
char* & dcursor,
const char *
const dend );
227 static int QuotedPrintableDecoder_maxDecodedSizeFor(
int insize,
bool withCRLF )
243 return new QuotedPrintableEncoder( withCRLF );
248 return new QuotedPrintableDecoder( withCRLF );
253 return QuotedPrintableDecoder_maxDecodedSizeFor(insize, withCRLF);
258 return new Rfc2047QEncodingEncoder( withCRLF );
263 return new QuotedPrintableDecoder( withCRLF,
true );
268 return QuotedPrintableDecoder_maxDecodedSizeFor(insize, withCRLF);
273 return new Rfc2047QEncodingEncoder( withCRLF,
'%' );
278 return new QuotedPrintableDecoder( withCRLF,
true,
'%' );
283 return QuotedPrintableDecoder_maxDecodedSizeFor(insize, withCRLF);
290 bool QuotedPrintableDecoder::decode(
const char* &scursor,
291 const char *
const send,
292 char* &dcursor,
const char *
const dend )
295 kWarning() <<
"CRLF output for decoders isn't yet supported!";
298 while ( scursor != send && dcursor != dend ) {
309 if ( mInsideHexChar ) {
311 *dcursor++ = mEscapeChar;
312 mInsideHexChar =
false;
313 }
else if ( mHaveAccu ) {
315 *dcursor++ = mLastChar;
320 assert( mAccu == 0 );
322 if ( mBadChar ==
'=' ) {
323 mInsideHexChar =
true;
325 *dcursor++ = mBadChar;
333 assert( mBadChar == 0 );
335 uchar ch = *scursor++;
338 if ( mExpectLF && ch !=
'\n' ) {
339 kWarning() <<
"QuotedPrintableDecoder:"
340 "illegally formed soft linebreak or lonely CR!";
341 mInsideHexChar =
false;
343 assert( mAccu == 0 );
346 if ( mInsideHexChar ) {
360 mInsideHexChar =
false;
365 kWarning() <<
"QuotedPrintableDecoder:"
366 "illegally formed hex char! Outputting verbatim.";
375 value = 10 + ch -
'A';
382 if ( ch <= 'f' && ch >=
'a' ) {
383 value = 10 + ch -
'a';
392 assert( value < 16 );
393 assert( mBadChar == 0 );
394 assert( !mExpectLF );
397 *dcursor++ = char( mAccu | value );
400 mInsideHexChar =
false;
407 if ( ( ch <= '~' && ch >=
' ' ) || ch ==
'\t' ) {
408 if ( ch == mEscapeChar ) {
409 mInsideHexChar =
true;
410 }
else if ( mQEncoding && ch ==
'_' ) {
411 *dcursor++ = char( 0x20 );
413 *dcursor++ = char( ch );
415 }
else if ( ch ==
'\n' ) {
418 }
else if ( ch ==
'\r' ) {
423 *dcursor++ = char( ch );
428 return scursor == send;
431 bool QuotedPrintableDecoder::finish(
char* &dcursor,
const char *
const dend )
433 while ( ( mInsideHexChar || mHaveAccu || mFlushing ) && dcursor != dend ) {
435 if ( mInsideHexChar ) {
437 *dcursor++ = mEscapeChar;
438 mInsideHexChar =
false;
440 else if ( mHaveAccu ) {
442 *dcursor++ = mLastChar;
447 assert( mAccu == 0 );
449 *dcursor++ = mBadChar;
457 return !( mHaveAccu || mFlushing );
460 bool QuotedPrintableEncoder::fillInputBuffer(
const char* &scursor,
461 const char *
const send ) {
469 for ( ; ( mInputBufferWriteCursor + 1 ) % 16 != mInputBufferReadCursor &&
470 scursor != send ; mInputBufferWriteCursor++ ) {
471 char ch = *scursor++;
474 }
else if ( ch ==
'\n' ) {
479 assert( mInputBufferWriteCursor != mInputBufferReadCursor );
480 mInputBufferWriteCursor--;
487 mInputBuffer[ mInputBufferWriteCursor ] = ch;
493 bool QuotedPrintableEncoder::processNextChar()
501 const int minBufferFillWithoutLineEnd = 4;
503 assert( mOutputBufferCursor == 0 );
506 int( mInputBufferWriteCursor ) - int( mInputBufferReadCursor ) ;
507 if ( bufferFill < 0 ) {
511 assert( bufferFill >=0 && bufferFill <= 15 );
513 if ( !mFinishing && !mSawLineEnd &&
514 bufferFill < minBufferFillWithoutLineEnd ) {
519 if ( mInputBufferReadCursor == mInputBufferWriteCursor ) {
524 mAccu = mInputBuffer[ mInputBufferReadCursor++ ];
525 if ( needsEncoding( mAccu ) ) {
526 mAccuNeedsEncoding = Definitely;
527 }
else if ( ( mSawLineEnd || mFinishing ) &&
529 needsEncodingAtEOL( mAccu ) ) {
530 mAccuNeedsEncoding = Definitely;
531 }
else if ( needsEncodingAtBOL( mAccu ) ) {
532 mAccuNeedsEncoding = AtBOL;
535 mAccuNeedsEncoding = Never;
545 void QuotedPrintableEncoder::createOutputBuffer(
char* &dcursor,
546 const char *
const dend )
548 const int maxLineLength = 76;
550 assert( mOutputBufferCursor == 0 );
552 bool lastOneOnThisLine = mSawLineEnd
553 && mInputBufferReadCursor == mInputBufferWriteCursor;
556 if ( mAccuNeedsEncoding == Definitely ) {
561 if ( !lastOneOnThisLine ) {
565 if ( mCurrentLineLength > maxLineLength - neededSpace ) {
567 write(
'=', dcursor, dend );
568 writeCRLF( dcursor, dend );
569 mCurrentLineLength = 0;
572 if ( Never == mAccuNeedsEncoding ||
573 ( AtBOL == mAccuNeedsEncoding && mCurrentLineLength != 0 ) ) {
574 write( mAccu, dcursor, dend );
575 mCurrentLineLength++;
577 write(
'=', dcursor, dend );
578 write( binToHex( highNibble( mAccu ) ), dcursor, dend );
579 write( binToHex( lowNibble( mAccu ) ), dcursor, dend );
580 mCurrentLineLength += 3;
584 bool QuotedPrintableEncoder::encode(
const char* &scursor,
585 const char *
const send,
586 char* &dcursor,
const char *
const dend )
593 while ( scursor != send && dcursor != dend ) {
594 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) {
595 return scursor == send;
598 assert( mOutputBufferCursor == 0 );
602 fillInputBuffer( scursor, send );
604 if ( processNextChar() ) {
606 createOutputBuffer( dcursor, dend );
607 }
else if ( mSawLineEnd &&
608 mInputBufferWriteCursor == mInputBufferReadCursor ) {
610 writeCRLF( dcursor, dend );
613 mCurrentLineLength = 0;
622 if ( mOutputBufferCursor ) {
623 flushOutputBuffer( dcursor, dend );
626 return scursor == send;
630 bool QuotedPrintableEncoder::finish(
char* &dcursor,
const char *
const dend )
635 return flushOutputBuffer( dcursor, dend );
638 while ( dcursor != dend ) {
639 if ( mOutputBufferCursor && !flushOutputBuffer( dcursor, dend ) ) {
643 assert( mOutputBufferCursor == 0 );
645 if ( processNextChar() ) {
647 createOutputBuffer( dcursor, dend );
648 }
else if ( mSawLineEnd &&
649 mInputBufferWriteCursor == mInputBufferReadCursor ) {
651 writeCRLF( dcursor, dend );
653 mCurrentLineLength = 0;
656 return flushOutputBuffer( dcursor, dend );
660 return mFinished && !mOutputBufferCursor;
664 bool Rfc2047QEncodingEncoder::encode(
const char* &scursor,
665 const char *
const send,
666 char* &dcursor,
const char *
const dend )
668 if ( mInsideFinishing ) {
672 while ( scursor != send && dcursor != dend ) {
678 if ( !needsEncoding( mAccu ) ) {
679 *dcursor++ = char( mAccu );
680 }
else if ( mEscapeChar ==
'=' && mAccu == 0x20 ) {
686 *dcursor++ = mEscapeChar;
692 value = highNibble( mAccu );
697 value = lowNibble( mAccu );
700 default: assert( 0 );
704 *dcursor++ = binToHex( value );
707 return scursor == send;
710 #include <QtCore/QString>
712 bool Rfc2047QEncodingEncoder::finish(
char* &dcursor,
const char *
const dend )
714 mInsideFinishing =
true;
717 while ( mStepNo != 0 && dcursor != dend ) {
722 value = highNibble( mAccu );
727 value = lowNibble( mAccu );
730 default: assert( 0 );
734 *dcursor++ = binToHex( value );
int maxDecodedSizeFor(int insize, bool withCRLF=false) const
Encoder * makeEncoder(bool withCRLF=false) const
A class representing the codec for QuotedPrintable as specified in RFC2045 (section 6...
Decoder * makeDecoder(bool withCRLF=false) const
int maxDecodedSizeFor(int insize, bool withCRLF=false) const
int maxDecodedSizeFor(int insize, bool withCRLF=false) const
A class representing the codec for RFC2231.
Decoder * makeDecoder(bool withCRLF=false) const
Decoder * makeDecoder(bool withCRLF=false) const
Stateful CTE decoder class.
Encoder * makeEncoder(bool withCRLF=false) const
This file is part of the API for handling MIME data and defines the QuotedPrintable, RFC2047Q, and RFC2231 Codec classes.
Encoder * makeEncoder(bool withCRLF=false) const
A class representing the codec for the Q encoding as specified in RFC2047Q.