File indexing completed on 2024-09-22 04:52:48

0001 /*
0002    Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
0003    Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
0004 
0005    This program is free software; you can redistribute it and/or modify
0006    it under the terms of the GNU Lesser General Public License (LGPL)
0007    version 2 as published by the Free Software Foundation.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012    GNU Lesser General Public License for more details.
0013 
0014    You should have received a copy of the GNU Lesser General Public
0015    License along with this program; if not, write to the Free Software
0016    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0017 
0018    The encoding and decoding utilities in KCodecs with the exception of
0019    quoted-printable are based on the java implementation in HTTPClient
0020    package by Ronald Tschalär Copyright (C) 1996-1999.                          // krazy:exclude=copyright
0021 
0022    The quoted-printable codec as described in RFC 2045, section 6.7. is by
0023    Rik Hemsley (C) 2001.
0024 */
0025 
0026 #include "kcodecs.h"
0027 
0028 #include <stdio.h>
0029 #include <string.h>
0030 
0031 #ifdef _MSC_VER
0032 #define strcasecmp stricmp
0033 #define strncasecmp  strnicmp
0034 #endif
0035 
0036 #include <stdlib.h>
0037 
0038 //#include <kdebug.h>
0039 #include <QtCore/QIODevice>
0040 
0041 namespace KCodecs
0042 {
0043 
0044 static const char hexChars[16] =
0045 {
0046   '0', '1', '2', '3', '4', '5', '6', '7',
0047   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
0048 };
0049 
0050 static const unsigned int maxQPLineLength = 76;
0051 
0052 } // namespace KCodecs
0053 
0054 
0055 /******************************** KCodecs ********************************/
0056 // strchr(3) for broken systems.
0057 static int rikFindChar(const char * _s, const char c)
0058 {
0059   const char * s = _s;
0060 
0061   while (true)
0062   {
0063     if ((0 == *s) || (c == *s)) break;
0064     ++s;
0065     if ((0 == *s) || (c == *s)) break;
0066     ++s;
0067     if ((0 == *s) || (c == *s)) break;
0068     ++s;
0069     if ((0 == *s) || (c == *s)) break;
0070     ++s;
0071   }
0072 
0073   return s - _s;
0074 }
0075 
0076 QByteArray KCodecs::quotedPrintableEncode(const QByteArray& in, bool useCRLF)
0077 {
0078   QByteArray out;
0079   quotedPrintableEncode (in, out, useCRLF);
0080   return out;
0081 }
0082 
0083 void KCodecs::quotedPrintableEncode(const QByteArray& in, QByteArray& out, bool useCRLF)
0084 {
0085   out.resize (0);
0086   if (in.isEmpty())
0087     return;
0088 
0089   char *cursor;
0090   const char *data;
0091   unsigned int lineLength = 0;
0092   unsigned int pos = 0;
0093 
0094   const unsigned int length = in.size();
0095   const unsigned int end = length - 1;
0096 
0097 
0098   // Reasonable guess for output size when we're encoding
0099   // mostly-ASCII data. It doesn't really matter, because
0100   // the underlying allocation routines are quite efficient,
0101   // but it's nice to have 0 allocations in many cases.
0102   out.resize ((length*12)/10);
0103   cursor = out.data();
0104   data = in.data();
0105 
0106   for (unsigned int i = 0; i < length; i++)
0107   {
0108     unsigned char c (data[i]);
0109 
0110     // check if we have to enlarge the output buffer, use
0111     // a safety margin of 16 byte
0112     pos = cursor-out.data();
0113     if (out.size()-pos < 16) {
0114       out.resize(out.size()+4096);
0115       cursor = out.data()+pos;
0116     }
0117 
0118     // Plain ASCII chars just go straight out.
0119 
0120     if ((c >= 33) && (c <= 126) && ('=' != c))
0121     {
0122       *cursor++ = c;
0123       ++lineLength;
0124     }
0125 
0126     // Spaces need some thought. We have to encode them at eol (or eof).
0127 
0128     else if (' ' == c)
0129     {
0130       if
0131         (
0132          (i >= length)
0133          ||
0134          ((i < end) && ((useCRLF && ('\r' == data[i + 1]) && ('\n' == data[i + 2]))
0135                         ||
0136                         (!useCRLF && ('\n' == data[i + 1]))))
0137         )
0138       {
0139         *cursor++ = '=';
0140         *cursor++ = '2';
0141         *cursor++ = '0';
0142 
0143         lineLength += 3;
0144       }
0145       else
0146       {
0147         *cursor++ = ' ';
0148         ++lineLength;
0149       }
0150     }
0151     // If we find a line break, just let it through.
0152     else if ((useCRLF && ('\r' == c) && (i < end) && ('\n' == data[i + 1])) ||
0153              (!useCRLF && ('\n' == c)))
0154     {
0155       lineLength = 0;
0156 
0157       if (useCRLF) {
0158         *cursor++ = '\r';
0159         *cursor++ = '\n';
0160         ++i;
0161       } else {
0162         *cursor++ = '\n';
0163       }
0164     }
0165 
0166     // Anything else is converted to =XX.
0167 
0168     else
0169     {
0170       *cursor++ = '=';
0171       *cursor++ = hexChars[c / 16];
0172       *cursor++ = hexChars[c % 16];
0173 
0174       lineLength += 3;
0175     }
0176 
0177     // If we're approaching the maximum line length, do a soft line break.
0178 
0179     if ((lineLength > maxQPLineLength) && (i < end))
0180     {
0181       if (useCRLF) {
0182         *cursor++ = '=';
0183         *cursor++ = '\r';
0184         *cursor++ = '\n';
0185       } else {
0186         *cursor++ = '=';
0187         *cursor++ = '\n';
0188       }
0189 
0190       lineLength = 0;
0191     }
0192   }
0193 
0194   out.truncate(cursor - out.data());
0195 }
0196 
0197 QByteArray KCodecs::quotedPrintableDecode(const QByteArray & in)
0198 {
0199   QByteArray out;
0200   quotedPrintableDecode (in, out);
0201   return out;
0202 }
0203 
0204 
0205 void KCodecs::quotedPrintableDecode(const QByteArray& in, QByteArray& out)
0206 {
0207   // clear out the output buffer
0208   out.resize (0);
0209   if (in.isEmpty())
0210       return;
0211 
0212   char *cursor;
0213   const unsigned int length = in.size();
0214 
0215   out.resize (length);
0216   cursor = out.data();
0217 
0218   for (unsigned int i = 0; i < length; i++)
0219   {
0220     char c(in[i]);
0221 
0222     if ('=' == c)
0223     {
0224       if (i < length - 2)
0225       {
0226         char c1 = in[i + 1];
0227         char c2 = in[i + 2];
0228 
0229         if (('\n' == c1) || ('\r' == c1 && '\n' == c2))
0230         {
0231           // Soft line break. No output.
0232           if ('\r' == c1)
0233             i += 2;        // CRLF line breaks
0234           else
0235             i += 1;
0236         }
0237         else
0238         {
0239           // =XX encoded byte.
0240 
0241           int hexChar0 = rikFindChar(hexChars, c1);
0242           int hexChar1 = rikFindChar(hexChars, c2);
0243 
0244           if (hexChar0 < 16 && hexChar1 < 16)
0245           {
0246             *cursor++ = char((hexChar0 * 16) | hexChar1);
0247             i += 2;
0248           }
0249         }
0250       }
0251     }
0252     else
0253     {
0254       *cursor++ = c;
0255     }
0256   }
0257 
0258   out.truncate(cursor - out.data());
0259 }