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