| 6529 | |
| 6530 | |
| 6531 | Object *Script::FindClass(LPCTSTR aClassName, size_t aClassNameLength) |
| 6532 | { |
| 6533 | if (!aClassNameLength) |
| 6534 | aClassNameLength = _tcslen(aClassName); |
| 6535 | if (!aClassNameLength || aClassNameLength > MAX_CLASS_NAME_LENGTH) |
| 6536 | return NULL; |
| 6537 | |
| 6538 | LPTSTR cp, key; |
| 6539 | ExprTokenType token; |
| 6540 | Object *base_object = NULL; |
| 6541 | TCHAR class_name[MAX_CLASS_NAME_LENGTH + 2]; // Extra +1 for '.' to simplify parsing. |
| 6542 | |
| 6543 | // Make temporary copy which we can modify. |
| 6544 | tmemcpy(class_name, aClassName, aClassNameLength); |
| 6545 | class_name[aClassNameLength] = '.'; // To simplify parsing. |
| 6546 | class_name[aClassNameLength + 1] = '\0'; |
| 6547 | |
| 6548 | // Get base variable; e.g. "MyClass" in "MyClass.MySubClass". |
| 6549 | cp = _tcschr(class_name + 1, '.'); |
| 6550 | // To reserve for possible future use with local classes, resolve the class variable according |
| 6551 | // to the current scope (which is always global for class..extends, but often local for Catch). |
| 6552 | // This also avoids confusion due to inconsistency between `catch x` and other references to x. |
| 6553 | Var *base_var = FindVar(class_name, cp - class_name); |
| 6554 | if (!base_var) |
| 6555 | return NULL; |
| 6556 | |
| 6557 | // Although at load time only the "Object" type can exist, dynamic_cast is used in case we're called at run-time: |
| 6558 | if ( !(base_var->IsObject() && (base_object = dynamic_cast<Object *>(base_var->Object())) |
| 6559 | && base_object->IsDerivedFrom(Object::sClassPrototype)) ) // Rule out something silly like "class x extends MsgBox". |
| 6560 | return NULL; |
| 6561 | |
| 6562 | // Even if the loop below has no iterations, it initializes 'key' to the appropriate value: |
| 6563 | for (key = cp + 1; cp = _tcschr(key, '.'); key = cp + 1) // For each key in something like TypeVar.Key1.Key2. |
| 6564 | { |
| 6565 | if (cp == key) |
| 6566 | return NULL; // ScriptError(_T("Missing name."), cp); |
| 6567 | *cp = '\0'; // Terminate at the delimiting dot. |
| 6568 | // Invoking at this stage isn't safe since aClassName could include the name of a |
| 6569 | // user-defined property getter, or the class might implement __Get, and the script |
| 6570 | // isn't necessarily ready to execute. Get it this way instead: |
| 6571 | auto getter = dynamic_cast<BuiltInFunc*>(base_object->GetOwnPropGetter(key)); |
| 6572 | if (!getter || getter->mBIF != Class_GetNestedClass) |
| 6573 | return NULL; |
| 6574 | base_object = ((NestedClassInfo*)getter->mData)->class_object; |
| 6575 | } |
| 6576 | |
| 6577 | return base_object; |
| 6578 | } |
| 6579 | |
| 6580 | |
| 6581 | Object *Object::GetUnresolvedClass(LPTSTR &aName) |
nothing calls this directly
no test coverage detected