[RTL]
[reactos.git] / reactos / lib / rtl / dos8dot3.c
index 7b8bc4b..75524c1 100644 (file)
@@ -1,4 +1,5 @@
-/* COPYRIGHT:       See COPYING in the top level directory
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/rtl/dos8dot3.c
  * PURPOSE:         Short name (8.3 name) functions
@@ -29,17 +30,42 @@ RtlpIsShortIllegal(CHAR Char)
 static USHORT
 RtlpGetCheckSum(PUNICODE_STRING Name)
 {
-   USHORT Hash = 0;
-   ULONG Length;
-   PWCHAR c;
+   USHORT Hash, Saved;
+   WCHAR * CurChar;
+   USHORT Len;
+
+   if (Name->Length == 0)
+   {
+      return 0;
+   }
+
+   if (Name->Length == sizeof(WCHAR))
+   {
+      return Name->Buffer[0];
+   }
 
-   Length = Name->Length / sizeof(WCHAR);
-   c = Name->Buffer;
-   while(Length--)
+   CurChar = Name->Buffer;
+   Hash = (*CurChar << 8) + *(CurChar + 1);
+   if (Name->Length == 2 * sizeof(WCHAR))
    {
-      Hash = (Hash + (*c << 4) + (*c >> 4)) * 11;
-      c++;
+      return Hash;
    }
+
+   Saved = Hash;
+   Len = 2;
+   do
+   {
+      CurChar = CurChar + 2;
+      Hash = (Hash << 7) + *CurChar;
+      Hash = (Saved >> 1) + (Hash << 8);
+      if (Len + 1 < Name->Length / sizeof(WCHAR))
+      {
+         Hash += *(CurChar + 1);
+      }
+      Saved = Hash;
+      Len += 2;
+   } while (Len < Name->Length / sizeof(WCHAR));
+
    return Hash;
 }
 
@@ -77,7 +103,7 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    ULONG IndexLength;
    ULONG CurrentIndex;
    USHORT Checksum;
-   CHAR c;
+   WCHAR c;
 
    StrLength = Name->Length / sizeof(WCHAR);
    DPRINT("StrLength: %lu\n", StrLength);
@@ -97,15 +123,27 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    /* Copy name (6 valid characters max) */
    for (i = 0, NameLength = 0; NameLength < 6 && i < DotPos; i++)
    {
-      c = 0;
-      RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
-      if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
+      c = UNICODE_NULL;
+      if (AllowExtendedCharacters)
+      {
+          c = RtlUpcaseUnicodeChar(Name->Buffer[i]);
+          Count = 1;
+      }
+      else
+      {
+          RtlUpcaseUnicodeToOemN((CHAR *)&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
+      }
+
+      if (Count != 1 || c == UNICODE_NULL || RtlpIsShortIllegal(c))
       {
          NameBuffer[NameLength++] = L'_';
       }
-      else if (c != '.' && c != ' ')
+      else if (c != L'.' && c != L' ')
       {
-         NameBuffer[NameLength++] = (WCHAR)c;
+         if (isgraph(c) || (AllowExtendedCharacters && iswgraph(c)))
+         {
+            NameBuffer[NameLength++] = c;
+         }
       }
    }
 
@@ -117,15 +155,27 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    {
       for (i = DotPos, ExtLength = 0; ExtLength < 4 && i < StrLength; i++)
       {
-         c = 0;
-         RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
-         if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
+          c = UNICODE_NULL;
+          if (AllowExtendedCharacters)
+          {
+              c = RtlUpcaseUnicodeChar(Name->Buffer[i]);
+              Count = 1;
+          }
+          else
+          {
+              RtlUpcaseUnicodeToOemN((CHAR *)&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
+          }
+
+         if (Count != 1 || c == UNICODE_NULL || RtlpIsShortIllegal(c))
          {
             ExtBuffer[ExtLength++] = L'_';
          }
-         else if (c != ' ')
+         else if (c != L' ')
          {
-            ExtBuffer[ExtLength++] = c;
+            if (isgraph(c) || c == L'.' || (AllowExtendedCharacters && iswgraph(c)))
+            {
+               ExtBuffer[ExtLength++] = c;
+            }
          }
       }
    }
@@ -170,7 +220,15 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    else
    {
       Context->LastIndexValue = 1;
-      Context->CheckSumInserted = FALSE;
+      if (NameLength == 0)
+      {
+         Context->CheckSumInserted = TRUE;
+         Context->Checksum = RtlpGetCheckSum(Name);
+      }
+      else
+      {
+         Context->CheckSumInserted = FALSE;
+      }
    }
 
    IndexLength = RtlpGetIndexLength(Context->LastIndexValue);
@@ -191,12 +249,11 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
    j = CopyLength;
    if (Context->CheckSumInserted)
    {
-      j += 3;
       Checksum = Context->Checksum;
       for (i = 0; i < 4; i++)
       {
-         Name8dot3->Buffer[j--] = (Checksum % 16) > 9 ? (Checksum % 16) + L'A' - 10 : (Checksum % 16) + L'0';
-         Checksum /= 16;
+         Name8dot3->Buffer[j++] = (Checksum & 0xF) > 9 ? (Checksum & 0xF) + L'A' - 10 : (Checksum & 0xF) + L'0';
+         Checksum >>= 4;
       }
       j = CopyLength + 4;
    }
@@ -225,12 +282,18 @@ RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
 
 /*
  * @implemented
+ * Note: the function does not conform to the annotations.
+ * SpacesFound is not always set!
  */
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
 BOOLEAN
 NTAPI
-RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName,
-                       IN OUT POEM_STRING AnsiName OPTIONAL,
-                       IN OUT PBOOLEAN SpacesFound OPTIONAL)
+RtlIsNameLegalDOS8Dot3 (
+    _In_ PCUNICODE_STRING Name,
+    _Inout_opt_ POEM_STRING OemName,
+    _Out_opt_ PBOOLEAN NameContainsSpaces)
 {
     static const char Illegal[] = "*?<>|\"+=,;[]:/\\\345";
     int Dot = -1;
@@ -238,34 +301,37 @@ RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName,
     char Buffer[12];
     OEM_STRING OemString;
     BOOLEAN GotSpace = FALSE;
+    NTSTATUS Status;
 
-    if (!AnsiName)
+    if (!OemName)
     {
         OemString.Length = sizeof(Buffer);
         OemString.MaximumLength = sizeof(Buffer);
         OemString.Buffer = Buffer;
-        AnsiName = &OemString;
+        OemName = &OemString;
     }
-    if (RtlUpcaseUnicodeStringToCountedOemString( AnsiName, UnicodeName, FALSE ) != STATUS_SUCCESS)
+
+    Status = RtlUpcaseUnicodeStringToCountedOemString(OemName, Name, FALSE);
+    if (!NT_SUCCESS(Status))
         return FALSE;
 
-    if ((AnsiName->Length > 12) || (AnsiName->Buffer == NULL)) return FALSE;
+    if ((OemName->Length > 12) || (OemName->Buffer == NULL)) return FALSE;
 
     /* a starting . is invalid, except for . and .. */
-    if (AnsiName->Buffer[0] == '.')
+    if (OemName->Buffer[0] == '.')
     {
-        if (AnsiName->Length != 1 && (AnsiName->Length != 2 || AnsiName->Buffer[1] != '.')) return FALSE;
-        if (SpacesFound) *SpacesFound = FALSE;
+        if (OemName->Length != 1 && (OemName->Length != 2 || OemName->Buffer[1] != '.')) return FALSE;
+        if (NameContainsSpaces) *NameContainsSpaces = FALSE;
         return TRUE;
     }
 
-    for (i = 0; i < AnsiName->Length; i++)
+    for (i = 0; i < OemName->Length; i++)
     {
-        switch (AnsiName->Buffer[i])
+        switch (OemName->Buffer[i])
         {
         case ' ':
             /* leading/trailing spaces not allowed */
-            if (!i || i == AnsiName->Length-1 || AnsiName->Buffer[i+1] == '.') return FALSE;
+            if (!i || i == OemName->Length-1 || OemName->Buffer[i+1] == '.') return FALSE;
             GotSpace = TRUE;
             break;
         case '.':
@@ -273,7 +339,7 @@ RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName,
             Dot = i;
             break;
         default:
-            if (strchr(Illegal, AnsiName->Buffer[i])) return FALSE;
+            if (strchr(Illegal, OemName->Buffer[i])) return FALSE;
             break;
         }
     }
@@ -282,13 +348,13 @@ RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName,
      */
     if (Dot == -1)
     {
-        if (AnsiName->Length > 8) return FALSE;
+        if (OemName->Length > 8) return FALSE;
     }
     else
     {
-        if (Dot > 8 || (AnsiName->Length - Dot > 4) || Dot == AnsiName->Length - 1) return FALSE;
+        if (Dot > 8 || (OemName->Length - Dot > 4) || Dot == OemName->Length - 1) return FALSE;
     }
-    if (SpacesFound) *SpacesFound = GotSpace;
+    if (NameContainsSpaces) *NameContainsSpaces = GotSpace;
     return TRUE;
 }