[NTOS:FSRTL]
[reactos.git] / reactos / ntoskrnl / fsrtl / dbcsname.c
index cd2e912..d6913f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:         ReactOS Kernel
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/fsrtl/name.c
+ * FILE:            ntoskrnl/fsrtl/dbcsname.c
  * PURPOSE:         Provides DBCS parsing and other support routines for FSDs
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Pierre Schweitzer (pierre.schweitzer@reactos.org)
@@ -160,16 +160,78 @@ NTAPI
 FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
                         IN PANSI_STRING Name)
 {
-    SHORT StarFound = -1;
-    PUSHORT BackTracking = NULL;
-    USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars;
-    BOOLEAN BeyondName;
+    SHORT StarFound = -1, DosStarFound = -1;
+    PUSHORT BackTracking = NULL, DosBackTracking = NULL;
+    USHORT ExpressionPosition = 0, NamePosition = 0, MatchingChars, LastDot;
     PAGED_CODE();
 
     ASSERT(Name->Length);
     ASSERT(Expression->Length);
     ASSERT(!FsRtlDoesDbcsContainWildCards(Name));
 
+    /* Check if we were given strings at all */
+    if (!Name->Length || !Expression->Length)
+    {
+        /* Return TRUE if both strings are empty, otherwise FALSE */
+        if (Name->Length == 0 && Expression->Length == 0)
+            return TRUE;
+        else
+            return FALSE;
+    }
+
+    /* Check for a shortcut: just one wildcard */
+    if (Expression->Length == sizeof(CHAR))
+    {
+        if (Expression->Buffer[0] == '*')
+            return TRUE;
+    }
+
+    //ASSERT(FsRtlDoesDbcsContainWildCards(Expression));
+
+    /* Another shortcut, wildcard followed by some string */
+    if (Expression->Buffer[0] == '*')
+    {
+        /* Copy Expression to our local variable */
+        ANSI_STRING IntExpression = *Expression;
+
+        /* Skip the first char */
+        IntExpression.Buffer++;
+        IntExpression.Length -= sizeof(CHAR);
+
+        /* Continue only if the rest of the expression does NOT contain
+           any more wildcards */
+        if (!FsRtlDoesDbcsContainWildCards(&IntExpression))
+        {
+            /* Check for a degenerate case */
+            if (Name->Length < (Expression->Length - sizeof(CHAR)))
+                return FALSE;
+
+            /* Calculate position */
+            NamePosition = (Name->Length - IntExpression.Length) / sizeof(CHAR);
+
+            /* Check whether we are breaking a two chars char (DBCS) */
+            if (NlsMbOemCodePageTag)
+            {
+                MatchingChars = 0;
+
+                while (MatchingChars < NamePosition)
+                {
+                    /* Check if current char is DBCS lead char, if so, jump by two chars */
+                    MatchingChars += FsRtlIsLeadDbcsCharacter(Name->Buffer[MatchingChars]) ? 2 : 1;
+                }
+
+                /* If so, deny */
+                if (MatchingChars > NamePosition)
+                    return FALSE;
+            }
+
+            /* Compare */
+            return RtlEqualMemory(IntExpression.Buffer,
+                                  (Name->Buffer + NamePosition),
+                                  IntExpression.Length);
+        }
+    }
+
     while (NamePosition < Name->Length && ExpressionPosition < Expression->Length)
     {
         /* Basic check to test if chars are equal */
@@ -179,8 +241,7 @@ FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
             ExpressionPosition++;
         }
         /* Check cases that eat one char */
-        else if ((Expression->Buffer[ExpressionPosition] == '?') || (Expression->Buffer[ExpressionPosition] == ANSI_DOS_QM) ||
-                 (Expression->Buffer[ExpressionPosition] == ANSI_DOS_DOT && Name->Buffer[NamePosition] == '.'))
+        else if (Expression->Buffer[ExpressionPosition] == '?')
         {
             NamePosition++;
             ExpressionPosition++;
@@ -218,57 +279,84 @@ FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
         /* Check DOS_STAR */
         else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_STAR)
         {
-            MatchingChars = NamePosition;
-            while (MatchingChars < Name->Length)
+            /* Skip contigous stars */
+            while (ExpressionPosition + 1 < Expression->Length && Expression->Buffer[ExpressionPosition + 1] == ANSI_DOS_STAR)
             {
-                if (Name->Buffer[MatchingChars] == '.')
-                {
-                    NamePosition = MatchingChars;
-                }
-                MatchingChars++;
+                ExpressionPosition++;
             }
-            ExpressionPosition++;
-        }
-        /* Check DOS_DOT */
-        else if (Expression->Buffer[ExpressionPosition] == DOS_DOT)
-        {
-            /* First try to find whether we are beyond last dot (beyond name) */
-            BeyondName = TRUE;
-            MatchingChars = NamePosition + 1;
+
+            /* Look for last dot */
+            MatchingChars = 0;
+            LastDot = (USHORT)-1;
             while (MatchingChars < Name->Length)
             {
                 if (Name->Buffer[MatchingChars] == '.')
                 {
-                    BeyondName = FALSE;
-                    break;
+                    LastDot = MatchingChars;
+                    if (LastDot > NamePosition)
+                        break;
                 }
+
                 MatchingChars++;
             }
 
-            /* If we are beyond name, we null match */
-            if (BeyondName)
+            /* If we don't have dots or we didn't find last yet
+             * start eating everything
+             */
+            if (MatchingChars != Name->Length || LastDot == (USHORT)-1)
             {
-                ExpressionPosition++;
-                continue;
+                if (!DosBackTracking) DosBackTracking = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,
+                                                                              Expression->Length * sizeof(USHORT), 'nrSF');
+                DosBackTracking[++DosStarFound] = ExpressionPosition++;
+
+                /* Not the same char, start exploring */
+                if (Expression->Buffer[ExpressionPosition] != Name->Buffer[NamePosition])
+                    NamePosition++;
+            }
+            else
+            {
+                /* Else, if we are at last dot, eat it - otherwise, null match */
+                if (Name->Buffer[NamePosition] == '.')
+                    NamePosition++;
+
+                 ExpressionPosition++;
             }
-            /* If not, we only match a dot */
-            else if (Name->Buffer[NamePosition] == '.')
+        }
+        /* Check DOS_DOT */
+        else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_DOT)
+        {
+            /* We only match dots */
+            if (Name->Buffer[NamePosition] == '.')
             {
                 NamePosition++;
-                ExpressionPosition++;
-                continue;
             }
-            /* Otherwise, fail */
-            else
+            /* Try to explore later on for null matching */
+            else if (ExpressionPosition + 1 < Expression->Length &&
+                     Name->Buffer[NamePosition] == Expression->Buffer[ExpressionPosition + 1])
             {
-                break;
+                NamePosition++;
+            }
+            ExpressionPosition++;
+        }
+        /* Check DOS_QM */
+        else if (Expression->Buffer[ExpressionPosition] == ANSI_DOS_QM)
+        {
+            /* We match everything except dots */
+            if (Name->Buffer[NamePosition] != '.')
+            {
+                NamePosition++;
             }
+            ExpressionPosition++;
         }
         /* If nothing match, try to backtrack */
         else if (StarFound >= 0)
         {
             ExpressionPosition = BackTracking[StarFound--];
         }
