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