]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c
Update question validation logic, move the check pointer from after user input to...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / IfrParse.c
index ac7dce694be096a3409abbf8f99e975cf82f5602..b4f045df601ae543f46ae214729fce4d54bedfc9 100644 (file)
@@ -17,7 +17,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 UINT16           mStatementIndex;\r
 UINT16           mExpressionOpCodeIndex;\r
 EFI_QUESTION_ID  mUsedQuestionId;\r
-BOOLEAN          mInScopeSubtitle;\r
 extern LIST_ENTRY      gBrowserStorageList;\r
 /**\r
   Initialize Statement header members.\r
@@ -79,8 +78,6 @@ CreateStatement (
     CopyMem (Statement->Expression->Expression, GetConditionalExpressionList(ExpressStatement), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount));\r
   }\r
 \r
-  Statement->InSubtitle = mInScopeSubtitle;\r
-\r
   //\r
   // Insert this Statement into current Form\r
   //\r
@@ -289,13 +286,15 @@ CreateQuestion (
   Allocate a FORM_EXPRESSION node.\r
 \r
   @param  Form                   The Form associated with this Expression\r
+  @param  OpCode                 The binary opcode data.\r
 \r
   @return Pointer to a FORM_EXPRESSION data structure.\r
 \r
 **/\r
 FORM_EXPRESSION *\r
 CreateExpression (\r
-  IN OUT FORM_BROWSER_FORM        *Form\r
+  IN OUT FORM_BROWSER_FORM        *Form,\r
+  IN     UINT8                    *OpCode\r
   )\r
 {\r
   FORM_EXPRESSION  *Expression;\r
@@ -304,6 +303,7 @@ CreateExpression (
   ASSERT (Expression != NULL);\r
   Expression->Signature = FORM_EXPRESSION_SIGNATURE;\r
   InitializeListHead (&Expression->OpCodeListHead);\r
+  Expression->OpCode = (EFI_IFR_OP_HEADER *) OpCode;\r
 \r
   return Expression;\r
 }\r
@@ -348,9 +348,19 @@ InitializeConfigHdr (
 /**\r
   Find the global storage link base on the input storate type, name and guid.\r
 \r
+  For EFI_HII_VARSTORE_EFI_VARIABLE and EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER,\r
+  same guid + name = same storage\r
+\r
+  For EFI_HII_VARSTORE_NAME_VALUE:\r
+  same guid + HiiHandle = same storage\r
+\r
+  For EFI_HII_VARSTORE_BUFFER:\r
+  same guid + name + HiiHandle = same storage\r
+\r
   @param  StorageType                Storage type.\r
   @param  StorageGuid                Storage guid.\r
   @param  StorageName                Storage Name.\r
+  @param  HiiHandle                  HiiHandle for this varstore.\r
 \r
   @return Pointer to a GLOBAL_STORAGE data structure.\r
 \r
@@ -359,7 +369,8 @@ BROWSER_STORAGE *
 FindStorageInList (\r
   IN UINT8                 StorageType,\r
   IN EFI_GUID              *StorageGuid,\r
-  IN CHAR16                *StorageName\r
+  IN CHAR16                *StorageName,\r
+  IN EFI_HII_HANDLE        HiiHandle\r
   )\r
 {\r
   LIST_ENTRY       *Link;\r
@@ -368,21 +379,26 @@ FindStorageInList (
   Link  = GetFirstNode (&gBrowserStorageList);\r
   while (!IsNull (&gBrowserStorageList, Link)) {\r
     BrowserStorage = BROWSER_STORAGE_FROM_LINK (Link);\r
+    Link = GetNextNode (&gBrowserStorageList, Link);\r
 \r
     if ((BrowserStorage->Type == StorageType) && CompareGuid (&BrowserStorage->Guid, StorageGuid)) {\r
       if (StorageType == EFI_HII_VARSTORE_NAME_VALUE) {\r
-        return BrowserStorage;\r
+        if (BrowserStorage->HiiHandle == HiiHandle) {\r
+          return BrowserStorage;\r
+        }\r
+\r
+        continue;\r
       }\r
 \r
+      ASSERT (StorageName != NULL);\r
       if (StrCmp (BrowserStorage->Name, StorageName) == 0) {\r
-        return BrowserStorage;\r
+        if (StorageType == EFI_HII_VARSTORE_EFI_VARIABLE || StorageType == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+          return BrowserStorage;\r
+        } else if (StorageType == EFI_HII_VARSTORE_BUFFER && BrowserStorage->HiiHandle == HiiHandle) {\r
+          return BrowserStorage;\r
+        }\r
       }\r
     }\r
-\r
-    //\r
-    // Get Next Storage.\r
-    //\r
-    Link = GetNextNode (&gBrowserStorageList, Link);\r
   }\r
 \r
   return NULL;\r
@@ -494,7 +510,7 @@ CreateStorage (
   Storage->Signature = FORMSET_STORAGE_SIGNATURE;\r
   InsertTailList (&FormSet->StorageListHead, &Storage->Link);\r
 \r
-  BrowserStorage = FindStorageInList(StorageType, StorageGuid, UnicodeString);\r
+  BrowserStorage = FindStorageInList(StorageType, StorageGuid, UnicodeString, FormSet->HiiHandle);\r
   if (BrowserStorage == NULL) {\r
     BrowserStorage = AllocateZeroPool (sizeof (BROWSER_STORAGE));\r
     ASSERT (BrowserStorage != NULL);\r
@@ -508,12 +524,11 @@ CreateStorage (
       BrowserStorage->Name = UnicodeString;\r
     }\r
 \r
+    BrowserStorage->HiiHandle = FormSet->HiiHandle;\r
     InitializeConfigHdr (FormSet, BrowserStorage);\r
+\r
+    BrowserStorage->Initialized = FALSE;\r
   }\r
-  //\r
-  // Add count because one formset storage use this global storage.\r
-  //\r
-  BrowserStorage->ReferenceCount++;\r
 \r
   Storage->BrowserStorage = BrowserStorage;\r
   Storage->ConfigRequest = AllocateCopyPool (StrSize (BrowserStorage->ConfigHdr), BrowserStorage->ConfigHdr);\r
@@ -742,12 +757,6 @@ DestroyStorage (
     FreePool (Storage->ConfigRequest);\r
   }\r
 \r
-  //\r
-  // Minus the reference to the global storage.\r
-  //\r
-  ASSERT (Storage->BrowserStorage->ReferenceCount > 0);\r
-  Storage->BrowserStorage->ReferenceCount--; \r
-\r
   FreePool (Storage);\r
 }\r
 \r
@@ -1030,6 +1039,39 @@ IsExpressionOpCode (
   }\r
 }\r
 \r
+/**\r
+  Tell whether this Operand is an Statement OpCode.\r
+\r
+  @param  Operand                Operand of an IFR OpCode.\r
+\r
+  @retval TRUE                   This is an Statement OpCode.\r
+  @retval FALSE                  Not an Statement OpCode.\r
+\r
+**/\r
+BOOLEAN\r
+IsStatementOpCode (\r
+  IN UINT8              Operand\r
+  )\r
+{\r
+  if ((Operand == EFI_IFR_SUBTITLE_OP) ||\r
+      (Operand == EFI_IFR_TEXT_OP) ||\r
+      (Operand == EFI_IFR_RESET_BUTTON_OP) ||\r
+      (Operand == EFI_IFR_REF_OP) ||\r
+      (Operand == EFI_IFR_ACTION_OP) ||\r
+      (Operand == EFI_IFR_NUMERIC_OP) ||\r
+      (Operand == EFI_IFR_ORDERED_LIST_OP) ||\r
+      (Operand == EFI_IFR_CHECKBOX_OP) ||\r
+      (Operand == EFI_IFR_STRING_OP) ||\r
+      (Operand == EFI_IFR_PASSWORD_OP) ||\r
+      (Operand == EFI_IFR_DATE_OP) ||\r
+      (Operand == EFI_IFR_TIME_OP) ||\r
+      (Operand == EFI_IFR_GUID_OP) ||\r
+      (Operand == EFI_IFR_ONE_OF_OP)) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
 \r
 /**\r
   Calculate number of Statemens(Questions) and Expression OpCodes.\r
@@ -1091,6 +1133,7 @@ ParseOpCodes (
   EFI_STATUS              Status;\r
   FORM_BROWSER_FORM       *CurrentForm;\r
   FORM_BROWSER_STATEMENT  *CurrentStatement;\r
+  FORM_BROWSER_STATEMENT  *ParentStatement;\r
   EXPRESSION_OPCODE       *ExpressionOpCode;\r
   FORM_EXPRESSION         *CurrentExpression;\r
   UINT8                   Operand;\r
@@ -1123,7 +1166,6 @@ ParseOpCodes (
   BOOLEAN                 InScopeDisable;\r
   INTN                    ConditionalExprCount;\r
 \r
-  mInScopeSubtitle         = FALSE;\r
   SuppressForQuestion      = FALSE;\r
   SuppressForOption        = FALSE;\r
   InScopeDisable           = FALSE;\r
@@ -1171,6 +1213,7 @@ ParseOpCodes (
 \r
   CurrentForm = NULL;\r
   CurrentStatement = NULL;\r
+  ParentStatement  = NULL;\r
 \r
   ResetScopeStack ();\r
 \r
@@ -1261,8 +1304,8 @@ ParseOpCodes (
         break;\r
 \r
       case EFI_IFR_THIS_OP:\r
-        ASSERT (CurrentStatement != NULL);\r
-        ExpressionOpCode->QuestionId = CurrentStatement->QuestionId;\r
+        ASSERT (ParentStatement != NULL);\r
+        ExpressionOpCode->QuestionId = ParentStatement->QuestionId;\r
         break;\r
 \r
       case EFI_IFR_SECURITY_OP:\r
@@ -1426,7 +1469,7 @@ ParseOpCodes (
       // Create sub expression nested in MAP opcode\r
       //\r
       if (CurrentExpression == NULL && MapScopeDepth > 0) {\r
-        CurrentExpression = CreateExpression (CurrentForm);\r
+        CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
         ASSERT (MapExpressionList != NULL);\r
         InsertTailList (MapExpressionList, &CurrentExpression->Link);\r
         if (Scope == 0) {\r
@@ -1676,9 +1719,6 @@ ParseOpCodes (
 \r
       CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;\r
       CurrentStatement->FakeQuestionId = mUsedQuestionId++;\r
-      if (Scope != 0) {\r
-        mInScopeSubtitle = TRUE;\r
-      }\r
       break;\r
 \r
     case EFI_IFR_TEXT_OP:\r
@@ -1918,7 +1958,7 @@ ParseOpCodes (
       //\r
       // Insert to Default Value list of current Question\r
       //\r
-      InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link);\r
+      InsertTailList (&ParentStatement->DefaultListHead, &CurrentDefault->Link);\r
 \r
       if (Scope != 0) {\r
         InScopeDefault = TRUE;\r
@@ -1957,16 +1997,15 @@ ParseOpCodes (
         CopyMem (CurrentOption->SuppressExpression->Expression, GetConditionalExpressionList(ExpressOption), (UINTN) (sizeof (FORM_EXPRESSION *) * ConditionalExprCount));\r
       }\r
 \r
+      ASSERT (ParentStatement != NULL);\r
       //\r
       // Insert to Option list of current Question\r
       //\r
-      InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link);\r
-\r
+      InsertTailList (&ParentStatement->OptionListHead, &CurrentOption->Link);\r
       //\r
       // Now we know the Storage width of nested Ordered List\r
       //\r
-      ASSERT (CurrentStatement != NULL);\r
-      if ((CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (CurrentStatement->BufferValue == NULL)) {\r
+      if ((ParentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (ParentStatement->BufferValue == NULL)) {\r
         Width = 1;\r
         switch (CurrentOption->Value.Type) {\r
         case EFI_IFR_TYPE_NUM_SIZE_8:\r
@@ -1992,15 +2031,15 @@ ParseOpCodes (
           break;\r
         }\r
 \r
-        CurrentStatement->StorageWidth = (UINT16) (CurrentStatement->MaxContainers * Width);\r
-        CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth);\r
-        CurrentStatement->ValueType = CurrentOption->Value.Type;\r
-        if (CurrentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {\r
-          CurrentStatement->HiiValue.Buffer = CurrentStatement->BufferValue;\r
-          CurrentStatement->HiiValue.BufferLen = CurrentStatement->StorageWidth;\r
+        ParentStatement->StorageWidth = (UINT16) (ParentStatement->MaxContainers * Width);\r
+        ParentStatement->BufferValue = AllocateZeroPool (ParentStatement->StorageWidth);\r
+        ParentStatement->ValueType = CurrentOption->Value.Type;\r
+        if (ParentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {\r
+          ParentStatement->HiiValue.Buffer = ParentStatement->BufferValue;\r
+          ParentStatement->HiiValue.BufferLen = ParentStatement->StorageWidth;\r
         }\r
 \r
-        InitializeRequestElement (FormSet, CurrentStatement, CurrentForm);\r
+        InitializeRequestElement (FormSet, ParentStatement, CurrentForm);\r
       }\r
       break;\r
 \r
@@ -2012,15 +2051,15 @@ ParseOpCodes (
       //\r
       // Create an Expression node\r
       //\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID));\r
 \r
       if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {\r
         CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;\r
-        InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link);\r
+        InsertTailList (&ParentStatement->NoSubmitListHead, &CurrentExpression->Link);\r
       } else {\r
         CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;\r
-        InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link);\r
+        InsertTailList (&ParentStatement->InconsistentListHead, &CurrentExpression->Link);\r
       }\r
 \r
       //\r
@@ -2036,11 +2075,11 @@ ParseOpCodes (
       //\r
       // Create an Expression node\r
       //\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *) OpCodeData)->Warning, sizeof (EFI_STRING_ID));\r
       CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeData)->TimeOut;\r
       CurrentExpression->Type    = EFI_HII_EXPRESSION_WARNING_IF;\r
-      InsertTailList (&CurrentStatement->WarningListHead, &CurrentExpression->Link);\r
+      InsertTailList (&ParentStatement->WarningListHead, &CurrentExpression->Link);\r
 \r
       //\r
       // Take a look at next OpCode to see whether current expression consists\r
@@ -2055,7 +2094,7 @@ ParseOpCodes (
       //\r
       // Question and Option will appear in scope of this OpCode\r
       //\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;\r
 \r
       if (CurrentForm == NULL) {\r
@@ -2085,7 +2124,7 @@ ParseOpCodes (
       //\r
       // Questions will appear in scope of this OpCode\r
       //\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;\r
       InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);\r
       PushConditionalExpression(CurrentExpression, ExpressStatement);\r
@@ -2133,7 +2172,7 @@ ParseOpCodes (
     // Expression\r
     //\r
     case EFI_IFR_VALUE_OP:\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;\r
       InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);\r
 \r
@@ -2151,8 +2190,8 @@ ParseOpCodes (
         // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR\r
         // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.\r
         //\r
-        ASSERT (CurrentStatement != NULL);\r
-        CurrentStatement->ValueExpression = CurrentExpression;\r
+        ASSERT (ParentStatement != NULL);\r
+        ParentStatement->ValueExpression = CurrentExpression;\r
       }\r
 \r
       //\r
@@ -2165,7 +2204,7 @@ ParseOpCodes (
       break;\r
 \r
     case EFI_IFR_RULE_OP:\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;\r
 \r
       CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId;\r
@@ -2181,7 +2220,7 @@ ParseOpCodes (
       break;\r
 \r
     case EFI_IFR_READ_OP:\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CurrentExpression->Type = EFI_HII_EXPRESSION_READ;\r
       InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);\r
 \r
@@ -2190,8 +2229,8 @@ ParseOpCodes (
       // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR\r
       // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.\r
       //\r
-      ASSERT (CurrentStatement != NULL);\r
-      CurrentStatement->ReadExpression = CurrentExpression;\r
+      ASSERT (ParentStatement != NULL);\r
+      ParentStatement->ReadExpression = CurrentExpression;\r
 \r
       //\r
       // Take a look at next OpCode to see whether current expression consists\r
@@ -2203,7 +2242,7 @@ ParseOpCodes (
       break;\r
 \r
     case EFI_IFR_WRITE_OP:\r
-      CurrentExpression = CreateExpression (CurrentForm);\r
+      CurrentExpression = CreateExpression (CurrentForm, OpCodeData);\r
       CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;\r
       InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);\r
 \r
@@ -2212,8 +2251,8 @@ ParseOpCodes (
       // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR\r
       // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.\r
       //\r
-      ASSERT (CurrentStatement != NULL);\r
-      CurrentStatement->WriteExpression = CurrentExpression;\r
+      ASSERT (ParentStatement != NULL);\r
+      ParentStatement->WriteExpression = CurrentExpression;\r
 \r
       //\r
       // Take a look at next OpCode to see whether current expression consists\r
@@ -2255,8 +2294,8 @@ ParseOpCodes (
         // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR\r
         // file is wrongly generated by tools such as VFR Compiler.\r
         //\r
-        ASSERT (CurrentStatement != NULL);\r
-        ImageId = &CurrentStatement->ImageId;\r
+        ASSERT (ParentStatement != NULL);\r
+        ImageId = &ParentStatement->ImageId;\r
         break;\r
       }\r
 \r
@@ -2268,16 +2307,16 @@ ParseOpCodes (
     // Refresh\r
     //\r
     case EFI_IFR_REFRESH_OP:\r
-      ASSERT (CurrentStatement != NULL);\r
-      CurrentStatement->RefreshInterval = ((EFI_IFR_REFRESH *) OpCodeData)->RefreshInterval;\r
+      ASSERT (ParentStatement != NULL);\r
+      ParentStatement->RefreshInterval = ((EFI_IFR_REFRESH *) OpCodeData)->RefreshInterval;\r
       break;\r
 \r
     //\r
     // Refresh guid.\r
     //\r
     case EFI_IFR_REFRESH_ID_OP:\r
-      ASSERT (CurrentStatement != NULL);\r
-      CopyMem (&CurrentStatement->RefreshGuid, &((EFI_IFR_REFRESH_ID *) OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID));\r
+      ASSERT (ParentStatement != NULL);\r
+      CopyMem (&ParentStatement->RefreshGuid, &((EFI_IFR_REFRESH_ID *) OpCodeData)->RefreshEventGroupId, sizeof (EFI_GUID));\r
       break;\r
 \r
     //\r
@@ -2305,8 +2344,8 @@ ParseOpCodes (
         break;\r
 \r
       default:\r
-        ASSERT (CurrentStatement != NULL);\r
-        CurrentStatement->Locked = TRUE;\r
+        ASSERT (ParentStatement != NULL);\r
+        ParentStatement->Locked = TRUE;\r
       }      \r
       break;\r
 \r
@@ -2326,6 +2365,13 @@ ParseOpCodes (
         ResetScopeStack ();\r
         return Status;\r
       }\r
+      \r
+      //\r
+      // Parent statement end tag found, update ParentStatement info.\r
+      //\r
+      if (IsStatementOpCode(ScopeOpCode) && (ParentStatement != NULL) && (ParentStatement->Operand == ScopeOpCode)) {\r
+        ParentStatement  = ParentStatement->ParentStatement;\r
+      }\r
 \r
       switch (ScopeOpCode) {\r
       case EFI_IFR_FORM_SET_OP:\r
@@ -2352,10 +2398,6 @@ ParseOpCodes (
         CurrentOption = NULL;\r
         break;\r
 \r
-      case EFI_IFR_SUBTITLE_OP:\r
-        mInScopeSubtitle = FALSE;\r
-        break;\r
-\r
       case EFI_IFR_NO_SUBMIT_IF_OP:\r
       case EFI_IFR_INCONSISTENT_IF_OP:\r
       case EFI_IFR_WARNING_IF_OP:\r
@@ -2447,6 +2489,17 @@ ParseOpCodes (
     default:\r
       break;\r
     }\r
+\r
+    if (IsStatementOpCode(Operand)) {\r
+      CurrentStatement->ParentStatement = ParentStatement;\r
+      if (Scope != 0) {\r
+        //\r
+        // Scope != 0, other statements or options may nest in this statement.\r
+        // Update the ParentStatement info.\r
+        //\r
+        ParentStatement = CurrentStatement;\r
+      }\r
+    }\r
   }\r
 \r
   return EFI_SUCCESS;\r