• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

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 Aug 27 2012 22:08:31 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KMIME Library

Skip menu "KMIME Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.8.5 API Reference

Skip menu "kdepimlibs-4.8.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal