You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/07/25 12:54:14 UTC
svn commit: r1613382 -
/subversion/branches/svn-auth-x509/subversion/libsvn_subr/win32_xlate.c
Author: breser
Date: Fri Jul 25 10:54:13 2014
New Revision: 1613382
URL: http://svn.apache.org/r1613382
Log:
On svn-auth-x509 branch, Extend the win32_xlate code to support converting
from UTF-16 and UTF-32 Big Endian.
* subversion/libsvn_subr/win32_xlate.c
(UTF16BE, UTF32BE): New constants.
(get_page_id_from_name): Use new constants and clean up some formatting.
(svn_subr__win32_xlate_to_stringbuf): Add new code to handle the half of the
conversion from UTF-16/32 BE to UTF-8 that Windows can't do. Also fix
formatting that didn't match our style while I'm at it.
Modified:
subversion/branches/svn-auth-x509/subversion/libsvn_subr/win32_xlate.c
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_subr/win32_xlate.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_subr/win32_xlate.c?rev=1613382&r1=1613381&r2=1613382&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_subr/win32_xlate.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_subr/win32_xlate.c Fri Jul 25 10:54:13 2014
@@ -53,6 +53,9 @@ typedef int win32_xlate__dummy;
#include "svn_private_config.h"
+#define UTF16BE 1201
+#define UTF32BE 12001
+
static svn_atomic_t com_initialized = 0;
/* Initializes COM and keeps COM available until process exit.
@@ -109,16 +112,16 @@ get_page_id_from_name(UINT *page_id_p, c
}
else if (!strcmp(page_name, "ISO-10646-UCS-2"))
{
- *page_id_p = 1201; /* UTF-16 Big Endian, strictly speaking it isn't
- exactly UCS-2 Big Endian but it's a superset
- so it works well enough. */
+ *page_id_p = UTF16BE; /* UTF-16 Big Endian, strictly speaking it isn't
+ exactly UCS-2 Big Endian but it's a superset
+ so it works well enough. */
return APR_SUCCESS;
}
else if (!strcmp(page_name, "ISO-10646-UCS-4"))
{
- *page_id_p = 12001; /* UTF-32 Big Endian, again, it isn't strictly
- speaking UCS-4 Big Endian, but it's a superset
- so it works well enough. */
+ *page_id_p = UTF32BE; /* UTF-32 Big Endian, again, it isn't strictly
+ speaking UCS-4 Big Endian, but it's a superset
+ so it works well enough. */
return APR_SUCCESS;
}
@@ -204,34 +207,130 @@ svn_subr__win32_xlate_to_stringbuf(win32
int retval, wide_size;
if (src_length == 0)
- {
- *dest = svn_stringbuf_create_empty(pool);
- return APR_SUCCESS;
- }
-
- retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length,
- NULL, 0);
- if (retval == 0)
- return apr_get_os_error();
-
- wide_size = retval;
+ {
+ *dest = svn_stringbuf_create_empty(pool);
+ return APR_SUCCESS;
+ }
- /* Allocate temporary buffer for small strings on stack instead of heap. */
- if (wide_size <= MAX_PATH)
+ /* Convert from current encoding to UTF-16 Little Endian */
+ if (handle->from_page_id == UTF16BE)
{
- wide_str = alloca(wide_size * sizeof(WCHAR));
+ int w, s;
+
+ /* Incoming length needs to enough for wide characters */
+ if (src_length % 2)
+ return APR_EINVAL;
+
+ /* Calcuate the size and allocate the memory for the UTF-16 LE */
+ wide_size = src_length / 2;
+ if (wide_size <= MAX_PATH)
+ {
+ wide_str = alloca(wide_size * sizeof(WCHAR));
+ }
+ else
+ {
+ wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR));
+ }
+
+ /* Since we're converting from UTF-16 Big Endian just swap
+ * bytes and copy */
+ for (w = 0; w < wide_size; w++)
+ {
+ s = w * 2; /* position in src_data for start of character's 2 bytes */
+ wide_str[w] = ((src_data[s] & 0xFF) << 8) | (src_data[s + 1] & 0xFF);
+ }
+ }
+ else if (handle->from_page_id == UTF32BE)
+ {
+ int s, c, w = 0, surrogates = 0;
+
+ /* Incoming length needs to be enough for 4 bytes per char */
+ if (src_length % 4)
+ return APR_EINVAL;
+
+ /* Calculate the size and allocate the memory for UTF-16 LE */
+ wide_size = src_length / 4;
+ /* Look for characters that won't fit in 16 bits, add a character for
+ * the surrogate, note that the documentation for WideCharToMultiByte
+ * says that wide_size should be the number of characters, however that's
+ * not entirely true, it was true when it only supported UCS-2, but since
+ * Windows 2000 it supports UTF-16 but the count is the number of WCHARs
+ * which doesn't exactly map to characters since surrogates take up 2
+ * WCHARs for one character. TODO: Should we fail here if this isn't
+ * at least Windows 2000 since it won't know what to do with the
+ * surrogates? */
+ for (s = 0; s < wide_size * 4; s += 4)
+ {
+ if ((src_data[s] & 0xFF) != 0 || (src_data[s + 1] & 0xFF) != 0)
+ surrogates++;
+ }
+ wide_size += surrogates;
+ if (wide_size <= MAX_PATH)
+ {
+ wide_str = alloca(wide_size * sizeof(WCHAR));
+ }
+ else
+ {
+ wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR));
+ }
+
+ /* Since we're converting from UTF-32 Big Endian we have to swap bytes
+ * and deal with converting unicode values that won't fit into 16-bits to
+ * use surrogates, iterate by actual characters */
+ for (c = 0; c < (wide_size - surrogates); c++)
+ {
+ s = c * 4; /* position in src_data for start of character's 4 bytes */
+ if ((src_data[s] & 0xFF) == 0 && (src_data[s + 1] & 0xFF) == 0)
+ {
+ /* easy case it fits in UTF-16 just have to swap byte order */
+ wide_str[w] = (src_data[s + 2] & 0xFF) << 8;
+ wide_str[w++] |= src_data[s + 3] & 0xFF;
+ }
+ else
+ {
+ /* character too wide for going straight to UTF-16 have to use
+ * a surrogate pair, so first we swap characters to get a
+ * Little Endian long */
+ unsigned long ch = ((src_data[s] & 0xFF) << 24);
+ ch |= ((src_data[s + 1] & 0xFF) << 16);
+ ch |= ((src_data[s + 2] & 0xFF) << 8);
+ ch |= (src_data[s + 3] & 0xFF);
+ /* now calculate the surrogates */
+ ch -= 0x10000;
+ wide_str[w++] = (WCHAR) (0xD800 + ((ch & 0xFFC00) >> 10));
+ wide_str[w++] = (WCHAR) (0xDC00 + (ch & 0x3FF));
+ }
+ }
}
else
{
- wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR));
- }
+ /* Other encodings that hopefully Windows knows how to convert to
+ * UTF-16 Little Endian */
+ retval = MultiByteToWideChar(handle->from_page_id, 0, src_data,
+ src_length, NULL, 0);
+ if (retval == 0)
+ return apr_get_os_error();
+
+ wide_size = retval;
+
+ /* Allocate temporary buffer for small strings on stack instead of heap. */
+ if (wide_size <= MAX_PATH)
+ {
+ wide_str = alloca(wide_size * sizeof(WCHAR));
+ }
+ else
+ {
+ wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR));
+ }
- retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length,
- wide_str, wide_size);
+ retval = MultiByteToWideChar(handle->from_page_id, 0, src_data,
+ src_length, wide_str, wide_size);
- if (retval == 0)
- return apr_get_os_error();
+ if (retval == 0)
+ return apr_get_os_error();
+ }
+ /* Determine how much space we'll require to store the converted string */
retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size,
NULL, 0, NULL, NULL);
@@ -243,6 +342,7 @@ svn_subr__win32_xlate_to_stringbuf(win32
*dest = svn_stringbuf_create_ensure(retval + 1, pool);
(*dest)->len = retval;
+ /* Convert from UTF-16 Little Endian to the desired encoding */
retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size,
(*dest)->data, (*dest)->len, NULL, NULL);
if (retval == 0)