/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
- * FILE: dll/win32/kernel32/misc/nls.c
+ * FILE: dll/win32/kernel32/winnls/string/nls.c
* PURPOSE: National Language Support
* PROGRAMMER: Filip Navara
* Hartmut Birr
RtlInitCodePageTable((PUSHORT)AnsiCodePage.SectionMapping,
&AnsiCodePage.CodePageTable);
AnsiCodePage.CodePage = AnsiCodePage.CodePageTable.CodePage;
-
+
InsertTailList(&CodePageListHead, &AnsiCodePage.Entry);
/* Setup OEM code page. */
/* Last error is set by GetLocaleInfoW. */
return NULL;
}
+ if (CodePage == 0)
+ return &AnsiCodePage;
}
else if (CodePage == CP_MACCP)
{
{
PCODEPAGE_ENTRY CodePageEntry;
PCPTABLEINFO CodePageTable;
+ PUSHORT MultiByteTable;
LPCSTR TempString;
INT TempLength;
+ USHORT WideChar;
/* Get code page table. */
CodePageEntry = IntGetCodePageEntry(CodePage);
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
+
CodePageTable = &CodePageEntry->CodePageTable;
- /* Different handling for DBCS code pages. */
- if (CodePageTable->MaximumCharacterSize > 1)
+ /* If MB_USEGLYPHCHARS flag present and glyph table present */
+ if ((Flags & MB_USEGLYPHCHARS) && CodePageTable->MultiByteTable[256])
{
- /* FIXME */
+ /* Use glyph table */
+ MultiByteTable = CodePageTable->MultiByteTable + 256 + 1;
+ }
+ else
+ {
+ MultiByteTable = CodePageTable->MultiByteTable;
+ }
+ /* Different handling for DBCS code pages. */
+ if (CodePageTable->DBCSCodePage)
+ {
UCHAR Char;
USHORT DBCSOffset;
LPCSTR MbsEnd = MultiByteString + MultiByteCount;
INT Count;
+ if (Flags & MB_ERR_INVALID_CHARS)
+ {
+ TempString = MultiByteString;
+
+ while (TempString < MbsEnd)
+ {
+ DBCSOffset = CodePageTable->DBCSOffsets[(UCHAR)*TempString];
+
+ if (DBCSOffset)
+ {
+ /* If lead byte is presented, but behind it there is no symbol */
+ if (((TempString + 1) == MbsEnd) || (*(TempString + 1) == 0))
+ {
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return 0;
+ }
+
+ WideChar = CodePageTable->DBCSOffsets[DBCSOffset + *(TempString + 1)];
+
+ if (WideChar == CodePageTable->UniDefaultChar &&
+ MAKEWORD(*(TempString + 1), *TempString) != CodePageTable->TransUniDefaultChar)
+ {
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return 0;
+ }
+
+ TempString++;
+ }
+ else
+ {
+ WideChar = MultiByteTable[(UCHAR)*TempString];
+
+ if ((WideChar == CodePageTable->UniDefaultChar &&
+ *TempString != CodePageTable->TransUniDefaultChar) ||
+ /* "Private Use" characters */
+ (WideChar >= 0xE000 && WideChar <= 0xF8FF))
+ {
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return 0;
+ }
+ }
+
+ TempString++;
+ }
+ }
+
/* Does caller query for output buffer size? */
if (WideCharCount == 0)
{
{
Char = *MultiByteString++;
- if (Char < 0x80)
- continue;
-
DBCSOffset = CodePageTable->DBCSOffsets[Char];
if (!DBCSOffset)
{
Char = *MultiByteString++;
- if (Char < 0x80)
- {
- *WideCharString++ = Char;
- continue;
- }
-
DBCSOffset = CodePageTable->DBCSOffsets[Char];
if (!DBCSOffset)
{
- *WideCharString++ = CodePageTable->MultiByteTable[Char];
+ *WideCharString++ = MultiByteTable[Char];
continue;
}
- if (MultiByteString < MbsEnd)
- *WideCharString++ = CodePageTable->DBCSOffsets[DBCSOffset + *(PUCHAR)MultiByteString++];
+ if (MultiByteString == MbsEnd)
+ {
+ *WideCharString++ = UNICODE_NULL;
+ }
+ else if (*MultiByteString == 0)
+ {
+ *WideCharString++ = UNICODE_NULL;
+ MultiByteString++;
+ }
+ else
+ {
+ *WideCharString++ = CodePageTable->DBCSOffsets[DBCSOffset + (UCHAR)*MultiByteString++];
+ }
}
if (MultiByteString < MbsEnd)
return Count;
}
- else /* Not DBCS code page */
+ else /* SBCS code page */
{
/* Check for invalid characters. */
if (Flags & MB_ERR_INVALID_CHARS)
TempLength > 0;
TempString++, TempLength--)
{
- if (CodePageTable->MultiByteTable[(UCHAR)*TempString] ==
- CodePageTable->UniDefaultChar &&
- *TempString != CodePageEntry->CodePageTable.DefaultChar)
+ WideChar = MultiByteTable[(UCHAR)*TempString];
+
+ if ((WideChar == CodePageTable->UniDefaultChar &&
+ *TempString != CodePageTable->TransUniDefaultChar) ||
+ /* "Private Use" characters */
+ (WideChar >= 0xE000 && WideChar <= 0xF8FF))
{
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
return 0;
TempLength > 0;
MultiByteString++, TempLength--)
{
- *WideCharString++ = CodePageTable->MultiByteTable[(UCHAR)*MultiByteString];
+ *WideCharString++ = MultiByteTable[(UCHAR)*MultiByteString];
}
/* Adjust buffer size. Wine trick ;-) */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
- return MultiByteCount;
+ return MultiByteCount;
}
}
LPBOOL UsedDefaultChar)
{
INT TempLength;
- WCHAR Char;
+ DWORD Char;
/* Does caller query for output buffer size? */
if (MultiByteCount == 0)
{
TempLength++;
if (*WideCharString >= 0x800)
+ {
TempLength++;
+ if (*WideCharString >= 0xd800 && *WideCharString < 0xdc00 &&
+ WideCharCount >= 1 &&
+ WideCharString[1] >= 0xdc00 && WideCharString[1] <= 0xe000)
+ {
+ WideCharCount--;
+ WideCharString++;
+ TempLength++;
+ }
+ }
}
}
return TempLength;
continue;
}
+ /* surrogate pair 0x10000-0x10ffff: 4 bytes */
+ if (Char >= 0xd800 && Char < 0xdc00 &&
+ WideCharCount >= 1 &&
+ WideCharString[1] >= 0xdc00 && WideCharString[1] < 0xe000)
+ {
+ WideCharCount--;
+ WideCharString++;
+
+ if (TempLength < 4)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ break;
+ }
+
+ Char = (Char - 0xd800) << 10;
+ Char |= *WideCharString - 0xdc00;
+ ASSERT(Char <= 0xfffff);
+ Char += 0x10000;
+ ASSERT(Char <= 0x10ffff);
+
+ MultiByteString[3] = 0x80 | (Char & 0x3f); Char >>= 6;
+ MultiByteString[2] = 0x80 | (Char & 0x3f); Char >>= 6;
+ MultiByteString[1] = 0x80 | (Char & 0x3f); Char >>= 6;
+ MultiByteString[0] = 0xf0 | Char;
+ MultiByteString += 4;
+ TempLength -= 4;
+ continue;
+ }
+
/* 0x800-0xffff: 3 bytes */
if (TempLength < 3)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
+
CodePageTable = &CodePageEntry->CodePageTable;
/* Different handling for DBCS code pages. */
- if (CodePageTable->MaximumCharacterSize > 1)
+ if (CodePageTable->DBCSCodePage)
{
/* If Flags, DefaultChar or UsedDefaultChar were given, we have to do some more work */
- if(Flags || DefaultChar || UsedDefaultChar)
+ if (Flags || DefaultChar || UsedDefaultChar)
{
BOOL TempUsedDefaultChar;
USHORT DefChar;
/* If UsedDefaultChar is not set, set it to a temporary value, so we don't have
to check on every character */
- if(!UsedDefaultChar)
+ if (!UsedDefaultChar)
UsedDefaultChar = &TempUsedDefaultChar;
*UsedDefaultChar = FALSE;
/* Use the CodePage's TransDefaultChar if none was given. Don't modify the DefaultChar pointer here. */
- if(DefaultChar)
+ if (DefaultChar)
DefChar = DefaultChar[1] ? ((DefaultChar[0] << 8) | DefaultChar[1]) : DefaultChar[0];
else
DefChar = CodePageTable->TransDefaultChar;
/* Does caller query for output buffer size? */
- if(!MultiByteCount)
+ if (!MultiByteCount)
{
- for(TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++)
+ for (TempLength = 0; WideCharCount; WideCharCount--, WideCharString++, TempLength++)
{
USHORT uChar;
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
{
/* FIXME: Handle WC_COMPOSITECHECK */
+ DPRINT1("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
}
uChar = ((PUSHORT) CodePageTable->WideCharTable)[*WideCharString];
}
/* Convert the WideCharString to the MultiByteString and verify if the mapping is valid */
- for(TempLength = MultiByteCount;
- WideCharCount && TempLength;
- TempLength--, WideCharString++, WideCharCount--)
+ for (TempLength = MultiByteCount;
+ WideCharCount && TempLength;
+ TempLength--, WideCharString++, WideCharCount--)
{
USHORT uChar;
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
{
/* FIXME: Handle WC_COMPOSITECHECK */
+ DPRINT1("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
}
uChar = ((PUSHORT)CodePageTable->WideCharTable)[*WideCharString];
return MultiByteCount - TempLength;
}
- else /* Not DBCS code page */
+ else /* SBCS code page */
{
INT nReturn;
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
{
/* FIXME: Handle WC_COMPOSITECHECK */
+ DPRINT1("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
}
if (!*UsedDefaultChar)
if ((Flags & WC_COMPOSITECHECK) && WideCharCount > 1)
{
/* FIXME: Handle WC_COMPOSITECHECK */
+ DPRINT1("WC_COMPOSITECHECK flag UNIMPLEMENTED\n");
}
*MultiByteString = ((PCHAR)CodePageTable->WideCharTable)[*WideCharString];
return GetCPFileNameFromRegistry(CodePage, NULL, 0);
}
-static const signed char
-base64inv[] =
+static inline BOOL utf7_write_w(WCHAR *dst, int dstlen, int *index, WCHAR character)
{
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
-};
-
-static VOID Utf7Base64Decode(BYTE *pbDest, LPCSTR pszSrc, INT cchSrc)
-{
- INT i, j, n;
- BYTE b;
-
- for(i = 0; i < cchSrc / 4 * 4; i += 4)
+ if (dstlen > 0)
{
- for(j = n = 0; j < 4; )
- {
- b = (BYTE) base64inv[(BYTE) *pszSrc++];
- n |= (((INT) b) << ((3 - j) * 6));
- j++;
- }
- for(j = 0; j < 3; j++)
- *pbDest++ = (BYTE) ((n >> (8 * (2 - j))) & 0xFF);
- }
- for(j = n = 0; j < cchSrc % 4; )
- {
- b = (BYTE) base64inv[(BYTE) *pszSrc++];
- n |= (((INT) b) << ((3 - j) * 6));
- j++;
- }
- for(j = 0; j < ((cchSrc % 4) * 6 / 8); j++)
- *pbDest++ = (BYTE) ((n >> (8 * (2 - j))) & 0xFF);
-}
+ if (*index >= dstlen)
+ return FALSE;
-static VOID myswab(LPVOID pv, INT cw)
-{
- LPBYTE pb = (LPBYTE) pv;
- BYTE b;
- while(cw > 0)
- {
- b = *pb;
- *pb = pb[1];
- pb[1] = b;
- pb += 2;
- cw--;
+ dst[*index] = character;
}
+
+ (*index)++;
+
+ return TRUE;
}
-static INT Utf7ToWideCharSize(LPCSTR pszUtf7, INT cchUtf7)
+static INT Utf7ToWideChar(const char *src, int srclen, WCHAR *dst, int dstlen)
{
- INT n, c, cch;
- CHAR ch;
- LPCSTR pch;
-
- c = 0;
- while(cchUtf7 > 0)
+ static const signed char base64_decoding_table[] =
{
- ch = *pszUtf7++;
- if (ch == '+')
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
+ };
+
+ const char *source_end = src + srclen;
+ int dest_index = 0;
+
+ DWORD byte_pair = 0;
+ short offset = 0;
+
+ while (src < source_end)
+ {
+ if (*src == '+')
{
- ch = *pszUtf7;
- if (ch == '-')
+ src++;
+ if (src >= source_end)
+ break;
+
+ if (*src == '-')
{
- c++;
- pszUtf7++;
- cchUtf7 -= 2;
+ /* just a plus sign escaped as +- */
+ if (!utf7_write_w(dst, dstlen, &dest_index, '+'))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ src++;
continue;
}
- cchUtf7--;
- pch = pszUtf7;
- while(cchUtf7 > 0 && (BYTE) *pszUtf7 < 0x80 &&
- base64inv[*pszUtf7] >= 0)
- {
- cchUtf7--;
- pszUtf7++;
- }
- cch = pszUtf7 - pch;
- n = (cch * 3) / 8;
- c += n;
- if (cchUtf7 > 0 && *pszUtf7 == '-')
- {
- pszUtf7++;
- cchUtf7--;
- }
- }
- else
- {
- c++;
- cchUtf7--;
- }
- }
- return c;
-}
+ do
+ {
+ signed char sextet = *src;
+ if (sextet == '-')
+ {
+ /* skip over the dash and end base64 decoding
+ * the current, unfinished byte pair is discarded */
+ src++;
+ offset = 0;
+ break;
+ }
+ if (sextet < 0)
+ {
+ /* the next character of src is < 0 and therefore not part of a base64 sequence
+ * the current, unfinished byte pair is NOT discarded in this case
+ * this is probably a bug in Windows */
+ break;
+ }
-static INT Utf7ToWideChar(LPCSTR pszUtf7, INT cchUtf7, LPWSTR pszWide, INT cchWide)
-{
- INT n, c, cch;
- CHAR ch;
- LPCSTR pch;
- WORD *pwsz;
+ sextet = base64_decoding_table[sextet];
+ if (sextet == -1)
+ {
+ /* -1 means that the next character of src is not part of a base64 sequence
+ * in other words, all sextets in this base64 sequence have been processed
+ * the current, unfinished byte pair is discarded */
+ offset = 0;
+ break;
+ }
- c = Utf7ToWideCharSize(pszUtf7, cchUtf7);
- if (cchWide == 0)
- return c;
+ byte_pair = (byte_pair << 6) | sextet;
+ offset += 6;
- if (cchWide < c)
- {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return 0;
- }
+ if (offset >= 16)
+ {
+ /* this byte pair is done */
+ if (!utf7_write_w(dst, dstlen, &dest_index, (byte_pair >> (offset - 16)) & 0xFFFF))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ offset -= 16;
+ }
- while(cchUtf7 > 0)
- {
- ch = *pszUtf7++;
- if (ch == '+')
- {
- if (*pszUtf7 == '-')
- {
- *pszWide++ = L'+';
- pszUtf7++;
- cchUtf7 -= 2;
- continue;
- }
- cchUtf7--;
- pch = pszUtf7;
- while(cchUtf7 > 0 && (BYTE) *pszUtf7 < 0x80 &&
- base64inv[*pszUtf7] >= 0)
- {
- cchUtf7--;
- pszUtf7++;
- }
- cch = pszUtf7 - pch;
- n = (cch * 3) / 8;
- pwsz = (WORD *) HeapAlloc(GetProcessHeap(), 0, (n + 1) * sizeof(WORD));
- if (pwsz == NULL)
- return 0;
- ZeroMemory(pwsz, n * sizeof(WORD));
- Utf7Base64Decode((BYTE *) pwsz, pch, cch);
- myswab(pwsz, n);
- CopyMemory(pszWide, pwsz, n * sizeof(WORD));
- HeapFree(GetProcessHeap(), 0, pwsz);
- pszWide += n;
- if (cchUtf7 > 0 && *pszUtf7 == '-')
- {
- pszUtf7++;
- cchUtf7--;
+ src++;
}
+ while (src < source_end);
}
else
{
- *pszWide++ = (WCHAR) ch;
- cchUtf7--;
+ /* we have to convert to unsigned char in case *src < 0 */
+ if (!utf7_write_w(dst, dstlen, &dest_index, (unsigned char)*src))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ src++;
}
}
- return c;
+ return dest_index;
}
/**
{
/* Check the parameters. */
if (MultiByteString == NULL ||
- MultiByteCount == 0 ||
- (WideCharString == NULL && WideCharCount > 0) ||
- (PVOID)MultiByteString == (PVOID)WideCharString)
+ MultiByteCount == 0 || WideCharCount < 0 ||
+ (WideCharCount && (WideCharString == NULL ||
+ (PVOID)MultiByteString == (PVOID)WideCharString)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
-static const char mustshift[] =
+static inline BOOL utf7_can_directly_encode(WCHAR codepoint)
{
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1
-};
-
-static const char base64[] =
-"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ static const BOOL directly_encodable_table[] =
+ {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
+ 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7A */
+ };
+
+ return codepoint <= 0x7A ? directly_encodable_table[codepoint] : FALSE;
+}
-static INT WideCharToUtf7Size(LPCWSTR pszWide, INT cchWide)
+static inline BOOL utf7_write_c(char *dst, int dstlen, int *index, char character)
{
- WCHAR wch;
- INT c = 0;
- BOOL fShift = FALSE;
-
- while(cchWide > 0)
+ if (dstlen > 0)
{
- wch = *pszWide;
- if (wch < 0x80 && !mustshift[wch])
- {
- c++;
- cchWide--;
- pszWide++;
- }
- else
- {
- if (wch == L'+')
- {
- c++;
- c++;
- cchWide--;
- pszWide++;
- continue;
- }
- if (!fShift)
- {
- c++;
- fShift = TRUE;
- }
- pszWide++;
- cchWide--;
- c += 3;
- if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide]))
- {
- pszWide++;
- cchWide--;
- c += 3;
- if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide]))
- {
- pszWide++;
- cchWide--;
- c += 2;
- }
- }
- if (cchWide > 0 && *pszWide < 0x80 && !mustshift[*pszWide])
- {
- c++;
- fShift = FALSE;
- }
- }
+ if (*index >= dstlen)
+ return FALSE;
+
+ dst[*index] = character;
}
- if (fShift)
- c++;
- return c;
+ (*index)++;
+
+ return TRUE;
}
-static INT WideCharToUtf7(LPCWSTR pszWide, INT cchWide, LPSTR pszUtf7, INT cchUtf7)
+static INT WideCharToUtf7(const WCHAR *src, int srclen, char *dst, int dstlen)
{
- WCHAR wch;
- INT c, n;
- WCHAR wsz[3];
- BOOL fShift = FALSE;
+ static const char base64_encoding_table[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- c = WideCharToUtf7Size(pszWide, cchWide);
- if (cchUtf7 == 0)
- return c;
+ const WCHAR *source_end = src + srclen;
+ int dest_index = 0;
- if (cchUtf7 < c)
+ while (src < source_end)
{
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- return 0;
- }
-
- while(cchWide > 0)
- {
- wch = *pszWide;
- if (wch < 0x80 && !mustshift[wch])
+ if (*src == '+')
{
- *pszUtf7++ = (CHAR) wch;
- cchWide--;
- pszWide++;
+ if (!utf7_write_c(dst, dstlen, &dest_index, '+'))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ if (!utf7_write_c(dst, dstlen, &dest_index, '-'))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ src++;
}
- else
+ else if (utf7_can_directly_encode(*src))
{
- if (wch == L'+')
+ if (!utf7_write_c(dst, dstlen, &dest_index, *src))
{
- *pszUtf7++ = '+';
- *pszUtf7++ = '-';
- cchWide--;
- pszWide++;
- continue;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
}
- if (!fShift)
+ src++;
+ }
+ else
+ {
+ unsigned int offset = 0;
+ DWORD byte_pair = 0;
+
+ if (!utf7_write_c(dst, dstlen, &dest_index, '+'))
{
- *pszUtf7++ = '+';
- fShift = TRUE;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
}
- wsz[0] = *pszWide++;
- cchWide--;
- n = 1;
- if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide]))
+
+ while (src < source_end && !utf7_can_directly_encode(*src))
{
- wsz[1] = *pszWide++;
- cchWide--;
- n++;
- if (cchWide > 0 && (*pszWide >= 0x80 || mustshift[*pszWide]))
+ byte_pair = (byte_pair << 16) | *src;
+ offset += 16;
+ while (offset >= 6)
{
- wsz[2] = *pszWide++;
- cchWide--;
- n++;
+ if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[(byte_pair >> (offset - 6)) & 0x3F]))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ offset -= 6;
}
+ src++;
}
- *pszUtf7++ = base64[wsz[0] >> 10];
- *pszUtf7++ = base64[(wsz[0] >> 4) & 0x3F];
- *pszUtf7++ = base64[(wsz[0] << 2 | wsz[1] >> 14) & 0x3F];
- if (n >= 2)
+
+ if (offset)
{
- *pszUtf7++ = base64[(wsz[1] >> 8) & 0x3F];
- *pszUtf7++ = base64[(wsz[1] >> 2) & 0x3F];
- *pszUtf7++ = base64[(wsz[1] << 4 | wsz[2] >> 12) & 0x3F];
- if (n >= 3)
+ /* Windows won't create a padded base64 character if there's no room for the - sign
+ * as well ; this is probably a bug in Windows */
+ if (dstlen > 0 && dest_index + 1 >= dstlen)
{
- *pszUtf7++ = base64[(wsz[2] >> 6) & 0x3F];
- *pszUtf7++ = base64[wsz[2] & 0x3F];
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+
+ byte_pair <<= (6 - offset);
+ if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[byte_pair & 0x3F]))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
}
}
- if (cchWide > 0 && *pszWide < 0x80 && !mustshift[*pszWide])
+
+ /* Windows always explicitly terminates the base64 sequence
+ even though RFC 2152 (page 3, rule 2) does not require this */
+ if (!utf7_write_c(dst, dstlen, &dest_index, '-'))
{
- *pszUtf7++ = '-';
- fShift = FALSE;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
}
}
}
- if (fShift)
- *pszUtf7 = '-';
- return c;
+ return dest_index;
}
-static BOOL
-GetLocalisedText(DWORD dwResId, WCHAR *lpszDest)
+DWORD
+GetLocalisedText(DWORD dwResId, WCHAR *lpszDest, DWORD dwDestSize)
{
HRSRC hrsrc;
LCID lcid;
{
const WCHAR *p;
unsigned int i;
+ unsigned int len;
p = LockResource(hmem);
+
for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
- memcpy(lpszDest, p + 1, *p * sizeof(WCHAR));
+ if(dwDestSize == 0)
+ return *p + 1;
+
+ len = *p * sizeof(WCHAR);
+
+ if(len + sizeof(WCHAR) > dwDestSize)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+
+ memcpy(lpszDest, p + 1, len);
lpszDest[*p] = '\0';
return TRUE;
}
}
- DPRINT1("Could not get codepage name. dwResId = %lu\n", dwResId);
+ DPRINT1("Resource not found: dwResId = %lu\n", dwResId);
+ SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
{
lpCPInfoEx->CodePage = CP_UTF7;
lpCPInfoEx->UnicodeDefaultChar = 0x3f;
- return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName);
+ return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName, sizeof(lpCPInfoEx->CodePageName)) != 0;
}
break;
{
lpCPInfoEx->CodePage = CP_UTF8;
lpCPInfoEx->UnicodeDefaultChar = 0x3f;
- return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName);
+ return GetLocalisedText((DWORD)CodePage, lpCPInfoEx->CodePageName, sizeof(lpCPInfoEx->CodePageName)) != 0;
}
default:
lpCPInfoEx->CodePage = CodePageEntry->CodePageTable.CodePage;
lpCPInfoEx->UnicodeDefaultChar = CodePageEntry->CodePageTable.UniDefaultChar;
- return GetLocalisedText(CodePageEntry->CodePageTable.CodePage, lpCPInfoEx->CodePageName);
+ return GetLocalisedText(CodePageEntry->CodePageTable.CodePage, lpCPInfoEx->CodePageName, sizeof(lpCPInfoEx->CodePageName)) != 0;
}
break;
}