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