• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ================================================================ */
2 /*
3 File:   ConvertUTF7.c
4 Author: David B. Goldsmith
5 Copyright (C) 1994, 1996 IBM Corporation All rights reserved.
6 Revisions: Header update only July, 2001.
7 
8 This code is copyrighted. Under the copyright laws, this code may not
9 be copied, in whole or part, without prior written consent of IBM Corporation.
10 
11 IBM Corporation grants the right to use this code as long as this ENTIRE
12 copyright notice is reproduced in the code.  The code is provided
13 AS-IS, AND IBM CORPORATION DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR
14 IMPLIED, INCLUDING, BUT NOT LIMITED TO IMPLIED WARRANTIES OF
15 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT
16 WILL IBM CORPORATION BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING,
17 WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS
18 INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY
19 LOSS) ARISING OUT OF THE USE OR INABILITY TO USE THIS CODE, EVEN
20 IF IBM CORPORATION HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
21 BECAUSE SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF
22 LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE
23 LIMITATION MAY NOT APPLY TO YOU.
24 
25 RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
26 government is subject to restrictions as set forth in subparagraph
27 (c)(l)(ii) of the Rights in Technical Data and Computer Software
28 clause at DFARS 252.227-7013 and FAR 52.227-19.
29 
30 This code may be protected by one or more U.S. and International
31 Patents.
32 
33 */
34 
35 #include "CVTUTF7.H"
36 
37 static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
38 static short invbase64[128];
39 
40 static char direct[] =
41 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?";
42 static char optional[] = "!\"#$%&*;<=>@[]^_`{|}";
43 static char spaces[] = " \011\015\012";		/* space, tab, return, line feed */
44 static char mustshiftsafe[128];
45 static char mustshiftopt[128];
46 
47 static int needtables = 1;
48 
49 #define SHIFT_IN '+'
50 #define SHIFT_OUT '-'
51 
52 static void
tabinit()53 tabinit()
54 {
55 	int i, limit;
56 
57 	for (i = 0; i < 128; ++i)
58 	{
59 		mustshiftopt[i] = mustshiftsafe[i] = 1;
60 		invbase64[i] = -1;
61 	}
62 	limit = strlen(direct);
63 	for (i = 0; i < limit; ++i)
64 		mustshiftopt[direct[i]] = mustshiftsafe[direct[i]] = 0;
65 	limit = strlen(spaces);
66 	for (i = 0; i < limit; ++i)
67 		mustshiftopt[spaces[i]] = mustshiftsafe[spaces[i]] = 0;
68 	limit = strlen(optional);
69 	for (i = 0; i < limit; ++i)
70 		mustshiftopt[optional[i]] = 0;
71 	limit = strlen(base64);
72 	for (i = 0; i < limit; ++i)
73 		invbase64[base64[i]] = i;
74 
75 	needtables = 0;
76 }
77 
78 #define DECLARE_BIT_BUFFER register unsigned long BITbuffer = 0, buffertemp = 0; int bufferbits = 0
79 #define BITS_IN_BUFFER bufferbits
80 #define WRITE_N_BITS(x, n) ((BITbuffer |= ( ((x) & ~(-1L<<(n))) << (32-(n)-bufferbits) ) ), bufferbits += (n) )
81 #define READ_N_BITS(n) ((buffertemp = (BITbuffer >> (32-(n)))), (BITbuffer <<= (n)), (bufferbits -= (n)), buffertemp)
82 #define TARGETCHECK  {if (target >= targetEnd) {result = targetExhausted; break;}}
83 
ConvertUCS2toUTF7(UCS2 ** sourceStart,UCS2 * sourceEnd,char ** targetStart,char * targetEnd,int optional,int verbose)84 ConversionResult ConvertUCS2toUTF7(
85                 UCS2** sourceStart, UCS2* sourceEnd,
86                 char** targetStart, char* targetEnd,
87                 int optional, int verbose)
88 {
89 	ConversionResult result = ok;
90 	DECLARE_BIT_BUFFER;
91 	int shifted = 0, needshift = 0, done = 0;
92 	register UCS2 *source = *sourceStart;
93 	register char *target = *targetStart;
94 	char *mustshift;
95 
96 	if (needtables)
97 		tabinit();
98 
99 	if (optional)
100 		mustshift = mustshiftopt;
101 	else
102 		mustshift = mustshiftsafe;
103 
104 	do
105 	{
106 		register UCS2 r;
107 
108 		if (!(done = (source >= sourceEnd)))
109 			r = *source++;
110 		needshift = (!done && ((r > 0x7f) || mustshift[r]));
111 
112 		if (needshift && !shifted)
113 		{
114 			TARGETCHECK;
115 			*target++ = SHIFT_IN;
116 			/* Special case handling of the SHIFT_IN character */
117 			if (r == (UCS2)SHIFT_IN) {
118 				TARGETCHECK;
119 				*target++ = SHIFT_OUT;
120 			}
121 			else
122 				shifted = 1;
123 		}
124 
125 		if (shifted)
126 		{
127 			/* Either write the character to the bit buffer, or pad
128 			   the bit buffer out to a full base64 character.
129 			 */
130 			if (needshift)
131 				WRITE_N_BITS(r, 16);
132 			else
133 				WRITE_N_BITS(0, (6 - (BITS_IN_BUFFER % 6))%6);
134 
135 			/* Flush out as many full base64 characters as possible
136 			   from the bit buffer.
137 			 */
138 			while ((target < targetEnd) && BITS_IN_BUFFER >= 6)
139 			{
140 				*target++ = base64[READ_N_BITS(6)];
141 			}
142 
143 			if (BITS_IN_BUFFER >= 6)
144 				TARGETCHECK;
145 
146 			if (!needshift)
147 			{
148 				/* Write the explicit shift out character if
149 				   1) The caller has requested we always do it, or
150 				   2) The directly encoded character is in the
151 				   base64 set, or
152 				   3) The directly encoded character is SHIFT_OUT.
153 				 */
154 				if (verbose || ((!done) && (invbase64[r] >=0 || r == SHIFT_OUT)))
155 				{
156 					TARGETCHECK;
157 					*target++ = SHIFT_OUT;
158 				}
159 				shifted = 0;
160 			}
161 		}
162 
163 		/* The character can be directly encoded as ASCII. */
164 		if (!needshift && !done)
165 		{
166 			TARGETCHECK;
167 			*target++ = (char) r;
168 		}
169 
170 	}
171 	while (!done);
172 
173     *sourceStart = source;
174     *targetStart = target;
175     return result;
176 }
177 
ConvertUTF7toUCS2(char ** sourceStart,char * sourceEnd,UCS2 ** targetStart,UCS2 * targetEnd)178 ConversionResult ConvertUTF7toUCS2(
179                 char** sourceStart, char* sourceEnd,
180                 UCS2** targetStart, UCS2* targetEnd)
181 {
182 	ConversionResult result = ok;
183 	DECLARE_BIT_BUFFER;
184 	int shifted = 0, first = 0, wroteone = 0, base64EOF, base64value, done;
185 	unsigned int c, prevc;
186 	unsigned long junk;
187 	register char *source = *sourceStart;
188 	register UCS2 *target = *targetStart;
189 
190 	if (needtables)
191 		tabinit();
192 
193 	do
194 	{
195 		/* read an ASCII character c */
196 		if (!(done = (source >= sourceEnd)))
197 			c = *source++;
198 		if (shifted)
199 		{
200 			/* We're done with a base64 string if we hit EOF, it's not a valid
201 			   ASCII character, or it's not in the base64 set.
202 			 */
203 			base64EOF = done || (c > 0x7f) || (base64value = invbase64[c]) < 0;
204 			if (base64EOF)
205 			{
206 				shifted = 0;
207 				/* If the character causing us to drop out was SHIFT_IN or
208 				   SHIFT_OUT, it may be a special escape for SHIFT_IN. The
209 				   test for SHIFT_IN is not necessary, but allows an alternate
210 				   form of UTF-7 where SHIFT_IN is escaped by SHIFT_IN. This
211 				   only works for some values of SHIFT_IN.
212 				 */
213 				if (!done && (c == SHIFT_IN || c == SHIFT_OUT))
214 				{
215 					/* get another character c */
216 					prevc = c;
217 					if (!(done = (source >= sourceEnd)))
218 						c = *source++;
219 					/* If no base64 characters were encountered, and the
220 					   character terminating the shift sequence was
221 					   SHIFT_OUT, then it's a special escape for SHIFT_IN.
222 					 */
223 					if (first && prevc == SHIFT_OUT)
224 					{
225 						/* write SHIFT_IN unicode */
226 						TARGETCHECK;
227 						*target++ = (UCS2)SHIFT_IN;
228 					}
229 					else if (!wroteone)
230 					{
231 						result = sourceCorrupt;
232 						/* fprintf(stderr, "UTF7: empty sequence near byte %ld in input\n", source-sourceStart) */;
233 					}
234 				}
235 				else if (!wroteone)
236 				{
237 					result = sourceCorrupt;
238 					/* fprintf(stderr, "UTF7: empty sequence near byte %ld in input\n", source-sourceStart) */;
239 				}
240 			}
241 			else
242 			{
243 				/* Add another 6 bits of base64 to the bit buffer. */
244 				WRITE_N_BITS(base64value, 6);
245 				first = 0;
246 			}
247 
248 			/* Extract as many full 16 bit characters as possible from the
249 			   bit buffer.
250 			 */
251 			while (BITS_IN_BUFFER >= 16 && (target < targetEnd))
252 			{
253 				/* write a unicode */
254 				*target++ = READ_N_BITS(16);
255 				wroteone = 1;
256 			}
257 
258 			if (BITS_IN_BUFFER >= 16)
259 				TARGETCHECK;
260 
261 			if (base64EOF)
262 			{
263 				junk = READ_N_BITS(BITS_IN_BUFFER);
264 				if (junk)
265 				{
266 					result = sourceCorrupt;
267 					/* fprintf(stderr, "UTF7: non-zero pad bits near byte %ld in input\n", source-sourceStart) */;
268 				}
269 			}
270 		}
271 
272 		if (!shifted && !done)
273 		{
274 			if (c == SHIFT_IN)
275 			{
276 				shifted = 1;
277 				first = 1;
278 				wroteone = 0;
279 			}
280 			else
281 			{
282 				/* It must be a directly encoded character. */
283 				if (c > 0x7f)
284 				{
285 					result = sourceCorrupt;
286 					/* fprintf(stderr, "UTF7: non-ASCII character near byte %ld in input\n", source-sourceStart) */;
287 				}
288 				/* write a unicode */
289 				TARGETCHECK;
290 				*target++ = c;
291 			}
292 		}
293 	}
294 	while (!done);
295 
296     *sourceStart = source;
297     *targetStart = target;
298     return result;
299 }
300