- Change RtlIsDosDeviceName_U() implementation to a better Wine implementation
authorAleksey Bragin <aleksey@reactos.org>
Mon, 17 Sep 2007 19:51:32 +0000 (19:51 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Mon, 17 Sep 2007 19:51:32 +0000 (19:51 +0000)
- Winesync RtlIsNameLegalDOS8Dot3()
- "ntdll_winetest.exe path" reduced to 3 failures (which happen on XP too), so considering "path" done 100% now.

svn path=/trunk/; revision=29084

reactos/lib/rtl/dos8dot3.c
reactos/lib/rtl/path.c

index 2335c92..d8051bc 100644 (file)
@@ -238,79 +238,64 @@ RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName,
                        IN OUT POEM_STRING AnsiName OPTIONAL,
                        IN OUT PBOOLEAN SpacesFound OPTIONAL)
 {
-   PANSI_STRING name = AnsiName;
-   ANSI_STRING DummyString;
-   CHAR Buffer[12];
-   char *str;
-   ULONG Length;
-   ULONG i;
-   NTSTATUS Status;
-   BOOLEAN HasSpace = FALSE;
-   BOOLEAN HasDot = FALSE;
-
-   if (UnicodeName->Length > 24)
-   {
-      return(FALSE); /* name too long */
-   }
-
-   if (!name)
-   {
-      name = &DummyString;
-      name->Length = 0;
-      name->MaximumLength = 12;
-      name->Buffer = Buffer;
-   }
-
-   Status = RtlUpcaseUnicodeStringToCountedOemString(name,
-            UnicodeName,
-            FALSE);
-   if (!NT_SUCCESS(Status))
-   {
-      return(FALSE);
-   }
-
-   Length = name->Length;
-   str = name->Buffer;
-
-   if (!(Length == 1 && *str == '.') &&
-         !(Length == 2 && *str == '.' && *(str + 1) == '.'))
-   {
-      for (i = 0; i < Length; i++, str++)
-      {
-         switch (*str)
-         {
-            case ' ':
-               HasSpace = TRUE;
-               break;
-
-            case '.':
-               if ((HasDot) ||   /* two or more dots */
-                     (i == 0) ||   /* dot is first char */
-                     (i + 1 == Length) || /* dot is last char */
-                     (Length - i > 4) ||  /* more than 3 chars of extension */
-                     (HasDot == FALSE && i > 8)) /* name is longer than 8 chars */
-                  return(FALSE);
-               HasDot = TRUE;
-               break;
-            default:
-               if (RtlpIsShortIllegal(*str))
-               {
-                  return(FALSE);
-               }
-         }
-      }
-   }
-
-   /* Name is longer than 8 chars and does not have an extension */
-   if (Length > 8 && HasDot == FALSE)
-   {
-      return(FALSE);
-   }
-
-   if (SpacesFound)
-      *SpacesFound = HasSpace;
-
-   return(TRUE);
+    static const char Illegal[] = "*?<>|\"+=,;[]:/\\\345";
+    int Dot = -1;
+    int i;
+    char Buffer[12];
+    OEM_STRING OemString;
+    BOOLEAN GotSpace = FALSE;
+
+    if (!AnsiName)
+    {
+        OemString.Length = sizeof(Buffer);
+        OemString.MaximumLength = sizeof(Buffer);
+        OemString.Buffer = Buffer;
+        AnsiName = &OemString;
+    }
+    if (RtlUpcaseUnicodeStringToCountedOemString( AnsiName, UnicodeName, FALSE ) != STATUS_SUCCESS)
+        return FALSE;
+
+    if (AnsiName->Length > 12) return FALSE;
+
+    /* a starting . is invalid, except for . and .. */
+    if (AnsiName->Buffer[0] == '.')
+    {
+        if (AnsiName->Length != 1 && (AnsiName->Length != 2 || AnsiName->Buffer[1] != '.')) return FALSE;
+        if (SpacesFound) *SpacesFound = FALSE;
+        return TRUE;
+    }
+
+    for (i = 0; i < AnsiName->Length; i++)
+    {
+        switch (AnsiName->Buffer[i])
+        {
+        case ' ':
+            /* leading/trailing spaces not allowed */
+            if (!i || i == AnsiName->Length-1 || AnsiName->Buffer[i+1] == '.') return FALSE;
+            GotSpace = TRUE;
+            break;
+        case '.':
+            if (Dot != -1) return FALSE;
+            Dot = i;
+            break;
+        default:
+            if (strchr(Illegal, AnsiName->Buffer[i])) return FALSE;
+            break;
+        }
+    }
+    /* check file part is shorter than 8, extension shorter than 3
+     * dot cannot be last in string
+     */
+    if (Dot == -1)
+    {
+        if (AnsiName->Length > 8) return FALSE;
+    }
+    else
+    {
+        if (Dot > 8 || (AnsiName->Length - Dot > 4) || Dot == AnsiName->Length - 1) return FALSE;
+    }
+    if (SpacesFound) *SpacesFound = GotSpace;
+    return TRUE;
 }
 
 /*
index 96185ad..5bf176f 100644 (file)
@@ -91,92 +91,69 @@ RtlDetermineDosPathNameType_U(PCWSTR Path)
  * @implemented
  */
 ULONG NTAPI
