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