1 /* 2 * Copyright (c) 2001-2006, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Erik Jaesler (erik@cgsoftware.com) 7 */ 8 9 /** Description: BArchivable mix-in class defines the archiving 10 protocol. Also some global archiving functions.*/ 11 12 13 #include <ctype.h> 14 #include <errno.h> 15 #include <stdlib.h> 16 #include <stdio.h> 17 #include <string> 18 #include <typeinfo> 19 #include <vector> 20 21 #include <AppFileInfo.h> 22 #include <Archivable.h> 23 #include <Entry.h> 24 #include <List.h> 25 #include <OS.h> 26 #include <Path.h> 27 #include <Roster.h> 28 #include <String.h> 29 #include <SupportDefs.h> 30 #include <syslog.h> 31 32 33 using std::string; 34 using std::vector; 35 36 const char* B_CLASS_FIELD = "class"; 37 const char* B_ADD_ON_FIELD = "add_on"; 38 const int32 FUNC_NAME_LEN = 1024; 39 40 // TODO: consider moving these 41 // to a separate module, and making them more full-featured (e.g., taking 42 // NS::ClassName::Function(Param p) instead 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 // TODO: Where do these get triggered from? 51 Log entries graciously coughed up by the Be implementation: 52 Nov 28 01:40:45 instantiate_object failed: NULL BMessage argument 53 Nov 28 01:40:45 instantiate_object failed: Failed to find an entrydefining the class name (Name not found). 54 Nov 28 01:40:45 instantiate_object failed: No signature specified in archive, looking for class "TInvalidClassName". 55 Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) 56 Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) 57 Nov 28 01:40:45 instantiate_object failed: Failed to find exported Instantiate static function for class TInvalidClassName. 58 Nov 28 01:40:45 instantiate_object failed: Invalid argument (80000005) 59 Nov 28 01:40:45 instantiate_object failed: No signature specified in archive, looking for class "TRemoteTestObject". 60 Nov 28 01:40:45 instantiate_object - couldn't get mime sig for /boot/home/src/projects/OpenBeOS/app_kit/test/lib/support/BArchivable/./BArchivableSystemTester 61 Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) 62 Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) 63 Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) 64 Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) 65 Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) 66 Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) 67 */ 68 69 70 BArchivable::BArchivable() 71 { 72 } 73 74 75 BArchivable::BArchivable(BMessage* from) 76 { 77 } 78 79 80 BArchivable::~BArchivable() 81 { 82 } 83 84 85 status_t 86 BArchivable::Archive(BMessage* into, bool deep) const 87 { 88 if (!into) { 89 // TODO: logging/other error reporting? 90 return B_BAD_VALUE; 91 } 92 93 BString name; 94 Demangle(typeid(*this).name(), name); 95 96 return into->AddString(B_CLASS_FIELD, name); 97 } 98 99 100 BArchivable* 101 BArchivable::Instantiate(BMessage* from) 102 { 103 debugger("Can't create a plain BArchivable object"); 104 return NULL; 105 } 106 107 108 status_t 109 BArchivable::Perform(perform_code d, void* arg) 110 { 111 // TODO: Check against original 112 return B_ERROR; 113 } 114 115 116 void BArchivable::_ReservedArchivable1() {} 117 void BArchivable::_ReservedArchivable2() {} 118 void BArchivable::_ReservedArchivable3() {} 119 120 121 // #pragma mark - 122 123 124 void 125 BuildFuncName(const char* className, BString& funcName) 126 { 127 funcName = ""; 128 129 // This is what we're after: 130 // Instantiate__Q28OpenBeOS11BArchivableP8BMessage 131 Mangle(className, funcName); 132 #if __GNUC__ >= 4 133 funcName.Prepend("_ZN"); 134 funcName.Append("11InstantiateE"); 135 #else 136 funcName.Prepend("Instantiate__"); 137 #endif 138 funcName.Append("P8BMessage"); 139 } 140 141 142 BArchivable* 143 instantiate_object(BMessage* archive, image_id* id) 144 { 145 errno = B_OK; 146 147 // Check our params 148 if (id) { 149 *id = B_BAD_VALUE; 150 } 151 152 if (!archive) { 153 // TODO: extended error handling 154 errno = B_BAD_VALUE; 155 syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); 156 return NULL; 157 } 158 159 // Get class name from archive 160 const char* name = NULL; 161 status_t err = archive->FindString(B_CLASS_FIELD, &name); 162 if (err) { 163 // TODO: extended error handling 164 syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " 165 "defining the class name (%s).", strerror(err)); 166 return NULL; 167 } 168 169 // Get sig from archive 170 const char* sig = NULL; 171 bool hasSig = (archive->FindString(B_ADD_ON_FIELD, &sig) == B_OK); 172 173 instantiation_func iFunc = find_instantiation_func(name, sig); 174 175 // if find_instantiation_func() can't locate Class::Instantiate() 176 // and a signature was specified 177 if (!iFunc && hasSig) { 178 // use BRoster::FindApp() to locate an app or add-on with the symbol 179 BRoster Roster; 180 entry_ref ref; 181 err = Roster.FindApp(sig, &ref); 182 183 BEntry entry; 184 185 // if an entry_ref is obtained 186 if (!err) 187 err = entry.SetTo(&ref); 188 189 if (err) { 190 syslog(LOG_ERR, "instantiate_object failed: Error finding app " 191 "with signature \"%s\" (%s)", sig, strerror(err)); 192 } 193 194 if (!err) { 195 BPath path; 196 err = entry.GetPath(&path); 197 if (!err) { 198 // load the app/add-on 199 image_id theImage = load_add_on(path.Path()); 200 if (theImage < 0) { 201 // TODO: extended error handling 202 return NULL; 203 } 204 205 // Save the image_id 206 if (id) { 207 *id = theImage; 208 } 209 210 BString funcName; 211 BuildFuncName(name, funcName); 212 iFunc = FindFuncInImage(funcName, theImage, err); 213 if (!iFunc) 214 { 215 syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " 216 "Instantiate static function for class %s.", name); 217 } 218 } 219 } 220 } else if (!iFunc) { 221 syslog(LOG_ERR, "instantiate_object failed: No signature specified " 222 "in archive, looking for class \"%s\".", name); 223 errno = B_BAD_VALUE; 224 } 225 226 if (err) { 227 // TODO: extended error handling 228 syslog(LOG_ERR, "instantiate_object failed: %s (%x)", 229 strerror(err), err); 230 errno = err; 231 return NULL; 232 } 233 234 // if Class::Instantiate(BMessage*) was found 235 if (iFunc) { 236 // use to create and return an object instance 237 return iFunc(archive); 238 } 239 240 return NULL; 241 } 242 243 244 BArchivable* 245 instantiate_object(BMessage* from) 246 { 247 return instantiate_object(from, NULL); 248 } 249 250 251 bool 252 validate_instantiation(BMessage* from, const char* class_name) 253 { 254 errno = B_OK; 255 256 // Make sure our params are kosher -- original skimped here =P 257 if (!from) { 258 // Not standard; Be implementation has a segment 259 // violation on this error mode 260 errno = B_BAD_VALUE; 261 262 return false; 263 } 264 265 status_t err = B_OK; 266 const char* data; 267 for (int32 index = 0; err == B_OK; ++index) { 268 err = from->FindString(B_CLASS_FIELD, index, &data); 269 if (!err && strcmp(data, class_name) == 0) { 270 return true; 271 } 272 } 273 274 errno = B_MISMATCHED_VALUES; 275 syslog(LOG_ERR, "validate_instantiation failed on class %s.", class_name); 276 277 return false; 278 } 279 280 281 instantiation_func 282 find_instantiation_func(const char* class_name, const char* sig) 283 { 284 errno = B_OK; 285 if (!class_name) { 286 errno = B_BAD_VALUE; 287 return NULL; 288 } 289 290 instantiation_func theFunc = NULL; 291 BString funcName; 292 293 BuildFuncName(class_name, funcName); 294 295 //printf("find_instantiation_func() - looking for '%s'\n", funcName.String()); 296 297 thread_id tid = find_thread(NULL); 298 thread_info ti; 299 status_t err = get_thread_info(tid, &ti); 300 if (!err) { 301 // for each image_id in team_id 302 image_info info; 303 int32 cookie = 0; 304 while (!theFunc && (get_next_image_info(ti.team, &cookie, &info) == B_OK)) { 305 theFunc = FindFuncInImage(funcName, info.id, err); 306 } 307 308 if (theFunc && !CheckSig(sig, info)) { 309 // TODO: extended error handling 310 theFunc = NULL; 311 } 312 } 313 314 //printf("find_instantiation_func(): %p\n", theFunc); 315 316 return theFunc; 317 } 318 319 320 instantiation_func 321 find_instantiation_func(const char* class_name) 322 { 323 return find_instantiation_func(class_name, NULL); 324 } 325 326 327 instantiation_func 328 find_instantiation_func(BMessage* archive_data) 329 { 330 errno = B_OK; 331 332 if (!archive_data) { 333 // TODO: extended error handling 334 errno = B_BAD_VALUE; 335 return NULL; 336 } 337 338 const char* name = NULL; 339 const char* sig = NULL; 340 status_t err; 341 342 err = archive_data->FindString(B_CLASS_FIELD, &name); 343 if (err) { 344 // TODO: extended error handling 345 return NULL; 346 } 347 348 err = archive_data->FindString(B_ADD_ON_FIELD, &sig); 349 350 return find_instantiation_func(name, sig); 351 } 352 353 354 // #pragma mark - 355 356 357 int 358 GetNumber(const char*& name) 359 { 360 int val = atoi(name); 361 while (isdigit(*name)) { 362 ++name; 363 } 364 365 return val; 366 } 367 368 369 void 370 Demangle(const char* name, BString& out) 371 { 372 // TODO: add support for template classes 373 // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl 374 375 out = ""; 376 377 // Are we in a namespace? 378 if (*name == 'Q') { 379 // Yessir, we are; how many deep are we? 380 int nsCount = 0; 381 ++name; 382 if (*name == '_') { 383 // more than 10 deep 384 ++name; 385 if (!isdigit(*name)) 386 ; // TODO: error handling 387 388 nsCount = GetNumber(name); 389 if (*name == '_') // more than 10 deep 390 ++name; 391 else 392 ; // this should be an error condition 393 } else { 394 nsCount = *name - '0'; 395 ++name; 396 } 397 398 int nameLen = 0; 399 for (int i = 0; i < nsCount - 1; ++i) { 400 if (!isdigit(*name)) 401 ; // TODO: error handling 402 403 nameLen = GetNumber(name); 404 out.Append(name, nameLen); 405 out += "::"; 406 name += nameLen; 407 } 408 } 409 410 out.Append(name, GetNumber(name)); 411 } 412 413 414 void 415 Mangle(const char* name, BString& out) 416 { 417 // TODO: add support for template classes 418 // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl 419 420 // Chop this: 421 // testthree::testfour::Testthree::Testfour 422 // up into little bite-sized pieces 423 int count = 0; 424 string origName(name); 425 vector<string> spacenames; 426 427 string::size_type pos = 0; 428 string::size_type oldpos = 0; 429 while (pos != string::npos) { 430 pos = origName.find_first_of("::", oldpos); 431 spacenames.push_back(string(origName, oldpos, pos - oldpos)); 432 pos = origName.find_first_not_of("::", pos); 433 oldpos = pos; 434 ++count; 435 } 436 437 // Now mangle it into this: 438 // Q49testthree8testfour9Testthree8Testfour 439 out = ""; 440 if (count > 1) { 441 out += 'Q'; 442 if (count > 10) 443 out += '_'; 444 out << count; 445 if (count > 10) 446 out += '_'; 447 } 448 449 for (unsigned int i = 0; i < spacenames.size(); ++i) { 450 out << (int)spacenames[i].length(); 451 out += spacenames[i].c_str(); 452 } 453 } 454 455 456 instantiation_func 457 FindFuncInImage(BString& funcName, image_id id, status_t& err) 458 { 459 err = B_OK; 460 instantiation_func theFunc = NULL; 461 462 // Don't need to do it this way ... 463 #if 0 464 char foundFuncName[FUNC_NAME_LEN]; 465 int32 symbolType; 466 int32 funcNameLen; 467 468 // for each B_SYMBOL_TYPE_TEXT in image_id 469 for (int32 i = 0; !err; ++i) { 470 funcNameLen = FUNC_NAME_LEN; 471 err = get_nth_image_symbol(id, i, foundFuncName, &funcNameLen, 472 &symbolType, (void**)&theFunc); 473 474 if (!err && symbolType == B_SYMBOL_TYPE_TEXT) { 475 // try to match Class::Instantiate(BMessage*) signature 476 if (funcName.ICompare(foundFuncName, funcNameLen) == 0) 477 break; 478 else 479 theFunc = NULL; 480 } 481 } 482 #endif 483 484 err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, 485 (void**)&theFunc); 486 487 if (err) { 488 // TODO: error handling 489 theFunc = NULL; 490 } 491 492 return theFunc; 493 } 494 495 496 bool 497 CheckSig(const char* sig, image_info& info) 498 { 499 if (!sig) { 500 // If it wasn't specified, anything "matches" 501 return true; 502 } 503 504 status_t err = B_OK; 505 506 // Get image signature 507 BFile ImageFile(info.name, B_READ_ONLY); 508 err = ImageFile.InitCheck(); 509 if (err) { 510 // TODO: extended error handling 511 return false; 512 } 513 514 char imageSig[B_MIME_TYPE_LENGTH]; 515 BAppFileInfo AFI(&ImageFile); 516 err = AFI.GetSignature(imageSig); 517 if (err) { 518 // TODO: extended error handling 519 syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", 520 info.name); 521 return false; 522 } 523 524 return strcmp(sig, imageSig) == 0; 525 } 526 527