[vbox-dev] Patch to resolve the unicode-composite character problem of the shared-folder in Mac OS X

Gi youl Kim aingoppa at gmail.com
Thu Jun 19 07:01:01 GMT 2008


Mac OS X deals with filename using unicode, especially
NFD(Normalization Form D - Canonical Decomposition). Here is link
about the topic.

http://unicode.org/reports/tr15/

Mac OS X understands NFD and NFC(Normalization Form C - Canonical
Decomposition, followed by Canonical Composition), but uses NFD as
filename. Windows XP understands NFC but not NFD.

So, when you tries to access the files in the Mac OS X (host) via
Shared Folder from Windows XP (guest), and if the filename is Korean,
Japanese or any language which has form in NFC & NFC, The filename
does not appear correctly. Windows Vista understands NFD, so it won't
be matter with Vista (guest).

To resolve this problem, you should normalize the filename to NFC(from
Mac OS X to Windows XP) or NFD(from Windows XP to Mac OS X).

Following patch does that. Tested with VB 1.6.2 and revision 9784

Index: src/VBox/HostServices/SharedFolders/vbsf.cpp
===================================================================
--- src/VBox/HostServices/SharedFolders/vbsf.cpp	(revision 9784)
+++ src/VBox/HostServices/SharedFolders/vbsf.cpp	(working copy)
@@ -33,6 +33,10 @@
 #include <iprt/string.h>
 #include <iprt/uni.h>

+#ifdef RT_OS_DARWIN
+#include <Carbon/Carbon.h>
+#endif
+
 #undef LogFlow
 #define LogFlow Log

@@ -231,6 +235,36 @@
     }
     else
     {
+#ifdef RT_OS_DARWIN
+		SHFLSTRING *pPathParameter = pPath;
+		size_t cbPathLength;
+		CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
+		uint16_t ucs2Length;
+		CFRange rangeCharacters;
+		
+		// Is 8 times length enough for decomposed in worst case...?
+		cbPathLength = sizeof(SHFLSTRING) + pPathParameter->u16Length * 8 + 2;
+		pPath = (SHFLSTRING *)RTMemAllocZ (cbPathLength);
+		if (!pPath)
+		{
+			rc = VERR_NO_MEMORY;
+			Log(("RTMemAllocZ %x failed!!\n", cbPathLength));
+			return rc;
+		}
+		
+		::CFStringAppendCharacters(inStr, (UniChar
*)pPathParameter->String.ucs2, pPathParameter->u16Length /
sizeof(pPathParameter->String.ucs2[0]));
+		::CFStringNormalize(inStr, kCFStringNormalizationFormD);
+		ucs2Length = ::CFStringGetLength(inStr);
+		
+		rangeCharacters.location = 0;
+		rangeCharacters.length = ucs2Length;
+		::CFStringGetCharacters(inStr, rangeCharacters, pPath->String.ucs2);
+		pPath->String.ucs2[ucs2Length] = 0x0000; // NULL terminated
+		pPath->u16Length = ucs2Length * sizeof(pPath->String.ucs2[0]);
+		pPath->u16Size = pPath->u16Length + sizeof(pPath->String.ucs2[0]);
+		
+		CFRelease(inStr);
+#endif
         /* Client sends us UCS2, so convert it to UTF8. */
         Log(("Root %ls path %.*ls\n", pwszRoot,
pPath->u16Length/sizeof(pPath->String.ucs2[0]), pPath->String.ucs2));

@@ -255,6 +289,10 @@
             if (VBOX_FAILURE(rc))
             {
                 AssertFailed();
+#ifdef RT_OS_DARWIN
+				RTMemFree(pPath);
+				pPath = pPathParameter;
+#endif
                 return rc;
             }

@@ -312,6 +350,10 @@
             /* Nul terminate the string */
             *dst = 0;
         }
+#ifdef RT_OS_DARWIN
+		RTMemFree(pPath);
+		pPath = pPathParameter;
+#endif
     }

     if (VBOX_SUCCESS (rc))
@@ -1340,6 +1382,28 @@
             int rc2 = RTStrToUtf16Ex(pDirEntry->szName, RTSTR_MAX,
&pwszString, pDirEntry->cbName+1, NULL);
             AssertRC(rc2);

+#ifdef RT_OS_DARWIN
+			{
+				// Convert to
+				// Normalization Form C (composed Unicode). We need this because
+				// Mac OS X file system uses NFD (Normalization Form D :
decomposed Unicode)
+				// while most other OS', server-side programs usually expect NFC.
+				uint16_t ucs2Length;
+				CFRange rangeCharacters;
+				CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
+				
+				::CFStringAppendCharacters(inStr, (UniChar *)pwszString,
RTUtf16Len (pwszString));
+				::CFStringNormalize(inStr, kCFStringNormalizationFormC);
+				ucs2Length = ::CFStringGetLength(inStr);
+				
+				rangeCharacters.location = 0;
+				rangeCharacters.length = ucs2Length;
+				::CFStringGetCharacters(inStr, rangeCharacters, pwszString);
+				pwszString[ucs2Length] = 0x0000; // NULL terminated
+				
+				CFRelease(inStr);
+			}
+#endif
             pSFDEntry->name.u16Length = RTUtf16Len
(pSFDEntry->name.String.ucs2) * 2;
             pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;

Index: src/VBox/HostServices/SharedFolders/Makefile.kmk
===================================================================
--- src/VBox/HostServices/SharedFolders/Makefile.kmk	(revision 9784)
+++ src/VBox/HostServices/SharedFolders/Makefile.kmk	(working copy)
@@ -36,6 +36,9 @@
 VBoxSharedFolders_INCS.win  = \
 	$(PATH_TOOL_$(VBOX_VCC_TOOL)_ATLMFC_INC) \
 	$(VBOX_PATH_SDK)
+	
+VBoxSharedFolders_LDFLAGS.darwin = \
+	-framework Carbon

 VBoxSharedFolders_SOURCES = \
 	service.cpp \




More information about the vbox-dev mailing list