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