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