[ros-diffs] [fireball] 54018: [RTL] - Post-r52687 implementation of RtlIsDosDeviceName_U is more advanced than pre-r52687 one and covers more corner cases which may not be tested by existing winetests. - Thus ...

fireball at svn.reactos.org fireball at svn.reactos.org
Wed Oct 5 22:20:31 UTC 2011


Author: fireball
Date: Wed Oct  5 22:20:30 2011
New Revision: 54018

URL: http://svn.reactos.org/svn/reactos?rev=54018&view=rev
Log:
[RTL]
- Post-r52687 implementation of RtlIsDosDeviceName_U is more advanced than pre-r52687 one and covers more corner cases which may not be tested by existing winetests.
- Thus bring back the post-r52687 and also introduce fixes for the following bugs in it:
* Incorrect extension/space-at-the-end truncation
* Incorrect encoding of returned offset/length pair
* Incorrect condition for for-loop exit
* Incorrect calculation of the return length in case of COMx/AUX devices (it should not include the terminating 0 character)
- After those trivial fixes (mostly oneliners and typos), the function works as expected and passes all ntdll_winetest path tests. Sorry for any inconviniences!

Modified:
    trunk/reactos/lib/rtl/path.c

Modified: trunk/reactos/lib/rtl/path.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/path.c?rev=54018&r1=54017&r2=54018&view=diff
==============================================================================
--- trunk/reactos/lib/rtl/path.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/path.c [iso-8859-1] Wed Oct  5 22:20:30 2011
@@ -45,9 +45,11 @@
 NTAPI
 RtlIsDosDeviceName_Ustr(IN PUNICODE_STRING PathString)
 {
-    UNICODE_STRING DeviceName;
-    PWCHAR Start, End, Ptr;
-    SIZE_T DeviceNameLength;
+    UNICODE_STRING PathCopy;
+    PWCHAR Start, End;
+    ULONG PathChars, ColonCount = 0;
+    USHORT ReturnOffset = 0, ReturnLength;
+    WCHAR c;
 
     /* Validate the input */
     if (!PathString) return 0;
@@ -69,58 +71,128 @@
             }
             return 0;
 
-        /* Skip the drive name for drive relative or absolute paths */
-        case RtlPathTypeDriveAbsolute:
-        case RtlPathTypeDriveRelative:
-            Start = PathString->Buffer + 2;
+        default:
             break;
