00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
#include "kmime_codec_uuencode.h"
00033
00034
#include <kdebug.h>
00035
00036
#include <cassert>
00037
00038
using namespace KMime;
00039
00040
namespace KMime {
00041
00042
00043
class UUDecoder :
public Decoder {
00044 uint mStepNo;
00045 uchar mAnnouncedOctetCount;
00046 uchar mCurrentOctetCount;
00047 uchar mOutbits;
00048
bool mLastWasCRLF : 1;
00049
bool mSawBegin : 1;
00050 uint mIntoBeginLine : 3;
00051
bool mSawEnd : 1;
00052 uint mIntoEndLine : 2;
00053
00054
void searchForBegin(
const char* & scursor,
const char *
const send );
00055
00056
protected:
00057
friend class UUCodec;
00058 UUDecoder(
bool withCRLF=
false )
00059 : Decoder( withCRLF ), mStepNo(0),
00060 mAnnouncedOctetCount(0), mCurrentOctetCount(0),
00061 mOutbits(0), mLastWasCRLF(true),
00062 mSawBegin(false), mIntoBeginLine(0),
00063 mSawEnd(false), mIntoEndLine(0) {}
00064
00065
public:
00066
virtual ~UUDecoder() {}
00067
00068
bool decode(
const char* & scursor,
const char *
const send,
00069
char* & dcursor,
const char *
const dend );
00070
00071
bool finish(
char* & ,
const char *
const ) {
return true; }
00072 };
00073
00074
00075
00076
Encoder * UUCodec::makeEncoder(
bool )
const {
00077
return 0;
00078 }
00079
00080 Decoder * UUCodec::makeDecoder(
bool withCRLF )
const {
00081
return new UUDecoder( withCRLF );
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
void UUDecoder::searchForBegin(
const char* & scursor,
const char *
const send ) {
00092
static const char begin[] =
"begin\n";
00093
static const uint beginLength = 5;
00094
00095 assert( !mSawBegin || mIntoBeginLine > 0 );
00096
00097
while ( scursor != send ) {
00098 uchar ch = *scursor++;
00099
if ( ch == begin[mIntoBeginLine] ) {
00100
if ( mIntoBeginLine < beginLength ) {
00101
00102 ++mIntoBeginLine;
00103
if ( mIntoBeginLine == beginLength )
00104 mSawBegin =
true;
00105 }
else {
00106
00107 mLastWasCRLF =
true;
00108 mIntoBeginLine = 0;
00109
return;
00110 }
00111 }
else if ( mSawBegin ) {
00112
00113 }
else {
00114 kdWarning() <<
"UUDecoder: garbage before \"begin\", resetting parser"
00115 << endl;
00116 mIntoBeginLine = 0;
00117 }
00118 }
00119
00120 }
00121
00122
00123
00124
00125
static inline uchar uuDecode( uchar c ) {
00126
return ( c -
' ' )
00127 & 0x3F;
00128 }
00129
00130
00131
bool UUDecoder::decode(
const char* & scursor,
const char *
const send,
00132
char* & dcursor,
const char *
const dend )
00133 {
00134
00135
if ( !mSawBegin || mIntoBeginLine != 0 )
00136 searchForBegin( scursor, send );
00137
00138
else if ( mSawEnd ) {
00139 scursor = send;
00140
return true;
00141 }
00142
00143
while ( dcursor != dend && scursor != send ) {
00144 uchar ch = *scursor++;
00145 uchar value;
00146
00147
00148
if ( mIntoEndLine > 0 ) {
00149
static const char end[] =
"end";
00150
static const uint endLength = 3;
00151
00152
if ( ch == end[mIntoEndLine] ) {
00153 ++mIntoEndLine;
00154
if ( mIntoEndLine == endLength ) {
00155 mSawEnd =
true;
00156 scursor = send;
00157
return true;
00158 }
00159
continue;
00160 }
else {
00161 kdWarning() <<
"UUDecoder: invalid line octet count looks like \"end\" (mIntoEndLine = " << mIntoEndLine <<
" )!" << endl;
00162 mIntoEndLine = 0;
00163
00164 }
00165 }
00166
00167
00168
00169
00170
00171
if ( mLastWasCRLF ) {
00172
00173 mLastWasCRLF =
false;
00174 mCurrentOctetCount = 0;
00175
00176
00177
if ( ch ==
'e' )
00178 mIntoEndLine = 1;
00179
else if ( ch > 0x60 )
00180 {}
00181
else if ( ch >
' ' )
00182 mAnnouncedOctetCount = uuDecode( ch );
00183
else if ( ch ==
'\n' )
00184 mLastWasCRLF =
true;
00185
00186
continue;
00187 }
00188
00189
00190
if ( ch > 0x60 )
00191
continue;
00192
else if ( ch >
' ' )
00193 value = uuDecode( ch );
00194
else if ( ch ==
'\n' ) {
00195 mLastWasCRLF =
true;
00196
continue;
00197 }
else
00198
continue;
00199
00200
00201
switch ( mStepNo ) {
00202
case 0:
00203 mOutbits = value << 2;
00204
break;
00205
case 1:
00206
if ( mCurrentOctetCount < mAnnouncedOctetCount )
00207 *dcursor++ = (
char)(mOutbits | value >> 4);
00208 ++mCurrentOctetCount;
00209 mOutbits = value << 4;
00210
break;
00211
case 2:
00212
if ( mCurrentOctetCount < mAnnouncedOctetCount )
00213 *dcursor++ = (
char)(mOutbits | value >> 2);
00214 ++mCurrentOctetCount;
00215 mOutbits = value << 6;
00216
break;
00217
case 3:
00218
if ( mCurrentOctetCount < mAnnouncedOctetCount )
00219 *dcursor++ = (
char)(mOutbits | value);
00220 ++mCurrentOctetCount;
00221 mOutbits = 0;
00222
break;
00223
default:
00224 assert( 0 );
00225 }
00226 mStepNo = (mStepNo + 1) % 4;
00227
00228
00229 kdWarning( mCurrentOctetCount == mAnnouncedOctetCount + 1 )
00230 <<
"UUDecoder: mismatch between announced ("
00231 << mAnnouncedOctetCount <<
") and actual line octet count!" << endl;
00232
00233 }
00234
00235
00236
return (scursor == send);
00237 }
00238
00239
00240 }