[ros-diffs] [ion] 54274: [KERNEL32]: Rewrite (in some cases, simply clean-up) environment handling functions for better string handling, error codes, and performance. Part of ongoing kernel32 work.

ion at svn.reactos.org ion at svn.reactos.org
Sun Oct 30 01:07:10 UTC 2011


Author: ion
Date: Sun Oct 30 01:07:09 2011
New Revision: 54274

URL: http://svn.reactos.org/svn/reactos?rev=54274&view=rev
Log:
[KERNEL32]: Rewrite (in some cases, simply clean-up) environment handling functions for better string handling, error codes, and performance. Part of ongoing kernel32 work.

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

Modified: trunk/reactos/dll/win32/kernel32/client/environ.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/environ.c?rev=54274&r1=54273&r2=54274&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/environ.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/environ.c [iso-8859-1] Sun Oct 30 01:07:09 2011
@@ -24,489 +24,506 @@
  */
 DWORD
 WINAPI
-GetEnvironmentVariableA (
-	LPCSTR	lpName,
-	LPSTR	lpBuffer,
-	DWORD	nSize
-	)
-{
-	ANSI_STRING VarName;
-	ANSI_STRING VarValue;
-	UNICODE_STRING VarNameU;
-	UNICODE_STRING VarValueU;
-	NTSTATUS Status;
-
-	/* initialize unicode variable name string */
-	RtlInitAnsiString (&VarName,
-	                   (LPSTR)lpName);
-	RtlAnsiStringToUnicodeString (&VarNameU,
-	                              &VarName,
-	                              TRUE);
-
-	/* initialize ansi variable value string */
-	VarValue.Length = 0;
-	VarValue.MaximumLength = (USHORT)nSize;
-	VarValue.Buffer = lpBuffer;
-
-	/* initialize unicode variable value string and allocate buffer */
-	VarValueU.Length = 0;
-	if (nSize != 0)
-	{
-	    VarValueU.MaximumLength = (USHORT)(nSize - 1) * sizeof(WCHAR);
-	    VarValueU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
-	                                        0,
-	                                        nSize * sizeof(WCHAR));
-            if (VarValueU.Buffer != NULL)
-            {
-                /* NULL-terminate the buffer in any case! RtlQueryEnvironmentVariable_U
-                   only terminates it if MaximumLength < Length! */
-                VarValueU.Buffer[nSize - 1] = L'\0';
-            }
-        }
-	else
-	{
-            VarValueU.MaximumLength = 0;
-            VarValueU.Buffer = NULL;
-	}
-
-        if (VarValueU.Buffer != NULL || nSize == 0)
-        {
-            /* get unicode environment variable */
-	    Status = RtlQueryEnvironmentVariable_U (NULL,
-	                                            &VarNameU,
-	                                            &VarValueU);
-	    if (!NT_SUCCESS(Status))
-	    {
-		/* free unicode buffer */
-		RtlFreeHeap (RtlGetProcessHeap (),
-		             0,
-		             VarValueU.Buffer);
-
-		/* free unicode variable name string */
-		RtlFreeUnicodeString (&VarNameU);
-
-		BaseSetLastNTError (Status);
-		if (Status == STATUS_BUFFER_TOO_SMALL)
-		{
-			return (VarValueU.Length / sizeof(WCHAR)) + 1;
-		}
-		else
-		{
-			return 0;
-		}
-	    }
-
-	    /* convert unicode value string to ansi */
-	    RtlUnicodeStringToAnsiString (&VarValue,
-	                                  &VarValueU,
-	                                  FALSE);
-
-            if (VarValueU.Buffer != NULL)
-            {
-                /* free unicode buffer */
-	        RtlFreeHeap (RtlGetProcessHeap (),
-	                     0,
-	                     VarValueU.Buffer);
-            }
-
-	    /* free unicode variable name string */
-	    RtlFreeUnicodeString (&VarNameU);
-
-	    return (VarValueU.Length / sizeof(WCHAR));
-        }
-        else
-        {
-            SetLastError (ERROR_NOT_ENOUGH_MEMORY);
-            return 0;
-        }
-}
-
+GetEnvironmentVariableA(IN LPCSTR lpName,
+                        IN LPSTR lpBuffer,
+                        IN DWORD nSize)
+{
+    ANSI_STRING VarName, VarValue;
+    UNICODE_STRING VarNameU, VarValueU;
+    PWSTR Buffer;
+    ULONG Result = 0, UniSize = 0;
+    NTSTATUS Status;
+
+    /* Initialize all the strings */
+    RtlInitAnsiString(&VarName, lpName);
+    RtlInitUnicodeString(&VarNameU, NULL);
+    RtlInitUnicodeString(&VarValueU, NULL);
+    Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
+    if (!NT_SUCCESS(Status)) goto Quickie;
+
+    /* Check if the size is too big to fit */
+    if (nSize <= UNICODE_STRING_MAX_BYTES)
+    {
+        /* Keep the given size, minus a NULL-char */
+        if (nSize) UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
+    }
+    else
+    {
+        /* Set the maximum possible */
+        UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
+    }
+
+    /* Allocate the value string buffer */
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize);
+    if (!Buffer)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* And initialize its string */
+    RtlInitEmptyUnicodeString(&VarValueU, Buffer, UniSize);
+
+    /* Acquire the PEB lock since we'll be querying variables now */
+    RtlAcquirePebLock();
+
+    /* Query the variable */
+    Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
+    if ((NT_SUCCESS(Status)) && !(nSize)) Status = STATUS_BUFFER_TOO_SMALL;
+
+    /* Check if we didn't have enough space */
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        /* Fixup the length that the API returned */
+        VarValueU.MaximumLength = VarValueU.Length + 2;
+
+        /* Free old Unicode buffer */
+        RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
+
+        /* Allocate new one */
+        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VarValueU.MaximumLength);
+        if (Buffer)
+        {
+            /* Query the variable so we can know its size */
+            VarValueU.Buffer = Buffer;
+            Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
+            if (NT_SUCCESS(Status))
+            {
+                /* Get the ASCII length of the variable */
+                Result = RtlUnicodeStringToAnsiSize(&VarValueU);
+            }
+        }
+        else
+        {
+            /* Set failure status */
+            Status = STATUS_NO_MEMORY;
+        }
+    }
+    else
+    {
+        /* Check if the size is too big to fit */
+        if (nSize <= MAXULONG)
+        {
+            /* Keep the given size, minus a NULL-char */
+            if (nSize) nSize = nSize - sizeof(ANSI_NULL);
+        }
+        else
+        {
+            /* Set the maximum possible */
+            nSize = MAXULONG - sizeof(ANSI_NULL);
+        }
+
+        /* Check the size */
+        Result = RtlUnicodeStringToAnsiSize(&VarValueU);
+        if (Result <= nSize)
+        {
+            /* Convert the string */
+            RtlInitEmptyAnsiString(&VarValue, lpBuffer, nSize);
+            Status = RtlUnicodeStringToAnsiString(&VarValue, &VarValueU, FALSE);
+            if (NT_SUCCESS(Status))
+            {
+                /* NULL-terminate and set the final length */
+                lpBuffer[VarValue.Length] = ANSI_NULL;
+                Result = VarValue.Length;
+            }
+        }
+    }
+
+    /* Release the lock */
+    RtlReleasePebLock();
+
+Quickie:
+    /* Free the strings */
+    RtlFreeUnicodeString(&VarNameU);
+    if (VarValueU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
+
+    /* Check if we suceeded */
+    if (!NT_SUCCESS(Status))
+    {
+        /* We did not, clear the result and set the error code */
+        BaseSetLastNTError(Status);
+        Result = 0;
+    }
+
+    /* Return the result */
+    return Result;
+}
 
 /*
  * @implemented
  */
 DWORD
 WINAPI
