1 /* 2 * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Wilber 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 /*! 11 This class is the guts of the translation kit, it makes the 12 whole thing happen. It bridges the applications using this 13 object with the translators that the apps need to access. 14 */ 15 16 17 #include "FuncTranslator.h" 18 #include "TranslatorRosterPrivate.h" 19 20 #include <Application.h> 21 #include <Autolock.h> 22 #include <Directory.h> 23 #include <FindDirectory.h> 24 #include <driver_settings.h> 25 #include <image.h> 26 #include <NodeMonitor.h> 27 #include <Path.h> 28 #include <String.h> 29 #include <TranslatorRoster.h> 30 31 #include <new> 32 #include <string.h> 33 34 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 35 extern "C" status_t _kern_get_safemode_option(const char *parameter, 36 char *buffer, size_t *_bufferSize); 37 #else 38 extern "C" status_t _kget_safemode_option_(const char *parameter, 39 char *buffer, size_t *_bufferSize); 40 #endif 41 42 43 #if !defined(HAIKU_TARGET_PLATFORM_HAIKU) && !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST) 44 // building under R5 or Dano/Zeta 45 enum { 46 B_TRANSLATOR_ADDED = '_ART', 47 B_TRANSLATOR_REMOVED = '_RRT', 48 }; 49 #endif 50 51 namespace BPrivate { 52 53 class QuarantineTranslatorImage { 54 public: 55 QuarantineTranslatorImage(BTranslatorRoster::Private& privateRoster); 56 ~QuarantineTranslatorImage(); 57 58 void Put(const entry_ref& ref); 59 void Remove(); 60 61 private: 62 BTranslatorRoster::Private& fRoster; 63 entry_ref fRef; 64 bool fRemove; 65 }; 66 67 } // namespace BPrivate 68 69 // Extensions used in the extension BMessage, defined in TranslatorFormats.h 70 char B_TRANSLATOR_EXT_HEADER_ONLY[] = "/headerOnly"; 71 char B_TRANSLATOR_EXT_DATA_ONLY[] = "/dataOnly"; 72 char B_TRANSLATOR_EXT_COMMENT[] = "/comment"; 73 char B_TRANSLATOR_EXT_TIME[] = "/time"; 74 char B_TRANSLATOR_EXT_FRAME[] = "/frame"; 75 char B_TRANSLATOR_EXT_BITMAP_RECT[] = "bits/Rect"; 76 char B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE[] = "bits/space"; 77 char B_TRANSLATOR_EXT_BITMAP_PALETTE[] = "bits/palette"; 78 char B_TRANSLATOR_EXT_SOUND_CHANNEL[] = "nois/channel"; 79 char B_TRANSLATOR_EXT_SOUND_MONO[] = "nois/mono"; 80 char B_TRANSLATOR_EXT_SOUND_MARKER[] = "nois/marker"; 81 char B_TRANSLATOR_EXT_SOUND_LOOP[] = "nois/loop"; 82 83 BTranslatorRoster* BTranslatorRoster::sDefaultRoster = NULL; 84 85 86 namespace BPrivate { 87 88 /*! 89 The purpose of this class is to put a translator entry_ref into - and remove 90 it from the list of translators on destruction (if Remove() was called before). 91 92 This is used in Private::CreateTranslators() in case a translator hides a 93 previous one (ie. if you install a translator in the user's translators directory 94 that has the same name as one in the system's directory, it will hide this 95 entry). 96 */ 97 QuarantineTranslatorImage::QuarantineTranslatorImage(BTranslatorRoster::Private& privateRoster) 98 : 99 fRoster(privateRoster), 100 fRemove(false) 101 { 102 } 103 104 105 QuarantineTranslatorImage::~QuarantineTranslatorImage() 106 { 107 if (fRef.device == -1 || !fRemove) 108 return; 109 110 fRoster.RemoveTranslators(fRef); 111 } 112 113 114 void 115 QuarantineTranslatorImage::Put(const entry_ref& ref) 116 { 117 fRef = ref; 118 } 119 120 121 void 122 QuarantineTranslatorImage::Remove() 123 { 124 fRemove = true; 125 } 126 127 } // namespace BPrivate 128 129 130 // #pragma mark - 131 132 133 BTranslatorRoster::Private::Private() 134 : BHandler("translator roster"), BLocker("translator list"), 135 fNextID(1), 136 fLazyScanning(true), 137 fSafeMode(false) 138 { 139 140 char parameter[32]; 141 size_t parameterLength = sizeof(parameter); 142 143 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 144 if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, parameter, ¶meterLength) == B_OK) 145 #else 146 if (_kget_safemode_option_(B_SAFEMODE_SAFE_MODE, parameter, ¶meterLength) == B_OK) 147 #endif 148 { 149 if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on") 150 || !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes") 151 || !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) 152 fSafeMode = true; 153 } 154 155 // we're sneaking us into the BApplication 156 if (be_app != NULL && be_app->Lock()) { 157 be_app->AddHandler(this); 158 be_app->Unlock(); 159 } 160 } 161 162 163 BTranslatorRoster::Private::~Private() 164 { 165 stop_watching(this); 166 167 if (Looper() && LockLooper()) { 168 BLooper* looper = Looper(); 169 Looper()->RemoveHandler(this); 170 looper->Unlock(); 171 } 172 173 // Release all translators, so that they can delete themselves 174 175 TranslatorMap::iterator iterator = fTranslators.begin(); 176 std::set<image_id> images; 177 178 while (iterator != fTranslators.end()) { 179 BTranslator* translator = iterator->second.translator; 180 181 translator->fOwningRoster = NULL; 182 // we don't want to be notified about this anymore 183 184 images.insert(iterator->second.image); 185 translator->Release(); 186 187 iterator++; 188 } 189 190 // Unload all images 191 192 std::set<image_id>::const_iterator imageIterator = images.begin(); 193 194 while (imageIterator != images.end()) { 195 unload_add_on(*imageIterator); 196 imageIterator++; 197 } 198 } 199 200 201 void 202 BTranslatorRoster::Private::MessageReceived(BMessage* message) 203 { 204 switch (message->what) { 205 case B_NODE_MONITOR: 206 { 207 BAutolock locker(this); 208 209 printf("translator roster node monitor: "); 210 message->PrintToStream(); 211 212 int32 opcode; 213 if (message->FindInt32("opcode", &opcode) != B_OK) 214 return; 215 216 switch (opcode) { 217 case B_ENTRY_CREATED: 218 { 219 const char* name; 220 node_ref nodeRef; 221 if (message->FindInt32("device", &nodeRef.device) != B_OK 222 || message->FindInt64("directory", &nodeRef.node) != B_OK 223 || message->FindString("name", &name) != B_OK) 224 break; 225 226 // TODO: make this better (possible under Haiku) 227 snooze(100000); 228 // let the font be written completely before trying to open it 229 230 _EntryAdded(nodeRef, name); 231 break; 232 } 233 234 case B_ENTRY_MOVED: 235 { 236 // has the entry been moved into a monitored directory or has 237 // it been removed from one? 238 const char* name; 239 node_ref toNodeRef; 240 node_ref fromNodeRef; 241 node_ref nodeRef; 242 243 if (message->FindInt32("device", &nodeRef.device) != B_OK 244 || message->FindInt64("to directory", &toNodeRef.node) != B_OK 245 || message->FindInt64("from directory", (int64 *)&fromNodeRef.node) != B_OK 246 || message->FindInt64("node", (int64 *)&nodeRef.node) != B_OK 247 || message->FindString("name", &name) != B_OK) 248 break; 249 250 fromNodeRef.device = nodeRef.device; 251 toNodeRef.device = nodeRef.device; 252 253 // Do we know this one yet? 254 translator_item* item = _FindTranslator(nodeRef); 255 if (item == NULL) { 256 // it's a new one! 257 if (_IsKnownDirectory(toNodeRef)) 258 _EntryAdded(toNodeRef, name); 259 break; 260 } 261 262 if (!_IsKnownDirectory(toNodeRef)) { 263 // translator got removed 264 _RemoveTranslators(&nodeRef); 265 break; 266 } 267 268 // the name may have changed 269 item->ref.set_name(name); 270 item->ref.directory = toNodeRef.node; 271 272 if (_IsKnownDirectory(fromNodeRef) 273 && _IsKnownDirectory(toNodeRef)) { 274 // TODO: we should rescan for the name, there might be name 275 // clashes with translators in other directories 276 // (as well as old ones revealed) 277 break; 278 } 279 break; 280 } 281 282 case B_ENTRY_REMOVED: 283 { 284 node_ref nodeRef; 285 uint64 directoryNode; 286 if (message->FindInt32("device", &nodeRef.device) != B_OK 287 || message->FindInt64("directory", (int64 *)&directoryNode) != B_OK 288 || message->FindInt64("node", &nodeRef.node) != B_OK) 289 break; 290 291 translator_item* item = _FindTranslator(nodeRef); 292 if (item != NULL) 293 _RemoveTranslators(&nodeRef); 294 break; 295 } 296 } 297 break; 298 } 299 300 default: 301 BHandler::MessageReceived(message); 302 break; 303 } 304 } 305 306 307 void 308 BTranslatorRoster::Private::AddDefaultPaths() 309 { 310 // add user directories first, so that they can override system translators 311 const directory_which paths[] = { 312 B_USER_ADDONS_DIRECTORY, 313 B_COMMON_ADDONS_DIRECTORY, 314 B_BEOS_ADDONS_DIRECTORY, 315 }; 316 317 for (uint32 i = fSafeMode ? 1 : 0; i < sizeof(paths) / sizeof(paths[0]); i++) { 318 BPath path; 319 status_t status = find_directory(paths[i], &path, true); 320 if (status == B_OK && path.Append("Translators") == B_OK) { 321 mkdir(path.Path(), 0755); 322 // make sure the directory exists before we add it 323 AddPath(path.Path()); 324 } 325 } 326 } 327 328 329 /*! 330 Adds the colon separated list of directories to the roster. 331 332 Note, the order in which these directories are added to actually matters, 333 translators with the same name will be taken from the earlier directory 334 first. See _CompareTranslatorDirectoryPriority(). 335 */ 336 status_t 337 BTranslatorRoster::Private::AddPaths(const char* paths) 338 { 339 if (paths == NULL) 340 return B_BAD_VALUE; 341 342 status_t status = B_OK; 343 int32 added = 0; 344 345 while (paths != NULL) { 346 const char* end = strchr(paths, ':'); 347 BString path; 348 349 if (end != NULL) { 350 path.SetTo(paths, end - 1 - paths); 351 paths = end + 1; 352 } else { 353 path.SetTo(paths); 354 paths = NULL; 355 } 356 357 // Keep the last error that occured, and return it 358 // but don't overwrite it, if the last path was 359 // added successfully. 360 int32 count; 361 status_t error = AddPath(path.String(), &count); 362 if (error != B_NO_ERROR) 363 status = error; 364 365 added += count; 366 } 367 368 if (added == 0) 369 return status; 370 371 return B_OK; 372 } 373 374 375 /*! 376 Adds a new directory to the roster. 377 378 Note, the order in which these directories are added to actually matters, 379 see AddPaths(). 380 */ 381 status_t 382 BTranslatorRoster::Private::AddPath(const char* path, int32* _added) 383 { 384 BDirectory directory(path); 385 status_t status = directory.InitCheck(); 386 if (status < B_OK) 387 return status; 388 389 node_ref nodeRef; 390 status = directory.GetNodeRef(&nodeRef); 391 if (status < B_OK) 392 return status; 393 394 // do we know this directory already? 395 if (_IsKnownDirectory(nodeRef)) 396 return B_OK; 397 398 if (Looper() != NULL) { 399 // watch that directory 400 watch_node(&nodeRef, B_WATCH_DIRECTORY, this); 401 fDirectories.push_back(nodeRef); 402 } 403 404 int32 count = 0; 405 int32 files = 0; 406 407 entry_ref ref; 408 while (directory.GetNextRef(&ref) == B_OK) { 409 if (CreateTranslators(ref, count) == B_OK) 410 count++; 411 412 files++; 413 } 414 415 if (_added) 416 *_added = count; 417 418 if (files != 0 && count == 0) 419 return B_BAD_VALUE; 420 421 return B_OK; 422 } 423 424 425 status_t 426 BTranslatorRoster::Private::AddTranslator(BTranslator* translator, 427 image_id image, const entry_ref* ref, ino_t node) 428 { 429 BAutolock locker(this); 430 431 translator_item item; 432 item.translator = translator; 433 item.image = image; 434 item.node = node; 435 if (ref != NULL) 436 item.ref = *ref; 437 438 try { 439 fTranslators[fNextID] = item; 440 } catch (...) { 441 return B_NO_MEMORY; 442 } 443 444 translator->fOwningRoster = this; 445 translator->fID = fNextID++; 446 return B_OK; 447 } 448 449 450 void 451 BTranslatorRoster::Private::RemoveTranslators(entry_ref& ref) 452 { 453 _RemoveTranslators(NULL, &ref); 454 } 455 456 457 BTranslator* 458 BTranslatorRoster::Private::FindTranslator(translator_id id) 459 { 460 if (!IsLocked()) { 461 debugger("translator must be locked!"); 462 return NULL; 463 } 464 465 const translator_item* item = _FindTranslator(id); 466 if (item != NULL) 467 return item->translator; 468 469 return NULL; 470 } 471 472 473 status_t 474 BTranslatorRoster::Private::GetTranslatorData(image_id image, translator_data& data) 475 { 476 // If this is a translator add-on, it is in the C format 477 memset(&data, 0, sizeof(translator_data)); 478 479 // find all the symbols 480 481 int32* version; 482 if (get_image_symbol(image, "translatorName", B_SYMBOL_TYPE_DATA, (void**)&data.name) < B_OK 483 || get_image_symbol(image, "translatorInfo", B_SYMBOL_TYPE_DATA, (void**)&data.info) < B_OK 484 || get_image_symbol(image, "translatorVersion", B_SYMBOL_TYPE_DATA, (void**)&version) < B_OK || version == NULL 485 || get_image_symbol(image, "inputFormats", B_SYMBOL_TYPE_DATA, (void**)&data.input_formats) < B_OK 486 || get_image_symbol(image, "outputFormats", B_SYMBOL_TYPE_DATA, (void**)&data.output_formats) < B_OK 487 || get_image_symbol(image, "Identify", B_SYMBOL_TYPE_TEXT, (void**)&data.identify_hook) < B_OK 488 || get_image_symbol(image, "Translate", B_SYMBOL_TYPE_TEXT, (void**)&data.translate_hook) < B_OK) 489 return B_BAD_TYPE; 490 491 data.version = *version; 492 493 // those calls are optional 494 get_image_symbol(image, "MakeConfig", B_SYMBOL_TYPE_TEXT, (void**)&data.make_config_hook); 495 get_image_symbol(image, "GetConfigMessage", B_SYMBOL_TYPE_TEXT, (void**)&data.get_config_message_hook); 496 497 return B_OK; 498 } 499 500 501 status_t 502 BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count, 503 BMessage* update) 504 { 505 BAutolock locker(this); 506 507 BPrivate::QuarantineTranslatorImage quarantine(*this); 508 509 const translator_item* item = _FindTranslator(ref.name); 510 if (item != NULL) { 511 // check if the known translator has a higher priority 512 if (_CompareTranslatorDirectoryPriority(item->ref, ref) <= 0) { 513 // keep the existing add-on 514 return B_OK; 515 } 516 517 // replace existing translator(s) if the new translator succeeds 518 quarantine.Put(item->ref); 519 } 520 521 BEntry entry(&ref); 522 node_ref nodeRef; 523 status_t status = entry.GetNodeRef(&nodeRef); 524 if (status < B_OK) 525 return status; 526 527 BPath path(&ref); 528 image_id image = load_add_on(path.Path()); 529 if (image < B_OK) 530 return image; 531 532 // Function pointer used to create post R4.5 style translators 533 BTranslator *(*makeNthTranslator)(int32 n, image_id you, uint32 flags, ...); 534 535 status = get_image_symbol(image, "make_nth_translator", 536 B_SYMBOL_TYPE_TEXT, (void**)&makeNthTranslator); 537 if (status == B_OK) { 538 // If the translator add-on supports the post R4.5 539 // translator creation mechanism, keep loading translators 540 // until MakeNthTranslator stops returning them. 541 BTranslator* translator = NULL; 542 int32 created = 0; 543 for (int32 n = 0; (translator = makeNthTranslator(n, image, 0)) != NULL; n++) { 544 if (AddTranslator(translator, image, &ref, nodeRef.node) == B_OK) { 545 if (update) 546 update->AddInt32("translator_id", translator->fID); 547 count++; 548 created++; 549 } else { 550 translator->Release(); 551 // this will delete the translator 552 } 553 } 554 555 if (created == 0) 556 unload_add_on(image); 557 558 quarantine.Remove(); 559 return B_OK; 560 } 561 562 // If this is a translator add-on, it is in the C format 563 translator_data translatorData; 564 status = GetTranslatorData(image, translatorData); 565 566 // add this translator to the list 567 BPrivate::BFuncTranslator* translator = NULL; 568 if (status == B_OK) { 569 translator = new (std::nothrow) BPrivate::BFuncTranslator(translatorData); 570 if (translator == NULL) 571 status = B_NO_MEMORY; 572 } 573 574 if (status == B_OK) 575 status = AddTranslator(translator, image, &ref, nodeRef.node); 576 577 if (status == B_OK) { 578 if (update) 579 update->AddInt32("translator_id", translator->fID); 580 quarantine.Remove(); 581 count++; 582 } else 583 unload_add_on(image); 584 585 return status; 586 } 587 588 589 status_t 590 BTranslatorRoster::Private::StartWatching(BMessenger target) 591 { 592 try { 593 fMessengers.push_back(target); 594 } catch (...) { 595 return B_NO_MEMORY; 596 } 597 598 if (fLazyScanning) { 599 fLazyScanning = false; 600 // Since we now have someone to report to, we cannot lazily 601 // adopt changes to the translator any longer 602 603 _RescanChanged(); 604 } 605 606 return B_OK; 607 } 608 609 610 status_t 611 BTranslatorRoster::Private::StopWatching(BMessenger target) 612 { 613 MessengerList::iterator iterator = fMessengers.begin(); 614 615 while (iterator != fMessengers.end()) { 616 if (*iterator == target) { 617 fMessengers.erase(iterator); 618 if (fMessengers.empty()) 619 fLazyScanning = true; 620 621 return B_OK; 622 } 623 624 iterator++; 625 } 626 627 return B_BAD_VALUE; 628 } 629 630 631 status_t 632 BTranslatorRoster::Private::StoreTranslators(BMessage& archive) 633 { 634 BAutolock locker(this); 635 636 TranslatorMap::const_iterator iterator = fTranslators.begin(); 637 638 while (iterator != fTranslators.end()) { 639 const translator_item& item = iterator->second; 640 BPath path(&item.ref); 641 if (path.InitCheck() == B_OK) 642 archive.AddString("be:translator_path", path.Path()); 643 644 iterator++; 645 } 646 647 return B_OK; 648 } 649 650 651 status_t 652 BTranslatorRoster::Private::Identify(BPositionIO* source, 653 BMessage* ioExtension, uint32 hintType, const char* hintMIME, 654 uint32 wantType, translator_info* _info) 655 { 656 BAutolock locker(this); 657 658 _RescanChanged(); 659 660 TranslatorMap::const_iterator iterator = fTranslators.begin(); 661 float bestWeight = 0.0f; 662 663 while (iterator != fTranslators.end()) { 664 BTranslator& translator = *iterator->second.translator; 665 666 status_t status = source->Seek(0, SEEK_SET); 667 if (status != B_OK) 668 return status; 669 670 int32 formatsCount = 0; 671 const translation_format* formats = translator.InputFormats(&formatsCount); 672 const translation_format* format = _CheckHints(formats, formatsCount, hintType, 673 hintMIME); 674 675 translator_info info; 676 if (translator.Identify(source, format, ioExtension, &info, wantType) == B_OK) { 677 float weight = info.quality * info.capability; 678 if (weight > bestWeight) { 679 bestWeight = weight; 680 681 info.translator = iterator->first; 682 memcpy(_info, &info, sizeof(translator_info)); 683 } 684 } 685 686 iterator++; 687 } 688 689 if (bestWeight > 0.0f) 690 return B_OK; 691 692 return B_NO_TRANSLATOR; 693 } 694 695 696 status_t 697 BTranslatorRoster::Private::GetTranslators(BPositionIO* source, 698 BMessage* ioExtension, uint32 hintType, const char* hintMIME, 699 uint32 wantType, translator_info** _info, int32* _numInfo) 700 { 701 BAutolock locker(this); 702 703 _RescanChanged(); 704 705 int32 arraySize = fTranslators.size(); 706 translator_info* array = new (std::nothrow) translator_info[arraySize]; 707 if (array == NULL) 708 return B_NO_MEMORY; 709 710 TranslatorMap::const_iterator iterator = fTranslators.begin(); 711 int32 count = 0; 712 713 while (iterator != fTranslators.end()) { 714 BTranslator& translator = *iterator->second.translator; 715 716 status_t status = source->Seek(0, SEEK_SET); 717 if (status < B_OK) { 718 delete[] array; 719 return status; 720 } 721 722 int32 formatsCount = 0; 723 const translation_format* formats = translator.InputFormats(&formatsCount); 724 const translation_format* format = _CheckHints(formats, formatsCount, hintType, 725 hintMIME); 726 727 translator_info info; 728 if (translator.Identify(source, format, ioExtension, &info, wantType) == B_OK) { 729 info.translator = iterator->first; 730 array[count++] = info; 731 } 732 733 iterator++; 734 } 735 736 *_info = array; 737 *_numInfo = count; 738 qsort(array, count, sizeof(translator_info), BTranslatorRoster::Private::_CompareSupport); 739 // translators are sorted by best support 740 741 return B_OK; 742 } 743 744 745 status_t 746 BTranslatorRoster::Private::GetAllTranslators(translator_id** _ids, int32* _count) 747 { 748 BAutolock locker(this); 749 750 _RescanChanged(); 751 752 int32 arraySize = fTranslators.size(); 753 translator_id* array = new (std::nothrow) translator_id[arraySize]; 754 if (array == NULL) 755 return B_NO_MEMORY; 756 757 TranslatorMap::const_iterator iterator = fTranslators.begin(); 758 int32 count = 0; 759 760 while (iterator != fTranslators.end()) { 761 array[count++] = iterator->first; 762 iterator++; 763 } 764 765 *_ids = array; 766 *_count = count; 767 return B_OK; 768 } 769 770 771 status_t 772 BTranslatorRoster::Private::GetRefFor(translator_id id, entry_ref& ref) 773 { 774 BAutolock locker(this); 775 776 const translator_item* item = _FindTranslator(id); 777 if (item == NULL) 778 return B_NO_TRANSLATOR; 779 780 BEntry entry(&item->ref); 781 if (entry.InitCheck() == B_OK && entry.Exists() && entry.IsFile()) { 782 ref = item->ref; 783 return B_OK; 784 } 785 786 return B_ERROR; 787 } 788 789 790 void 791 BTranslatorRoster::Private::TranslatorDeleted(translator_id id) 792 { 793 BAutolock locker(this); 794 795 TranslatorMap::iterator iterator = fTranslators.find(id); 796 if (iterator == fTranslators.end()) 797 return; 798 799 fTranslators.erase(iterator); 800 } 801 802 803 /*static*/ int 804 BTranslatorRoster::Private::_CompareSupport(const void* _a, const void* _b) 805 { 806 const translator_info* infoA = (const translator_info*)_a; 807 const translator_info* infoB = (const translator_info*)_b; 808 809 float weightA = infoA->quality * infoA->capability; 810 float weightB = infoB->quality * infoB->capability; 811 812 if (weightA == weightB) 813 return 0; 814 if (weightA > weightB) 815 return -1; 816 817 return 1; 818 } 819 820 821 /*! 822 In lazy mode, freshly installed translator are not scanned immediately 823 when they become available. Instead, they are put into a set. 824 825 When a method is called that may be interested in these new translators, 826 they are scanned on the fly. Since lazy mode also means that this roster 827 does not have any listeners, we don't need to notify anyone about those 828 changes. 829 */ 830 void 831 BTranslatorRoster::Private::_RescanChanged() 832 { 833 EntryRefSet::iterator iterator = fRescanEntries.begin(); 834 835 while (iterator != fRescanEntries.end()) { 836 int32 count; 837 CreateTranslators(*iterator, count); 838 839 fRescanEntries.erase(iterator); 840 iterator++; 841 } 842 } 843 844 845 /*! 846 Tests if the hints provided for a source stream are compatible to 847 the formats the translator exports. 848 */ 849 const translation_format* 850 BTranslatorRoster::Private::_CheckHints(const translation_format* formats, 851 int32 formatsCount, uint32 hintType, const char* hintMIME) 852 { 853 if (formats == NULL || formatsCount <= 0 || (!hintType && hintMIME == NULL)) 854 return NULL; 855 856 // The provided MIME type hint may be a super type 857 int32 super = 0; 858 if (hintMIME && !strchr(hintMIME, '/')) 859 super = strlen(hintMIME); 860 861 // scan for suitable format 862 for (int32 i = 0; i < formatsCount && formats[i].type; i++) { 863 if (formats[i].type == hintType 864 || hintMIME && ((super && !strncmp(formats[i].MIME, hintMIME, super)) 865 || !strcmp(formats[i].MIME, hintMIME))) 866 return &formats[i]; 867 } 868 869 return NULL; 870 } 871 872 873 const translator_item* 874 BTranslatorRoster::Private::_FindTranslator(translator_id id) const 875 { 876 TranslatorMap::const_iterator iterator = fTranslators.find(id); 877 if (iterator == fTranslators.end()) 878 return NULL; 879 880 return &iterator->second; 881 } 882 883 884 const translator_item* 885 BTranslatorRoster::Private::_FindTranslator(const char* name) const 886 { 887 if (name == NULL) 888 return NULL; 889 890 TranslatorMap::const_iterator iterator = fTranslators.begin(); 891 892 while (iterator != fTranslators.end()) { 893 const translator_item& item = iterator->second; 894 if (item.ref.name != NULL && !strcmp(item.ref.name, name)) 895 return &item; 896 897 iterator++; 898 } 899 900 return NULL; 901 } 902 903 904 const translator_item* 905 BTranslatorRoster::Private::_FindTranslator(entry_ref& ref) const 906 { 907 if (ref.name == NULL) 908 return NULL; 909 910 TranslatorMap::const_iterator iterator = fTranslators.begin(); 911 912 while (iterator != fTranslators.end()) { 913 const translator_item& item = iterator->second; 914 if (item.ref == ref) 915 return &item; 916 917 iterator++; 918 } 919 920 return NULL; 921 } 922 923 924 translator_item* 925 BTranslatorRoster::Private::_FindTranslator(node_ref& nodeRef) 926 { 927 if (nodeRef.device < 0) 928 return NULL; 929 930 TranslatorMap::iterator iterator = fTranslators.begin(); 931 932 while (iterator != fTranslators.end()) { 933 translator_item& item = iterator->second; 934 if (item.ref.device == nodeRef.device 935 && item.node == nodeRef.node) 936 return &item; 937 938 iterator++; 939 } 940 941 return NULL; 942 } 943 944 945 /*! 946 Directories added to the roster have a certain priority - the first entry 947 to be added has the highest priority; if a translator with the same name 948 is to be found in two directories, the one with the higher priority is 949 chosen. 950 */ 951 int32 952 BTranslatorRoster::Private::_CompareTranslatorDirectoryPriority(const entry_ref& a, 953 const entry_ref& b) const 954 { 955 // priority is determined by the order in the list 956 957 node_ref nodeRefA; 958 nodeRefA.device = a.device; 959 nodeRefA.node = a.directory; 960 961 node_ref nodeRefB; 962 nodeRefB.device = b.device; 963 nodeRefB.node = b.directory; 964 965 NodeRefList::const_iterator iterator = fDirectories.begin(); 966 967 while (iterator != fDirectories.end()) { 968 if (*iterator == nodeRefA) 969 return -1; 970 if (*iterator == nodeRefB) 971 return 1; 972 973 iterator++; 974 } 975 976 return 0; 977 } 978 979 980 bool 981 BTranslatorRoster::Private::_IsKnownDirectory(const node_ref& nodeRef) const 982 { 983 NodeRefList::const_iterator iterator = fDirectories.begin(); 984 985 while (iterator != fDirectories.end()) { 986 if (*iterator == nodeRef) 987 return true; 988 989 iterator++; 990 } 991 992 return false; 993 } 994 995 996 void 997 BTranslatorRoster::Private::_RemoveTranslators(const node_ref* nodeRef, const entry_ref* ref) 998 { 999 if (ref == NULL && nodeRef == NULL) 1000 return; 1001 1002 TranslatorMap::iterator iterator = fTranslators.begin(); 1003 BMessage update(B_TRANSLATOR_REMOVED); 1004 image_id image = -1; 1005 1006 while (iterator != fTranslators.end()) { 1007 const translator_item& item = iterator->second; 1008 if ((ref != NULL && item.ref == *ref) 1009 || (nodeRef != NULL && item.ref.device == nodeRef->device 1010 && item.node == nodeRef->node)) { 1011 item.translator->fOwningRoster = NULL; 1012 // if the translator is busy, we don't want to be notified 1013 // about the removal later on 1014 item.translator->Release(); 1015 image = item.image; 1016 update.AddInt32("translator_id", iterator->first); 1017 1018 fTranslators.erase(iterator); 1019 } 1020 1021 iterator++; 1022 } 1023 1024 // Unload image from the removed translator 1025 1026 if (image >= B_OK) 1027 unload_add_on(image); 1028 1029 _NotifyListeners(update); 1030 } 1031 1032 1033 void 1034 BTranslatorRoster::Private::_EntryAdded(const node_ref& nodeRef, const char* name) 1035 { 1036 entry_ref ref; 1037 ref.device = nodeRef.device; 1038 ref.directory = nodeRef.node; 1039 ref.set_name(name); 1040 1041 _EntryAdded(ref); 1042 } 1043 1044 1045 /*! 1046 In lazy mode, the entry is marked to be rescanned on next use of any 1047 translation method (that could make use of it). 1048 In non-lazy mode, the translators for this entry are created directly 1049 and listeners notified. 1050 1051 Called by the node monitor handling. 1052 */ 1053 void 1054 BTranslatorRoster::Private::_EntryAdded(const entry_ref& ref) 1055 { 1056 BEntry entry; 1057 if (entry.SetTo(&ref) != B_OK || !entry.IsFile()) 1058 return; 1059 1060 if (fLazyScanning) { 1061 fRescanEntries.insert(ref); 1062 return; 1063 } 1064 1065 BMessage update(B_TRANSLATOR_ADDED); 1066 int32 count = 0; 1067 CreateTranslators(ref, count, &update); 1068 1069 _NotifyListeners(update); 1070 } 1071 1072 1073 void 1074 BTranslatorRoster::Private::_NotifyListeners(BMessage& update) const 1075 { 1076 MessengerList::const_iterator iterator = fMessengers.begin(); 1077 1078 while (iterator != fMessengers.end()) { 1079 (*iterator).SendMessage(&update); 1080 iterator++; 1081 } 1082 } 1083 1084 1085 // #pragma mark - 1086 1087 1088 BTranslatorRoster::BTranslatorRoster() 1089 { 1090 _Initialize(); 1091 } 1092 1093 1094 BTranslatorRoster::BTranslatorRoster(BMessage* model) 1095 { 1096 _Initialize(); 1097 1098 if (model) { 1099 const char* path; 1100 for (int32 i = 0; model->FindString("be:translator_path", i, &path) == B_OK; i++) { 1101 BEntry entry(path); 1102 entry_ref ref; 1103 if (entry.GetRef(&ref) == B_OK) { 1104 int32 count = 0; 1105 fPrivate->CreateTranslators(ref, count); 1106 } 1107 } 1108 } 1109 } 1110 1111 1112 BTranslatorRoster::~BTranslatorRoster() 1113 { 1114 // If the default BTranslatorRoster is being 1115 // deleted, set the pointer to the default 1116 // BTranslatorRoster to NULL 1117 if (sDefaultRoster == this) 1118 sDefaultRoster = NULL; 1119 1120 delete fPrivate; 1121 } 1122 1123 1124 void 1125 BTranslatorRoster::_Initialize() 1126 { 1127 fPrivate = new BTranslatorRoster::Private(); 1128 } 1129 1130 1131 status_t 1132 BTranslatorRoster::Archive(BMessage* into, bool deep) const 1133 { 1134 status_t status = BArchivable::Archive(into, deep); 1135 if (status != B_OK) 1136 return status; 1137 1138 return fPrivate->StoreTranslators(*into); 1139 } 1140 1141 1142 BArchivable * 1143 BTranslatorRoster::Instantiate(BMessage* from) 1144 { 1145 if (!from || !validate_instantiation(from, "BTranslatorRoster")) 1146 return NULL; 1147 1148 return new BTranslatorRoster(from); 1149 } 1150 1151 1152 BTranslatorRoster * 1153 BTranslatorRoster::Default() 1154 { 1155 static int32 lock = 0; 1156 1157 if (sDefaultRoster != NULL) 1158 return sDefaultRoster; 1159 1160 if (atomic_add(&lock, 1) != 0) { 1161 // Just wait for the default translator to be instantiated 1162 while (sDefaultRoster == NULL) 1163 snooze(10000); 1164 1165 atomic_add(&lock, -1); 1166 return sDefaultRoster; 1167 } 1168 1169 // If the default translators have not been loaded, 1170 // create a new BTranslatorRoster for them, and load them. 1171 if (sDefaultRoster == NULL) { 1172 BTranslatorRoster* roster = new BTranslatorRoster(); 1173 roster->AddTranslators(NULL); 1174 1175 sDefaultRoster = roster; 1176 // this will unlock any other threads waiting for 1177 // the default roster to become available 1178 } 1179 1180 atomic_add(&lock, -1); 1181 return sDefaultRoster; 1182 } 1183 1184 1185 /*! 1186 This function takes a string of colon delimited paths, and adds 1187 the translators from those paths to this BTranslatorRoster. 1188 1189 If load_path is NULL, it parses the environment variable 1190 TRANSLATORS. If that does not exist, it uses the system paths: 1191 /boot/home/config/add-ons/Translators, 1192 /system/add-ons/Translators. 1193 */ 1194 status_t 1195 BTranslatorRoster::AddTranslators(const char* path) 1196 { 1197 if (path == NULL) 1198 path = getenv("TRANSLATORS"); 1199 if (path == NULL) { 1200 fPrivate->AddDefaultPaths(); 1201 return B_OK; 1202 } 1203 1204 return fPrivate->AddPaths(path); 1205 } 1206 1207 1208 /*! 1209 Adds a BTranslator based object to the BTranslatorRoster. 1210 When you add a BTranslator roster, it is Acquire()'d by 1211 BTranslatorRoster; it is Release()'d when the 1212 BTranslatorRoster is deleted. 1213 1214 \param translator the translator to be added to the 1215 BTranslatorRoster 1216 1217 \return B_BAD_VALUE, if translator is NULL, 1218 B_OK if all went well 1219 */ 1220 status_t 1221 BTranslatorRoster::AddTranslator(BTranslator* translator) 1222 { 1223 if (!translator) 1224 return B_BAD_VALUE; 1225 1226 return fPrivate->AddTranslator(translator); 1227 } 1228 1229 1230 bool 1231 BTranslatorRoster::IsTranslator(entry_ref* ref) 1232 { 1233 if (ref == NULL) 1234 return false; 1235 1236 BPath path(ref); 1237 image_id image = load_add_on(path.Path()); 1238 if (image < B_OK) 1239 return false; 1240 1241 // Function pointer used to create post R4.5 style translators 1242 BTranslator *(*makeNthTranslator)(int32 n, image_id you, uint32 flags, ...); 1243 1244 status_t status = get_image_symbol(image, "make_nth_translator", 1245 B_SYMBOL_TYPE_TEXT, (void**)&makeNthTranslator); 1246 if (status < B_OK) { 1247 // If this is a translator add-on, it is in the C format 1248 translator_data translatorData; 1249 status = fPrivate->GetTranslatorData(image, translatorData); 1250 } 1251 1252 unload_add_on(image); 1253 return status == B_OK; 1254 } 1255 1256 1257 /*! 1258 This function determines which translator is best suited 1259 to convert the data from \a source. 1260 1261 \param source the data to be identified 1262 \param ioExtension the configuration data for the translator 1263 \param _info the information about the chosen translator is put here 1264 \param hintType a hint about the type of data that is in \a source, set 1265 it to zero if the type is not known 1266 \param hintMIME a hint about the MIME type of \a source, set it to NULL 1267 if the type is not known. 1268 \param wantType the desired output type - if zero, any type is okay. 1269 1270 \return B_OK, identification of \a source was successful, 1271 B_NO_TRANSLATOR, no appropriate translator found, 1272 and other errors from accessing the source stream 1273 */ 1274 status_t 1275 BTranslatorRoster::Identify(BPositionIO* source, BMessage* ioExtension, 1276 translator_info* _info, uint32 hintType, const char* hintMIME, 1277 uint32 wantType) 1278 { 1279 if (source == NULL || _info == NULL) 1280 return B_BAD_VALUE; 1281 1282 return fPrivate->Identify(source, ioExtension, hintType, hintMIME, wantType, _info); 1283 } 1284 1285 1286 /*! 1287 Finds all translators capable of handling the data in \a source 1288 and puts them into the outInfo array (which you must delete 1289 yourself when you are done with it). Specifying a value for 1290 \a hintType, \a hintMIME and/or \a wantType causes only the 1291 translators that satisfy them to be included in the outInfo. 1292 1293 \param source the data to be translated 1294 \param ioExtension the configuration data for the translator 1295 \param _info, the array of acceptable translators is stored here if 1296 the function succeeds. It's the caller's responsibility to free 1297 the array using delete[]. 1298 \param _numInfo, number of entries in the \a _info array 1299 \param hintType a hint about the type of data that is in \a source, set 1300 it to zero if the type is not known 1301 \param hintMIME a hint about the MIME type of \a source, set it to NULL 1302 if the type is not known. 1303 \param wantType the desired output type - if zero, any type is okay. 1304 1305 \return B_OK, successfully indentified the data in \a source 1306 B_NO_TRANSLATOR, no translator could handle \a source 1307 other errors, problems using \a source 1308 */ 1309 status_t 1310 BTranslatorRoster::GetTranslators(BPositionIO* source, BMessage* ioExtension, 1311 translator_info** _info, int32* _numInfo, uint32 hintType, 1312 const char* hintMIME, uint32 wantType) 1313 { 1314 if (source == NULL || _info == NULL || _numInfo == NULL) 1315 return B_BAD_VALUE; 1316 1317 return fPrivate->GetTranslators(source, ioExtension, hintType, hintMIME, 1318 wantType, _info, _numInfo); 1319 } 1320 1321 1322 /*! 1323 Returns an array in \a _ids of all of the translators stored by this 1324 object. 1325 You must free the array using delete[] when you are done with it. 1326 1327 \param _ids the array is stored there (you own the array). 1328 \param _count number of IDs in the array. 1329 */ 1330 status_t 1331 BTranslatorRoster::GetAllTranslators(translator_id** _ids, int32* _count) 1332 { 1333 if (_ids == NULL || _count == NULL) 1334 return B_BAD_VALUE; 1335 1336 return fPrivate->GetAllTranslators(_ids, _count); 1337 } 1338 1339 1340 /*! 1341 Returns information about the translator with the specified 1342 translator \a id. 1343 You must not free any of the data you get back. 1344 1345 \param id identifies which translator you want info for 1346 \param _name the translator name is put here 1347 \param _info the translator description is put here 1348 \param _version the translation version is put here 1349 1350 \return B_OK if successful, 1351 B_BAD_VALUE, if all parameters are NULL 1352 B_NO_TRANSLATOR, \id didn't identify an existing translator 1353 */ 1354 status_t 1355 BTranslatorRoster::GetTranslatorInfo(translator_id id, const char** _name, 1356 const char** _info, int32* _version) 1357 { 1358 if (_name == NULL && _info == NULL && _version == NULL) 1359 return B_BAD_VALUE; 1360 1361 BAutolock locker(fPrivate); 1362 1363 BTranslator* translator = fPrivate->FindTranslator(id); 1364 if (translator == NULL) 1365 return B_NO_TRANSLATOR; 1366 1367 if (_name) 1368 *_name = translator->TranslatorName(); 1369 if (_info) 1370 *_info = translator->TranslatorInfo(); 1371 if (_version) 1372 *_version = translator->TranslatorVersion(); 1373 1374 return B_OK; 1375 } 1376 1377 1378 /*! 1379 Returns all of the input formats for the translator specified 1380 by \a id. 1381 You must not free any of the data you get back. 1382 1383 \param id identifies which translator you want the input formats for 1384 \param _formats array of input formats 1385 \param _numFormats number of formats in the array 1386 1387 \return B_OK if successful, 1388 B_BAD_VALUE, if any parameter is NULL 1389 B_NO_TRANSLATOR, \id didn't identify an existing translator 1390 */ 1391 status_t 1392 BTranslatorRoster::GetInputFormats(translator_id id, 1393 const translation_format** _formats, int32* _numFormats) 1394 { 1395 if (_formats == NULL || _numFormats == NULL) 1396 return B_BAD_VALUE; 1397 1398 BAutolock locker(fPrivate); 1399 1400 BTranslator* translator = fPrivate->FindTranslator(id); 1401 if (translator == NULL) 1402 return B_NO_TRANSLATOR; 1403 1404 *_formats = translator->InputFormats(_numFormats); 1405 return B_OK; 1406 } 1407 1408 1409 /*! 1410 Returns all of the output formats for the translator specified 1411 by \a id. 1412 You must not free any of the data you get back. 1413 1414 \param id identifies which translator you want the output formats for 1415 \param _formats array of output formats 1416 \param _numFormats number of formats in the array 1417 1418 \return B_OK if successful, 1419 B_BAD_VALUE, if any parameter is NULL 1420 B_NO_TRANSLATOR, \id didn't identify an existing translator 1421 */ 1422 status_t 1423 BTranslatorRoster::GetOutputFormats(translator_id id, 1424 const translation_format** _formats, int32* _numFormats) 1425 { 1426 if (_formats == NULL || _numFormats == NULL) 1427 return B_BAD_VALUE; 1428 1429 BAutolock locker(fPrivate); 1430 1431 BTranslator* translator = fPrivate->FindTranslator(id); 1432 if (translator == NULL) 1433 return B_NO_TRANSLATOR; 1434 1435 *_formats = translator->OutputFormats(_numFormats); 1436 return B_OK; 1437 } 1438 1439 1440 /*! 1441 This function is the whole point of the Translation Kit. 1442 This is for translating the data in \a source to \a destination 1443 using the format \a wantOutType. 1444 1445 \param source the data to be translated 1446 \param ioExtension the configuration data for the translator 1447 \param info information about translator to use (can be NULL, in which 1448 case the \a source is identified first) 1449 \param destination where \a source is translated to 1450 \param hintType a hint about the type of data that is in \a source, set 1451 it to zero if the type is not known 1452 \param hintMIME a hint about the MIME type of \a source, set it to NULL 1453 if the type is not known. 1454 \param wantType the desired output type - if zero, any type is okay. 1455 1456 \return B_OK, translation of \a source was successful, 1457 B_NO_TRANSLATOR, no appropriate translator found, 1458 and other errors from accessing the source and destination streams 1459 */ 1460 status_t 1461 BTranslatorRoster::Translate(BPositionIO* source, const translator_info* info, 1462 BMessage* ioExtension, BPositionIO* destination, uint32 wantOutType, 1463 uint32 hintType, const char* hintMIME) 1464 { 1465 if (source == NULL || destination == NULL) 1466 return B_BAD_VALUE; 1467 1468 translator_info infoBuffer; 1469 1470 if (info == NULL) { 1471 // look for a suitable translator 1472 status_t status = fPrivate->Identify(source, ioExtension, hintType, 1473 hintMIME, wantOutType, &infoBuffer); 1474 if (status < B_OK) 1475 return status; 1476 1477 info = &infoBuffer; 1478 } 1479 1480 if (!fPrivate->Lock()) 1481 return B_ERROR; 1482 1483 BTranslator* translator = fPrivate->FindTranslator(info->translator); 1484 if (translator != NULL) { 1485 translator->Acquire(); 1486 // make sure this translator is not removed while we're playing with it; 1487 // translating shouldn't be serialized! 1488 } 1489 1490 fPrivate->Unlock(); 1491 1492 if (translator == NULL) 1493 return B_NO_TRANSLATOR; 1494 1495 status_t status = source->Seek(0, SEEK_SET); 1496 if (status == B_OK) { 1497 status = translator->Translate(source, info, ioExtension, wantOutType, 1498 destination); 1499 } 1500 translator->Release(); 1501 1502 return status; 1503 } 1504 1505 1506 /*! 1507 This function is the whole point of the Translation Kit. 1508 This is for translating the data in \a source to \a destination 1509 using the format \a wantOutType and the translator identified 1510 by \a id. 1511 1512 \param id the translator to be used 1513 \param source the data to be translated 1514 \param ioExtension the configuration data for the translator 1515 \param destination where \a source is translated to 1516 \param wantType the desired output type - if zero, any type is okay. 1517 1518 \return B_OK, translation of \a source was successful, 1519 B_NO_TRANSLATOR, no appropriate translator found, 1520 and other errors from accessing the source and destination streams 1521 */ 1522 status_t 1523 BTranslatorRoster::Translate(translator_id id, BPositionIO* source, 1524 BMessage* ioExtension, BPositionIO* destination, uint32 wantOutType) 1525 { 1526 if (source == NULL || destination == NULL) 1527 return B_BAD_VALUE; 1528 1529 BTranslator* translator = fPrivate->FindTranslator(id); 1530 if (translator != NULL) { 1531 translator->Acquire(); 1532 // make sure this translator is not removed while we're playing with it; 1533 // translating shouldn't be serialized! 1534 } 1535 1536 fPrivate->Unlock(); 1537 1538 if (translator == NULL) 1539 return B_NO_TRANSLATOR; 1540 1541 status_t status = source->Seek(0, SEEK_SET); 1542 if (status == B_OK) { 1543 translator_info info; 1544 status = translator->Identify(source, NULL, ioExtension, &info, wantOutType); 1545 if (status >= B_OK) { 1546 status = translator->Translate(source, &info, ioExtension, wantOutType, 1547 destination); 1548 } 1549 } 1550 translator->Release(); 1551 1552 return status; 1553 } 1554 1555 1556 /*! 1557 Creates a BView in \a _view for configuring the translator specified 1558 by \a id. Not all translators support this, though. 1559 1560 \param id identifies which translator you want the input formats for 1561 \param ioExtension the configuration data for the translator 1562 \param _view the view for configuring the translator 1563 \param _extent the bounds for the (resizable) view 1564 1565 \return B_OK if successful, 1566 B_BAD_VALUE, if any parameter is NULL 1567 B_NO_TRANSLATOR, \id didn't identify an existing translator 1568 */ 1569 status_t 1570 BTranslatorRoster::MakeConfigurationView(translator_id id, BMessage* ioExtension, 1571 BView** _view, BRect* _extent) 1572 { 1573 if (_view == NULL || _extent == NULL) 1574 return B_BAD_VALUE; 1575 1576 BAutolock locker(fPrivate); 1577 1578 BTranslator* translator = fPrivate->FindTranslator(id); 1579 if (translator == NULL) 1580 return B_NO_TRANSLATOR; 1581 1582 return translator->MakeConfigurationView(ioExtension, _view, _extent); 1583 } 1584 1585 1586 /*! 1587 Gets the configuration setttings for the translator 1588 specified by \a id and puts them into \a ioExtension. 1589 1590 \param id identifies which translator you want the input formats for 1591 \param ioExtension the configuration data for the translator 1592 1593 \return B_OK if successful, 1594 B_BAD_VALUE, if \a ioExtension is NULL 1595 B_NO_TRANSLATOR, \id didn't identify an existing translator 1596 */ 1597 status_t 1598 BTranslatorRoster::GetConfigurationMessage(translator_id id, BMessage* ioExtension) 1599 { 1600 if (!ioExtension) 1601 return B_BAD_VALUE; 1602 1603 BAutolock locker(fPrivate); 1604 1605 BTranslator* translator = fPrivate->FindTranslator(id); 1606 if (translator == NULL) 1607 return B_NO_TRANSLATOR; 1608 1609 return translator->GetConfigurationMessage(ioExtension); 1610 } 1611 1612 1613 /*! 1614 Gets the entry_ref for the given translator (of course, this works only 1615 for disk based translators). 1616 1617 \param id identifies which translator you want the input formats for 1618 \param ref the entry ref is stored there 1619 1620 \return B_OK if successful, 1621 B_ERROR, if this is not a disk based translator 1622 B_BAD_VALUE, if \a ref is NULL 1623 B_NO_TRANSLATOR, \id didn't identify an existing translator 1624 */ 1625 status_t 1626 BTranslatorRoster::GetRefFor(translator_id id, entry_ref* ref) 1627 { 1628 if (ref == NULL) 1629 return B_BAD_VALUE; 1630 1631 return fPrivate->GetRefFor(id, *ref); 1632 } 1633 1634 1635 status_t 1636 BTranslatorRoster::StartWatching(BMessenger target) 1637 { 1638 return fPrivate->StartWatching(target); 1639 } 1640 1641 1642 status_t 1643 BTranslatorRoster::StopWatching(BMessenger target) 1644 { 1645 return fPrivate->StopWatching(target); 1646 } 1647 1648 1649 // #pragma mark - private 1650 1651 1652 BTranslatorRoster::BTranslatorRoster(const BTranslatorRoster &other) 1653 { 1654 } 1655 1656 1657 BTranslatorRoster & 1658 BTranslatorRoster::operator=(const BTranslatorRoster &tr) 1659 { 1660 return *this; 1661 } 1662 1663 1664 const char * 1665 Version__17BTranslatorRosterPlT1l(int32 *outCurVersion, int32 *outMinVersion, 1666 int32 inAppVersion) 1667 { 1668 if (!outCurVersion || !outMinVersion) 1669 return ""; 1670 1671 static char vString[50]; 1672 static char vDate[] = __DATE__; 1673 if (!vString[0]) { 1674 sprintf(vString, "Translation Kit v%d.%d.%d %s\n", 1675 static_cast<int>(B_TRANSLATION_MAJOR_VERSION(B_TRANSLATION_CURRENT_VERSION)), 1676 static_cast<int>(B_TRANSLATION_MINOR_VERSION(B_TRANSLATION_CURRENT_VERSION)), 1677 static_cast<int>(B_TRANSLATION_REVISION_VERSION(B_TRANSLATION_CURRENT_VERSION)), 1678 vDate); 1679 } 1680 *outCurVersion = B_TRANSLATION_CURRENT_VERSION; 1681 *outMinVersion = B_TRANSLATION_MIN_VERSION; 1682 return vString; 1683 } 1684 1685 1686 void BTranslatorRoster::ReservedTranslatorRoster1() {} 1687 void BTranslatorRoster::ReservedTranslatorRoster2() {} 1688 void BTranslatorRoster::ReservedTranslatorRoster3() {} 1689 void BTranslatorRoster::ReservedTranslatorRoster4() {} 1690 void BTranslatorRoster::ReservedTranslatorRoster5() {} 1691 void BTranslatorRoster::ReservedTranslatorRoster6() {} 1692