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