Changeset 25124

Show
Ignore:
Timestamp:
04/24/08 04:56:03 (3 weeks ago)
Author:
axeld
Message:
* Large cleanup. Removed inconsistent usage of errno in instantiate_object();
  instead, it will now use the image_id parameter to store errors in.
* find_instantiation_func() and validate_instantiation() will no longer
  overwrite errno with B_OK.
* Made private functions static, and moved them to the top.
* If the class name starts with '_', it will now try to add a BPrivate namespace
  in case it could not find the class. This should help with the compatibility
  issues Shinta reported (also part of ticket #2086).
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • haiku/trunk/src/kits/support/Archivable.cpp

    r22117 r25124  
    11/* 
    2  * Copyright (c) 2001-2007, Haiku, Inc. 
     2 * Copyright (c) 2001-2008, Haiku, Inc. 
    33 * Distributed under the terms of the MIT License. 
    44 * 
     
    4141//      full-featured (e.g., taking NS::ClassName::Function(Param p) instead 
    4242//      of just NS::ClassName) 
    43 static void Demangle(const char *name, BString &out); 
    44 static void Mangle(const char *name, BString &out); 
    45 static instantiation_func FindFuncInImage(BString& funcName, image_id id, 
    46         status_t& err); 
    47 static bool CheckSig(const char* sig, image_info& info); 
    48  
    49  
    50 BArchivable::BArchivable() 
    51 
    52 
    53  
    54  
    55 BArchivable::BArchivable(BMessage* from) 
    56 
    57 
    58  
    59  
    60 BArchivable::~BArchivable() 
    61 
    62 
    63  
    64  
    65 status_t 
    66 BArchivable::Archive(BMessage* into, bool deep) const 
    67 
    68         if (!into) { 
    69                 // TODO: logging/other error reporting? 
    70                 return B_BAD_VALUE; 
    71         } 
    72  
    73         BString name; 
    74         Demangle(typeid(*this).name(), name); 
    75  
    76         return into->AddString(B_CLASS_FIELD, name); 
    77 
    78  
    79  
    80 BArchivable* 
    81 BArchivable::Instantiate(BMessage* from) 
    82 
    83         debugger("Can't create a plain BArchivable object"); 
    84         return NULL; 
    85 
    86  
    87  
    88 status_t 
    89 BArchivable::Perform(perform_code d, void* arg) 
    90 
    91         // TODO: Check against original 
    92         return B_ERROR; 
    93 
    94  
    95  
    96 void BArchivable::_ReservedArchivable1() {} 
    97 void BArchivable::_ReservedArchivable2() {} 
    98 void BArchivable::_ReservedArchivable3() {} 
    99  
    100  
    101 // #pragma mark - 
    102  
    103  
    104 void 
    105 BuildFuncName(const char* className, BString& funcName) 
    106 
    107         funcName = ""; 
    108  
    109         //      This is what we're after: 
    110         //              Instantiate__Q28OpenBeOS11BArchivableP8BMessage 
    111         Mangle(className, funcName); 
    112 #if __GNUC__ >= 4 
    113         funcName.Prepend("_ZN"); 
    114         funcName.Append("11InstantiateE"); 
    115 #else 
    116         funcName.Prepend("Instantiate__"); 
    117 #endif 
    118         funcName.Append("P8BMessage"); 
    119 
    120  
    121  
    122 BArchivable* 
    123 instantiate_object(BMessage* archive, image_id* id) 
    124 
    125         // Check our params 
    126         if (id) 
    127                 *id = B_BAD_VALUE; 
    128  
    129         if (!archive) { 
    130                 // TODO: extended error handling 
    131                 errno = B_BAD_VALUE; 
    132                 syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); 
    133                 return NULL; 
    134         } 
    135  
    136         // Get class name from archive 
    137         const char* name = NULL; 
    138         status_t err = archive->FindString(B_CLASS_FIELD, &name); 
    139         if (err) { 
    140                 // TODO: extended error handling 
    141                 syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " 
    142                         "defining the class name (%s).", strerror(err)); 
    143                 return NULL; 
    144         } 
    145  
    146         // Get sig from archive 
    147         const char* sig = NULL; 
    148         bool hasSig = (archive->FindString(B_ADD_ON_FIELD, &sig) == B_OK); 
    149  
    150         instantiation_func iFunc = find_instantiation_func(name, sig); 
    151  
    152         // if find_instantiation_func() can't locate Class::Instantiate() 
    153         // and a signature was specified 
    154         if (!iFunc && hasSig) { 
    155                 // use BRoster::FindApp() to locate an app or add-on with the symbol 
    156                 BRoster Roster; 
    157                 entry_ref ref; 
    158                 err = Roster.FindApp(sig, &ref); 
    159  
    160                 // if an entry_ref is obtained 
    161                 BEntry entry; 
    162                 if (!err) 
    163                         err = entry.SetTo(&ref); 
    164  
    165                 if (err) { 
    166                         syslog(LOG_ERR, "instantiate_object failed: Error finding app " 
    167                                 "with signature \"%s\" (%s)", sig, strerror(err)); 
    168                 } 
    169  
    170                 if (!err) { 
    171                         BPath path; 
    172                         err = entry.GetPath(&path); 
    173                         if (!err) { 
    174                                 // load the app/add-on 
    175                                 image_id addOn = load_add_on(path.Path()); 
    176                                 if (addOn < 0) { 
    177                                         // TODO: extended error handling 
    178                                         syslog(LOG_ERR, "instantiate_object failed: Could not load " 
    179                                                 "add-on %s: %s.", path.Path(), strerror(addOn)); 
    180                                         return NULL; 
    181                                 } 
    182  
    183                                 // Save the image_id 
    184                                 if (id) 
    185                                         *id = addOn; 
    186  
    187                                 BString funcName; 
    188                                 BuildFuncName(name, funcName); 
    189  
    190                                 iFunc = FindFuncInImage(funcName, addOn, err); 
    191                                 if (!iFunc) { 
    192                                         syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " 
    193                                                 "Instantiate static function for class %s.", name); 
    194                                 } 
    195                         } 
    196                 } 
    197         } else if (!iFunc) { 
    198                 syslog(LOG_ERR, "instantiate_object failed: No signature specified " 
    199                         "in archive, looking for class \"%s\".", name); 
    200                 errno = B_BAD_VALUE; 
    201         } 
    202  
    203         if (err) { 
    204                 // TODO: extended error handling 
    205                 syslog(LOG_ERR, "instantiate_object failed: %s (%x)", 
    206                         strerror(err), err); 
    207                 errno = err; 
    208                 return NULL; 
    209         } 
    210  
    211         // if Class::Instantiate(BMessage*) was found 
    212         if (iFunc) { 
    213                 // use to create and return an object instance 
    214                 return iFunc(archive); 
    215         } 
    216  
    217         return NULL; 
    218 
    219  
    220  
    221 BArchivable* 
    222 instantiate_object(BMessage* from) 
    223 
    224         return instantiate_object(from, NULL); 
    225 
    226  
    227  
    228 bool 
    229 validate_instantiation(BMessage* from, const char* class_name) 
    230 
    231         errno = B_OK; 
    232  
    233         // Make sure our params are kosher -- original skimped here =P 
    234         if (!from) { 
    235                 // Not standard; Be implementation has a segment 
    236                 // violation on this error mode 
    237                 errno = B_BAD_VALUE; 
    238  
    239                 return false; 
    240         } 
    241  
    242         status_t err = B_OK; 
    243         const char* data; 
    244         for (int32 index = 0; err == B_OK; ++index) { 
    245                 err = from->FindString(B_CLASS_FIELD, index, &data); 
    246                 if (!err && strcmp(data, class_name) == 0) { 
    247                         return true; 
    248                 } 
    249         } 
    250  
    251         errno = B_MISMATCHED_VALUES; 
    252         syslog(LOG_ERR, "validate_instantiation failed on class %s.", class_name); 
    253  
    254         return false; 
    255 
    256  
    257  
    258 instantiation_func  
    259 find_instantiation_func(const char* class_name, const char* sig) 
    260 
    261         errno = B_OK; 
    262         if (!class_name) { 
    263                 errno = B_BAD_VALUE; 
    264                 return NULL; 
    265         } 
    266  
    267         instantiation_func theFunc = NULL; 
    268         BString funcName; 
    269  
    270         BuildFuncName(class_name, funcName); 
    271  
    272 //printf("find_instantiation_func() - looking for '%s'\n", funcName.String()); 
    273  
    274         thread_id tid = find_thread(NULL); 
    275         thread_info ti; 
    276         status_t err = get_thread_info(tid, &ti); 
    277         if (!err) { 
    278                 //      for each image_id in team_id 
    279                 image_info info; 
    280                 int32 cookie = 0; 
    281                 while (!theFunc && (get_next_image_info(ti.team, &cookie, &info) == B_OK)) { 
    282                         theFunc = FindFuncInImage(funcName, info.id, err); 
    283                 } 
    284          
    285                 if (theFunc && !CheckSig(sig, info)) { 
    286                         // TODO: extended error handling 
    287                         theFunc = NULL; 
    288                 } 
    289         } 
    290  
    291 //printf("find_instantiation_func(): %p\n", theFunc); 
    292  
    293         return theFunc; 
    294 
    295  
    296  
    297 instantiation_func 
    298 find_instantiation_func(const char* class_name) 
    299 
    300         return find_instantiation_func(class_name, NULL); 
    301 
    302  
    303  
    304 instantiation_func 
    305 find_instantiation_func(BMessage* archive_data) 
    306 
    307         errno = B_OK; 
    308  
    309         if (!archive_data) { 
    310                 // TODO:  extended error handling 
    311                 errno = B_BAD_VALUE; 
    312                 return NULL; 
    313         } 
    314  
    315         const char* name = NULL; 
    316         const char* sig = NULL; 
    317         status_t err; 
    318  
    319         err = archive_data->FindString(B_CLASS_FIELD, &name); 
    320         if (err) { 
    321                 // TODO:  extended error handling 
    322                 return NULL; 
    323         } 
    324  
    325         err = archive_data->FindString(B_ADD_ON_FIELD, &sig); 
    326  
    327         return find_instantiation_func(name, sig); 
    328 
    329  
    330  
    331 // #pragma mark - 
    332  
    333  
    334 int 
     43 
     44 
     45static int 
    33546GetNumber(const char*& name) 
    33647{ 
     
    34455 
    34556 
    346 void 
    347 Demangle(const char* name, BString& out) 
     57static void 
     58demangle_class_name(const char* name, BString& out) 
    34859{ 
    34960// TODO: add support for template classes 
     
    389100 
    390101 
    391 void 
    392 Mangle(const char* name, BString& out) 
     102static void 
     103mangle_class_name(const char* name, BString& out) 
    393104{ 
    394105// TODO: add support for template classes 
     
    431142 
    432143 
     144static void 
     145build_function_name(const BString& className, BString& funcName) 
     146{ 
     147        funcName = ""; 
     148 
     149        //      This is what we're after: 
     150        //              Instantiate__Q28OpenBeOS11BArchivableP8BMessage 
     151        mangle_class_name(className.String(), funcName); 
     152#if __GNUC__ >= 4 
     153        funcName.Prepend("_ZN"); 
     154        funcName.Append("11InstantiateE"); 
     155#else 
     156        funcName.Prepend("Instantiate__"); 
     157#endif 
     158        funcName.Append("P8BMessage"); 
     159} 
     160 
     161 
     162static bool 
     163add_private_namespace(BString& name) 
     164{ 
     165        if (name.Compare("_", 1) != 0) 
     166                return false; 
     167 
     168        name.Prepend("BPrivate::"); 
     169        return true; 
     170} 
     171 
     172 
     173static instantiation_func 
     174find_function_in_image(BString& funcName, image_id id, status_t& err) 
     175{ 
     176        instantiation_func instantiationFunc = NULL; 
     177        err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, 
     178                (void**)&instantiationFunc); 
     179        if (err != B_OK) 
     180                return NULL; 
     181 
     182        return instantiationFunc; 
     183} 
     184 
     185 
     186static status_t 
     187check_signature(const char* signature, image_info& info) 
     188{ 
     189        if (signature == NULL) { 
     190                // If it wasn't specified, anything "matches" 
     191                return B_OK; 
     192        } 
     193 
     194        // Get image signature 
     195        BFile file(info.name, B_READ_ONLY); 
     196        status_t err = file.InitCheck(); 
     197        if (err != B_OK) 
     198                return err; 
     199 
     200        char imageSignature[B_MIME_TYPE_LENGTH]; 
     201        BAppFileInfo appFileInfo(&file); 
     202        err = appFileInfo.GetSignature(imageSignature); 
     203        if (err != B_OK) { 
     204                syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", 
     205                        info.name); 
     206                return err; 
     207        } 
     208 
     209        if (strcmp(signature, imageSignature)) 
     210                return B_MISMATCHED_VALUES; 
     211 
     212        return B_OK; 
     213} 
     214 
     215 
     216//      #pragma mark - 
     217 
     218 
     219BArchivable::BArchivable() 
     220{ 
     221} 
     222 
     223 
     224BArchivable::BArchivable(BMessage* from) 
     225{ 
     226} 
     227 
     228 
     229BArchivable::~BArchivable() 
     230{ 
     231} 
     232 
     233 
     234status_t 
     235BArchivable::Archive(BMessage* into, bool deep) const 
     236{ 
     237        if (!into) { 
     238                // TODO: logging/other error reporting? 
     239                return B_BAD_VALUE; 
     240        } 
     241 
     242        BString name; 
     243        demangle_class_name(typeid(*this).name(), name); 
     244 
     245        return into->AddString(B_CLASS_FIELD, name); 
     246} 
     247 
     248 
     249BArchivable* 
     250BArchivable::Instantiate(BMessage* from) 
     251{ 
     252        debugger("Can't create a plain BArchivable object"); 
     253        return NULL; 
     254} 
     255 
     256 
     257status_t 
     258BArchivable::Perform(perform_code d, void* arg) 
     259{ 
     260        // TODO: Check against original 
     261        return B_ERROR; 
     262} 
     263 
     264 
     265void BArchivable::_ReservedArchivable1() {} 
     266void BArchivable::_ReservedArchivable2() {} 
     267void BArchivable::_ReservedArchivable3() {} 
     268 
     269 
     270// #pragma mark - 
     271 
     272 
     273BArchivable* 
     274instantiate_object(BMessage* archive, image_id* _id) 
     275{ 
     276        status_t statusBuffer; 
     277        status_t* status = &statusBuffer; 
     278        if (_id != NULL) 
     279                status = _id; 
     280 
     281        // Check our params 
     282        if (archive == NULL) { 
     283                syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); 
     284                *status = B_BAD_VALUE; 
     285                return NULL; 
     286        } 
     287 
     288        // Get class name from archive 
     289        const char* className = NULL; 
     290        status_t err = archive->FindString(B_CLASS_FIELD, &className); 
     291        if (err) { 
     292                syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " 
     293                        "defining the class name (%s).", strerror(err)); 
     294                *status = B_BAD_VALUE; 
     295                return NULL; 
     296        } 
     297 
     298        // Get sig from archive 
     299        const char* signature = NULL; 
     300        bool hasSignature = archive->FindString(B_ADD_ON_FIELD, &signature) == B_OK; 
     301 
     302        instantiation_func instantiationFunc = find_instantiation_func(className, 
     303                signature); 
     304 
     305        // if find_instantiation_func() can't locate Class::Instantiate() 
     306        // and a signature was specified 
     307        if (!instantiationFunc && hasSignature) { 
     308                // use BRoster::FindApp() to locate an app or add-on with the symbol 
     309                BRoster Roster; 
     310                entry_ref ref; 
     311                err = Roster.FindApp(signature, &ref); 
     312 
     313                // if an entry_ref is obtained 
     314                BEntry entry; 
     315                if (err == B_OK) 
     316                        err = entry.SetTo(&ref); 
     317 
     318                BPath path; 
     319                if (err == B_OK) 
     320                        err = entry.GetPath(&path); 
     321 
     322                if (err != B_OK) { 
     323                        syslog(LOG_ERR, "instantiate_object failed: Error finding app " 
     324                                "with signature \"%s\" (%s)", signature, strerror(err)); 
     325                        *status = err; 
     326                        return NULL; 
     327                } 
     328 
     329                // load the app/add-on 
     330                image_id addOn = load_add_on(path.Path()); 
     331                if (addOn < B_OK) { 
     332                        syslog(LOG_ERR, "instantiate_object failed: Could not load " 
     333                                "add-on %s: %s.", path.Path(), strerror(addOn)); 
     334                        *status = addOn; 
     335                        return NULL; 
     336                } 
     337 
     338                // Save the image_id 
     339                if (_id != NULL) 
     340                        *_id = addOn; 
     341 
     342                BString name = className; 
     343                for (int32 pass = 0; pass < 2; pass++) { 
     344                        BString funcName; 
     345                        build_function_name(name, funcName); 
     346 
     347                        instantiationFunc = find_function_in_image(funcName, addOn, err); 
     348                        if (instantiationFunc != NULL) 
     349                                break; 
     350 
     351                        // Check if we have a private class, and add the BPrivate namespace 
     352                        // (for backwards compatibility) 
     353                        if (!add_private_namespace(name)) 
     354                                break; 
     355                } 
     356 
     357                if (instantiationFunc == NULL) { 
     358                        syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " 
     359                                "Instantiate static function for class %s.", className); 
     360                        *status = B_NAME_NOT_FOUND; 
     361                        return NULL; 
     362                } 
     363        } else if (instantiationFunc == NULL) { 
     364                syslog(LOG_ERR, "instantiate_object failed: No signature specified " 
     365                        "in archive, looking for class \"%s\".", className); 
     366                *status = B_NAME_NOT_FOUND; 
     367                return NULL; 
     368        } 
     369 
     370        // if Class::Instantiate(BMessage*) was found 
     371        if (instantiationFunc != NULL) { 
     372                // use to create and return an object instance 
     373                return instantiationFunc(archive); 
     374        } 
     375 
     376        return NULL; 
     377} 
     378 
     379 
     380BArchivable* 
     381instantiate_object(BMessage* from) 
     382{ 
     383        return instantiate_object(from, NULL); 
     384} 
     385 
     386 
     387bool 
     388validate_instantiation(BMessage* from, const char* className) 
     389{ 
     390        // Make sure our params are kosher -- original skimped here =P 
     391        if (!from) { 
     392                errno = B_BAD_VALUE; 
     393                return false; 
     394        } 
     395 
     396        const char* data; 
     397        for (int32 index = 0; from->FindString(B_CLASS_FIELD, index, &data) == B_OK; 
     398                        ++index) { 
     399                if (!strcmp(data, className)) 
     400                        return true; 
     401        } 
     402 
     403        errno = B_MISMATCHED_VALUES; 
     404        syslog(LOG_ERR, "validate_instantiation failed on class %s.", className); 
     405 
     406        return false; 
     407} 
     408 
     409 
    433410instantiation_func 
    434 FindFuncInImage(BString& funcName, image_id id, status_t& err) 
    435 
    436         err = B_OK; 
    437         instantiation_func theFunc = NULL; 
    438  
    439         // Don't need to do it this way ... 
    440 #if 0 
    441         char foundFuncName[FUNC_NAME_LEN]; 
    442         int32 symbolType; 
    443         int32 funcNameLen; 
    444  
    445         //      for each B_SYMBOL_TYPE_TEXT in image_id 
    446         for (int32 i = 0; !err; ++i) { 
    447                 funcNameLen = FUNC_NAME_LEN; 
    448                 err = get_nth_image_symbol(id, i, foundFuncName, &funcNameLen, 
    449                                                                    &symbolType, (void**)&theFunc); 
    450  
    451                 if (!err && symbolType == B_SYMBOL_TYPE_TEXT) { 
    452                         //      try to match Class::Instantiate(BMessage*) signature 
    453                         if (funcName.ICompare(foundFuncName, funcNameLen) == 0) 
    454                                 break; 
    455                         else 
    456                                 theFunc = NULL; 
    457                 } 
    458         } 
    459 #endif 
    460  
    461         err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, 
    462                                                    (void**)&theFunc); 
    463  
    464         if (err) { 
    465                 // TODO: error handling 
    466                 theFunc = NULL; 
    467         } 
    468  
    469         return theFunc; 
    470 
    471  
    472  
    473 bool 
    474 CheckSig(const char* sig, image_info& info) 
    475 
    476         if (!sig) { 
    477                 // If it wasn't specified, anything "matches" 
    478                 return true; 
    479         } 
    480  
    481         status_t err = B_OK; 
    482  
    483         // Get image signature 
    484         BFile ImageFile(info.name, B_READ_ONLY); 
    485         err = ImageFile.InitCheck(); 
    486         if (err) { 
    487                 // TODO: extended error handling 
    488                 return false; 
    489         } 
    490  
    491         char imageSig[B_MIME_TYPE_LENGTH]; 
    492         BAppFileInfo AFI(&ImageFile); 
    493         err = AFI.GetSignature(imageSig); 
    494         if (err) { 
    495                 // TODO: extended error handling 
    496                 syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", 
    497                            info.name); 
    498                 return false; 
    499         } 
    500  
    501         return strcmp(sig, imageSig) == 0; 
    502 
    503  
     411find_instantiation_func(const char* className, const char* signature) 
     412
     413        if (className == NULL) { 
     414                errno = B_BAD_VALUE; 
     415                return NULL; 
     416        } 
     417 
     418        thread_info threadInfo; 
     419        status_t err = get_thread_info(find_thread(NULL), &threadInfo); 
     420        if (err != B_OK) { 
     421                errno = err; 
     422                return NULL; 
     423        } 
     424 
     425        instantiation_func instantiationFunc = NULL; 
     426        image_info imageInfo; 
     427 
     428        BString name = className; 
     429        for (int32 pass = 0; pass < 2; pass++) { 
     430                BString funcName; 
     431                build_function_name(name, funcName); 
     432 
     433                // for each image_id in team_id 
     434                int32 cookie = 0; 
     435                while (instantiationFunc == NULL 
     436                        && get_next_image_info(threadInfo.team, &cookie, &imageInfo) 
     437                                == B_OK) { 
     438                        instantiationFunc = find_function_in_image(funcName, imageInfo.id, 
     439                                err); 
     440                } 
     441                if (instantiationFunc != NULL) 
     442                        break; 
     443 
     444                // Check if we have a private class, and add the BPrivate namespace 
     445                // (for backwards compatibility) 
     446                if (!add_private_namespace(name)) 
     447                        break; 
     448        } 
     449 
     450        if (instantiationFunc != NULL 
     451                && check_signature(signature, imageInfo) != B_OK) 
     452                return NULL; 
     453 
     454        return instantiationFunc; 
     455
     456 
     457 
     458instantiation_func 
     459find_instantiation_func(const char* className) 
     460
     461        return find_instantiation_func(className, NULL); 
     462
     463 
     464 
     465instantiation_func 
     466find_instantiation_func(BMessage* archive) 
     467
     468        if (archive == NULL) { 
     469                errno = B_BAD_VALUE; 
     470                return NULL; 
     471        } 
     472 
     473        const char* name = NULL; 
     474        const char* signature = NULL; 
     475        if (archive->FindString(B_CLASS_FIELD, &name) != B_OK 
     476                || archive->FindString(B_ADD_ON_FIELD, &signature)) { 
     477                errno = B_BAD_VALUE; 
     478                return NULL; 
     479        } 
     480 
     481        return find_instantiation_func(name, signature); 
     482
     483