-
-        default:
-            Start = PathString->Buffer;
-            break;
-    }
-
-    /* Find start of file name */
-    for (Ptr = Start; *Ptr; Ptr++)
-        if (IS_PATH_SEPARATOR(*Ptr))
-            Start = Ptr + 1;
-
-    /* Truncate at extension or stream */
-    for (End = Start; *End; End++)
-        if (*End == L'.' || *End == L':')
-            break;
-    End--;
-
-    /* Remove trailing spaces */
-    while (End >= Start && *End == L' ')
-        End--;
-
-    /* Build the device name string */
-    DeviceNameLength = End - Start + 1;
-    DeviceName.Buffer = Start;
-    DeviceName.Length = (USHORT)DeviceNameLength * sizeof(WCHAR);
-    DeviceName.MaximumLength = DeviceName.Length;
-
-    /* Check the device name */
-    if (DeviceNameLength == 3)
-    {
-        if (RtlPrefixUnicodeString(&RtlpDosAUXDevice, &DeviceName, TRUE) ||
-            RtlPrefixUnicodeString(&RtlpDosCONDevice, &DeviceName, TRUE) ||
-            RtlPrefixUnicodeString(&RtlpDosNULDevice, &DeviceName, TRUE) ||
-            RtlPrefixUnicodeString(&RtlpDosPRNDevice, &DeviceName, TRUE))
-        {
-            return MAKELONG(DeviceNameLength * sizeof(WCHAR), (Start - PathString->Buffer) * sizeof(WCHAR));
-        }
-    }
-    else if (DeviceNameLength == 4)
-    {
-        if ((RtlPrefixUnicodeString(&RtlpDosCOMDevice, &DeviceName, TRUE) ||
-             RtlPrefixUnicodeString(&RtlpDosLPTDevice, &DeviceName, TRUE)) &&
-            iswdigit(DeviceName.Buffer[3]) &&
-            DeviceName.Buffer[3] != L'0')
-        {
-            return MAKELONG(DeviceNameLength * sizeof(WCHAR), (Start - PathString->Buffer) * sizeof(WCHAR));
-        }
+    }
+
+    /* Make a copy of the string */
+    PathCopy = *PathString;
+
+    /* Return if there's no characters */
+    PathChars = PathCopy.Length / sizeof(WCHAR);
+    if (!PathChars) return 0;
+
+    /* Check for drive path and truncate */
+    if (PathCopy.Buffer[PathChars - 1] == L':')
+    {
+        /* Fixup the lengths */
+        PathCopy.Length -= sizeof(WCHAR);
+        if (!--PathChars) return 0;
+
+        /* Remember this for later */
+        ColonCount = 1;
+    }
+
+    /* Check for extension or space, and truncate */
+    c = PathCopy.Buffer[PathChars - 1];
+    do
+    {
+        /* Stop if we hit something else than a space or period */
+        if ((c != '.') && (c != ' ')) break;
+
+        /* Fixup the lengths and get the next character */
+        PathCopy.Length -= sizeof(WCHAR);
+        if (--PathChars) c = PathCopy.Buffer[PathChars - 1];
+
+        /* Remember this for later */
+        ColonCount++;
+    } while (PathChars);
+
+    /* Anything still left? */
+    if (PathChars)
+    {
+        /* Loop from the end */
+        for (End = &PathCopy.Buffer[PathChars - 1];
+             End >= PathCopy.Buffer;
+             --End)
+        {
+            /* Check if the character is a path or drive separator */
+            c = *End;
+            if ((c == '\\') || (c == '/') || ((c == ':') && (End == PathCopy.Buffer + 1)))
+            {
+                /* Get the next lower case character */
+                End++;
+                c = *End | ' '; // ' ' == ('z' - 'Z')
+
+                /* Check if it's a DOS device (LPT, COM, PRN, AUX, or NUL) */
+                if ((End < &PathCopy.Buffer[PathCopy.Length / sizeof(WCHAR)]) &&
+                    ((c == 'l') || (c == 'c') || (c == 'p') || (c == 'a') || (c == 'n')))
+                {
+                    /* Calculate the offset */
+                    ReturnOffset = (PCHAR)End - (PCHAR)PathCopy.Buffer;
+
+                    /* Build the final string */
+                    PathCopy.Length -= ReturnOffset;
+                    PathCopy.Length -= (ColonCount * sizeof(WCHAR));
+                    PathCopy.Buffer = End;
+                    break;
+                }
+                else
+                {
+                    return 0;
+                }
+            }
+        }
+
+        /* Get the next lower case character and check if it's a DOS device */
+        c = *PathCopy.Buffer | ' '; // ' ' == ('z' - 'Z')
+        if ((c != 'l') && (c != 'c') && (c != 'p') && (c != 'a') && (c != 'n'))
+        {
+            /* Not LPT, COM, PRN, AUX, or NUL */
+            return 0;
+        }
+    }
+
+    /* Now skip past any extra extension or drive letter characters */
+    Start = PathCopy.Buffer;
+    End = &Start[PathChars];
+    while (Start < End)
+    {
+        c = *Start;
+        if ((c == '.') || (c == ':')) break;
+        Start++;
+    }
+
+    /* And then go backwards to get rid of spaces */
+    while ((Start > PathCopy.Buffer) && (Start[-1] == ' ')) --Start;
+
+    /* Finally see how many characters are left, and that's our size */
+    PathChars = Start - PathCopy.Buffer;
+    PathCopy.Length = PathChars * sizeof(WCHAR);
+
+    /* Check if this is a COM or LPT port, which has a digit after it */
+    if ((PathChars == 4) &&
+        (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != '0')))
+    {
+        /* Don't compare the number part, just check for LPT or COM */
+        PathCopy.Length -= sizeof(WCHAR);
+        if ((RtlEqualUnicodeString(&PathCopy, &RtlpDosLPTDevice, TRUE)) ||
+            (RtlEqualUnicodeString(&PathCopy, &RtlpDosCOMDevice, TRUE)))
+        {
+            /* Found it */
+            ReturnLength = sizeof(L"COM1") - sizeof(WCHAR);
+            return MAKELONG(ReturnLength, ReturnOffset);
+        }
+    }
+    else if ((PathChars == 3) &&
+             ((RtlEqualUnicodeString(&PathCopy, &RtlpDosPRNDevice, TRUE)) ||
+              (RtlEqualUnicodeString(&PathCopy, &RtlpDosAUXDevice, TRUE)) ||
+              (RtlEqualUnicodeString(&PathCopy, &RtlpDosNULDevice, TRUE)) ||
+              (RtlEqualUnicodeString(&PathCopy, &RtlpDosCONDevice, TRUE))))
+    {
+        /* Otherwise this was something like AUX, NUL, PRN, or CON */
+        ReturnLength = sizeof(L"AUX") - sizeof(WCHAR);
+        return MAKELONG(ReturnLength, ReturnOffset);
     }
 
     /* Otherwise, this is not a valid DOS device */




More information about the Ros-diffs mailing list