1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsUnicodeToUTF7.h"
39 : #include <string.h>
40 :
41 : //----------------------------------------------------------------------
42 : // Global functions and data [declaration]
43 :
44 : #define ENC_DIRECT 0
45 : #define ENC_BASE64 1
46 :
47 : //----------------------------------------------------------------------
48 : // Class nsBasicUTF7Encoder [implementation]
49 :
50 27 : nsBasicUTF7Encoder::nsBasicUTF7Encoder(char aLastChar, char aEscChar)
51 27 : : nsEncoderSupport(5)
52 : {
53 27 : mLastChar = aLastChar;
54 27 : mEscChar = aEscChar;
55 27 : Reset();
56 27 : }
57 :
58 120 : nsresult nsBasicUTF7Encoder::ShiftEncoding(PRInt32 aEncoding,
59 : char * aDest,
60 : PRInt32 * aDestLength)
61 : {
62 120 : if (aEncoding == mEncoding) {
63 12 : *aDestLength = 0;
64 12 : return NS_OK;
65 : }
66 :
67 108 : nsresult res = NS_OK;
68 108 : char * dest = aDest;
69 108 : char * destEnd = aDest + *aDestLength;
70 :
71 108 : if (mEncStep != 0) {
72 36 : if (dest >= destEnd) return NS_OK_UENC_MOREOUTPUT;
73 36 : *(dest++)=ValueToChar(mEncBits);
74 36 : mEncStep = 0;
75 36 : mEncBits = 0;
76 : }
77 :
78 108 : if (dest >= destEnd) {
79 0 : res = NS_OK_UENC_MOREOUTPUT;
80 : } else {
81 108 : switch (aEncoding) {
82 : case 0:
83 54 : *(dest++) = '-';
84 54 : mEncStep = 0;
85 54 : mEncBits = 0;
86 54 : break;
87 : case 1:
88 54 : *(dest++) = mEscChar;
89 54 : break;
90 : }
91 108 : mEncoding = aEncoding;
92 : }
93 :
94 108 : *aDestLength = dest - aDest;
95 108 : return res;
96 : }
97 :
98 54 : nsresult nsBasicUTF7Encoder::EncodeDirect(
99 : const PRUnichar * aSrc,
100 : PRInt32 * aSrcLength,
101 : char * aDest,
102 : PRInt32 * aDestLength)
103 : {
104 54 : nsresult res = NS_OK;
105 54 : const PRUnichar * src = aSrc;
106 54 : const PRUnichar * srcEnd = aSrc + *aSrcLength;
107 54 : char * dest = aDest;
108 54 : char * destEnd = aDest + *aDestLength;
109 : PRUnichar ch;
110 :
111 222 : while (src < srcEnd) {
112 162 : ch = *src;
113 :
114 : // stop when we reach Unicode chars
115 162 : if (!DirectEncodable(ch)) break;
116 :
117 114 : if (ch == mEscChar) {
118 : // special case for the escape char
119 0 : if (destEnd - dest < 1) {
120 0 : res = NS_OK_UENC_MOREOUTPUT;
121 0 : break;
122 : } else {
123 0 : *dest++ = (char)ch;
124 0 : *dest++ = (char)'-';
125 0 : src++;
126 : }
127 : } else {
128 : //classic direct encoding
129 114 : if (dest >= destEnd) {
130 0 : res = NS_OK_UENC_MOREOUTPUT;
131 0 : break;
132 : } else {
133 114 : *dest++ = (char)ch;
134 114 : src++;
135 : }
136 : }
137 : }
138 :
139 54 : *aSrcLength = src - aSrc;
140 54 : *aDestLength = dest - aDest;
141 54 : return res;
142 : }
143 :
144 54 : nsresult nsBasicUTF7Encoder::EncodeBase64(
145 : const PRUnichar * aSrc,
146 : PRInt32 * aSrcLength,
147 : char * aDest,
148 : PRInt32 * aDestLength)
149 : {
150 54 : nsresult res = NS_OK;
151 54 : const PRUnichar * src = aSrc;
152 54 : const PRUnichar * srcEnd = aSrc + *aSrcLength;
153 54 : char * dest = aDest;
154 54 : char * destEnd = aDest + *aDestLength;
155 : PRUnichar ch;
156 : PRUint32 value;
157 :
158 216 : while (src < srcEnd) {
159 162 : ch = *src;
160 :
161 : // stop when we reach printable US-ASCII chars
162 162 : if (DirectEncodable(ch)) break;
163 :
164 108 : switch (mEncStep) {
165 : case 0:
166 54 : if (destEnd - dest < 2) {
167 0 : res = NS_OK_UENC_MOREOUTPUT;
168 0 : break;
169 : }
170 54 : value=ch>>10;
171 54 : *(dest++)=ValueToChar(value);
172 54 : value=(ch>>4)&0x3f;
173 54 : *(dest++)=ValueToChar(value);
174 54 : mEncBits=(ch&0x0f)<<2;
175 54 : break;
176 : case 1:
177 36 : if (destEnd - dest < 3) {
178 0 : res = NS_OK_UENC_MOREOUTPUT;
179 0 : break;
180 : }
181 36 : value=mEncBits+(ch>>14);
182 36 : *(dest++)=ValueToChar(value);
183 36 : value=(ch>>8)&0x3f;
184 36 : *(dest++)=ValueToChar(value);
185 36 : value=(ch>>2)&0x3f;
186 36 : *(dest++)=ValueToChar(value);
187 36 : mEncBits=(ch&0x03)<<4;
188 36 : break;
189 : case 2:
190 18 : if (destEnd - dest < 3) {
191 0 : res = NS_OK_UENC_MOREOUTPUT;
192 0 : break;
193 : }
194 18 : value=mEncBits+(ch>>12);
195 18 : *(dest++)=ValueToChar(value);
196 18 : value=(ch>>6)&0x3f;
197 18 : *(dest++)=ValueToChar(value);
198 18 : value=ch&0x3f;
199 18 : *(dest++)=ValueToChar(value);
200 18 : mEncBits=0;
201 18 : break;
202 : }
203 :
204 108 : if (res != NS_OK) break;
205 :
206 108 : src++;
207 108 : (++mEncStep)%=3;
208 : }
209 :
210 54 : *aSrcLength = src - aSrc;
211 54 : *aDestLength = dest - aDest;
212 54 : return res;
213 : }
214 :
215 306 : char nsBasicUTF7Encoder::ValueToChar(PRUint32 aValue) {
216 306 : if (aValue < 26)
217 204 : return (char)('A'+aValue);
218 102 : else if (aValue < 26 + 26)
219 72 : return (char)('a' + aValue - 26);
220 30 : else if (aValue < 26 + 26 + 10)
221 30 : return (char)('0' + aValue - 26 - 26);
222 0 : else if (aValue == 26 + 26 + 10)
223 0 : return '+';
224 0 : else if (aValue == 26 + 26 + 10 + 1)
225 0 : return mLastChar;
226 : else
227 0 : return -1;
228 : }
229 :
230 0 : bool nsBasicUTF7Encoder::DirectEncodable(PRUnichar aChar) {
231 : // spec says: printable US-ASCII chars
232 0 : if ((aChar >= 0x20) && (aChar <= 0x7e)) return true;
233 0 : else return false;
234 : }
235 :
236 : //----------------------------------------------------------------------
237 : // Subclassing of nsEncoderSupport class [implementation]
238 :
239 6 : NS_IMETHODIMP nsBasicUTF7Encoder::ConvertNoBuffNoErr(
240 : const PRUnichar * aSrc,
241 : PRInt32 * aSrcLength,
242 : char * aDest,
243 : PRInt32 * aDestLength)
244 : {
245 6 : nsresult res = NS_OK;
246 6 : const PRUnichar * src = aSrc;
247 6 : const PRUnichar * srcEnd = aSrc + *aSrcLength;
248 6 : char * dest = aDest;
249 6 : char * destEnd = aDest + *aDestLength;
250 : PRInt32 bcr,bcw;
251 : PRUnichar ch;
252 : PRInt32 enc;
253 :
254 120 : while (src < srcEnd) {
255 : // find the encoding for the next char
256 108 : ch = *src;
257 108 : if (DirectEncodable(ch))
258 54 : enc = ENC_DIRECT;
259 : else
260 54 : enc = ENC_BASE64;
261 :
262 : // if necessary, shift into the required encoding
263 108 : bcw = destEnd - dest;
264 108 : res = ShiftEncoding(enc, dest, &bcw);
265 108 : dest += bcw;
266 108 : if (res != NS_OK) break;
267 :
268 : // now encode (as much as you can)
269 108 : bcr = srcEnd - src;
270 108 : bcw = destEnd - dest;
271 108 : if (enc == ENC_DIRECT)
272 54 : res = EncodeDirect(src, &bcr, dest, &bcw);
273 : else
274 54 : res = EncodeBase64(src, &bcr, dest, &bcw);
275 108 : src += bcr;
276 108 : dest += bcw;
277 :
278 108 : if (res != NS_OK) break;
279 : }
280 :
281 6 : *aSrcLength = src - aSrc;
282 6 : *aDestLength = dest - aDest;
283 6 : return res;
284 : }
285 :
286 12 : NS_IMETHODIMP nsBasicUTF7Encoder::FinishNoBuff(char * aDest,
287 : PRInt32 * aDestLength)
288 : {
289 12 : return ShiftEncoding(ENC_DIRECT, aDest, aDestLength);
290 : }
291 :
292 27 : NS_IMETHODIMP nsBasicUTF7Encoder::Reset()
293 : {
294 27 : mEncoding = ENC_DIRECT;
295 27 : mEncBits = 0;
296 27 : mEncStep = 0;
297 27 : return nsEncoderSupport::Reset();
298 : }
299 :
300 : //----------------------------------------------------------------------
301 : // Class nsUnicodeToUTF7 [implementation]
302 :
303 26 : nsUnicodeToUTF7::nsUnicodeToUTF7()
304 26 : : nsBasicUTF7Encoder('/', '+')
305 : {
306 26 : }
307 :
308 :
309 432 : bool nsUnicodeToUTF7::DirectEncodable(PRUnichar aChar) {
310 432 : if ((aChar >= 'A') && (aChar <= 'Z')) return true;
311 414 : else if ((aChar >= 'a') && (aChar <= 'z')) return true;
312 342 : else if ((aChar >= '0') && (aChar <= '9')) return true;
313 342 : else if ((aChar >= 39) && (aChar <= 41)) return true;
314 342 : else if ((aChar >= 44) && (aChar <= 47)) return true;
315 324 : else if (aChar == 58) return true;
316 324 : else if (aChar == 63) return true;
317 324 : else if (aChar == ' ') return true;
318 210 : else if (aChar == 9) return true;
319 210 : else if (aChar == 13) return true;
320 210 : else if (aChar == 10) return true;
321 210 : else if (aChar == 60) return true; // '<'
322 210 : else if (aChar == 33) return true; // '!'
323 210 : else if (aChar == 34) return true; // '"'
324 210 : else if (aChar == 62) return true; // '>'
325 210 : else if (aChar == 61) return true; // '='
326 210 : else if (aChar == 59) return true; // ';'
327 210 : else if (aChar == 91) return true; // '['
328 210 : else if (aChar == 93) return true; // ']'
329 210 : else return false;
330 : }
|