KMIME Library
kmime_codec_uuencode.cpp
Go to the documentation of this file.
00001 /* -*- c++ -*- 00002 kmime_codec_uuencode.cpp 00003 00004 KMime, the KDE Internet mail/usenet news message library. 00005 Copyright (c) 2002 Marc Mutz <mutz@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00033 #include "kmime_codec_uuencode.h" 00034 00035 #include <kdebug.h> 00036 00037 #include <cassert> 00038 00039 using namespace KMime; 00040 00041 namespace KMime { 00042 00043 class UUDecoder : public Decoder 00044 { 00045 uint mStepNo; 00046 uchar mAnnouncedOctetCount; // (on current line) 00047 uchar mCurrentOctetCount; // (on current line) 00048 uchar mOutbits; 00049 bool mLastWasCRLF : 1; 00050 bool mSawBegin : 1; // whether we already saw ^begin... 00051 uint mIntoBeginLine : 3; // count #chars we compared against "begin" 0..5 00052 bool mSawEnd : 1; // whether we already saw ^end... 00053 uint mIntoEndLine : 2; // count #chars we compared against "end" 0..3 00054 00055 void searchForBegin( const char* &scursor, const char * const send ); 00056 00057 protected: 00058 friend class UUCodec; 00059 UUDecoder( bool withCRLF=false ) 00060 : Decoder( withCRLF ), mStepNo( 0 ), 00061 mAnnouncedOctetCount( 0 ), mCurrentOctetCount( 0 ), 00062 mOutbits( 0 ), mLastWasCRLF( true ), 00063 mSawBegin( false ), mIntoBeginLine( 0 ), 00064 mSawEnd( false ), mIntoEndLine( 0 ) {} 00065 00066 public: 00067 virtual ~UUDecoder() {} 00068 00069 bool decode( const char* &scursor, const char * const send, 00070 char* &dcursor, const char * const dend ); 00071 // ### really needs no finishing??? 00072 bool finish( char* &dcursor, const char * const dend ) 00073 { Q_UNUSED( dcursor ); Q_UNUSED( dend ); return true; } 00074 }; 00075 00076 Encoder * UUCodec::makeEncoder( bool ) const 00077 { 00078 return 0; // encoding not supported 00079 } 00080 00081 Decoder * UUCodec::makeDecoder( bool withCRLF ) const 00082 { 00083 return new UUDecoder( withCRLF ); 00084 } 00085 00086 /********************************************************/ 00087 /********************************************************/ 00088 /********************************************************/ 00089 00090 void UUDecoder::searchForBegin( const char* &scursor, const char * const send ) 00091 { 00092 static const char begin[] = "begin\n"; 00093 static const uint beginLength = 5; // sic! 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 // found another char 00102 ++mIntoBeginLine; 00103 if ( mIntoBeginLine == beginLength ) { 00104 mSawBegin = true; // "begin" complete, now search the next \n... 00105 } 00106 } else { // mIntoBeginLine == beginLength 00107 // found '\n': begin line complete 00108 mLastWasCRLF = true; 00109 mIntoBeginLine = 0; 00110 return; 00111 } 00112 } else if ( mSawBegin ) { 00113 // OK, skip stuff until the next \n 00114 } else { 00115 kWarning() << "UUDecoder: garbage before \"begin\", resetting parser"; 00116 mIntoBeginLine = 0; 00117 } 00118 } 00119 00120 } 00121 00122 // uuencoding just shifts all 6-bit octets by 32 (SP/' '), except NUL, 00123 // which gets mapped to 0x60 00124 static inline uchar uuDecode( uchar c ) 00125 { 00126 return ( c - ' ' ) // undo shift and 00127 & 0x3F; // map 0x40 (0x60-' ') to 0... 00128 } 00129 00130 bool UUDecoder::decode( const char* &scursor, const char * const send, 00131 char* &dcursor, const char * const dend ) 00132 { 00133 // First, check whether we still need to find the "begin" line: 00134 if ( !mSawBegin || mIntoBeginLine != 0 ) { 00135 searchForBegin( scursor, send ); 00136 } else if ( mSawEnd ) { 00137 // or if we are past the end line: 00138 scursor = send; // do nothing anymore... 00139 return true; 00140 } 00141 00142 while ( dcursor != dend && scursor != send ) { 00143 uchar ch = *scursor++; 00144 uchar value; 00145 00146 // Check whether we need to look for the "end" line: 00147 if ( mIntoEndLine > 0 ) { 00148 static const char end[] = "end"; 00149 static const uint endLength = 3; 00150 00151 if ( ch == end[mIntoEndLine] ) { 00152 ++mIntoEndLine; 00153 if ( mIntoEndLine == endLength ) { 00154 mSawEnd = true; 00155 scursor = send; // shortcut to the end 00156 return true; 00157 } 00158 continue; 00159 } else { 00160 kWarning() << "UUDecoder: invalid line octet count looks like \"end\" (mIntoEndLine =" 00161 << mIntoEndLine << ")!"; 00162 mIntoEndLine = 0; 00163 // fall through... 00164 } 00165 } 00166 00167 // Normal parsing: 00168 00169 // The first char of a line is an encoding of the length of the 00170 // current line. We simply ignore it: 00171 if ( mLastWasCRLF ) { 00172 // reset char-per-line counter: 00173 mLastWasCRLF = false; 00174 mCurrentOctetCount = 0; 00175 00176 // try to decode the chars-on-this-line announcement: 00177 if ( ch == 'e' ) { // maybe the beginning of the "end"? ;-) 00178 mIntoEndLine = 1; 00179 } else if ( ch > 0x60 ) { 00180 // ### invalid line length char: what shall we do?? 00181 } else if ( ch > ' ' ) { 00182 mAnnouncedOctetCount = uuDecode( ch ); 00183 } else if ( ch == '\n' ) { 00184 mLastWasCRLF = true; // oops, empty line 00185 } 00186 00187 continue; 00188 } 00189 00190 // try converting ch to a 6-bit value: 00191 if ( ch > 0x60 ) { 00192 continue; // invalid char 00193 } else if ( ch > ' ' ) { 00194 value = uuDecode( ch ); 00195 } else if ( ch == '\n' ) { // line end 00196 mLastWasCRLF = true; 00197 continue; 00198 } else { 00199 continue; 00200 } 00201 00202 // add the new bits to the output stream and flush full octets: 00203 switch ( mStepNo ) { 00204 case 0: 00205 mOutbits = value << 2; 00206 break; 00207 case 1: 00208 if ( mCurrentOctetCount < mAnnouncedOctetCount ) { 00209 *dcursor++ = (char)(mOutbits | value >> 4); 00210 } 00211 ++mCurrentOctetCount; 00212 mOutbits = value << 4; 00213 break; 00214 case 2: 00215 if ( mCurrentOctetCount < mAnnouncedOctetCount ) { 00216 *dcursor++ = (char)(mOutbits | value >> 2); 00217 } 00218 ++mCurrentOctetCount; 00219 mOutbits = value << 6; 00220 break; 00221 case 3: 00222 if ( mCurrentOctetCount < mAnnouncedOctetCount ) { 00223 *dcursor++ = (char)(mOutbits | value); 00224 } 00225 ++mCurrentOctetCount; 00226 mOutbits = 0; 00227 break; 00228 default: 00229 assert( 0 ); 00230 } 00231 mStepNo = (mStepNo + 1) % 4; 00232 00233 // check whether we ran over the announced octet count for this line: 00234 kWarning( mCurrentOctetCount == mAnnouncedOctetCount + 1 ) 00235 << "UUDecoder: mismatch between announced (" 00236 << mAnnouncedOctetCount << ") and actual line octet count!"; 00237 00238 } 00239 00240 // return false when caller should call us again: 00241 return scursor == send; 00242 } // UUDecoder::decode() 00243 00244 } // namespace KMime
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:48:40 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:48:40 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.