int WCSToMBEx( WORD wCodePage, LPCWSTR pUnicodeString, int cchUnicodeString, LPSTR *ppAnsiString, int nAnsiChar, BOOL bAllocateMem) { ULONG nCharsInAnsiString; #ifdef _USERK_ INT iCharsInAnsiString; #endif // _USERK_ if (nAnsiChar == 0 || cchUnicodeString == 0 || pUnicodeString == NULL) { return 0; // nothing to translate or nowhere to put it } /* * Adjust the cchUnicodeString value. If cchUnicodeString == -1 then the * string pointed to by pUnicodeString is NUL terminated so we * count the number of bytes. If cchUnicodeString < -1 this is an * illegal value so we return FALSE. Otherwise, cchUnicodeString is * set and requires no adjustment. */ if (cchUnicodeString == -1) { cchUnicodeString = (wcslen(pUnicodeString) + 1); } else if (cchUnicodeString < -1) { return 0; // illegal value } /* * Adjust the nAnsiChar value. If nAnsiChar == -1 then we pick a * value based on cchUnicodeString to hold the converted string. If * nAnsiChar < -1 this is an illegal value so we return FALSE. * Otherwise, nAnsiChar is set and requires no adjustment. */ if (nAnsiChar == -1) { if (bAllocateMem == FALSE) { return 0; // no destination } nAnsiChar = cchUnicodeString * DBCS_CHARSIZE; } else if (nAnsiChar < -1) { return 0; // illegal value } if (bAllocateMem) { /* * We need to allocate memory to hold the translated string. */ *ppAnsiString = (LPSTR)UserRtlAllocMem(nAnsiChar); if (*ppAnsiString == NULL) { return 0; } } /* * translate Unicode string pointed to by pUnicodeString into * ANSI and store in location pointed to by pAnsiString. We * stop translating when we fill up the ANSI buffer or reach * the end of the Unicode string. */ /* * if the target multibyte codepage is eqaul to ACP, Call faster Rtl function. */ if (IS_ACP(wCodePage)) { NTSTATUS Status; Status = RtlUnicodeToMultiByteN( (PCH)*ppAnsiString, nAnsiChar, &nCharsInAnsiString, (PWCH)pUnicodeString, cchUnicodeString * sizeof(WCHAR)); /* * If the ansi buffer is too small, RtlUnicodeToMultiByteN() * returns STATUS_BUFFER_OVERFLOW. In this case, the function * put as many ansi characters as specified in the buffer and * returns the number by chacacters(in bytes) written. We would * like to return the actual byte count written in the ansi * buffer rather than returnning 0 since callers of this function * don't expect to be returned 0 in most case. */ if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { if (bAllocateMem) { UserRtlFreeMem(*ppAnsiString); } return 0; // translation failed } return (int)nCharsInAnsiString; } else { #ifdef _USERK_ /* * Call GRE to convert string to Unicode. (Kernel mode) */ iCharsInAnsiString = EngWideCharToMultiByte( (UINT)wCodePage, (LPWSTR)pUnicodeString, cchUnicodeString * sizeof(WCHAR), (LPSTR)*ppAnsiString, nAnsiChar); nCharsInAnsiString = (iCharsInAnsiString == -1) ? 0 : (ULONG) iCharsInAnsiString; #else /* * Call NLS API (Kernel32) to convert string to Unicode. (User mode) */ nCharsInAnsiString = WideCharToMultiByte( (UINT)wCodePage, 0, (LPCWSTR)pUnicodeString, cchUnicodeString, (LPSTR)*ppAnsiString, nAnsiChar, NULL, NULL); #endif // _USERK_ if (nCharsInAnsiString == 0) { if (bAllocateMem) { UserRtlFreeMem(*ppAnsiString); } } return (int)nCharsInAnsiString; } }
int wvsprintfA( LPSTR lpOut, LPCSTR lpFmt, va_list arglist) { BOOL fAllocateMem; char prefix, fillch; int left, width, prec, size, sign, radix, upper, hprefix; int cchLimit = WSPRINTF_LIMIT, cch; LPSTR lpT, lpTMB; LPWSTR pwsz; va_list varglist = arglist; union { long l; unsigned long ul; char sz[2]; WCHAR wsz[2]; } val; while (*lpFmt != 0) { if (*lpFmt == '%') { /* * read the flags. These can be in any order */ left = 0; prefix = 0; while (*++lpFmt) { if (*lpFmt == '-') left++; else if (*lpFmt == '#') prefix++; else break; } /* * find fill character */ if (*lpFmt == '0') { fillch = '0'; lpFmt++; } else fillch = ' '; /* * read the width specification */ lpFmt = SP_GetFmtValue((LPCSTR)lpFmt, &cch); width = cch; /* * read the precision */ if (*lpFmt == '.') { lpFmt = SP_GetFmtValue((LPCSTR)++lpFmt, &cch); prec = cch; } else prec = -1; /* * get the operand size * default size: size == 0 * long number: size == 1 * wide chars: size == 2 * It may be a good idea to check the value of size when it * is tested for non-zero below (IanJa) */ hprefix = 0; if (*lpFmt == 'w') { size = 2; lpFmt++; } else if (*lpFmt == 'l') { size = 1; lpFmt++; } else if (*lpFmt == 't') { size = 0; lpFmt++; } else { size = 0; if (*lpFmt == 'h') { lpFmt++; hprefix = 1; } } upper = 0; sign = 0; radix = 10; switch (*lpFmt) { case 0: goto errorout; case 'i': case 'd': size=1; sign++; /*** FALL THROUGH to case 'u' ***/ case 'u': /* turn off prefix if decimal */ prefix = 0; donumeric: /* special cases to act like MSC v5.10 */ if (left || prec >= 0) fillch = ' '; /* * if size == 1, "%lu" was specified (good); * if size == 2, "%wu" was specified (bad) */ if (size) { val.l = va_arg(varglist, long); } else if (sign) { val.l = (long)va_arg(varglist, short); } else { val.ul = va_arg(varglist, unsigned); } if (sign && val.l < 0L) val.l = -val.l; else sign = 0; lpT = lpOut; /* * blast the number backwards into the user buffer */ cch = SP_PutNumber(lpOut, val.l, cchLimit, radix, upper); if (!(cchLimit -= cch)) goto errorout; lpOut += cch; width -= cch; prec -= cch; if (prec > 0) width -= prec; /* * fill to the field precision */ while (prec-- > 0) out('0'); if (width > 0 && !left) { /* * if we're filling with spaces, put sign first */ if (fillch != '0') { if (sign) { sign = 0; out('-'); width--; } if (prefix) { out(prefix); out('0'); prefix = 0; } } if (sign) width--; /* * fill to the field width */ while (width-- > 0) out(fillch); /* * still have a sign? */ if (sign) out('-'); if (prefix) { out(prefix); out('0'); } /* * now reverse the string in place */ SP_Reverse(lpT, lpOut - 1); } else { /* * add the sign character */ if (sign) { out('-'); width--; } if (prefix) { out(prefix); out('0'); } /* * reverse the string in place */ SP_Reverse(lpT, lpOut - 1); /* * pad to the right of the string in case left aligned */ while (width-- > 0) out(fillch); } break; case 'X': upper++; /*** FALL THROUGH to case 'x' ***/ case 'x': radix = 16; if (prefix) if (upper) prefix = 'X'; else prefix = 'x'; goto donumeric; case 'C': /* * explicit size specifier overrides case */ if (!size && !hprefix) { size = 1; // force WCHAR } /*** FALL THROUGH to case 'c' ***/ case 'c': /* * if size == 0, "%c" or "%hc" or "%tc" was specified (CHAR) * if size == 1, "%C" or "%lc" was specified (WCHAR); * if size == 2, "%wc" was specified (WCHAR) */ cch = 1; /* One character must be copied to the output buffer */ if (size) { val.wsz[0] = va_arg(varglist, WCHAR); val.wsz[1] = 0x0000; pwsz = val.wsz; goto putwstring; } else { val.sz[0] = va_arg(varglist, CHAR); val.sz[1] = 0; lpT = val.sz; goto putstring; } case 'S': /* * explicit size specifier overrides case */ if (!size && !hprefix) { size = 1; // force LPWSTR } /*** FALL THROUGH to case 's' ***/ case 's': /* * if size == 0, "%s" or "%hs" or "%ts" was specified (LPSTR); * if size == 1, "%S" or "%ls" was specified (LPWSTR); * if size == 2, "%ws" was specified (LPWSTR) */ if (size) { pwsz = va_arg(varglist, LPWSTR); cch = wcslen(pwsz); putwstring: cch = WCSToMB(pwsz, cch, &lpTMB, -1, TRUE); fAllocateMem = (BOOL) cch; lpT = lpTMB; } else { lpT = va_arg(varglist, LPSTR); cch = strlen(lpT); putstring: fAllocateMem = FALSE; } if (prec >= 0 && cch > prec) cch = prec; width -= cch; if (fAllocateMem) { if (cch + (width < 0 ? 0 : width) >= cchLimit) { UserRtlFreeMem(lpTMB); goto errorout; } } if (left) { while (cch--) out(*lpT++); while (width-- > 0) out(fillch); } else { while (width-- > 0) out(fillch); while (cch--) out(*lpT++); } if (fAllocateMem) { UserRtlFreeMem(lpTMB); } break; default: normalch: out(*lpFmt); break; } /* END OF SWITCH(*lpFmt) */
int MBToWCSEx( WORD wCodePage, LPCSTR pAnsiString, int nAnsiChar, LPWSTR *ppUnicodeString, int cchUnicodeString, BOOL bAllocateMem) { ULONG nBytesInUnicodeString; if (nAnsiChar == 0 || cchUnicodeString == 0 || pAnsiString == NULL) { return 0; // nothing to translate or nowhere to put it } /* * Adjust the nAnsiChar value. If nAnsiChar == -1 then the * string pointed to by pAnsiString is NUL terminated so we * count the number of bytes. If nAnsiChar < -1 this is an * illegal value so we return FALSE. Otherwise, nAnsiChar is * set and requires no adjustment. */ #ifdef _USERK_ UserAssert(nAnsiChar >= USER_AWCONV_COUNTSTRINGSZ); #endif if (nAnsiChar < 0) { /* * Bug 268035 - joejo * Need to fail if the count is a negative number less than -2! */ if (nAnsiChar < USER_AWCONV_COUNTSTRINGSZ) { return 0; } #if (USER_AWCONV_COUNTSTRING != -1 || USER_AWCONV_COUNTSTRINGSZ != -2) #error USER_AWCONV_COUNTSTRING or USER_AWCONV_COUNTSTRINGSZ has unexpected value. #endif /* HACK HACK HACK * If nAnsiChar is -1 (USER_AWCONV_COUNTSTRING), nAnsiChar length will be strlen() + 1, * to allocate the memory including trailing \0: this is compatible to the original code. * If nAnsiCahr is -2 (USER_AWCONV_COUNTSTRINGSZ), memory for trailing \0 will not be needed, * so memory allocation is optimized and the return value would be same as strlen(). */ nAnsiChar = strlen(pAnsiString) + 2 + nAnsiChar; // don't forget the NUL if nAnsiChar == -1 if (nAnsiChar == 0) { return 0; } } /* * Adjust the cchUnicodeString value. If cchUnicodeString == -1 then we * pick a value based on nAnsiChar to hold the converted string. If * cchUnicodeString < -1 this is an illegal value so we return FALSE. * Otherwise, cchUnicodeString is set and requires no adjustment. */ if (cchUnicodeString == -1) { if (bAllocateMem == FALSE) { return 0; // no destination } cchUnicodeString = nAnsiChar; } else if (cchUnicodeString < -1) { return 0; // illegal value } if (bAllocateMem) { *ppUnicodeString = (LPWSTR)UserRtlAllocMem(cchUnicodeString*sizeof(WCHAR)); if (*ppUnicodeString == NULL) { return 0; // allocation failed } } /* * if codepage is CP_ACP, We will call faster RtlXXX function. */ if (IS_ACP(wCodePage)) { /* * translate ANSI string pointed to by pAnsiString into Unicode * and store in location pointed to by pUnicodeString. We * stop translating when we fill up the Unicode buffer or reach * the end of the ANSI string. */ if (!NT_SUCCESS(RtlMultiByteToUnicodeN( (PWCH)*ppUnicodeString, cchUnicodeString * sizeof(WCHAR), &nBytesInUnicodeString, (PCH)pAnsiString, nAnsiChar ))) { if (bAllocateMem) { UserRtlFreeMem(*ppUnicodeString); } return 0; // translation failed } return (int)(nBytesInUnicodeString / sizeof(WCHAR)); } else { /* * if wCodePage is not ACP, Call NLS API. */ ULONG nCharsInUnicodeString; #ifdef _USERK_ /* * I believe we will never hit this code which is why I am * adding this assert. [gerritv] 5-21-96 */ #define SHOULD_NOT_REACH_HERE 0 UserAssert(SHOULD_NOT_REACH_HERE); #undef SHOULD_NOT_REACH_HERE return 0; #if 0 // FYI: old code INT iCharsInUnicodeString; /* * Call GRE to convert string to Unicode. (Kernel mode) * I believe we will never hit this code which is why I am * adding this assert. [gerritv] 5-21-96 */ UserAssert(0); iCharsInUnicodeString = EngMultiByteToWideChar( (UINT)wCodePage, (LPWSTR)*ppUnicodeString, (int)cchUnicodeString * sizeof(WCHAR), (LPSTR)pAnsiString, (int)nAnsiChar); nCharsInUnicodeString = (iCharsInUnicodeString == -1) ? 0 : (ULONG) iCharsInUnicodeString; #endif #else /* * Call NLS API (Kernel32) to convert string to Unicode. (User mode) */ nCharsInUnicodeString = MultiByteToWideChar( (UINT)wCodePage, 0, (LPCSTR)pAnsiString, (int)nAnsiChar, (LPWSTR)*ppUnicodeString, (int)cchUnicodeString); #endif // _USERK_ if (nCharsInUnicodeString == 0) { if (bAllocateMem) { UserRtlFreeMem(*ppUnicodeString); } } return (int)nCharsInUnicodeString; } }