+        else if (DosStarFound >= 0)
+        {
+            ExpressionPosition = DosBackTracking[DosStarFound--];
+        }
         /* Otherwise, fail */
         else
         {
@@ -302,6 +390,10 @@ FsRtlIsDbcsInExpression(IN PANSI_STRING Expression,
     {
         ExFreePoolWithTag(BackTracking, 'nrSF');
     }
+    if (DosBackTracking)
+    {
+        ExFreePoolWithTag(DosBackTracking, 'nrSF');
+    }
 
     return (ExpressionPosition == Expression->Length && NamePosition == Name->Length);
 }
@@ -383,7 +475,7 @@ FsRtlIsFatDbcsLegal(IN ANSI_STRING DbcsName,
         }
 
         /* Filename must be 8.3 filename */
-        if (FirstPart.Length < 3 || FirstPart.Length > 12)
+        if (FirstPart.Length > 12)
             return FALSE;
 
         /* Now, we will parse the filename to find everything bad in */
@@ -428,7 +520,7 @@ FsRtlIsFatDbcsLegal(IN ANSI_STRING DbcsName,
         if (FirstPart.Buffer[FirstPart.Length - 1] == ' ')
             return FALSE;
 
-        EndLoop:
+EndLoop:
         /* Preparing next loop */
         Name.Buffer = RemainingPart.Buffer;
         Name.Length = RemainingPart.Length;