Author: ion
Date: Sun Nov  6 22:46:31 2011
New Revision: 54322

URL: http://svn.reactos.org/svn/reactos?rev=54322&view=rev
Log:
[KERNEL32]: Give the same treatement to SearchPathA. Also add a comment on why 
exactly the A<->W conversion has to be more complex than what Wine was 
attempting.

Modified:
    trunk/reactos/dll/win32/kernel32/client/path.c

Modified: trunk/reactos/dll/win32/kernel32/client/path.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/path.c?rev=54322&r1=54321&r2=54322&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/path.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/path.c [iso-8859-1] Sun Nov  6 
22:46:31 2011
@@ -28,7 +28,7 @@
     0x10000000  // 7C not allowed
 };
 
-/* FUNCTIONS 
******************************************************************/
+/* PRIVATE FUNCTIONS 
**********************************************************/
 
 /*
  * Why not use RtlIsNameLegalDOS8Dot3? In fact the actual algorithm body is
@@ -267,6 +267,8 @@
     return !NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL;
 }
 
+/* PUBLIC FUNCTIONS 
***********************************************************/
+
 /*
  * @implemented
  */
@@ -450,6 +452,18 @@
 
 /*
  * @implemented
+ * 
+ * NOTE: Many of these A functions may seem to do rather complex A<->W mapping
+ * beyond what you would usually expect. There are two main reasons:
+ *
+ * First, these APIs are subject to the ANSI/OEM File API selection status that
+ * the caller has chosen, so we must use the "8BitString" internal Base APIs.
+ *
+ * Secondly, the Wide APIs (coming from the 9x world) are coded to return the
+ * length of the paths in "ANSI" by dividing their internal Wide character 
count
+ * by two... this is usually correct when dealing with pure-ASCII codepages but
+ * not necessarily when dealing with MBCS pre-Unicode sets, which NT supports
+ * for CJK, for example.
  */
 DWORD
 WINAPI
@@ -545,7 +559,7 @@
         /* Conversion worked, now copy the ANSI/OEM buffer into the buffer */
         RtlCopyMemory(lpBuffer, AnsiString.Buffer, PathSize + 1);
         RtlFreeAnsiString(&AnsiString);
