xref: /trunk/main/sal/textenc/tcvtutf7.c (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "tenchelp.h"
29 #include "unichars.h"
30 
31 #ifndef _RTL_ALLOC_H
32 #include "rtl/alloc.h"
33 #endif
34 #include "rtl/textcvt.h"
35 
36 /* ======================================================================= */
37 
38 static sal_uChar const aImplBase64Tab[64] =
39 {
40     /* A-Z */
41           0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
42     0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
43     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
44     0x58, 0x59, 0x5A,
45     /* a-z */
46           0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
47     0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
48     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
49     0x78, 0x79, 0x7A,
50     /* 0-9,+,/ */
51     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
52     0x38, 0x39, 0x2B, 0x2F
53 };
54 
55 /* Index in Base64Tab or 0xFF, when is a invalid character */
56 static sal_uChar const aImplBase64IndexTab[128] =
57 {
58     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x00-0x07 */
59     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x08-0x0F */
60     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x10-0x17 */
61     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x18-0x1F */
62     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x20-0x27  !"#$%&' */
63     0xFF, 0xFF, 0xFF,   62, 0xFF, 0xFF, 0xFF,   63,     /* 0x28-0x2F ()*+,-./ */
64       52,   53,   54,   55,   56,   57,   58,   59,     /* 0x30-0x37 01234567 */
65       60,   61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x38-0x3F 89:;<=>? */
66     0xFF,    0,    1,    2,    3,    4,    5,    6,     /* 0x40-0x47 @ABCDEFG */
67        7,    8,    9,   10,   11,   12,   13,   14,     /* 0x48-0x4F HIJKLMNO */
68       15,   16,   17,   18,   19,   20,   21,   22,     /* 0x50-0x57 PQRSTUVW */
69       23,   24,   25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,     /* 0x58-0x5F XYZ[\]^_ */
70     0xFF,   26,   27,   28,   29,   30,   31,   32,     /* 0x60-0x67 `abcdefg */
71       33,   34,   35,   36,   37,   38,   39,   40,     /* 0x68-0x6F hijklmno */
72       41,   42,   43,   44,   45,   46,   47,   48,     /* 0x70-0x77 pqrstuvw */
73       49,   50,   51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF      /* 0x78-0x7F xyz{|}~ */
74 };
75 
76 static sal_uChar const aImplMustShiftTab[128] =
77 {
78     1, 1, 1, 1, 1, 1, 1, 1,     /* 0x00-0x07 */
79     1, 0, 0, 1, 0, 1, 1, 1,     /* 0x08-0x0F 0x09 == HTAB, 0x0A == LF 0x0C == CR */
80     1, 1, 1, 1, 1, 1, 1, 1,     /* 0x10-0x17 */
81     1, 1, 1, 1, 1, 1, 1, 1,     /* 0x18-0x1F */
82     0, 1, 1, 1, 1, 1, 1, 0,     /* 0x20-0x27  !"#$%&' */
83     0, 0, 1, 1, 0, 1, 0, 0,     /* 0x28-0x2F ()*+,-./ */
84     0, 0, 0, 0, 0, 0, 0, 0,     /* 0x30-0x37 01234567 */
85     0, 0, 0, 1, 1, 1, 1, 0,     /* 0x38-0x3F 89:;<=>? */
86     1, 0, 0, 0, 0, 0, 0, 0,     /* 0x40-0x47 @ABCDEFG */
87     0, 0, 0, 0, 0, 0, 0, 0,     /* 0x48-0x4F HIJKLMNO */
88     0, 0, 0, 0, 0, 0, 0, 0,     /* 0x50-0x57 PQRSTUVW */
89     0, 0, 0, 1, 1, 1, 1, 1,     /* 0x58-0x5F XYZ[\]^_ */
90     1, 0, 0, 0, 0, 0, 0, 0,     /* 0x60-0x67 `abcdefg */
91     0, 0, 0, 0, 0, 0, 0, 0,     /* 0x68-0x6F hijklmno */
92     0, 0, 0, 0, 0, 0, 0, 0,     /* 0x70-0x77 pqrstuvw */
93     0, 0, 0, 1, 1, 1, 1, 1      /* 0x78-0x7F xyz{|}~ */
94 };
95 
96 /* + */
97 #define IMPL_SHIFT_IN_CHAR      0x2B
98 /* - */
99 #define IMPL_SHIFT_OUT_CHAR     0x2D
100 
101 /* ----------------------------------------------------------------------- */
102 
103 typedef struct
104 {
105     int                     mbShifted;
106     int                     mbFirst;
107     int                     mbWroteOne;
108     sal_uInt32              mnBitBuffer;
109     sal_uInt32              mnBufferBits;
110 } ImplUTF7ToUCContextData;
111 
112 /* ----------------------------------------------------------------------- */
113 
114 void* ImplUTF7CreateUTF7TextToUnicodeContext( void )
115 {
116     ImplUTF7ToUCContextData* pContextData;
117     pContextData = (ImplUTF7ToUCContextData*)rtl_allocateMemory( sizeof( ImplUTF7ToUCContextData ) );
118     pContextData->mbShifted         = sal_False;
119     pContextData->mbFirst           = sal_False;
120     pContextData->mbWroteOne        = sal_False;
121     pContextData->mnBitBuffer       = 0;
122     pContextData->mnBufferBits      = 0;
123     return (void*)pContextData;
124 }
125 
126 /* ----------------------------------------------------------------------- */
127 
128 void ImplUTF7DestroyTextToUnicodeContext( void* pContext )
129 {
130     rtl_freeMemory( pContext );
131 }
132 
133 /* ----------------------------------------------------------------------- */
134 
135 void ImplUTF7ResetTextToUnicodeContext( void* pContext )
136 {
137     ImplUTF7ToUCContextData* pContextData = (ImplUTF7ToUCContextData*)pContext;
138     pContextData->mbShifted         = sal_False;
139     pContextData->mbFirst           = sal_False;
140     pContextData->mbWroteOne        = sal_False;
141     pContextData->mnBitBuffer       = 0;
142     pContextData->mnBufferBits      = 0;
143 }
144 
145 /* ----------------------------------------------------------------------- */
146 
147 sal_Size ImplUTF7ToUnicode( const ImplTextConverterData* pData, void* pContext,
148                             const sal_Char* pSrcBuf, sal_Size nSrcBytes,
149                             sal_Unicode* pDestBuf, sal_Size nDestChars,
150                             sal_uInt32 nFlags, sal_uInt32* pInfo,
151                             sal_Size* pSrcCvtBytes )
152 {
153     ImplUTF7ToUCContextData*    pContextData = (ImplUTF7ToUCContextData*)pContext;
154     sal_uChar                   c ='\0';
155     sal_uChar                   nBase64Value = 0;
156     int                         bEnd = sal_False;
157     int                         bShifted;
158     int                         bFirst;
159     int                         bWroteOne;
160     int                         bBase64End;
161     sal_uInt32                  nBitBuffer;
162     sal_uInt32                  nBitBufferTemp;
163     sal_uInt32                  nBufferBits;
164     sal_Unicode*                pEndDestBuf;
165     const sal_Char*             pEndSrcBuf;
166 
167     (void) pData; /* unused */
168 
169 /* !!! Implementation not finnished !!!
170     if ( pContextData )
171     {
172         bShifted        = pContextData->mbShifted;
173         bFirst          = pContextData->mbFirst;
174         bWroteOne       = pContextData->mbWroteOne;
175         nBitBuffer      = pContextData->mnBitBuffer;
176         nBufferBits     = pContextData->mnBufferBits;
177     }
178     else
179 */
180     {
181         bShifted        = sal_False;
182         bFirst          = sal_False;
183         bWroteOne       = sal_False;
184         nBitBuffer      = 0;
185         nBufferBits     = 0;
186     }
187 
188     *pInfo = 0;
189     pEndDestBuf = pDestBuf+nDestChars;
190     pEndSrcBuf  = pSrcBuf+nSrcBytes;
191     do
192     {
193         if ( pSrcBuf < pEndSrcBuf )
194         {
195             c = (sal_uChar)*pSrcBuf;
196 
197             /* End, when not a base64 character */
198             bBase64End = sal_False;
199             if ( c <= 0x7F )
200             {
201                 nBase64Value = aImplBase64IndexTab[c];
202                 if ( nBase64Value == 0xFF )
203                     bBase64End = sal_True;
204             }
205         }
206         else
207         {
208             bEnd = sal_True;
209             bBase64End = sal_True;
210         }
211 
212         if ( bShifted )
213         {
214             if ( bBase64End )
215             {
216                 bShifted = sal_False;
217 
218                 /* If the character causing us to drop out was SHIFT_IN */
219                 /* or SHIFT_OUT, it may be a special escape for SHIFT_IN. */
220                 /* The test for SHIFT_IN is not necessary, but allows */
221                 /* an alternate form of UTF-7 where SHIFT_IN is escaped */
222                 /* by SHIFT_IN. This only works for some values of */
223                 /* SHIFT_IN. It is so implemented, because this comes */
224                 /* from the officel unicode book (The Unicode Standard, */
225                 /* Version 2.0) and so I think, that someone of the */
226                 /* world has used this feature. */
227                 if ( !bEnd )
228                 {
229                     if ( (c == IMPL_SHIFT_IN_CHAR) || (c == IMPL_SHIFT_OUT_CHAR) )
230                     {
231                         /* If no base64 character, and the terminating */
232                         /* character of the shift sequence was the */
233                         /* SHIFT_OUT_CHAR, then it't a special escape */
234                         /* for SHIFT_IN_CHAR. */
235                         if ( bFirst && (c == IMPL_SHIFT_OUT_CHAR) )
236                         {
237                             if ( pDestBuf >= pEndDestBuf )
238                             {
239                                 *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
240                                 break;
241                             }
242                             *pDestBuf = IMPL_SHIFT_IN_CHAR;
243                             pDestBuf++;
244                             bWroteOne = sal_True;
245                         }
246 
247                         /* Skip character */
248                         pSrcBuf++;
249                         if ( pSrcBuf < pEndSrcBuf )
250                             c = (sal_uChar)*pSrcBuf;
251                         else
252                             bEnd = sal_True;
253                     }
254                 }
255 
256                 /* Empty sequence not allowed, so when we don't write one */
257                 /* valid char, then the sequence is corrupt */
258                 if ( !bWroteOne )
259                 {
260                     /* When no more bytes in the source buffer, then */
261                     /* this buffer may be to small */
262                     if ( bEnd )
263                         *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL;
264                     else
265                     {
266                         *pInfo |= RTL_TEXTTOUNICODE_INFO_INVALID;
267                         if ( (nFlags & RTL_TEXTTOUNICODE_FLAGS_INVALID_MASK) == RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR )
268                         {
269                             *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR;
270                             break;
271                         }
272                         /* We insert here no default char, because I think */
273                         /* this is better to ignore this */
274                     }
275                 }
276             }
277             else
278             {
279                 /* Add 6 Bits from character to the bit buffer */
280                 nBufferBits += 6;
281                 nBitBuffer |= ((sal_uInt32)(nBase64Value & 0x3F)) << (32-nBufferBits);
282                 bFirst = sal_False;
283             }
284 
285             /* Extract as many full 16 bit characters as possible from the */
286             /* bit buffer. */
287             while ( (pDestBuf < pEndDestBuf) && (nBufferBits >= 16) )
288             {
289                 nBitBufferTemp = nBitBuffer >> (32-16);
290                 *pDestBuf = (sal_Unicode)((nBitBufferTemp) & 0xFFFF);
291                 pDestBuf++;
292                 nBitBuffer <<= 16;
293                 nBufferBits -= 16;
294                 bWroteOne = sal_True;
295             }
296 
297             if ( nBufferBits >= 16 )
298             {
299                 *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
300                 break;
301             }
302 
303             if ( bBase64End )
304             {
305                 /* Sequence ended and we have some bits, then the */
306                 /* sequence is corrupted */
307                 if ( nBufferBits && nBitBuffer )
308                 {
309                     /* When no more bytes in the source buffer, then */
310                     /* this buffer may be to small */
311                     if ( bEnd )
312                         *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL;
313                     else
314                     {
315                         *pInfo |= RTL_TEXTTOUNICODE_INFO_INVALID;
316                         if ( (nFlags & RTL_TEXTTOUNICODE_FLAGS_INVALID_MASK) == RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR )
317                         {
318                             *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR;
319                             break;
320                         }
321                         else if ( (nFlags & RTL_TEXTTOUNICODE_FLAGS_INVALID_MASK) != RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE )
322                         {
323                             if ( pDestBuf >= pEndDestBuf )
324                             {
325                                 *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
326                                 break;
327                             }
328                             *pDestBuf++
329                                 = RTL_TEXTENC_UNICODE_REPLACEMENT_CHARACTER;
330                         }
331                     }
332 
333                 }
334 
335                 nBitBuffer = 0;
336                 nBufferBits = 0;
337             }
338         }
339 
340         if ( !bEnd )
341         {
342             if ( !bShifted )
343             {
344                 if ( c == IMPL_SHIFT_IN_CHAR )
345                 {
346                     bShifted    = sal_True;
347                     bFirst      = sal_True;
348                     bWroteOne   = sal_False;
349                 }
350                 else
351                 {
352                     /* No direct encoded charcater, then the buffer is */
353                     /* corrupt */
354                     if ( c > 0x7F )
355                     {
356                         *pInfo |= RTL_TEXTTOUNICODE_INFO_INVALID;
357                         if ( (nFlags & RTL_TEXTTOUNICODE_FLAGS_INVALID_MASK) == RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR )
358                         {
359                             *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR;
360                             break;
361                         }
362                         else if ( (nFlags & RTL_TEXTTOUNICODE_FLAGS_INVALID_MASK) != RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE )
363                         {
364                             if ( pDestBuf >= pEndDestBuf )
365                             {
366                                 *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
367                                 break;
368                             }
369                             *pDestBuf++
370                                 = RTL_TEXTENC_UNICODE_REPLACEMENT_CHARACTER;
371                         }
372                     }
373 
374                     /* Write char to unicode buffer */
375                     if ( pDestBuf >= pEndDestBuf )
376                     {
377                         *pInfo |= RTL_TEXTTOUNICODE_INFO_ERROR | RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
378                         break;
379                     }
380                     *pDestBuf = c;
381                     pDestBuf++;
382                 }
383             }
384 
385             pSrcBuf++;
386         }
387     }
388     while ( !bEnd );
389 
390     if ( pContextData )
391     {
392         pContextData->mbShifted         = bShifted;
393         pContextData->mbFirst           = bFirst;
394         pContextData->mbWroteOne        = bWroteOne;
395         pContextData->mnBitBuffer       = nBitBuffer;
396         pContextData->mnBufferBits      = nBufferBits;
397     }
398 
399     *pSrcCvtBytes = nSrcBytes - (pEndSrcBuf-pSrcBuf);
400     return (nDestChars - (pEndDestBuf-pDestBuf));
401 }
402 
403 /* ======================================================================= */
404 
405 typedef struct
406 {
407     int                     mbShifted;
408     sal_uInt32              mnBitBuffer;
409     sal_uInt32              mnBufferBits;
410 } ImplUTF7FromUCContextData;
411 
412 /* ----------------------------------------------------------------------- */
413 
414 void* ImplUTF7CreateUnicodeToTextContext( void )
415 {
416     ImplUTF7FromUCContextData* pContextData;
417     pContextData = (ImplUTF7FromUCContextData*)rtl_allocateMemory( sizeof( ImplUTF7FromUCContextData ) );
418     pContextData->mbShifted         = sal_False;
419     pContextData->mnBitBuffer       = 0;
420     pContextData->mnBufferBits      = 0;
421     return (void*)pContextData;
422 }
423 
424 /* ----------------------------------------------------------------------- */
425 
426 void ImplUTF7DestroyUnicodeToTextContext( void* pContext )
427 {
428     rtl_freeMemory( pContext );
429 }
430 
431 /* ----------------------------------------------------------------------- */
432 
433 void ImplUTF7ResetUnicodeToTextContext( void* pContext )
434 {
435     ImplUTF7FromUCContextData* pContextData = (ImplUTF7FromUCContextData*)pContext;
436     pContextData->mbShifted         = sal_False;
437     pContextData->mnBitBuffer       = 0;
438     pContextData->mnBufferBits      = 0;
439 }
440 
441 /* ----------------------------------------------------------------------- */
442 
443 sal_Size ImplUnicodeToUTF7( const ImplTextConverterData* pData, void* pContext,
444                             const sal_Unicode* pSrcBuf, sal_Size nSrcChars,
445                             sal_Char* pDestBuf, sal_Size nDestBytes,
446                             sal_uInt32 nFlags, sal_uInt32* pInfo,
447                             sal_Size* pSrcCvtChars )
448 {
449     ImplUTF7FromUCContextData*  pContextData = (ImplUTF7FromUCContextData*)pContext;
450     sal_Unicode                 c = '\0';
451     int                         bEnd = sal_False;
452     int                         bShifted;
453     int                         bNeedShift;
454     sal_uInt32                  nBitBuffer;
455     sal_uInt32                  nBitBufferTemp;
456     sal_uInt32                  nBufferBits;
457     sal_Char*                   pEndDestBuf;
458     const sal_Unicode*          pEndSrcBuf;
459 
460     (void) pData; /* unused */
461     (void) nFlags; /* unused */
462 
463 /* !!! Implementation not finnished !!!
464     if ( pContextData )
465     {
466         bShifted        = pContextData->mbShifted;
467         nBitBuffer      = pContextData->mnBitBuffer;
468         nBufferBits     = pContextData->mnBufferBits;
469     }
470     else
471 */
472     {
473         bShifted        = sal_False;
474         nBitBuffer      = 0;
475         nBufferBits     = 0;
476     }
477 
478     *pInfo = 0;
479     pEndDestBuf = pDestBuf+nDestBytes;
480     pEndSrcBuf  = pSrcBuf+nSrcChars;
481     do
482     {
483         if ( pSrcBuf < pEndSrcBuf )
484         {
485             c = *pSrcBuf;
486 
487             bNeedShift = (c > 0x7F) || aImplMustShiftTab[c];
488             if ( bNeedShift && !bShifted )
489             {
490                 if ( pDestBuf >= pEndDestBuf )
491                 {
492                     *pInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
493                     break;
494                 }
495                 *pDestBuf = IMPL_SHIFT_IN_CHAR;
496                 pDestBuf++;
497                 /* Special case handling for SHIFT_IN_CHAR */
498                 if ( c == IMPL_SHIFT_IN_CHAR )
499                 {
500                     if ( pDestBuf >= pEndDestBuf )
501                     {
502                         *pInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
503                         break;
504                     }
505                     *pDestBuf = IMPL_SHIFT_OUT_CHAR;
506                     pDestBuf++;
507                 }
508                 else
509                     bShifted = sal_True;
510             }
511         }
512         else
513         {
514             bEnd = sal_True;
515             bNeedShift = sal_False;
516         }
517 
518         if ( bShifted )
519         {
520             /* Write the character to the bit buffer, or pad the bit */
521             /* buffer out to a full base64 character */
522             if ( bNeedShift )
523             {
524                 nBufferBits += 16;
525                 nBitBuffer |= ((sal_uInt32)c) << (32-nBufferBits);
526             }
527             else
528                 nBufferBits += (6-(nBufferBits%6))%6;
529 
530             /* Flush out as many full base64 characters as possible */
531             while ( (pDestBuf < pEndDestBuf) && (nBufferBits >= 6) )
532             {
533                 nBitBufferTemp = nBitBuffer >> (32-6);
534                 *pDestBuf = aImplBase64Tab[nBitBufferTemp];
535                 pDestBuf++;
536                 nBitBuffer <<= 6;
537                 nBufferBits -= 6;
538             }
539 
540             if ( nBufferBits >= 6 )
541             {
542                 *pInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
543                 break;
544             }
545 
546             /* Write SHIFT_OUT_CHAR, when needed */
547             if ( !bNeedShift )
548             {
549                 if ( pDestBuf >= pEndDestBuf )
550                 {
551                     *pInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
552                     break;
553                 }
554                 *pDestBuf = IMPL_SHIFT_OUT_CHAR;
555                 pDestBuf++;
556                 bShifted = sal_False;
557             }
558         }
559 
560         if ( !bEnd )
561         {
562             /* Character can be directly endcoded */
563             if ( !bNeedShift )
564             {
565                 if ( pDestBuf >= pEndDestBuf )
566                 {
567                     *pInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
568                     break;
569                 }
570                 *pDestBuf = (sal_Char)(sal_uChar)c;
571                 pDestBuf++;
572             }
573 
574             pSrcBuf++;
575         }
576     }
577     while ( !bEnd );
578 
579     if ( pContextData )
580     {
581         pContextData->mbShifted     = bShifted;
582         pContextData->mnBitBuffer   = nBitBuffer;
583         pContextData->mnBufferBits  = nBufferBits;
584     }
585 
586     *pSrcCvtChars = nSrcChars - (pEndSrcBuf-pSrcBuf);
587     return (nDestBytes - (pEndDestBuf-pDestBuf));
588 }
589