Back to index

courier  0.68.2
rfc2045cdecode.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 #include      "rfc2045.h"
00007 #include      <ctype.h>
00008 #include      <string.h>
00009 
00010 
00011 extern void rfc2045_add_buf( char **, size_t *, size_t *,
00012               const char *, size_t);
00013 extern void rfc2045_add_workbuf(struct rfc2045 *, const char *, size_t);
00014 extern void rfc2045_add_workbufch(struct rfc2045 *, int);
00015 
00016 static int decode_raw(struct rfc2045 *p, const char *s, size_t l)
00017 {
00018        if (s && l)   return ((*p->udecode_func)(s,l,p->misc_decode_ptr));
00019        return (0);
00020 }
00021 
00022 static const char xdigit[]="0123456789ABCDEF";
00023 
00024 static int tou(char c)
00025 {
00026        if (c >= 'a' && c <= 'f')
00027               return c + ('A'-'a');
00028        return c;
00029 }
00030 
00031 static int do_decode_qp(struct rfc2045 *p)
00032 {
00033 char   *a, *b, *c, *end;
00034 int    d;
00035 
00036        end=p->workbuf + p->workbuflen;
00037        for (a=b=p->workbuf; a < end; )
00038        {
00039               if (*a != '=')
00040               {
00041                      *b++ = *a++;
00042                      continue;
00043               }
00044               ++a;
00045               if (!*a || a >= end || isspace((int)(unsigned char)*a))
00046                      break;
00047 
00048               if ((c=strchr(xdigit, tou(*a))) == 0) continue;
00049               d= (c-xdigit)*16;
00050               ++a;
00051               if (!*a || a >= end)
00052                      break;
00053               if ((c=strchr(xdigit, tou(*a))) == 0) continue;
00054               d += c-xdigit;
00055               ++a;
00056               *b++=d;
00057        }
00058        p->workbuflen= b-p->workbuf;
00059        d=(*p->udecode_func)(p->workbuf, p->workbuflen, p->misc_decode_ptr);
00060        p->workbuflen=0;
00061        return (d);
00062 }
00063 
00064 static const unsigned char decode64tab[256]={
00065        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00066        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00067        100,100,100,100,100,100,100,100,100,100,100,62,100,100,100,63,
00068        52,53,54,55,56,57,58,59,60,61,100,100,100,99,100,100,
00069        100,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
00070        15,16,17,18,19,20,21,22,23,24,25,100,100,100,100,100,
00071        100,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
00072        41,42,43,44,45,46,47,48,49,50,51,100,100,100,100,100,
00073        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00074        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00075        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00076        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00077        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00078        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00079        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
00080        100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100
00081 };
00082 
00083 /* When we have enough base64-encoded data in the buffer, decode it. */
00084 
00085 static int do_decode_base64(struct rfc2045 *p)
00086 {
00087 size_t i, j;
00088 char   a,b,c;
00089 size_t k;
00090 int    rc;
00091 
00092        /* Remove everything except base64encoded data */
00093 
00094        for (i=j=0; i<p->workbuflen; i++)
00095               if (decode64tab[(int)(unsigned char)p->workbuf[i]] < 100)
00096                      p->workbuf[j++]=p->workbuf[i];
00097 
00098 
00099        p->workbuflen=j;
00100 
00101        /* Decode the data, in 4-byte pieces */
00102 
00103        i=j / 4;
00104        i=i*4;
00105        k=0;
00106        for (j=0; j<i; j += 4)
00107        {
00108        int    w=decode64tab[(int)(unsigned char)p->workbuf[j]];
00109        int    x=decode64tab[(int)(unsigned char)p->workbuf[j+1]];
00110        int    y=decode64tab[(int)(unsigned char)p->workbuf[j+2]];
00111        int    z=decode64tab[(int)(unsigned char)p->workbuf[j+3]];
00112 
00113               a= (w << 2) | (x >> 4);
00114               b= (x << 4) | (y >> 2);
00115               c= (y << 6) | z;
00116               p->workbuf[k++]=a;
00117               if ( p->workbuf[j+2] != '=')
00118                      p->workbuf[k++]=b;
00119               if ( p->workbuf[j+3] != '=')
00120                      p->workbuf[k++]=c;
00121        }
00122        rc=(*p->udecode_func)(p->workbuf, k, p->misc_decode_ptr);
00123 
00124        /* Anything left?  Move it to the start of the buffer */
00125 
00126        k=0;
00127        while (j < p->workbuflen)
00128               p->workbuf[k++]=p->workbuf[j++];
00129        p->workbuflen=k;
00130        return (rc);
00131 }
00132 
00133 static int decode_qp(struct rfc2045 *p, const char *s, size_t l)
00134 {
00135 size_t start,i;
00136 int    rc;
00137 
00138        if (!s)
00139               return (do_decode_qp(p));
00140 
00141        for (start=0; start<l; )
00142        {
00143               for (i=start; i<l; i++)
00144               {
00145                      if (s[i] != '\n') continue;
00146                      rfc2045_add_workbuf(p, s+start, i-start);
00147                      rfc2045_add_workbufch(p, '\n');
00148                      if ((rc=do_decode_qp(p)) != 0)     return (rc);
00149                      start= ++i;
00150                      break;
00151               }
00152               rfc2045_add_workbuf(p, s+start, i-start);
00153               if (p->workbuflen > 1024)
00154               {
00155               char   buf[10];
00156               int    i;
00157 
00158                      for (i=p->workbuflen - 5; i<p->workbuflen; i++)
00159                             if (p->workbuf[i] == '=')   break;
00160                      if (i < p->workbuflen)
00161                      {
00162                      int j=p->workbuflen-i;
00163 
00164                             memcpy(buf, p->workbuf+i, j);
00165                             buf[j]=0;
00166                             p->workbuflen=i;
00167                      }
00168                      else   buf[0]=0;
00169                      if ((rc=do_decode_qp(p)) != 0)     return (rc);
00170                      rfc2045_add_workbuf(p, buf, strlen(buf));
00171               }
00172               start=i;
00173        }
00174        return (0);
00175 }
00176 
00177 static int decode_base64(struct rfc2045 *p, const char *s, size_t l)
00178 {
00179        if (!s)
00180               return (do_decode_base64(p));
00181 
00182        rfc2045_add_workbuf(p, s, l);
00183        if (p->workbuflen > 256)
00184               return (do_decode_base64(p));
00185        return (0);
00186 }
00187 
00188 void rfc2045_cdecode_start(struct rfc2045 *p,
00189        int (*u)(const char *, size_t, void *), void *miscptr)
00190 {
00191        p->misc_decode_ptr=miscptr;
00192        p->udecode_func=u;
00193        p->decode_func= &decode_raw;
00194        p->workbuflen=0;
00195        if (p->content_transfer_encoding)
00196        {
00197               if (strcmp(p->content_transfer_encoding,
00198                             "quoted-printable") == 0)
00199                      p->decode_func= &decode_qp;
00200               else if (strcmp(p->content_transfer_encoding, "base64") == 0)
00201                      p->decode_func= &decode_base64;
00202        }
00203 }
00204 
00205 int rfc2045_cdecode_end(struct rfc2045 *p)
00206 {
00207        return ((*p->decode_func)(p, NULL, 0));
00208 }
00209 
00210 int rfc2045_cdecode(struct rfc2045 *p, const char *s, size_t l)
00211 {
00212        if (s && l)   return ((*p->decode_func)(p, s, l));
00213        return (0);
00214 }