-GetEnvironmentVariableW (
-	LPCWSTR	lpName,
-	LPWSTR	lpBuffer,
-	DWORD	nSize
-	)
-{
-	UNICODE_STRING VarName;
-	UNICODE_STRING VarValue;
-	NTSTATUS Status;
-
-	RtlInitUnicodeString (&VarName,
-	                      lpName);
-
-	VarValue.Length = 0;
-	VarValue.MaximumLength = (USHORT) (nSize ? nSize - 1 : 0) * sizeof(WCHAR);
-	VarValue.Buffer = lpBuffer;
-
-	Status = RtlQueryEnvironmentVariable_U (NULL,
-	                                        &VarName,
-	                                        &VarValue);
-	if (!NT_SUCCESS(Status))
-	{
-		if (Status == STATUS_BUFFER_TOO_SMALL)
-		{
-			return (VarValue.Length / sizeof(WCHAR)) + 1;
-		}
-		else
-		{
-			BaseSetLastNTError (Status);
-			return 0;
-		}
-	}
-	
-        if (nSize != 0)
-        {
-            /* make sure the string is NULL-terminated! RtlQueryEnvironmentVariable_U
-               only terminates it if MaximumLength < Length */
-	    lpBuffer[VarValue.Length / sizeof(WCHAR)] = L'\0';
-	}
-
-	return (VarValue.Length / sizeof(WCHAR));
-}
-
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetEnvironmentVariableA (
-	LPCSTR	lpName,
-	LPCSTR	lpValue
-	)
-{
-	ANSI_STRING VarName;
-	ANSI_STRING VarValue;
-	UNICODE_STRING VarNameU;
-	UNICODE_STRING VarValueU;
-	NTSTATUS Status;
-
-	DPRINT("SetEnvironmentVariableA(Name '%s', Value '%s')\n", lpName, lpValue);
-
-	RtlInitAnsiString (&VarName,
-	                   (LPSTR)lpName);
-	RtlAnsiStringToUnicodeString (&VarNameU,
-	                              &VarName,
-	                              TRUE);
-
-	if (lpValue)
-	{
-		RtlInitAnsiString (&VarValue,
-		                   (LPSTR)lpValue);
-		RtlAnsiStringToUnicodeString (&VarValueU,
-		                              &VarValue,
-		                              TRUE);
-
-		Status = RtlSetEnvironmentVariable (NULL,
-		                                    &VarNameU,
-		                                    &VarValueU);
-
-		RtlFreeUnicodeString (&VarValueU);
-	}
-	else
-	{
-		Status = RtlSetEnvironmentVariable (NULL,
-		                                    &VarNameU,
-		                                    NULL);
-	}
-	RtlFreeUnicodeString (&VarNameU);
-
-	if (!NT_SUCCESS(Status))
-	{
-		BaseSetLastNTError (Status);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetEnvironmentVariableW (
-	LPCWSTR	lpName,
-	LPCWSTR	lpValue
-	)
-{
-	UNICODE_STRING VarName;
-	UNICODE_STRING VarValue;
-	NTSTATUS Status;
-
-	DPRINT("SetEnvironmentVariableW(Name '%S', Value '%S')\n", lpName, lpValue);
-
-	RtlInitUnicodeString (&VarName,
-	                      lpName);
-
-	RtlInitUnicodeString (&VarValue,
-	                      lpValue);
-
-	Status = RtlSetEnvironmentVariable (NULL,
-	                                    &VarName,
-	                                    &VarValue);
-
-	if (!NT_SUCCESS(Status))
-	{
-		BaseSetLastNTError (Status);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-
-/*
- * @implemented
- */
-LPSTR
-WINAPI
-GetEnvironmentStringsA (
-	VOID
-	)
-{
-	UNICODE_STRING UnicodeString;
-	ANSI_STRING AnsiString;
-	PWCHAR EnvU;
-	PWCHAR PtrU;
-	ULONG  Length;
-	PCHAR EnvPtr = NULL;
-
-	EnvU = (PWCHAR)(NtCurrentPeb ()->ProcessParameters->Environment);
-
-	if (EnvU == NULL)
-		return NULL;
-
-	if (*EnvU == 0)
-		return NULL;
-
-	/* get environment size */
-	PtrU = EnvU;
-	while (*PtrU)
-	{
-		while (*PtrU)
-			PtrU++;
-		PtrU++;
-	}
-	Length = (ULONG)(PtrU - EnvU);
-	DPRINT("Length %lu\n", Length);
-
-	/* allocate environment buffer */
-	EnvPtr = RtlAllocateHeap (RtlGetProcessHeap (),
-	                          0,
-	                          Length + 1);
-        if (EnvPtr == NULL)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return NULL;
-        }
-	DPRINT("EnvPtr %p\n", EnvPtr);
-
-	/* convert unicode environment to ansi */
-	UnicodeString.MaximumLength = (USHORT)Length * sizeof(WCHAR) + sizeof(WCHAR);
-	UnicodeString.Buffer = EnvU;
-
-	AnsiString.MaximumLength = (USHORT)Length + 1;
-	AnsiString.Length = 0;
-	AnsiString.Buffer = EnvPtr;
-
-	DPRINT ("UnicodeString.Buffer \'%S\'\n", UnicodeString.Buffer);
-
-	while (*(UnicodeString.Buffer))
-	{
-		UnicodeString.Length = wcslen (UnicodeString.Buffer) * sizeof(WCHAR);
-		UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
-		if (UnicodeString.Length > 0)
-		{
-			AnsiString.Length = 0;
-			AnsiString.MaximumLength = (USHORT)Length + 1 - (AnsiString.Buffer - EnvPtr);
-
-			RtlUnicodeStringToAnsiString (&AnsiString,
-			                              &UnicodeString,
-			                              FALSE);
-
-			AnsiString.Buffer += (AnsiString.Length + 1);
-			UnicodeString.Buffer += ((UnicodeString.Length / sizeof(WCHAR)) + 1);
-		}
-	}
-	*(AnsiString.Buffer) = 0;
-
-	return EnvPtr;
-}
-
-
-/*
- * @implemented
- */
-LPWSTR
-WINAPI
-GetEnvironmentStringsW (
-	VOID
-	)
-{
-	return (LPWSTR)(NtCurrentPeb ()->ProcessParameters->Environment);
-}
-
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-FreeEnvironmentStringsA (
-	LPSTR	EnvironmentStrings
-	)
-{
-	if (EnvironmentStrings == NULL)
-		return FALSE;
-
-	RtlFreeHeap (RtlGetProcessHeap (),
-	             0,
-	             EnvironmentStrings);
-
-	return TRUE;
-}
-
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-FreeEnvironmentStringsW (
-	LPWSTR	EnvironmentStrings
-	)
-{
- return TRUE;
-}
-
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-ExpandEnvironmentStringsA (
-	LPCSTR	lpSrc,
-	LPSTR	lpDst,
-	DWORD	nSize
-	)
-{
-	ANSI_STRING Source;
-	ANSI_STRING Destination;
-	UNICODE_STRING SourceU;
-	UNICODE_STRING DestinationU;
-	NTSTATUS Status;
-	ULONG Length = 0;
-
-	RtlInitAnsiString (&Source,
-	                   (LPSTR)lpSrc);
-	Status = RtlAnsiStringToUnicodeString (&SourceU,
-	                                       &Source,
-	                                       TRUE);
+GetEnvironmentVariableW(IN LPCWSTR lpName,
+                        IN LPWSTR lpBuffer,
+                        IN DWORD nSize)
+{
+    UNICODE_STRING VarName, VarValue;
+    NTSTATUS Status;
+
+    if (nSize <= UNICODE_STRING_MAX_BYTES)
+    {
+        if (nSize) nSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
+    }
+    else
+    {
+        nSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
+    }
+
+    Status = RtlInitUnicodeStringEx(&VarName, lpName);
+    if (NT_SUCCESS(Status))
+    {
+        RtlInitEmptyUnicodeString(&VarValue, lpBuffer, nSize);
+
+        Status = RtlQueryEnvironmentVariable_U(NULL, &VarName, &VarValue);
         if (!NT_SUCCESS(Status))
         {
+            if (Status == STATUS_BUFFER_TOO_SMALL)
+            {
+                return (VarValue.Length / sizeof(WCHAR)) + sizeof(ANSI_NULL);
+            }
             BaseSetLastNTError (Status);
             return 0;
         }
 
-    /* make sure we don't overflow the maximum ANSI_STRING size */
-    if (nSize > 0x7fff)
-        nSize = 0x7fff;
-
-	Destination.Length = 0;
-	Destination.MaximumLength = (USHORT)nSize;
-	Destination.Buffer = lpDst;
-
-	DestinationU.Length = 0;
-	DestinationU.MaximumLength = (USHORT)nSize * sizeof(WCHAR);
-	DestinationU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
-	                                       0,
-	                                       DestinationU.MaximumLength);
-        if (DestinationU.Buffer == NULL)
-        {
-            RtlFreeUnicodeString(&SourceU);
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return 0;
-        }
-
-	Status = RtlExpandEnvironmentStrings_U (NULL,
-	                                        &SourceU,
-	                                        &DestinationU,
-	                                        &Length);
-
-	RtlFreeUnicodeString (&SourceU);
-
-	if (!NT_SUCCESS(Status))
-	{
-		BaseSetLastNTError (Status);
-		if (Status != STATUS_BUFFER_TOO_SMALL)
-		{
-			RtlFreeHeap (RtlGetProcessHeap (),
-			             0,
-			             DestinationU.Buffer);
-			return 0;
-		}
-	}
-
-	RtlUnicodeStringToAnsiString (&Destination,
-	                              &DestinationU,
-	                              FALSE);
-
-	RtlFreeHeap (RtlGetProcessHeap (),
-	             0,
-	             DestinationU.Buffer);
-
-	return (Length / sizeof(WCHAR));
-}
-
+        lpBuffer[VarValue.Length / sizeof(WCHAR)] = UNICODE_NULL;
+    }
+
+    return (VarValue.Length / sizeof(WCHAR));
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetEnvironmentVariableA(IN LPCSTR lpName,
+                        IN LPCSTR lpValue)
+{
+    ANSI_STRING VarName, VarValue;
+    UNICODE_STRING VarNameU, VarValueU;
+    NTSTATUS Status;
+
+    RtlInitAnsiString(&VarName, (LPSTR)lpName);
+    Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        if (lpValue)
+        {
+            RtlInitAnsiString(&VarValue, (LPSTR)lpValue);
+            Status = RtlAnsiStringToUnicodeString(&VarValueU, &VarValue, TRUE);
+            if (NT_SUCCESS(Status))
+            {
+                Status = RtlSetEnvironmentVariable(NULL, &VarNameU, &VarValueU);
+                RtlFreeUnicodeString(&VarValueU);
+            }
+        }
+        else
+        {
+            Status = RtlSetEnvironmentVariable(NULL, &VarNameU, NULL);
+        }
+
+        RtlFreeUnicodeString(&VarNameU);
+
+        if (NT_SUCCESS(Status)) return TRUE;
+    }
+
+    BaseSetLastNTError(Status);
+    return FALSE;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetEnvironmentVariableW(IN LPCWSTR lpName,
+                        IN LPCWSTR lpValue)
+{
+    UNICODE_STRING VarName, VarValue;
+    NTSTATUS Status;
+
+    Status = RtlInitUnicodeStringEx(&VarName, lpName);
+    if (NT_SUCCESS(Status))
+    {
+        if (lpValue)
+        {
+            Status = RtlInitUnicodeStringEx(&VarValue, lpValue);
+            if (NT_SUCCESS(Status))
+            {
+                Status = RtlSetEnvironmentVariable(NULL, &VarName, &VarValue);
+            }
+        }
+        else
+        {
+            Status = RtlSetEnvironmentVariable(NULL, &VarName, NULL);
+        }
+
+        if (NT_SUCCESS(Status)) return TRUE;
+    }
+
+    BaseSetLastNTError(Status);
+    return FALSE;
+}
+
+/*
+ * @implemented
+ */
+LPSTR
+WINAPI
+GetEnvironmentStringsA(VOID)
+{
+    ULONG Length, Size;
+    NTSTATUS Status;
+    PWCHAR Environment, p;
+    PCHAR Buffer = NULL;
+
+    RtlAcquirePebLock();
+    p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
+
+    do
+    {
+        p += wcslen(Environment) + 1;
+    } while (*p);
+
+    Length = p - Environment + sizeof(UNICODE_NULL);
+
+    Status = RtlUnicodeToMultiByteSize(&Size, Environment, Length);
+    if (NT_SUCCESS(Status))
+    {
+        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
+        if (Buffer)
+        {
+            Status = RtlUnicodeToOemN(Buffer, Size, 0, Environment, Length);
+            if (!NT_SUCCESS(Status))
+            {
+                RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+                Buffer = NULL;
+
+                BaseSetLastNTError(Status);
+            }
+        }
+        else
+        {
+            BaseSetLastNTError(STATUS_NO_MEMORY);
+        }
+    }
+    else
+    {
+        BaseSetLastNTError(Status);
+    }
+
+    RtlReleasePebLock();
+    return Buffer;
+}
+
+/*
+ * @implemented
+ */
+LPWSTR
+WINAPI
+GetEnvironmentStringsW(VOID)
+{
+    PWCHAR Environment, p;
+    ULONG Length;
+
+    RtlAcquirePebLock();
+
+    p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
+
+    do
+    {
+        p += wcslen(Environment) + 1;
+    } while (*p);
+
+    Length = p - Environment + sizeof(UNICODE_NULL);
+
+    p = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
+    if (p)
+    {
+        RtlCopyMemory(p, Environment, Length);
+    }
+    else
+    {
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+    }
+
+    RtlReleasePebLock();
+    return p;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+FreeEnvironmentStringsA(IN LPSTR EnvironmentStrings)
+{
+    return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+FreeEnvironmentStringsW(IN LPWSTR EnvironmentStrings)
+{
+    return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
+}
 
 /*
  * @implemented
  */
 DWORD
 WINAPI
-ExpandEnvironmentStringsW (
-	LPCWSTR	lpSrc,
-	LPWSTR	lpDst,
-	DWORD	nSize
-	)
-{
-	UNICODE_STRING Source;
-	UNICODE_STRING Destination;
-	NTSTATUS Status;
-	ULONG Length = 0;
-
-	RtlInitUnicodeString (&Source,
-	                      (LPWSTR)lpSrc);
+ExpandEnvironmentStringsA(IN LPCSTR lpSrc,
+                          IN LPSTR lpDst,
+                          IN DWORD nSize)
+{
+    ANSI_STRING Source, Dest;
+    UNICODE_STRING SourceU, DestU;
+    PWSTR Buffer;
+    ULONG Result = 0, UniSize = 0, Length;
+    NTSTATUS Status;
+
+    /* Initialize all the strings */
+    RtlInitAnsiString(&Source, lpSrc);
+    RtlInitUnicodeString(&SourceU, NULL);
+    RtlInitUnicodeString(&DestU, NULL);
+    Status = RtlAnsiStringToUnicodeString(&SourceU, &Source, TRUE);
+    if (!NT_SUCCESS(Status)) goto Quickie;
+
+    /* Check if the size is too big to fit */
+    if (nSize <= UNICODE_STRING_MAX_BYTES)
+    {
+        /* Keep the given size, minus a NULL-char */
+        if (nSize) UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
+    }
+    else
+    {
+        /* Set the maximum possible */
+        UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
+    }
+
+    /* Allocate the value string buffer */
+    Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize);
+    if (!Buffer)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* And initialize its string */
+    RtlInitEmptyUnicodeString(&DestU, Buffer, UniSize);
+
+    /* Query the variable */
+    Length = 0;
+    Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
+
+    /* Check if we didn't have enough space */
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        /* Fixup the length that the API returned */
+        DestU.MaximumLength = Length;
+
+        /* Free old Unicode buffer */
+        RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
+
+        /* Allocate new one */
+        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
+        if (Buffer)
+        {
+            /* Query the variable so we can know its size */
+            DestU.Buffer = Buffer;
+            Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
+            if (NT_SUCCESS(Status))
+            {
+                /* Get the ASCII length of the variable */
+                Result = RtlUnicodeStringToAnsiSize(&DestU);
+            }
+        }
+        else
+        {
+            /* Set failure status */
+            Status = STATUS_NO_MEMORY;
+        }
+    }
+    else
+    {
+        /* Check if the size is too big to fit */
+        if (nSize <= MAXULONG)
+        {
+            /* Keep the given size, minus a NULL-char */
+            if (nSize) nSize = nSize - sizeof(ANSI_NULL);
+        }
+        else
+        {
+            /* Set the maximum possible */
+            nSize = MAXULONG - sizeof(ANSI_NULL);
+        }
+
+        /* Check the size */
+        Result = RtlUnicodeStringToAnsiSize(&DestU);
+        if (Result <= nSize)
+        {
+            /* Convert the string */
+            RtlInitEmptyAnsiString(&Dest, lpDst, nSize);
+            Status = RtlUnicodeStringToAnsiString(&Dest, &DestU, FALSE);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Clear the destination */
+                *lpDst = ANSI_NULL;
+            }
+        }
+    }
+Quickie:
+    /* Free the strings */
+    RtlFreeUnicodeString(&SourceU);
+    if (DestU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
+
+    /* Check if we suceeded */
+    if (!NT_SUCCESS(Status))
+    {
+        /* We did not, clear the result and set the error code */
+        BaseSetLastNTError(Status);
+        Result = 0;
+    }
+
+    /* Return the result */
+    return Result;
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+ExpandEnvironmentStringsW(IN LPCWSTR lpSrc,
+                          IN LPWSTR lpDst,
+                          IN DWORD nSize)
+{
+    UNICODE_STRING Source, Destination;
+    NTSTATUS Status;;
+
+    RtlInitUnicodeString(&Source, (LPWSTR)lpSrc);
 
     /* make sure we don't overflow the maximum UNICODE_STRING size */
-    if (nSize > 0x7fff)
-        nSize = 0x7fff;
-
-	Destination.Length = 0;
-	Destination.MaximumLength = (USHORT)nSize * sizeof(WCHAR);
-	Destination.Buffer = lpDst;
-
-	Status = RtlExpandEnvironmentStrings_U (NULL,
-	                                        &Source,
-	                                        &Destination,
-	                                        &Length);
-	if (!NT_SUCCESS(Status))
-	{
-		BaseSetLastNTError (Status);
-		if (Status != STATUS_BUFFER_TOO_SMALL)
-			return 0;
-	}
-
-	return (Length / sizeof(WCHAR));
+    if (nSize > UNICODE_STRING_MAX_BYTES) nSize = UNICODE_STRING_MAX_BYTES;
+
+    RtlInitEmptyUnicodeString(&Destination, lpDst, nSize * sizeof(WCHAR));
+    Status = RtlExpandEnvironmentStrings_U(NULL,
+                                           &Source,
+                                           &Destination,
+                                           &nSize);
+    if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
+    {
+        return nSize / sizeof(WCHAR);
+    }
+
+    BaseSetLastNTError (Status);
+    return 0;
+
 }
 
 /*




More information about the Ros-diffs mailing list