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 "nsUTF7ToUnicode.h"
39 :
40 : #define ENC_DIRECT 0
41 : #define ENC_BASE64 1
42 :
43 : //----------------------------------------------------------------------
44 : // Class nsBasicUTF7Decoder [implementation]
45 :
46 12 : nsBasicUTF7Decoder::nsBasicUTF7Decoder(char aLastChar, char aEscChar)
47 12 : : nsBufferDecoderSupport(1)
48 : {
49 12 : mLastChar = aLastChar;
50 12 : mEscChar = aEscChar;
51 12 : Reset();
52 12 : }
53 :
54 60 : nsresult nsBasicUTF7Decoder::DecodeDirect(
55 : const char * aSrc,
56 : PRInt32 * aSrcLength,
57 : PRUnichar * aDest,
58 : PRInt32 * aDestLength)
59 : {
60 60 : const char * srcEnd = aSrc + *aSrcLength;
61 60 : const char * src = aSrc;
62 60 : PRUnichar * destEnd = aDest + *aDestLength;
63 60 : PRUnichar * dest = aDest;
64 60 : nsresult res = NS_OK;
65 : char ch;
66 :
67 234 : while (src < srcEnd) {
68 168 : ch = *src;
69 :
70 : // stop when we meet other chars or end of direct encoded seq.
71 : // if (!(DirectEncodable(ch)) || (ch == mEscChar)) {
72 : // but we are decoding; so we should be lax; pass everything until escchar
73 168 : if (ch == mEscChar) {
74 54 : res = NS_ERROR_UDEC_ILLEGALINPUT;
75 54 : break;
76 : }
77 :
78 114 : if (dest >= destEnd) {
79 0 : res = NS_OK_UDEC_MOREOUTPUT;
80 0 : break;
81 : } else {
82 114 : *dest++ = ch;
83 114 : src++;
84 : }
85 : }
86 :
87 60 : *aSrcLength = src - aSrc;
88 60 : *aDestLength = dest - aDest;
89 60 : return res;
90 : }
91 :
92 54 : nsresult nsBasicUTF7Decoder::DecodeBase64(
93 : const char * aSrc,
94 : PRInt32 * aSrcLength,
95 : PRUnichar * aDest,
96 : PRInt32 * aDestLength)
97 : {
98 54 : const char * srcEnd = aSrc + *aSrcLength;
99 54 : const char * src = aSrc;
100 54 : PRUnichar * destEnd = aDest + *aDestLength;
101 54 : PRUnichar * dest = aDest;
102 54 : nsresult res = NS_OK;
103 : char ch;
104 : PRUint32 value;
105 :
106 414 : while (src < srcEnd) {
107 360 : ch = *src;
108 :
109 : // stop when we meet other chars or end of direct encoded seq.
110 360 : value = CharToValue(ch);
111 360 : if (value > 0xff) {
112 54 : res = NS_ERROR_UDEC_ILLEGALINPUT;
113 54 : break;
114 : }
115 :
116 306 : switch (mEncStep) {
117 : case 0:
118 54 : mEncBits = value << 10;
119 54 : break;
120 : case 1:
121 54 : mEncBits += value << 4;
122 54 : break;
123 : case 2:
124 54 : if (dest >= destEnd) {
125 0 : res = NS_OK_UDEC_MOREOUTPUT;
126 0 : break;
127 : }
128 54 : mEncBits += value >> 2;
129 54 : *(dest++) = (PRUnichar) mEncBits;
130 54 : mEncBits = (value & 0x03) << 14;
131 54 : break;
132 : case 3:
133 36 : mEncBits += value << 8;
134 36 : break;
135 : case 4:
136 36 : mEncBits += value << 2;
137 36 : break;
138 : case 5:
139 36 : if (dest >= destEnd) {
140 0 : res = NS_OK_UDEC_MOREOUTPUT;
141 0 : break;
142 : }
143 36 : mEncBits += value >> 4;
144 36 : *(dest++) = (PRUnichar) mEncBits;
145 36 : mEncBits = (value & 0x0f) << 12;
146 36 : break;
147 : case 6:
148 18 : mEncBits += value << 6;
149 18 : break;
150 : case 7:
151 18 : if (dest >= destEnd) {
152 0 : res = NS_OK_UDEC_MOREOUTPUT;
153 0 : break;
154 : }
155 18 : mEncBits += value;
156 18 : *(dest++) = (PRUnichar) mEncBits;
157 18 : mEncBits = 0;
158 18 : break;
159 : }
160 :
161 306 : if (res != NS_OK) break;
162 :
163 306 : src++;
164 306 : (++mEncStep)%=8;
165 : }
166 :
167 54 : *aSrcLength = src - aSrc;
168 54 : *aDestLength = dest - aDest;
169 54 : return res;
170 : }
171 :
172 360 : PRUint32 nsBasicUTF7Decoder::CharToValue(char aChar) {
173 360 : if ((aChar>='A')&&(aChar<='Z'))
174 204 : return (PRUint8)(aChar-'A');
175 156 : else if ((aChar>='a')&&(aChar<='z'))
176 72 : return (PRUint8)(26+aChar-'a');
177 84 : else if ((aChar>='0')&&(aChar<='9'))
178 30 : return (PRUint8)(26+26+aChar-'0');
179 54 : else if (aChar=='+')
180 0 : return (PRUint8)(26+26+10);
181 54 : else if (aChar==mLastChar)
182 0 : return (PRUint8)(26+26+10+1);
183 : else
184 54 : return 0xffff;
185 : }
186 :
187 : //----------------------------------------------------------------------
188 : // Subclassing of nsBufferDecoderSupport class [implementation]
189 :
190 6 : NS_IMETHODIMP nsBasicUTF7Decoder::ConvertNoBuff(const char * aSrc,
191 : PRInt32 * aSrcLength,
192 : PRUnichar * aDest,
193 : PRInt32 * aDestLength)
194 : {
195 6 : const char * srcEnd = aSrc + *aSrcLength;
196 6 : const char * src = aSrc;
197 6 : PRUnichar * destEnd = aDest + *aDestLength;
198 6 : PRUnichar * dest = aDest;
199 : PRInt32 bcr,bcw;
200 6 : nsresult res = NS_OK;
201 : char ch;
202 :
203 126 : while (src < srcEnd) {
204 114 : ch = *src;
205 :
206 : // fist, attept to decode in the current mode
207 114 : bcr = srcEnd - src;
208 114 : bcw = destEnd - dest;
209 114 : if (mEncoding == ENC_DIRECT)
210 60 : res = DecodeDirect(src, &bcr, dest, &bcw);
211 54 : else if ((mFreshBase64) && (*src == '-')) {
212 0 : *dest = mEscChar;
213 0 : bcr = 0;
214 0 : bcw = 1;
215 0 : res = NS_ERROR_UDEC_ILLEGALINPUT;
216 : } else {
217 54 : mFreshBase64 = false;
218 54 : res = DecodeBase64(src, &bcr, dest, &bcw);
219 : }
220 114 : src += bcr;
221 114 : dest += bcw;
222 :
223 : // if an illegal char was encountered, test if it is an escape seq.
224 114 : if (res == NS_ERROR_UDEC_ILLEGALINPUT) {
225 108 : if (mEncoding == ENC_DIRECT) {
226 54 : if (*src == mEscChar) {
227 54 : mEncoding = ENC_BASE64;
228 54 : mFreshBase64 = true;
229 54 : mEncBits = 0;
230 54 : mEncStep = 0;
231 54 : src++;
232 54 : res = NS_OK;
233 0 : } else break;
234 : } else {
235 54 : mEncoding = ENC_DIRECT;
236 54 : res = NS_OK;
237 : // absorbe end of escape sequence
238 54 : if (*src == '-') src++;
239 : }
240 6 : } else if (res != NS_OK) break;
241 : }
242 :
243 6 : *aSrcLength = src - aSrc;
244 6 : *aDestLength = dest - aDest;
245 6 : return res;
246 : }
247 :
248 12 : NS_IMETHODIMP nsBasicUTF7Decoder::Reset()
249 : {
250 12 : mEncoding = ENC_DIRECT;
251 12 : mEncBits = 0;
252 12 : mEncStep = 0;
253 12 : return nsBufferDecoderSupport::Reset();
254 : }
255 :
256 : //----------------------------------------------------------------------
257 : // Class nsUTF7ToUnicode [implementation]
258 :
259 12 : nsUTF7ToUnicode::nsUTF7ToUnicode()
260 12 : : nsBasicUTF7Decoder('/', '+')
261 : {
262 12 : }
|