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 BEntry entry(&ref); 442 if (entry.IsDirectory()) 443 continue; 444 if (CreateTranslators(ref, count) == B_OK) 445 count++; 446 447 files++; 448 } 449 450 if (_added) 451 *_added = count; 452 453 if (files != 0 && count == 0) 454 return B_BAD_VALUE; 455 456 return B_OK; 457 } 458 459 460 status_t 461 BTranslatorRoster::Private::AddTranslator(BTranslator* translator, 462 image_id image, const entry_ref* ref, ino_t node) 463 { 464 BAutolock locker(this); 465 466 translator_item item; 467 item.translator = translator; 468 item.image = image; 469 item.node = node; 470 if (ref != NULL) 471 item.ref = *ref; 472 473 try { 474 fTranslators[fNextID] = item; 475 } catch (...) { 476 return B_NO_MEMORY; 477 } 478 479 translator->fOwningRoster = this; 480 translator->fID = fNextID++; 481 return B_OK; 482 } 483 484 485 void 486 BTranslatorRoster::Private::RemoveTranslators(entry_ref& ref) 487 { 488 _RemoveTranslators(NULL, &ref); 489 } 490 491 492 BTranslator* 493 BTranslatorRoster::Private::FindTranslator(translator_id id) 494 { 495 if (!IsLocked()) { 496 debugger("translator must be locked!"); 497 return NULL; 498 } 499 500 const translator_item* item = _FindTranslator(id); 501 if (item != NULL) 502 return item->translator; 503 504 return NULL; 505 } 506 507 508 status_t 509 BTranslatorRoster::Private::GetTranslatorData(image_id image, 510 translator_data& data) 511 { 512 // If this is a translator add-on, it is in the C format 513 memset(&data, 0, sizeof(translator_data)); 514 515 // find all the symbols 516 517 int32* version; 518 if (get_image_symbol(image, "translatorName", B_SYMBOL_TYPE_DATA, 519 (void**)&data.name) < B_OK 520 || get_image_symbol(image, "translatorInfo", B_SYMBOL_TYPE_DATA, 521 (void**)&data.info) < B_OK 522 || get_image_symbol(image, "translatorVersion", B_SYMBOL_TYPE_DATA, 523 (void**)&version) < B_OK || version == NULL 524 || get_image_symbol(image, "inputFormats", B_SYMBOL_TYPE_DATA, 525 (void**)&data.input_formats) < B_OK 526 || get_image_symbol(image, "outputFormats", B_SYMBOL_TYPE_DATA, 527 (void**)&data.output_formats) < B_OK 528 || get_image_symbol(image, "Identify", B_SYMBOL_TYPE_TEXT, 529 (void**)&data.identify_hook) < B_OK 530 || get_image_symbol(image, "Translate", B_SYMBOL_TYPE_TEXT, 531 (void**)&data.translate_hook) < B_OK) { 532 return B_BAD_TYPE; 533 } 534 535 data.version = *version; 536 537 // those calls are optional 538 get_image_symbol(image, "MakeConfig", B_SYMBOL_TYPE_TEXT, 539 (void**)&data.make_config_hook); 540 get_image_symbol(image, "GetConfigMessage", B_SYMBOL_TYPE_TEXT, 541 (void**)&data.get_config_message_hook); 542 543 return B_OK; 544 } 545 546 547 status_t 548 BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, 549 int32& count, BMessage* update) 550 { 551 BAutolock locker(this); 552 553 BPrivate::QuarantineTranslatorImage quarantine(*this); 554 555 const translator_item* item = _FindTranslator(ref.name); 556 if (item != NULL) { 557 // check if the known translator has a higher priority 558 if (_CompareTranslatorDirectoryPriority(item->ref, ref) <= 0) { 559 // keep the existing add-on 560 return B_OK; 561 } 562 563 // replace existing translator(s) if the new translator succeeds 564 quarantine.Put(item->ref); 565 } 566 567 BEntry entry(&ref); 568 node_ref nodeRef; 569 status_t status = entry.GetNodeRef(&nodeRef); 570 if (status < B_OK) 571 return status; 572 573 BPath path(&ref); 574 image_id image = load_add_on(path.Path()); 575 if (image < B_OK) 576 return image; 577 578 // Function pointer used to create post R4.5 style translators 579 BTranslator *(*makeNthTranslator)(int32 n, image_id you, uint32 flags, ...); 580 581 status = get_image_symbol(image, "make_nth_translator", 582 B_SYMBOL_TYPE_TEXT, (void**)&makeNthTranslator); 583 if (status == B_OK) { 584 // If the translator add-on supports the post R4.5 585 // translator creation mechanism, keep loading translators 586 // until MakeNthTranslator stops returning them. 587 BTranslator* translator = NULL; 588 int32 created = 0; 589 for (int32 n = 0; (translator = makeNthTranslator(n, image, 0)) != NULL; 590 n++) { 591 if (AddTranslator(translator, image, &ref, nodeRef.node) == B_OK) { 592 if (update) 593 update->AddInt32("translator_id", translator->fID); 594 count++; 595 created++; 596 } else { 597 translator->Release(); 598 // this will delete the translator 599 } 600 } 601 602 if (created == 0) 603 unload_add_on(image); 604 605 quarantine.Remove(); 606 return B_OK; 607 } 608 609 // If this is a translator add-on, it is in the C format 610 translator_data translatorData; 611 status = GetTranslatorData(image, translatorData); 612 613 // add this translator to the list 614 BPrivate::BFuncTranslator* translator = NULL; 615 if (status == B_OK) { 616 translator = new (std::nothrow) BPrivate::BFuncTranslator( 617 translatorData); 618 if (translator == NULL) 619 status = B_NO_MEMORY; 620 } 621 622 if (status == B_OK) 623 status = AddTranslator(translator, image, &ref, nodeRef.node); 624 625 if (status == B_OK) { 626 if (update) 627 update->AddInt32("translator_id", translator->fID); 628 quarantine.Remove(); 629 count++; 630 } else 631 unload_add_on(image); 632 633 return status; 634 } 635 636 637 status_t 638 BTranslatorRoster::Private::StartWatching(BMessenger target) 639 { 640 try { 641 fMessengers.push_back(target); 642 } catch (...) { 643 return B_NO_MEMORY; 644 } 645 646 if (fLazyScanning) { 647 fLazyScanning = false; 648 // Since we now have someone to report to, we cannot lazily 649 // adopt changes to the translator any longer 650 651 _RescanChanged(); 652 } 653 654 return B_OK; 655 } 656 657 658 status_t 659 BTranslatorRoster::Private::StopWatching(BMessenger target) 660 { 661 MessengerList::iterator iterator = fMessengers.begin(); 662 663 while (iterator != fMessengers.end()) { 664 if (*iterator == target) { 665 fMessengers.erase(iterator); 666 if (fMessengers.empty()) 667 fLazyScanning = true; 668 669 return B_OK; 670 } 671 672 iterator++; 673 } 674 675 return B_BAD_VALUE; 676 } 677 678 679 status_t 680 BTranslatorRoster::Private::StoreTranslators(BMessage& archive) 681 { 682 BAutolock locker(this); 683 684 TranslatorMap::const_iterator iterator = fTranslators.begin(); 685 686 while (iterator != fTranslators.end()) { 687 const translator_item& item = iterator->second; 688 BPath path(&item.ref); 689 if (path.InitCheck() == B_OK) 690 archive.AddString("be:translator_path", path.Path()); 691 692 iterator++; 693 } 694 695 return B_OK; 696 } 697 698 699 status_t 700 BTranslatorRoster::Private::Identify(BPositionIO* source, 701 BMessage* ioExtension, uint32 hintType, const char* hintMIME, 702 uint32 wantType, translator_info* _info) 703 { 704 BAutolock locker(this); 705 706 _RescanChanged(); 707 708 TranslatorMap::const_iterator iterator = fTranslators.begin(); 709 BMessage baseExtension; 710 if (ioExtension != NULL) 711 baseExtension = *ioExtension; 712 713 float bestWeight = 0.0f; 714 715 while (iterator != fTranslators.end()) { 716 BTranslator& translator = *iterator->second.translator; 717 718 off_t pos = source->Seek(0, SEEK_SET); 719 if (pos != 0) 720 return pos < 0 ? (status_t)pos : B_IO_ERROR; 721 722 int32 formatsCount = 0; 723 const translation_format* formats = translator.InputFormats( 724 &formatsCount); 725 const translation_format* format = _CheckHints(formats, formatsCount, 726 hintType, hintMIME); 727 728 BMessage extension(baseExtension); 729 translator_info info; 730 if (translator.Identify(source, format, &extension, &info, wantType) 731 == B_OK) { 732 float weight = info.quality * info.capability; 733 if (weight > bestWeight) { 734 if (ioExtension != NULL) 735 *ioExtension = extension; 736 bestWeight = weight; 737 738 info.translator = iterator->first; 739 memcpy(_info, &info, sizeof(translator_info)); 740 } 741 } 742 743 iterator++; 744 } 745 746 if (bestWeight > 0.0f) 747 return B_OK; 748 749 return B_NO_TRANSLATOR; 750 } 751 752 753 status_t 754 BTranslatorRoster::Private::GetTranslators(BPositionIO* source, 755 BMessage* ioExtension, uint32 hintType, const char* hintMIME, 756 uint32 wantType, translator_info** _info, int32* _numInfo) 757 { 758 BAutolock locker(this); 759 760 _RescanChanged(); 761 762 int32 arraySize = fTranslators.size(); 763 translator_info* array = new (std::nothrow) translator_info[arraySize]; 764 if (array == NULL) 765 return B_NO_MEMORY; 766 767 TranslatorMap::const_iterator iterator = fTranslators.begin(); 768 int32 count = 0; 769 770 while (iterator != fTranslators.end()) { 771 BTranslator& translator = *iterator->second.translator; 772 773 off_t pos = source->Seek(0, SEEK_SET); 774 if (pos != 0) { 775 delete[] array; 776 return pos < 0 ? status_t(pos) : B_IO_ERROR; 777 } 778 779 int32 formatsCount = 0; 780 const translation_format* formats = translator.InputFormats( 781 &formatsCount); 782 const translation_format* format = _CheckHints(formats, formatsCount, 783 hintType, hintMIME); 784 785 translator_info info; 786 if (translator.Identify(source, format, ioExtension, &info, wantType) 787 == B_OK) { 788 info.translator = iterator->first; 789 array[count++] = info; 790 } 791 792 iterator++; 793 } 794 795 *_info = array; 796 *_numInfo = count; 797 qsort(array, count, sizeof(translator_info), 798 BTranslatorRoster::Private::_CompareSupport); 799 // translators are sorted by best support 800 801 return B_OK; 802 } 803 804 805 status_t 806 BTranslatorRoster::Private::GetAllTranslators(translator_id** _ids, 807 int32* _count) 808 { 809 BAutolock locker(this); 810 811 _RescanChanged(); 812 813 int32 arraySize = fTranslators.size(); 814 translator_id* array = new (std::nothrow) translator_id[arraySize]; 815 if (array == NULL) 816 return B_NO_MEMORY; 817 818 TranslatorMap::const_iterator iterator = fTranslators.begin(); 819 int32 count = 0; 820 821 while (iterator != fTranslators.end()) { 822 array[count++] = iterator->first; 823 iterator++; 824 } 825 826 *_ids = array; 827 *_count = count; 828 return B_OK; 829 } 830 831 832 status_t 833 BTranslatorRoster::Private::GetRefFor(translator_id id, entry_ref& ref) 834 { 835 BAutolock locker(this); 836 837 const translator_item* item = _FindTranslator(id); 838 if (item == NULL) 839 return B_NO_TRANSLATOR; 840 841 BEntry entry(&item->ref); 842 if (entry.InitCheck() == B_OK && entry.Exists() && entry.IsFile()) { 843 ref = item->ref; 844 return B_OK; 845 } 846 847 return B_ERROR; 848 } 849 850 851 void 852 BTranslatorRoster::Private::TranslatorDeleted(translator_id id) 853 { 854 BAutolock locker(this); 855 856 TranslatorMap::iterator iterator = fTranslators.find(id); 857 if (iterator == fTranslators.end()) 858 return; 859 860 fTranslators.erase(iterator); 861 } 862 863 864 /*static*/ int 865 BTranslatorRoster::Private::_CompareSupport(const void* _a, const void* _b) 866 { 867 const translator_info* infoA = (const translator_info*)_a; 868 const translator_info* infoB = (const translator_info*)_b; 869 870 float weightA = infoA->quality * infoA->capability; 871 float weightB = infoB->quality * infoB->capability; 872 873 if (weightA == weightB) 874 return 0; 875 if (weightA > weightB) 876 return -1; 877 878 return 1; 879 } 880 881 882 /*! 883 In lazy mode, freshly installed translator are not scanned immediately 884 when they become available. Instead, they are put into a set. 885 886 When a method is called that may be interested in these new translators, 887 they are scanned on the fly. Since lazy mode also means that this roster 888 does not have any listeners, we don't need to notify anyone about those 889 changes. 890 */ 891 void 892 BTranslatorRoster::Private::_RescanChanged() 893 { 894 while (!fRescanEntries.empty()) { 895 EntryRefSet::iterator iterator = fRescanEntries.begin(); 896 int32 count; 897 CreateTranslators(*iterator, count); 898 899 fRescanEntries.erase(iterator); 900 } 901 } 902 903 904 /*! 905 Tests if the hints provided for a source stream are compatible to 906 the formats the translator exports. 907 */ 908 const translation_format* 909 BTranslatorRoster::Private::_CheckHints(const translation_format* formats, 910 int32 formatsCount, uint32 hintType, const char* hintMIME) 911 { 912 if (formats == NULL || formatsCount <= 0 || (!hintType && hintMIME == NULL)) 913 return NULL; 914 915 // The provided MIME type hint may be a super type 916 int32 super = 0; 917 if (hintMIME && !strchr(hintMIME, '/')) 918 super = strlen(hintMIME); 919 920 // scan for suitable format 921 for (int32 i = 0; i < formatsCount && formats[i].type; i++) { 922 if (formats[i].type == hintType 923 || (hintMIME 924 && ((super && !strncmp(formats[i].MIME, hintMIME, super)) 925 || !strcmp(formats[i].MIME, hintMIME)))) 926 return &formats[i]; 927 } 928 929 return NULL; 930 } 931 932 933 const translator_item* 934 BTranslatorRoster::Private::_FindTranslator(translator_id id) const 935 { 936 TranslatorMap::const_iterator iterator = fTranslators.find(id); 937 if (iterator == fTranslators.end()) 938 return NULL; 939 940 return &iterator->second; 941 } 942 943 944 const translator_item* 945 BTranslatorRoster::Private::_FindTranslator(const char* name) const 946 { 947 if (name == NULL) 948 return NULL; 949 950 TranslatorMap::const_iterator iterator = fTranslators.begin(); 951 952 while (iterator != fTranslators.end()) { 953 const translator_item& item = iterator->second; 954 if (item.ref.name != NULL && !strcmp(item.ref.name, name)) 955 return &item; 956 957 iterator++; 958 } 959 960 return NULL; 961 } 962 963 964 const translator_item* 965 BTranslatorRoster::Private::_FindTranslator(entry_ref& ref) const 966 { 967 if (ref.name == NULL) 968 return NULL; 969 970 TranslatorMap::const_iterator iterator = fTranslators.begin(); 971 972 while (iterator != fTranslators.end()) { 973 const translator_item& item = iterator->second; 974 if (item.ref == ref) 975 return &item; 976 977 iterator++; 978 } 979 980 return NULL; 981 } 982 983 984 translator_item* 985 BTranslatorRoster::Private::_FindTranslator(node_ref& nodeRef) 986 { 987 if (nodeRef.device < 0) 988 return NULL; 989 990 TranslatorMap::iterator iterator = fTranslators.begin(); 991 992 while (iterator != fTranslators.end()) { 993 translator_item& item = iterator->second; 994 if (item.ref.device == nodeRef.device 995 && item.node == nodeRef.node) 996 return &item; 997 998 iterator++; 999 } 1000 1001 return NULL; 1002 } 1003 1004 1005 /*! 1006 Directories added to the roster have a certain priority - the first entry 1007 to be added has the highest priority; if a translator with the same name 1008 is to be found in two directories, the one with the higher priority is 1009 chosen. 1010 */ 1011 int32 1012 BTranslatorRoster::Private::_CompareTranslatorDirectoryPriority( 1013 const entry_ref& a, const entry_ref& b) const 1014 { 1015 // priority is determined by the order in the list 1016 1017 node_ref nodeRefA; 1018 nodeRefA.device = a.device; 1019 nodeRefA.node = a.directory; 1020 1021 node_ref nodeRefB; 1022 nodeRefB.device = b.device; 1023 nodeRefB.node = b.directory; 1024 1025 NodeRefList::const_iterator iterator = fDirectories.begin(); 1026 1027 while (iterator != fDirectories.end()) { 1028 if (*iterator == nodeRefA) 1029 return -1; 1030 if (*iterator == nodeRefB) 1031 return 1; 1032 1033 iterator++; 1034 } 1035 1036 return 0; 1037 } 1038 1039 1040 bool 1041 BTranslatorRoster::Private::_IsKnownDirectory(const node_ref& nodeRef) const 1042 { 1043 NodeRefList::const_iterator iterator = fDirectories.begin(); 1044 1045 while (iterator != fDirectories.end()) { 1046 if (*iterator == nodeRef) 1047 return true; 1048 1049 iterator++; 1050 } 1051 1052 return false; 1053 } 1054 1055 1056 void 1057 BTranslatorRoster::Private::_RemoveTranslators(const node_ref* nodeRef, 1058 const entry_ref* ref) 1059 { 1060 if (ref == NULL && nodeRef == NULL) 1061 return; 1062 1063 TranslatorMap::iterator iterator = fTranslators.begin(); 1064 BMessage update(B_TRANSLATOR_REMOVED); 1065 image_id image = -1; 1066 1067 while (iterator != fTranslators.end()) { 1068 TranslatorMap::iterator next = iterator; 1069 next++; 1070 1071 const translator_item& item = iterator->second; 1072 if ((ref != NULL && item.ref == *ref) 1073 || (nodeRef != NULL && item.ref.device == nodeRef->device 1074 && item.node == nodeRef->node)) { 1075 item.translator->fOwningRoster = NULL; 1076 // if the translator is busy, we don't want to be notified 1077 // about the removal later on 1078 item.translator->Release(); 1079 image = item.image; 1080 update.AddInt32("translator_id", iterator->first); 1081 1082 fTranslators.erase(iterator); 1083 } 1084 1085 iterator = next; 1086 } 1087 1088 // Unload image from the removed translator 1089 1090 if (image >= B_OK) 1091 unload_add_on(image); 1092 1093 _NotifyListeners(update); 1094 } 1095 1096 1097 void 1098 BTranslatorRoster::Private::_EntryAdded(const node_ref& nodeRef, 1099 const char* name) 1100 { 1101 entry_ref ref; 1102 ref.device = nodeRef.device; 1103 ref.directory = nodeRef.node; 1104 ref.set_name(name); 1105 1106 _EntryAdded(ref); 1107 } 1108 1109 1110 /*! 1111 In lazy mode, the entry is marked to be rescanned on next use of any 1112 translation method (that could make use of it). 1113 In non-lazy mode, the translators for this entry are created directly 1114 and listeners notified. 1115 1116 Called by the node monitor handling. 1117 */ 1118 void 1119 BTranslatorRoster::Private::_EntryAdded(const entry_ref& ref) 1120 { 1121 BEntry entry; 1122 if (entry.SetTo(&ref) != B_OK || !entry.IsFile()) 1123 return; 1124 1125 if (fLazyScanning) { 1126 fRescanEntries.insert(ref); 1127 return; 1128 } 1129 1130 BMessage update(B_TRANSLATOR_ADDED); 1131 int32 count = 0; 1132 CreateTranslators(ref, count, &update); 1133 1134 _NotifyListeners(update); 1135 } 1136 1137 1138 void 1139 BTranslatorRoster::Private::_NotifyListeners(BMessage& update) const 1140 { 1141 MessengerList::const_iterator iterator = fMessengers.begin(); 1142 1143 while (iterator != fMessengers.end()) { 1144 (*iterator).SendMessage(&update); 1145 iterator++; 1146 } 1147 } 1148 1149 1150 // #pragma mark - 1151 1152 1153 BTranslatorRoster::BTranslatorRoster() 1154 { 1155 _Initialize(); 1156 } 1157 1158 1159 BTranslatorRoster::BTranslatorRoster(BMessage* model) 1160 { 1161 _Initialize(); 1162 1163 if (model) { 1164 const char* path; 1165 for (int32 i = 0; 1166 model->FindString("be:translator_path", i, &path) == B_OK; i++) { 1167 BEntry entry(path); 1168 entry_ref ref; 1169 if (entry.GetRef(&ref) == B_OK) { 1170 int32 count = 0; 1171 fPrivate->CreateTranslators(ref, count); 1172 } 1173 } 1174 } 1175 } 1176 1177 1178 BTranslatorRoster::~BTranslatorRoster() 1179 { 1180 // If the default BTranslatorRoster is being 1181 // deleted, set the pointer to the default 1182 // BTranslatorRoster to NULL 1183 if (sDefaultRoster == this) 1184 sDefaultRoster = NULL; 1185 1186 delete fPrivate; 1187 } 1188 1189 1190 void 1191 BTranslatorRoster::_Initialize() 1192 { 1193 fPrivate = new BTranslatorRoster::Private(); 1194 } 1195 1196 1197 status_t 1198 BTranslatorRoster::Archive(BMessage* into, bool deep) const 1199 { 1200 status_t status = BArchivable::Archive(into, deep); 1201 if (status != B_OK) 1202 return status; 1203 1204 return fPrivate->StoreTranslators(*into); 1205 } 1206 1207 1208 BArchivable* 1209 BTranslatorRoster::Instantiate(BMessage* from) 1210 { 1211 if (!from || !validate_instantiation(from, "BTranslatorRoster")) 1212 return NULL; 1213 1214 return new BTranslatorRoster(from); 1215 } 1216 1217 1218 BTranslatorRoster* 1219 BTranslatorRoster::Default() 1220 { 1221 static int32 lock = 0; 1222 1223 if (sDefaultRoster != NULL) 1224 return sDefaultRoster; 1225 1226 if (atomic_add(&lock, 1) != 0) { 1227 // Just wait for the default translator to be instantiated 1228 while (sDefaultRoster == NULL) 1229 snooze(10000); 1230 1231 atomic_add(&lock, -1); 1232 return sDefaultRoster; 1233 } 1234 1235 // If the default translators have not been loaded, 1236 // create a new BTranslatorRoster for them, and load them. 1237 if (sDefaultRoster == NULL) { 1238 BTranslatorRoster* roster = new BTranslatorRoster(); 1239 roster->AddTranslators(NULL); 1240 1241 sDefaultRoster = roster; 1242 // this will unlock any other threads waiting for 1243 // the default roster to become available 1244 } 1245 1246 atomic_add(&lock, -1); 1247 return sDefaultRoster; 1248 } 1249 1250 1251 /*! 1252 This function takes a string of colon delimited paths, and adds 1253 the translators from those paths to this BTranslatorRoster. 1254 1255 If load_path is NULL, it parses the environment variable 1256 TRANSLATORS. If that does not exist, it uses the system paths: 1257 /boot/home/config/add-ons/Translators, 1258 /system/add-ons/Translators. 1259 */ 1260 status_t 1261 BTranslatorRoster::AddTranslators(const char* path) 1262 { 1263 if (path == NULL) 1264 path = getenv("TRANSLATORS"); 1265 if (path == NULL) { 1266 fPrivate->AddDefaultPaths(); 1267 return B_OK; 1268 } 1269 1270 return fPrivate->AddPaths(path); 1271 } 1272 1273 1274 /*! 1275 Adds a BTranslator based object to the BTranslatorRoster. 1276 When you add a BTranslator roster, it is Acquire()'d by 1277 BTranslatorRoster; it is Release()'d when the 1278 BTranslatorRoster is deleted. 1279 1280 \param translator the translator to be added to the 1281 BTranslatorRoster 1282 1283 \return B_BAD_VALUE, if translator is NULL, 1284 B_OK if all went well 1285 */ 1286 status_t 1287 BTranslatorRoster::AddTranslator(BTranslator* translator) 1288 { 1289 if (!translator) 1290 return B_BAD_VALUE; 1291 1292 return fPrivate->AddTranslator(translator); 1293 } 1294 1295 1296 bool 1297 BTranslatorRoster::IsTranslator(entry_ref* ref) 1298 { 1299 if (ref == NULL) 1300 return false; 1301 1302 BPath path(ref); 1303 image_id image = load_add_on(path.Path()); 1304 if (image < B_OK) 1305 return false; 1306 1307 // Function pointer used to create post R4.5 style translators 1308 BTranslator* (*makeNthTranslator)(int32 n, image_id you, uint32 flags, ...); 1309 1310 status_t status = get_image_symbol(image, "make_nth_translator", 1311 B_SYMBOL_TYPE_TEXT, (void**)&makeNthTranslator); 1312 if (status < B_OK) { 1313 // If this is a translator add-on, it is in the C format 1314 translator_data translatorData; 1315 status = fPrivate->GetTranslatorData(image, translatorData); 1316 } 1317 1318 unload_add_on(image); 1319 return status == B_OK; 1320 } 1321 1322 1323 /*! 1324 This function determines which translator is best suited 1325 to convert the data from \a source. 1326 1327 \param source the data to be identified 1328 \param ioExtension the configuration data for the translator 1329 \param _info the information about the chosen translator is put here 1330 \param hintType a hint about the type of data that is in \a source, set 1331 it to zero if the type is not known 1332 \param hintMIME a hint about the MIME type of \a source, set it to NULL 1333 if the type is not known. 1334 \param wantType the desired output type - if zero, any type is okay. 1335 1336 \return B_OK, identification of \a source was successful, 1337 B_NO_TRANSLATOR, no appropriate translator found, 1338 and other errors from accessing the source stream 1339 */ 1340 status_t 1341 BTranslatorRoster::Identify(BPositionIO* source, BMessage* ioExtension, 1342 translator_info* _info, uint32 hintType, const char* hintMIME, 1343 uint32 wantType) 1344 { 1345 if (source == NULL || _info == NULL) 1346 return B_BAD_VALUE; 1347 1348 return fPrivate->Identify(source, ioExtension, hintType, hintMIME, wantType, 1349 _info); 1350 } 1351 1352 1353 /*! 1354 Finds all translators capable of handling the data in \a source 1355 and puts them into the outInfo array (which you must delete 1356 yourself when you are done with it). Specifying a value for 1357 \a hintType, \a hintMIME and/or \a wantType causes only the 1358 translators that satisfy them to be included in the outInfo. 1359 1360 \param source the data to be translated 1361 \param ioExtension the configuration data for the translator 1362 \param _info, the array of acceptable translators is stored here if 1363 the function succeeds. It's the caller's responsibility to free 1364 the array using delete[]. 1365 \param _numInfo, number of entries in the \a _info array 1366 \param hintType a hint about the type of data that is in \a source, set 1367 it to zero if the type is not known 1368 \param hintMIME a hint about the MIME type of \a source, set it to NULL 1369 if the type is not known. 1370 \param wantType the desired output type - if zero, any type is okay. 1371 1372 \return B_OK, successfully indentified the data in \a source 1373 B_NO_TRANSLATOR, no translator could handle \a source 1374 other errors, problems using \a source 1375 */ 1376 status_t 1377 BTranslatorRoster::GetTranslators(BPositionIO* source, BMessage* ioExtension, 1378 translator_info** _info, int32* _numInfo, uint32 hintType, 1379 const char* hintMIME, uint32 wantType) 1380 { 1381 if (source == NULL || _info == NULL || _numInfo == NULL) 1382 return B_BAD_VALUE; 1383 1384 return fPrivate->GetTranslators(source, ioExtension, hintType, hintMIME, 1385 wantType, _info, _numInfo); 1386 } 1387 1388 1389 /*! 1390 Returns an array in \a _ids of all of the translators stored by this 1391 object. 1392 You must free the array using delete[] when you are done with it. 1393 1394 \param _ids the array is stored there (you own the array). 1395 \param _count number of IDs in the array. 1396 */ 1397 status_t 1398 BTranslatorRoster::GetAllTranslators(translator_id** _ids, int32* _count) 1399 { 1400 if (_ids == NULL || _count == NULL) 1401 return B_BAD_VALUE; 1402 1403 return fPrivate->GetAllTranslators(_ids, _count); 1404 } 1405 1406 1407 /*! 1408 Returns information about the translator with the specified 1409 translator \a id. 1410 You must not free any of the data you get back. 1411 1412 \param id identifies which translator you want info for 1413 \param _name the translator name is put here 1414 \param _info the translator description is put here 1415 \param _version the translation version is put here 1416 1417 \return B_OK if successful, 1418 B_BAD_VALUE, if all parameters are NULL 1419 B_NO_TRANSLATOR, \id didn't identify an existing translator 1420 */ 1421 status_t 1422 BTranslatorRoster::GetTranslatorInfo(translator_id id, const char** _name, 1423 const char** _info, int32* _version) 1424 { 1425 if (_name == NULL && _info == NULL && _version == NULL) 1426 return B_BAD_VALUE; 1427 1428 BAutolock locker(fPrivate); 1429 1430 BTranslator* translator = fPrivate->FindTranslator(id); 1431 if (translator == NULL) 1432 return B_NO_TRANSLATOR; 1433 1434 if (_name) 1435 *_name = translator->TranslatorName(); 1436 if (_info) 1437 *_info = translator->TranslatorInfo(); 1438 if (_version) 1439 *_version = translator->TranslatorVersion(); 1440 1441 return B_OK; 1442 } 1443 1444 1445 /*! 1446 Returns all of the input formats for the translator specified 1447 by \a id. 1448 You must not free any of the data you get back. 1449 1450 \param id identifies which translator you want the input formats for 1451 \param _formats array of input formats 1452 \param _numFormats number of formats in the array 1453 1454 \return B_OK if successful, 1455 B_BAD_VALUE, if any parameter is NULL 1456 B_NO_TRANSLATOR, \id didn't identify an existing translator 1457 */ 1458 status_t 1459 BTranslatorRoster::GetInputFormats(translator_id id, 1460 const translation_format** _formats, int32* _numFormats) 1461 { 1462 if (_formats == NULL || _numFormats == NULL) 1463 return B_BAD_VALUE; 1464 1465 BAutolock locker(fPrivate); 1466 1467 BTranslator* translator = fPrivate->FindTranslator(id); 1468 if (translator == NULL) 1469 return B_NO_TRANSLATOR; 1470 1471 *_formats = translator->InputFormats(_numFormats); 1472 return B_OK; 1473 } 1474 1475 1476 /*! 1477 Returns all of the output formats for the translator specified 1478 by \a id. 1479 You must not free any of the data you get back. 1480 1481 \param id identifies which translator you want the output formats for 1482 \param _formats array of output formats 1483 \param _numFormats number of formats in the array 1484 1485 \return B_OK if successful, 1486 B_BAD_VALUE, if any parameter is NULL 1487 B_NO_TRANSLATOR, \id didn't identify an existing translator 1488 */ 1489 status_t 1490 BTranslatorRoster::GetOutputFormats(translator_id id, 1491 const translation_format** _formats, int32* _numFormats) 1492 { 1493 if (_formats == NULL || _numFormats == NULL) 1494 return B_BAD_VALUE; 1495 1496 BAutolock locker(fPrivate); 1497 1498 BTranslator* translator = fPrivate->FindTranslator(id); 1499 if (translator == NULL) 1500 return B_NO_TRANSLATOR; 1501 1502 *_formats = translator->OutputFormats(_numFormats); 1503 return B_OK; 1504 } 1505 1506 1507 /*! 1508 This function is the whole point of the Translation Kit. 1509 This is for translating the data in \a source to \a destination 1510 using the format \a wantOutType. 1511 1512 \param source the data to be translated 1513 \param ioExtension the configuration data for the translator 1514 \param info information about translator to use (can be NULL, in which 1515 case the \a source is identified first) 1516 \param destination where \a source is translated to 1517 \param hintType a hint about the type of data that is in \a source, set 1518 it to zero if the type is not known 1519 \param hintMIME a hint about the MIME type of \a source, set it to NULL 1520 if the type is not known. 1521 \param wantType the desired output type - if zero, any type is okay. 1522 1523 \return B_OK, translation of \a source was successful, 1524 B_NO_TRANSLATOR, no appropriate translator found, 1525 and other errors from accessing the source and destination streams 1526 */ 1527 status_t 1528 BTranslatorRoster::Translate(BPositionIO* source, const translator_info* info, 1529 BMessage* ioExtension, BPositionIO* destination, uint32 wantOutType, 1530 uint32 hintType, const char* hintMIME) 1531 { 1532 if (source == NULL || destination == NULL) 1533 return B_BAD_VALUE; 1534 1535 translator_info infoBuffer; 1536 1537 if (info == NULL) { 1538 // look for a suitable translator 1539 status_t status = fPrivate->Identify(source, ioExtension, hintType, 1540 hintMIME, wantOutType, &infoBuffer); 1541 if (status < B_OK) 1542 return status; 1543 1544 info = &infoBuffer; 1545 } 1546 1547 if (!fPrivate->Lock()) 1548 return B_ERROR; 1549 1550 BTranslator* translator = fPrivate->FindTranslator(info->translator); 1551 if (translator != NULL) { 1552 translator->Acquire(); 1553 // make sure this translator is not removed while we're playing with 1554 // it; translating shouldn't be serialized! 1555 } 1556 1557 fPrivate->Unlock(); 1558 1559 if (translator == NULL) 1560 return B_NO_TRANSLATOR; 1561 1562 status_t status = B_OK; 1563 off_t pos = source->Seek(0, SEEK_SET); 1564 if (pos != 0) 1565 status = pos < 0 ? (status_t)pos : B_IO_ERROR; 1566 if (status == B_OK) { 1567 status = translator->Translate(source, info, ioExtension, wantOutType, 1568 destination); 1569 } 1570 translator->Release(); 1571 1572 return status; 1573 } 1574 1575 1576 /*! 1577 This function is the whole point of the Translation Kit. 1578 This is for translating the data in \a source to \a destination 1579 using the format \a wantOutType and the translator identified 1580 by \a id. 1581 1582 \param id the translator to be used 1583 \param source the data to be translated 1584 \param ioExtension the configuration data for the translator 1585 \param destination where \a source is translated to 1586 \param wantType the desired output type - if zero, any type is okay. 1587 1588 \return B_OK, translation of \a source was successful, 1589 B_NO_TRANSLATOR, no appropriate translator found, 1590 and other errors from accessing the source and destination streams 1591 */ 1592 status_t 1593 BTranslatorRoster::Translate(translator_id id, BPositionIO* source, 1594 BMessage* ioExtension, BPositionIO* destination, uint32 wantOutType) 1595 { 1596 if (source == NULL || destination == NULL) 1597 return B_BAD_VALUE; 1598 1599 if (!fPrivate->Lock()) 1600 return B_ERROR; 1601 1602 BTranslator* translator = fPrivate->FindTranslator(id); 1603 if (translator != NULL) { 1604 translator->Acquire(); 1605 // make sure this translator is not removed while we're playing with 1606 // it; translating shouldn't be serialized! 1607 } 1608 1609 fPrivate->Unlock(); 1610 1611 if (translator == NULL) 1612 return B_NO_TRANSLATOR; 1613 1614 status_t status; 1615 off_t pos = source->Seek(0, SEEK_SET); 1616 if (pos == 0) { 1617 translator_info info; 1618 status = translator->Identify(source, NULL, ioExtension, &info, 1619 wantOutType); 1620 if (status >= B_OK) { 1621 off_t pos = source->Seek(0, SEEK_SET); 1622 if (pos != 0) 1623 status = pos < 0 ? (status_t)pos : B_IO_ERROR; 1624 else { 1625 status = translator->Translate(source, &info, ioExtension, 1626 wantOutType, destination); 1627 } 1628 } 1629 } else 1630 status = pos < 0 ? (status_t)pos : B_IO_ERROR; 1631 translator->Release(); 1632 1633 return status; 1634 } 1635 1636 1637 /*! 1638 Creates a BView in \a _view for configuring the translator specified 1639 by \a id. Not all translators support this, though. 1640 1641 \param id identifies which translator you want the input formats for 1642 \param ioExtension the configuration data for the translator 1643 \param _view the view for configuring the translator 1644 \param _extent the bounds for the (resizable) view 1645 1646 \return B_OK if successful, 1647 B_BAD_VALUE, if any parameter is NULL 1648 B_NO_TRANSLATOR, \id didn't identify an existing translator 1649 */ 1650 status_t 1651 BTranslatorRoster::MakeConfigurationView(translator_id id, 1652 BMessage* ioExtension, BView** _view, BRect* _extent) 1653 { 1654 if (_view == NULL || _extent == NULL) 1655 return B_BAD_VALUE; 1656 1657 BAutolock locker(fPrivate); 1658 1659 BTranslator* translator = fPrivate->FindTranslator(id); 1660 if (translator == NULL) 1661 return B_NO_TRANSLATOR; 1662 1663 return translator->MakeConfigurationView(ioExtension, _view, _extent); 1664 } 1665 1666 1667 /*! 1668 Gets the configuration setttings for the translator 1669 specified by \a id and puts them into \a ioExtension. 1670 1671 \param id identifies which translator you want the input formats for 1672 \param ioExtension the configuration data for the translator 1673 1674 \return B_OK if successful, 1675 B_BAD_VALUE, if \a ioExtension is NULL 1676 B_NO_TRANSLATOR, \id didn't identify an existing translator 1677 */ 1678 status_t 1679 BTranslatorRoster::GetConfigurationMessage(translator_id id, 1680 BMessage* ioExtension) 1681 { 1682 if (!ioExtension) 1683 return B_BAD_VALUE; 1684 1685 BAutolock locker(fPrivate); 1686 1687 BTranslator* translator = fPrivate->FindTranslator(id); 1688 if (translator == NULL) 1689 return B_NO_TRANSLATOR; 1690 1691 return translator->GetConfigurationMessage(ioExtension); 1692 } 1693 1694 1695 /*! 1696 Gets the entry_ref for the given translator (of course, this works only 1697 for disk based translators). 1698 1699 \param id identifies which translator you want the input formats for 1700 \param ref the entry ref is stored there 1701 1702 \return B_OK if successful, 1703 B_ERROR, if this is not a disk based translator 1704 B_BAD_VALUE, if \a ref is NULL 1705 B_NO_TRANSLATOR, \id didn't identify an existing translator 1706 */ 1707 status_t 1708 BTranslatorRoster::GetRefFor(translator_id id, entry_ref* ref) 1709 { 1710 if (ref == NULL) 1711 return B_BAD_VALUE; 1712 1713 return fPrivate->GetRefFor(id, *ref); 1714 } 1715 1716 1717 status_t 1718 BTranslatorRoster::StartWatching(BMessenger target) 1719 { 1720 return fPrivate->StartWatching(target); 1721 } 1722 1723 1724 status_t 1725 BTranslatorRoster::StopWatching(BMessenger target) 1726 { 1727 return fPrivate->StopWatching(target); 1728 } 1729 1730 1731 // #pragma mark - private 1732 1733 1734 BTranslatorRoster::BTranslatorRoster(const BTranslatorRoster &other) 1735 { 1736 } 1737 1738 1739 BTranslatorRoster & 1740 BTranslatorRoster::operator=(const BTranslatorRoster &tr) 1741 { 1742 return *this; 1743 } 1744 1745 1746 #if __GNUC__ == 2 // gcc 2 1747 1748 /*static*/ const char* 1749 BTranslatorRoster::Version(int32* outCurVersion, int32* outMinVersion, 1750 int32 inAppVersion) 1751 { 1752 if (!outCurVersion || !outMinVersion) 1753 return ""; 1754 1755 static char vString[50]; 1756 static char vDate[] = __DATE__; 1757 if (!vString[0]) { 1758 sprintf(vString, "Translation Kit v%d.%d.%d %s\n", 1759 int(B_TRANSLATION_MAJOR_VERSION(B_TRANSLATION_CURRENT_VERSION)), 1760 int(B_TRANSLATION_MINOR_VERSION(B_TRANSLATION_CURRENT_VERSION)), 1761 int(B_TRANSLATION_REVISION_VERSION(B_TRANSLATION_CURRENT_VERSION)), 1762 vDate); 1763 } 1764 *outCurVersion = B_TRANSLATION_CURRENT_VERSION; 1765 *outMinVersion = B_TRANSLATION_MIN_VERSION; 1766 return vString; 1767 } 1768 1769 #endif // gcc 2 1770 1771 1772 void BTranslatorRoster::ReservedTranslatorRoster1() {} 1773 void BTranslatorRoster::ReservedTranslatorRoster2() {} 1774 void BTranslatorRoster::ReservedTranslatorRoster3() {} 1775 void BTranslatorRoster::ReservedTranslatorRoster4() {} 1776 void BTranslatorRoster::ReservedTranslatorRoster5() {} 1777 void BTranslatorRoster::ReservedTranslatorRoster6() {} 1778