-        
+
         /* And finally, did the caller request file part information? */
         if (lpFilePart)
         {
@@ -583,149 +597,175 @@
  */
 DWORD
 WINAPI
-SearchPathA (
-        LPCSTR  lpPath,
-        LPCSTR  lpFileName,
-        LPCSTR  lpExtension,
-        DWORD   nBufferLength,
-        LPSTR   lpBuffer,
-        LPSTR   *lpFilePart
-        )
-{
-        UNICODE_STRING PathU      = { 0, 0, NULL };
-        UNICODE_STRING FileNameU  = { 0, 0, NULL };
-        UNICODE_STRING ExtensionU = { 0, 0, NULL };
-        UNICODE_STRING BufferU    = { 0, 0, NULL };
-        ANSI_STRING Path;
-        ANSI_STRING FileName;
-        ANSI_STRING Extension;
-        ANSI_STRING Buffer;
-        PWCHAR FilePartW;
-        DWORD RetValue = 0;
-        NTSTATUS Status = STATUS_SUCCESS;
-
-        if (!lpFileName)
-        {
-            SetLastError(ERROR_INVALID_PARAMETER);
-            return 0;
-        }
-
-        RtlInitAnsiString (&Path,
-                           (LPSTR)lpPath);
-        RtlInitAnsiString (&FileName,
-                           (LPSTR)lpFileName);
-        RtlInitAnsiString (&Extension,
-                           (LPSTR)lpExtension);
-
-        /* convert ansi (or oem) strings to unicode */
-        if (bIsFileApiAnsi)
-        {
-                Status = RtlAnsiStringToUnicodeString (&PathU,
-                                                       &Path,
-                                                       TRUE);
+SearchPathA(IN LPCSTR lpPath,
+            IN LPCSTR lpFileName,
+            IN LPCSTR lpExtension,
+            IN DWORD nBufferLength,
+            IN LPSTR lpBuffer,
+            OUT LPSTR *lpFilePart)
+{
+    PUNICODE_STRING FileNameString;
+    UNICODE_STRING PathString, ExtensionString;
+    NTSTATUS Status;
+    ULONG PathSize, FilePartSize, AnsiLength;
+    PWCHAR LocalFilePart, Buffer;
+    PWCHAR* FilePart;
+
+    /* If the caller wants filepart, use a local wide buffer since this is A */
+    FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
+
+    /* Initialize stuff for Quickie */
+    PathSize = 0;
+    Buffer = NULL;
+    ExtensionString.Buffer = PathString.Buffer = NULL;
+
+    /* Get the UNICODE_STRING file name */
+    FileNameString = Basep8BitStringToStaticUnicodeString(lpFileName);
+    if (!FileNameString) return 0;
+
+    /* Did the caller specify an extension */
+    if (lpExtension)
+    {
+        /* Yup, convert it into UNICODE_STRING */
+        Status = Basep8BitStringToDynamicUnicodeString(&ExtensionString,
+                                                       lpExtension);
+        if (!NT_SUCCESS(Status)) goto Quickie;
+    }
+
+    /* Did the caller specify a path */
+    if (lpPath)
+    {
+        /* Yup, convert it into UNICODE_STRING */
+        Status = Basep8BitStringToDynamicUnicodeString(&PathString, lpPath);
+        if (!NT_SUCCESS(Status)) goto Quickie;
+    }
+
+    /* Allocate our output buffer */
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nBufferLength * 
sizeof(WCHAR));
+    if (!Buffer)
+    {
+        /* It failed, bail out */
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        goto Quickie;
+    }
+
+    /* Now run the Wide search with the input buffer lengths */
+    PathSize = SearchPathW(PathString.Buffer,
+                           FileNameString->Buffer,
+                           ExtensionString.Buffer,
+                           nBufferLength,
+                           Buffer,
+                           FilePart);
+    if (PathSize <= nBufferLength)
+    {
+        /* It fits, but is it empty? If so, bail out */
+        if (!PathSize) goto Quickie;
+
+        /* The length above is inexact, we need it in ANSI */
+        Status = RtlUnicodeToMultiByteSize(&AnsiLength, Buffer, PathSize * 
sizeof(WCHAR));
+        if (!NT_SUCCESS(Status))
+        {
+            /* Conversion failed, fail the call */
+            PathSize = 0;
+            BaseSetLastNTError(Status);
+            goto Quickie;
+        }
+
+        /* If the correct ANSI size is too big, return requird length plus a 
NULL */
+        if (AnsiLength >= nBufferLength)
+        {
+            PathSize = AnsiLength + 1;
+            goto Quickie;
+        }
+
+        /* Now apply the final conversion to ANSI */
+        Status = RtlUnicodeToMultiByteN(lpBuffer,
+                                        nBufferLength - 1,
+                                        &AnsiLength,
+                                        Buffer,
+                                        PathSize * sizeof(WCHAR));
+        if (!NT_SUCCESS(Status))
+        {
+            /* Conversion failed, fail the whole call */
+            PathSize = 0;
+            BaseSetLastNTError(STATUS_NO_MEMORY);
+            goto Quickie;
+        }
+
+        /* NULL-terminate and return the real ANSI length */
+        lpBuffer[AnsiLength] = ANSI_NULL;
+        PathSize = AnsiLength;
+
+        /* Now check if the user wanted file part size as well */
+        if (lpFilePart)
+        {
+            /* If we didn't get a file part, clear the caller's */
+            if (!LocalFilePart)
+            {
+                *lpFilePart = NULL;
+            }
+            else
+            {
+                /* Yep, so in this case get the length of the file part too */
+                Status = RtlUnicodeToMultiByteSize(&FilePartSize,
+                                                   Buffer,
+                                                   (LocalFilePart - Buffer) *
+                                                   sizeof(WCHAR));
                 if (!NT_SUCCESS(Status))
-                    goto Cleanup;
-
-                Status = RtlAnsiStringToUnicodeString (&FileNameU,
-                                                       &FileName,
-                                                       TRUE);
-                if (!NT_SUCCESS(Status))
-                    goto Cleanup;
-
-                Status = RtlAnsiStringToUnicodeString (&ExtensionU,
-                                                       &Extension,
-                                                       TRUE);
-                if (!NT_SUCCESS(Status))
-                    goto Cleanup;
+                {
+                    /* We failed to do that, so fail the whole call */
+                    BaseSetLastNTError(Status);
+                    PathSize = 0;
+                }
+
+                /* Return the file part buffer */
+                *lpFilePart = lpBuffer + FilePartSize;
+            }
+        }
+    }
+    else
+    {
+        /* Our initial buffer guess was too small, allocate a bigger one */
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize * 
sizeof(WCHAR));
+        if (!Buffer)
+        {
+            /* Out of memory, fail everything */
+            BaseSetLastNTError(STATUS_NO_MEMORY);
+            goto Quickie;
+        }
+
+        /* Do the search again -- it will fail, we just want the path size */
+        PathSize = SearchPathW(PathString.Buffer,
+                               FileNameString->Buffer,
+                               ExtensionString.Buffer,
+                               PathSize,
+                               Buffer,
+                               FilePart);
+        if (!PathSize) goto Quickie;
+
+        /* Convert it to a correct size */
+        Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize * 
sizeof(WCHAR));
+        if (NT_SUCCESS(Status))
+        {
+            /* Make space for the NULL-char */
+            PathSize++;
         }
         else
         {
-                Status = RtlOemStringToUnicodeString (&PathU,
-                                                      &Path,
-                                                      TRUE);
-                if (!NT_SUCCESS(Status))
-                    goto Cleanup;
-                Status = RtlOemStringToUnicodeString (&FileNameU,
-                                                      &FileName,
-                                                      TRUE);
-                if (!NT_SUCCESS(Status))
-                    goto Cleanup;
-
-                Status = RtlOemStringToUnicodeString (&ExtensionU,
-                                                      &Extension,
-                                                      TRUE);
-                if (!NT_SUCCESS(Status))
-                    goto Cleanup;
-        }
-
-        BufferU.MaximumLength = min(nBufferLength * sizeof(WCHAR), USHRT_MAX);
-        BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
-                                          0,
-                                          BufferU.MaximumLength);
-        if (BufferU.Buffer == NULL)
-        {
-            Status = STATUS_NO_MEMORY;
-            goto Cleanup;
-        }
-
-        Buffer.MaximumLength = min(nBufferLength, USHRT_MAX);
-        Buffer.Buffer = lpBuffer;
-
-        RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer,
-                                NULL == lpFileName ? NULL : FileNameU.Buffer,
-                                NULL == lpExtension ? NULL : ExtensionU.Buffer,
-                                nBufferLength,
-                                BufferU.Buffer,
-                                &FilePartW);
-
-        if (0 != RetValue)
-        {
-                BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR);
-                /* convert ansi (or oem) string to unicode */
-                if (bIsFileApiAnsi)
-                    Status = RtlUnicodeStringToAnsiString(&Buffer,
-                                                          &BufferU,
-                                                          FALSE);
-                else
-                    Status = RtlUnicodeStringToOemString(&Buffer,
-                                                         &BufferU,
-                                                         FALSE);
-
-                if (NT_SUCCESS(Status) && Buffer.Buffer)
-                {
-                    /* nul-terminate ascii string */
-                    Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0';
-
-                    if (NULL != lpFilePart && BufferU.Length != 0)
-                    {
-                        *lpFilePart = strrchr (lpBuffer, '\\') + 1;
-                    }
-                }
-        }
-
-Cleanup:
-        RtlFreeHeap (RtlGetProcessHeap (),
-                     0,
-                     PathU.Buffer);
-        RtlFreeHeap (RtlGetProcessHeap (),
-                     0,
-                     FileNameU.Buffer);
-        RtlFreeHeap (RtlGetProcessHeap (),
-                     0,
-                     ExtensionU.Buffer);
-        RtlFreeHeap (RtlGetProcessHeap (),
-                     0,
-                     BufferU.Buffer);
-
-        if (!NT_SUCCESS(Status))
-        {
+            /* Conversion failed for some reason, fail the call */
             BaseSetLastNTError(Status);
-            return 0;
-        }
-
-        return RetValue;
-}
-
+            PathSize = 0;
+        }
+    }
+
+Quickie:
+    /* Cleanup/complete path */
+    if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+    if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString);
+    if (PathString.Buffer) RtlFreeUnicodeString(&PathString);
+    return PathSize;
+}
 
 /***********************************************************************
  *           ContainsPath (Wine name: contains_pathW)


Reply via email to