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