-RtlIsDosDeviceName_U(PWSTR DeviceName)
+RtlIsDosDeviceName_U(PWSTR dos_name)
 {
-   ULONG Type;
-   ULONG Length = 0;
-   ULONG Offset;
-   PWCHAR wc;
-   UNICODE_STRING DeviceNameU;
-
-   if (DeviceName == NULL)
-     {
-       return 0;
-     }
-
-   while (DeviceName[Length])
-     {
-       Length++;
-     }
-
-   Type = RtlDetermineDosPathNameType_U(DeviceName);
-   if (Type <= 1)
-     {
-       return 0;
-     }
-
-   if (Type == 6)
-     {
-        DeviceNameU.Length = DeviceNameU.MaximumLength = Length * sizeof(WCHAR);
-       DeviceNameU.Buffer = DeviceName;
-       if (Length == 7 &&
-           RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_condev, TRUE))
-               return 0x00080006;
-       return 0;
-     }
-
-   /* name can end with ':' */
-   if (Length && DeviceName[Length - 1 ] == L':')
-     {
-       Length--;
-     }
-
-   /* there can be spaces or points at the end of name */
-   wc = DeviceName + Length - 1;
-   while (Length && (*wc == L'.' || *wc == L' '))
-     {
-       Length--;
-       wc--;
-     }
-
-   /* let's find a beginning of name */
-   wc = DeviceName + Length - 1;
-   while (wc > DeviceName && !IS_PATH_SEPARATOR(*(wc - 1)))
-     {
-       wc--;
-     }
-   Offset = wc - DeviceName;
-   Length -= Offset;
-   DeviceNameU.Length = DeviceNameU.MaximumLength = 3 * sizeof(WCHAR);
-   DeviceNameU.Buffer = wc;
-
-   /* check for LPTx or COMx */
-   if (Length == 4 && wc[3] >= L'0' && wc[3] <= L'9')
-     {
-       if (wc[3] == L'0')
-         {
-            return 0;
-         }
-
-       if (RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_lpt, TRUE) ||
-           RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_com, TRUE))
-         {
-            return ((Offset * 2) << 16 ) | 8;
-         }
-       return 0;
-     }
-
-   /* check for PRN,AUX,NUL or CON */
-   if (Length == 3 &&
-       (RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_prn, TRUE) ||
-        RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_aux, TRUE) ||
-        RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_nul, TRUE) ||
-        RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_con, TRUE)))
-     {
-       return ((Offset * 2) << 16) | 6;
-     }
-
-   return 0;
+    static const WCHAR consoleW[] = {'\\','\\','.','\\','C','O','N',0};
+    static const WCHAR auxW[3] = {'A','U','X'};
+    static const WCHAR comW[3] = {'C','O','M'};
+    static const WCHAR conW[3] = {'C','O','N'};
+    static const WCHAR lptW[3] = {'L','P','T'};
+    static const WCHAR nulW[3] = {'N','U','L'};
+    static const WCHAR prnW[3] = {'P','R','N'};
+
+    const WCHAR *start, *end, *p;
+
+    switch(RtlDetermineDosPathNameType_U( dos_name ))
+    {
+    case RtlPathTypeUnknown:
+    case RtlPathTypeUncAbsolute:
+        return 0;
+    case RtlPathTypeLocalDevice:
+        if (!_wcsicmp( dos_name, consoleW ))
+            return MAKELONG( sizeof(conW), 4 * sizeof(WCHAR) );  /* 4 is length of \\.\ prefix */
+        return 0;
+    default:
+        break;
+    }
+
+    end = dos_name + wcslen(dos_name) - 1;
+    while (end >= dos_name && *end == ':') end--;  /* remove all trailing ':' */
+
+    /* find start of file name */
+    for (start = end; start >= dos_name; start--)
+    {
+        if (IS_PATH_SEPARATOR(start[0])) break;
+        /* check for ':' but ignore if before extension (for things like NUL:.txt) */
+        if (start[0] == ':' && start[1] != '.') break;
+    }
+    start++;
+
+    /* remove extension */
+    if ((p = wcschr( start, '.' )))
+    {
+        end = p - 1;
+        if (end >= dos_name && *end == ':') end--;  /* remove trailing ':' before extension */
+    }
+    /* remove trailing spaces */
+    while (end >= dos_name && *end == ' ') end--;
+
+    /* now we have a potential device name between start and end, check it */
+    switch(end - start + 1)
+    {
+    case 3:
+        if (_wcsnicmp( start, auxW, 3 ) &&
+            _wcsnicmp( start, conW, 3 ) &&
+            _wcsnicmp( start, nulW, 3 ) &&
+            _wcsnicmp( start, prnW, 3 )) break;
+        return MAKELONG( 3 * sizeof(WCHAR), (start - dos_name) * sizeof(WCHAR) );
+    case 4:
+        if (_wcsnicmp( start, comW, 3 ) && _wcsnicmp( start, lptW, 3 )) break;
+        if (*end <= '0' || *end > '9') break;
+        return MAKELONG( 4 * sizeof(WCHAR), (start - dos_name) * sizeof(WCHAR) );
+    default:  /* can't match anything */
+        break;
+    }
+    return 0;
 }
 
 
@@ -389,7 +366,12 @@ static __inline void collapse_path( WCHAR *path, UINT mark )
         }
         /* skip to the next component */
         while (*p && *p != '\\') p++;
-        if (*p == '\\') p++;
+        if (*p == '\\')
+        {
+            /* remove last dot in previous dir name */
+            if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) );
+            else p++;
+        }
     }
 
     /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */
@@ -439,7 +421,8 @@ static ULONG get_full_path_helper(
 
     RtlAcquirePebLock();
 
-    cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath;
+    //cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath;
+    cd = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath;
 
     switch (type = RtlDetermineDosPathNameType_U(name))
     {