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 }