diff --git a/src/kits/support/Archivable.cpp b/src/kits/support/Archivable.cpp index 3e82b1eceb..78d2ffa8eb 100644 --- a/src/kits/support/Archivable.cpp +++ b/src/kits/support/Archivable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2007, Haiku, Inc. + * Copyright (c) 2001-2008, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -40,298 +40,9 @@ const int32 FUNC_NAME_LEN = 1024; // TODO: consider moving these to a separate module, and making them more // full-featured (e.g., taking NS::ClassName::Function(Param p) instead // of just NS::ClassName) -static void Demangle(const char *name, BString &out); -static void Mangle(const char *name, BString &out); -static instantiation_func FindFuncInImage(BString& funcName, image_id id, - status_t& err); -static bool CheckSig(const char* sig, image_info& info); -BArchivable::BArchivable() -{ -} - - -BArchivable::BArchivable(BMessage* from) -{ -} - - -BArchivable::~BArchivable() -{ -} - - -status_t -BArchivable::Archive(BMessage* into, bool deep) const -{ - if (!into) { - // TODO: logging/other error reporting? - return B_BAD_VALUE; - } - - BString name; - Demangle(typeid(*this).name(), name); - - return into->AddString(B_CLASS_FIELD, name); -} - - -BArchivable* -BArchivable::Instantiate(BMessage* from) -{ - debugger("Can't create a plain BArchivable object"); - return NULL; -} - - -status_t -BArchivable::Perform(perform_code d, void* arg) -{ - // TODO: Check against original - return B_ERROR; -} - - -void BArchivable::_ReservedArchivable1() {} -void BArchivable::_ReservedArchivable2() {} -void BArchivable::_ReservedArchivable3() {} - - -// #pragma mark - - - -void -BuildFuncName(const char* className, BString& funcName) -{ - funcName = ""; - - // This is what we're after: - // Instantiate__Q28OpenBeOS11BArchivableP8BMessage - Mangle(className, funcName); -#if __GNUC__ >= 4 - funcName.Prepend("_ZN"); - funcName.Append("11InstantiateE"); -#else - funcName.Prepend("Instantiate__"); -#endif - funcName.Append("P8BMessage"); -} - - -BArchivable* -instantiate_object(BMessage* archive, image_id* id) -{ - // Check our params - if (id) - *id = B_BAD_VALUE; - - if (!archive) { - // TODO: extended error handling - errno = B_BAD_VALUE; - syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); - return NULL; - } - - // Get class name from archive - const char* name = NULL; - status_t err = archive->FindString(B_CLASS_FIELD, &name); - if (err) { - // TODO: extended error handling - syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " - "defining the class name (%s).", strerror(err)); - return NULL; - } - - // Get sig from archive - const char* sig = NULL; - bool hasSig = (archive->FindString(B_ADD_ON_FIELD, &sig) == B_OK); - - instantiation_func iFunc = find_instantiation_func(name, sig); - - // if find_instantiation_func() can't locate Class::Instantiate() - // and a signature was specified - if (!iFunc && hasSig) { - // use BRoster::FindApp() to locate an app or add-on with the symbol - BRoster Roster; - entry_ref ref; - err = Roster.FindApp(sig, &ref); - - // if an entry_ref is obtained - BEntry entry; - if (!err) - err = entry.SetTo(&ref); - - if (err) { - syslog(LOG_ERR, "instantiate_object failed: Error finding app " - "with signature \"%s\" (%s)", sig, strerror(err)); - } - - if (!err) { - BPath path; - err = entry.GetPath(&path); - if (!err) { - // load the app/add-on - image_id addOn = load_add_on(path.Path()); - if (addOn < 0) { - // TODO: extended error handling - syslog(LOG_ERR, "instantiate_object failed: Could not load " - "add-on %s: %s.", path.Path(), strerror(addOn)); - return NULL; - } - - // Save the image_id - if (id) - *id = addOn; - - BString funcName; - BuildFuncName(name, funcName); - - iFunc = FindFuncInImage(funcName, addOn, err); - if (!iFunc) { - syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " - "Instantiate static function for class %s.", name); - } - } - } - } else if (!iFunc) { - syslog(LOG_ERR, "instantiate_object failed: No signature specified " - "in archive, looking for class \"%s\".", name); - errno = B_BAD_VALUE; - } - - if (err) { - // TODO: extended error handling - syslog(LOG_ERR, "instantiate_object failed: %s (%x)", - strerror(err), err); - errno = err; - return NULL; - } - - // if Class::Instantiate(BMessage*) was found - if (iFunc) { - // use to create and return an object instance - return iFunc(archive); - } - - return NULL; -} - - -BArchivable* -instantiate_object(BMessage* from) -{ - return instantiate_object(from, NULL); -} - - -bool -validate_instantiation(BMessage* from, const char* class_name) -{ - errno = B_OK; - - // Make sure our params are kosher -- original skimped here =P - if (!from) { - // Not standard; Be implementation has a segment - // violation on this error mode - errno = B_BAD_VALUE; - - return false; - } - - status_t err = B_OK; - const char* data; - for (int32 index = 0; err == B_OK; ++index) { - err = from->FindString(B_CLASS_FIELD, index, &data); - if (!err && strcmp(data, class_name) == 0) { - return true; - } - } - - errno = B_MISMATCHED_VALUES; - syslog(LOG_ERR, "validate_instantiation failed on class %s.", class_name); - - return false; -} - - -instantiation_func -find_instantiation_func(const char* class_name, const char* sig) -{ - errno = B_OK; - if (!class_name) { - errno = B_BAD_VALUE; - return NULL; - } - - instantiation_func theFunc = NULL; - BString funcName; - - BuildFuncName(class_name, funcName); - -//printf("find_instantiation_func() - looking for '%s'\n", funcName.String()); - - thread_id tid = find_thread(NULL); - thread_info ti; - status_t err = get_thread_info(tid, &ti); - if (!err) { - // for each image_id in team_id - image_info info; - int32 cookie = 0; - while (!theFunc && (get_next_image_info(ti.team, &cookie, &info) == B_OK)) { - theFunc = FindFuncInImage(funcName, info.id, err); - } - - if (theFunc && !CheckSig(sig, info)) { - // TODO: extended error handling - theFunc = NULL; - } - } - -//printf("find_instantiation_func(): %p\n", theFunc); - - return theFunc; -} - - -instantiation_func -find_instantiation_func(const char* class_name) -{ - return find_instantiation_func(class_name, NULL); -} - - -instantiation_func -find_instantiation_func(BMessage* archive_data) -{ - errno = B_OK; - - if (!archive_data) { - // TODO: extended error handling - errno = B_BAD_VALUE; - return NULL; - } - - const char* name = NULL; - const char* sig = NULL; - status_t err; - - err = archive_data->FindString(B_CLASS_FIELD, &name); - if (err) { - // TODO: extended error handling - return NULL; - } - - err = archive_data->FindString(B_ADD_ON_FIELD, &sig); - - return find_instantiation_func(name, sig); -} - - -// #pragma mark - - - -int +static int GetNumber(const char*& name) { int val = atoi(name); @@ -343,8 +54,8 @@ GetNumber(const char*& name) } -void -Demangle(const char* name, BString& out) +static void +demangle_class_name(const char* name, BString& out) { // TODO: add support for template classes // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl @@ -388,8 +99,8 @@ Demangle(const char* name, BString& out) } -void -Mangle(const char* name, BString& out) +static void +mangle_class_name(const char* name, BString& out) { // TODO: add support for template classes // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl @@ -430,74 +141,343 @@ Mangle(const char* name, BString& out) } -instantiation_func -FindFuncInImage(BString& funcName, image_id id, status_t& err) +static void +build_function_name(const BString& className, BString& funcName) { - err = B_OK; - instantiation_func theFunc = NULL; + funcName = ""; - // Don't need to do it this way ... -#if 0 - char foundFuncName[FUNC_NAME_LEN]; - int32 symbolType; - int32 funcNameLen; - - // for each B_SYMBOL_TYPE_TEXT in image_id - for (int32 i = 0; !err; ++i) { - funcNameLen = FUNC_NAME_LEN; - err = get_nth_image_symbol(id, i, foundFuncName, &funcNameLen, - &symbolType, (void**)&theFunc); - - if (!err && symbolType == B_SYMBOL_TYPE_TEXT) { - // try to match Class::Instantiate(BMessage*) signature - if (funcName.ICompare(foundFuncName, funcNameLen) == 0) - break; - else - theFunc = NULL; - } - } + // This is what we're after: + // Instantiate__Q28OpenBeOS11BArchivableP8BMessage + mangle_class_name(className.String(), funcName); +#if __GNUC__ >= 4 + funcName.Prepend("_ZN"); + funcName.Append("11InstantiateE"); +#else + funcName.Prepend("Instantiate__"); #endif + funcName.Append("P8BMessage"); +} + +static bool +add_private_namespace(BString& name) +{ + if (name.Compare("_", 1) != 0) + return false; + + name.Prepend("BPrivate::"); + return true; +} + + +static instantiation_func +find_function_in_image(BString& funcName, image_id id, status_t& err) +{ + instantiation_func instantiationFunc = NULL; err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, - (void**)&theFunc); + (void**)&instantiationFunc); + if (err != B_OK) + return NULL; - if (err) { - // TODO: error handling - theFunc = NULL; + return instantiationFunc; +} + + +static status_t +check_signature(const char* signature, image_info& info) +{ + if (signature == NULL) { + // If it wasn't specified, anything "matches" + return B_OK; } - return theFunc; + // Get image signature + BFile file(info.name, B_READ_ONLY); + status_t err = file.InitCheck(); + if (err != B_OK) + return err; + + char imageSignature[B_MIME_TYPE_LENGTH]; + BAppFileInfo appFileInfo(&file); + err = appFileInfo.GetSignature(imageSignature); + if (err != B_OK) { + syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", + info.name); + return err; + } + + if (strcmp(signature, imageSignature)) + return B_MISMATCHED_VALUES; + + return B_OK; +} + + +// #pragma mark - + + +BArchivable::BArchivable() +{ +} + + +BArchivable::BArchivable(BMessage* from) +{ +} + + +BArchivable::~BArchivable() +{ +} + + +status_t +BArchivable::Archive(BMessage* into, bool deep) const +{ + if (!into) { + // TODO: logging/other error reporting? + return B_BAD_VALUE; + } + + BString name; + demangle_class_name(typeid(*this).name(), name); + + return into->AddString(B_CLASS_FIELD, name); +} + + +BArchivable* +BArchivable::Instantiate(BMessage* from) +{ + debugger("Can't create a plain BArchivable object"); + return NULL; +} + + +status_t +BArchivable::Perform(perform_code d, void* arg) +{ + // TODO: Check against original + return B_ERROR; +} + + +void BArchivable::_ReservedArchivable1() {} +void BArchivable::_ReservedArchivable2() {} +void BArchivable::_ReservedArchivable3() {} + + +// #pragma mark - + + +BArchivable* +instantiate_object(BMessage* archive, image_id* _id) +{ + status_t statusBuffer; + status_t* status = &statusBuffer; + if (_id != NULL) + status = _id; + + // Check our params + if (archive == NULL) { + syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); + *status = B_BAD_VALUE; + return NULL; + } + + // Get class name from archive + const char* className = NULL; + status_t err = archive->FindString(B_CLASS_FIELD, &className); + if (err) { + syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " + "defining the class name (%s).", strerror(err)); + *status = B_BAD_VALUE; + return NULL; + } + + // Get sig from archive + const char* signature = NULL; + bool hasSignature = archive->FindString(B_ADD_ON_FIELD, &signature) == B_OK; + + instantiation_func instantiationFunc = find_instantiation_func(className, + signature); + + // if find_instantiation_func() can't locate Class::Instantiate() + // and a signature was specified + if (!instantiationFunc && hasSignature) { + // use BRoster::FindApp() to locate an app or add-on with the symbol + BRoster Roster; + entry_ref ref; + err = Roster.FindApp(signature, &ref); + + // if an entry_ref is obtained + BEntry entry; + if (err == B_OK) + err = entry.SetTo(&ref); + + BPath path; + if (err == B_OK) + err = entry.GetPath(&path); + + if (err != B_OK) { + syslog(LOG_ERR, "instantiate_object failed: Error finding app " + "with signature \"%s\" (%s)", signature, strerror(err)); + *status = err; + return NULL; + } + + // load the app/add-on + image_id addOn = load_add_on(path.Path()); + if (addOn < B_OK) { + syslog(LOG_ERR, "instantiate_object failed: Could not load " + "add-on %s: %s.", path.Path(), strerror(addOn)); + *status = addOn; + return NULL; + } + + // Save the image_id + if (_id != NULL) + *_id = addOn; + + BString name = className; + for (int32 pass = 0; pass < 2; pass++) { + BString funcName; + build_function_name(name, funcName); + + instantiationFunc = find_function_in_image(funcName, addOn, err); + if (instantiationFunc != NULL) + break; + + // Check if we have a private class, and add the BPrivate namespace + // (for backwards compatibility) + if (!add_private_namespace(name)) + break; + } + + if (instantiationFunc == NULL) { + syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " + "Instantiate static function for class %s.", className); + *status = B_NAME_NOT_FOUND; + return NULL; + } + } else if (instantiationFunc == NULL) { + syslog(LOG_ERR, "instantiate_object failed: No signature specified " + "in archive, looking for class \"%s\".", className); + *status = B_NAME_NOT_FOUND; + return NULL; + } + + // if Class::Instantiate(BMessage*) was found + if (instantiationFunc != NULL) { + // use to create and return an object instance + return instantiationFunc(archive); + } + + return NULL; +} + + +BArchivable* +instantiate_object(BMessage* from) +{ + return instantiate_object(from, NULL); } bool -CheckSig(const char* sig, image_info& info) +validate_instantiation(BMessage* from, const char* className) { - if (!sig) { - // If it wasn't specified, anything "matches" - return true; - } - - status_t err = B_OK; - - // Get image signature - BFile ImageFile(info.name, B_READ_ONLY); - err = ImageFile.InitCheck(); - if (err) { - // TODO: extended error handling + // Make sure our params are kosher -- original skimped here =P + if (!from) { + errno = B_BAD_VALUE; return false; } - char imageSig[B_MIME_TYPE_LENGTH]; - BAppFileInfo AFI(&ImageFile); - err = AFI.GetSignature(imageSig); - if (err) { - // TODO: extended error handling - syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", - info.name); - return false; + const char* data; + for (int32 index = 0; from->FindString(B_CLASS_FIELD, index, &data) == B_OK; + ++index) { + if (!strcmp(data, className)) + return true; } - return strcmp(sig, imageSig) == 0; + errno = B_MISMATCHED_VALUES; + syslog(LOG_ERR, "validate_instantiation failed on class %s.", className); + + return false; +} + + +instantiation_func +find_instantiation_func(const char* className, const char* signature) +{ + if (className == NULL) { + errno = B_BAD_VALUE; + return NULL; + } + + thread_info threadInfo; + status_t err = get_thread_info(find_thread(NULL), &threadInfo); + if (err != B_OK) { + errno = err; + return NULL; + } + + instantiation_func instantiationFunc = NULL; + image_info imageInfo; + + BString name = className; + for (int32 pass = 0; pass < 2; pass++) { + BString funcName; + build_function_name(name, funcName); + + // for each image_id in team_id + int32 cookie = 0; + while (instantiationFunc == NULL + && get_next_image_info(threadInfo.team, &cookie, &imageInfo) + == B_OK) { + instantiationFunc = find_function_in_image(funcName, imageInfo.id, + err); + } + if (instantiationFunc != NULL) + break; + + // Check if we have a private class, and add the BPrivate namespace + // (for backwards compatibility) + if (!add_private_namespace(name)) + break; + } + + if (instantiationFunc != NULL + && check_signature(signature, imageInfo) != B_OK) + return NULL; + + return instantiationFunc; +} + + +instantiation_func +find_instantiation_func(const char* className) +{ + return find_instantiation_func(className, NULL); +} + + +instantiation_func +find_instantiation_func(BMessage* archive) +{ + if (archive == NULL) { + errno = B_BAD_VALUE; + return NULL; + } + + const char* name = NULL; + const char* signature = NULL; + if (archive->FindString(B_CLASS_FIELD, &name) != B_OK + || archive->FindString(B_ADD_ON_FIELD, &signature)) { + errno = B_BAD_VALUE; + return NULL; + } + + return find_instantiation_func(name, signature); }