1 /*****************************************************************************/ 2 // BaseTranslator 3 // Written by Michael Wilber, Haiku Translation Kit Team 4 // 5 // BaseTranslator.cpp 6 // 7 // The BaseTranslator class implements functionality common to most 8 // Translators so that this functionality need not be implemented over and 9 // over in each Translator. 10 // 11 // 12 // Copyright (c) 2004 Haiku, Inc. 13 // 14 // Permission is hereby granted, free of charge, to any person obtaining a 15 // copy of this software and associated documentation files (the "Software"), 16 // to deal in the Software without restriction, including without limitation 17 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 // and/or sell copies of the Software, and to permit persons to whom the 19 // Software is furnished to do so, subject to the following conditions: 20 // 21 // The above copyright notice and this permission notice shall be included 22 // in all copies or substantial portions of the Software. 23 // 24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 // DEALINGS IN THE SOFTWARE. 31 /*****************************************************************************/ 32 33 #include "BaseTranslator.h" 34 35 #include <string.h> 36 #include <stdio.h> 37 38 #include <algorithm> 39 40 #include <Catalog.h> 41 #include <Locale.h> 42 43 44 #undef B_TRANSLATION_CONTEXT 45 #define B_TRANSLATION_CONTEXT "BaseTranslator" 46 47 48 // --------------------------------------------------------------- 49 // Constructor 50 // 51 // Sets up the version info and the name of the translator so that 52 // these values can be returned when they are requested. 53 // 54 // Preconditions: 55 // 56 // Parameters: 57 // 58 // Postconditions: 59 // 60 // Returns: 61 // --------------------------------------------------------------- 62 BaseTranslator::BaseTranslator(const char *name, const char *info, 63 const int32 version, const translation_format *inFormats, 64 int32 inCount, const translation_format *outFormats, int32 outCount, 65 const char *settingsFile, const TranSetting *defaults, int32 defCount, 66 uint32 tranGroup, uint32 tranType) 67 : 68 BTranslator() 69 { 70 fSettings = new TranslatorSettings(settingsFile, defaults, defCount); 71 fSettings->LoadSettings(); 72 // load settings from the Base Translator settings file 73 74 fVersion = version; 75 fName = new char[strlen(name) + 1]; 76 strcpy(fName, name); 77 fInfo = new char[strlen(info) + 41]; 78 sprintf(fInfo, "%s v%d.%d.%d %s", info, 79 static_cast<int>(B_TRANSLATION_MAJOR_VERSION(fVersion)), 80 static_cast<int>(B_TRANSLATION_MINOR_VERSION(fVersion)), 81 static_cast<int>(B_TRANSLATION_REVISION_VERSION(fVersion)), 82 __DATE__); 83 84 fInputFormats = inFormats; 85 fInputCount = (fInputFormats) ? inCount : 0; 86 fOutputFormats = outFormats; 87 fOutputCount = (fOutputFormats) ? outCount : 0; 88 fTranGroup = tranGroup; 89 fTranType = tranType; 90 } 91 92 93 // --------------------------------------------------------------- 94 // Destructor 95 // 96 // Does nothing 97 // 98 // Preconditions: 99 // 100 // Parameters: 101 // 102 // Postconditions: 103 // 104 // Returns: 105 // --------------------------------------------------------------- 106 // 107 // NOTE: It may be the case, that under Be's libtranslation.so, 108 // that this destructor will never be called 109 BaseTranslator::~BaseTranslator() 110 { 111 fSettings->Release(); 112 delete[] fName; 113 delete[] fInfo; 114 } 115 116 117 // --------------------------------------------------------------- 118 // TranslatorName 119 // 120 // Returns the short name of the translator. 121 // 122 // Preconditions: 123 // 124 // Parameters: 125 // 126 // Postconditions: 127 // 128 // Returns: a const char * to the short name of the translator 129 // --------------------------------------------------------------- 130 const char * 131 BaseTranslator::TranslatorName() const 132 { 133 return fName; 134 } 135 136 137 // --------------------------------------------------------------- 138 // TranslatorInfo 139 // 140 // Returns a more verbose name for the translator than the one 141 // TranslatorName() returns. This usually includes version info. 142 // 143 // Preconditions: 144 // 145 // Parameters: 146 // 147 // Postconditions: 148 // 149 // Returns: a const char * to the verbose name of the translator 150 // --------------------------------------------------------------- 151 const char * 152 BaseTranslator::TranslatorInfo() const 153 { 154 return fInfo; 155 } 156 157 158 // --------------------------------------------------------------- 159 // TranslatorVersion 160 // 161 // Returns the integer representation of the current version of 162 // this translator. 163 // 164 // Preconditions: 165 // 166 // Parameters: 167 // 168 // Postconditions: 169 // 170 // Returns: 171 // --------------------------------------------------------------- 172 int32 173 BaseTranslator::TranslatorVersion() const 174 { 175 return fVersion; 176 } 177 178 179 // --------------------------------------------------------------- 180 // InputFormats 181 // 182 // Returns a list of input formats supported by this translator. 183 // 184 // Preconditions: 185 // 186 // Parameters: out_count, The number of input formats 187 // support is returned here. 188 // 189 // Postconditions: 190 // 191 // Returns: the array of input formats and the number of input 192 // formats through the out_count parameter 193 // --------------------------------------------------------------- 194 const translation_format * 195 BaseTranslator::InputFormats(int32 *out_count) const 196 { 197 if (out_count) { 198 *out_count = fInputCount; 199 return fInputFormats; 200 } else 201 return NULL; 202 } 203 204 205 // --------------------------------------------------------------- 206 // OutputFormats 207 // 208 // Returns a list of output formats supported by this translator. 209 // 210 // Preconditions: 211 // 212 // Parameters: out_count, The number of output formats 213 // support is returned here. 214 // 215 // Postconditions: 216 // 217 // Returns: the array of output formats and the number of output 218 // formats through the out_count parameter 219 // --------------------------------------------------------------- 220 const translation_format * 221 BaseTranslator::OutputFormats(int32 *out_count) const 222 { 223 if (out_count) { 224 *out_count = fOutputCount; 225 return fOutputFormats; 226 } else 227 return NULL; 228 } 229 230 231 // --------------------------------------------------------------- 232 // identify_bits_header 233 // 234 // Determines if the data in inSource is in the 235 // B_TRANSLATOR_BITMAP ('bits') format. If it is, it returns 236 // info about the data in inSource to outInfo and pheader. 237 // 238 // Preconditions: 239 // 240 // Parameters: inSource, The source of the image data 241 // 242 // outInfo, Information about the translator 243 // is copied here 244 // 245 // amtread, Amount of data read from inSource 246 // before this function was called 247 // 248 // read, Pointer to the data that was read 249 // in before this function was called 250 // 251 // pheader, The bits header is copied here after 252 // it is read in from inSource 253 // 254 // Postconditions: 255 // 256 // Returns: B_NO_TRANSLATOR, if the data does not look like 257 // bits format data 258 // 259 // B_ERROR, if the header data could not be converted to host 260 // format 261 // 262 // B_OK, if the data looks like bits data and no errors were 263 // encountered 264 // --------------------------------------------------------------- 265 status_t 266 BaseTranslator::identify_bits_header(BPositionIO *inSource, 267 translator_info *outInfo, TranslatorBitmap *pheader) 268 { 269 TranslatorBitmap header; 270 271 // read in the header 272 ssize_t size = sizeof(TranslatorBitmap); 273 if (inSource->Read( 274 (reinterpret_cast<uint8 *> (&header)), size) != size) 275 return B_NO_TRANSLATOR; 276 277 // convert to host byte order 278 if (swap_data(B_UINT32_TYPE, &header, sizeof(TranslatorBitmap), 279 B_SWAP_BENDIAN_TO_HOST) != B_OK) 280 return B_ERROR; 281 282 // check if header values are reasonable 283 if (header.colors != B_RGB32 && 284 header.colors != B_RGB32_BIG && 285 header.colors != B_RGBA32 && 286 header.colors != B_RGBA32_BIG && 287 header.colors != B_RGB24 && 288 header.colors != B_RGB24_BIG && 289 header.colors != B_RGB16 && 290 header.colors != B_RGB16_BIG && 291 header.colors != B_RGB15 && 292 header.colors != B_RGB15_BIG && 293 header.colors != B_RGBA15 && 294 header.colors != B_RGBA15_BIG && 295 header.colors != B_CMAP8 && 296 header.colors != B_GRAY8 && 297 header.colors != B_GRAY1 && 298 header.colors != B_CMYK32 && 299 header.colors != B_CMY32 && 300 header.colors != B_CMYA32 && 301 header.colors != B_CMY24) 302 return B_NO_TRANSLATOR; 303 if (header.rowBytes * (header.bounds.Height() + 1) != header.dataSize) 304 return B_NO_TRANSLATOR; 305 306 if (outInfo) { 307 outInfo->type = B_TRANSLATOR_BITMAP; 308 outInfo->group = B_TRANSLATOR_BITMAP; 309 outInfo->quality = 0.2; 310 outInfo->capability = 0.2; 311 strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format"), 312 sizeof(outInfo->name)); 313 strcpy(outInfo->MIME, "image/x-be-bitmap"); 314 315 // Look for quality / capability info in fInputFormats 316 for (int32 i = 0; i < fInputCount; i++) { 317 if (fInputFormats[i].type == B_TRANSLATOR_BITMAP && 318 fInputFormats[i].group == B_TRANSLATOR_BITMAP) { 319 outInfo->quality = fInputFormats[i].quality; 320 outInfo->capability = fInputFormats[i].capability; 321 strcpy(outInfo->name, fInputFormats[i].name); 322 break; 323 } 324 } 325 } 326 327 if (pheader) { 328 pheader->magic = header.magic; 329 pheader->bounds = header.bounds; 330 pheader->rowBytes = header.rowBytes; 331 pheader->colors = header.colors; 332 pheader->dataSize = header.dataSize; 333 } 334 335 return B_OK; 336 } 337 338 339 // --------------------------------------------------------------- 340 // BitsCheck 341 // 342 // Examines the input stream for B_TRANSLATOR_BITMAP format 343 // information and determines if BaseTranslator can handle 344 // the translation entirely, if it must pass the task of 345 // translation to the derived translator or if the stream cannot 346 // be decoded by the BaseTranslator or the derived translator. 347 // 348 // Preconditions: 349 // 350 // Parameters: inSource, where the data to examine is 351 // 352 // ioExtension, configuration settings for the 353 // translator 354 // 355 // outType, The format that the user wants 356 // the data in inSource to be 357 // converted to. NOTE: This is passed by 358 // reference so that it can modify the 359 // outType that is seen by the 360 // BaseTranslator and the derived 361 // translator 362 // 363 // Postconditions: 364 // 365 // Returns: B_NO_TRANSLATOR, if this translator can't handle 366 // the data in inSource 367 // 368 // B_ERROR, if there was an error converting the data to the host 369 // format 370 // 371 // B_BAD_VALUE, if the settings in ioExtension are bad 372 // 373 // B_OK, if this translator understand the data and there were 374 // no errors found 375 // --------------------------------------------------------------- 376 status_t 377 BaseTranslator::BitsCheck(BPositionIO *inSource, BMessage *ioExtension, 378 uint32 &outType) 379 { 380 if (!outType) 381 outType = B_TRANSLATOR_BITMAP; 382 if (outType != B_TRANSLATOR_BITMAP && outType != fTranType) 383 return B_NO_TRANSLATOR; 384 385 // Convert the magic numbers to the various byte orders so that 386 // I won't have to convert the data read in to see whether or not 387 // it is a supported type 388 const uint32 kBitsMagic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 389 390 // Read in the magic number and determine if it 391 // is a supported type 392 uint8 ch[4]; 393 if (inSource->Read(ch, 4) != 4) 394 return B_NO_TRANSLATOR; 395 inSource->Seek(-4, SEEK_CUR); 396 // seek backward becuase functions used after this one 397 // expect the stream to be at the beginning 398 399 // Read settings from ioExtension 400 if (ioExtension && fSettings->LoadSettings(ioExtension) < B_OK) 401 return B_BAD_VALUE; 402 403 uint32 sourceMagic; 404 memcpy(&sourceMagic, ch, sizeof(uint32)); 405 if (sourceMagic == kBitsMagic) 406 return B_OK; 407 return B_OK + 1; 408 } 409 410 411 status_t 412 BaseTranslator::BitsIdentify(BPositionIO *inSource, 413 const translation_format *inFormat, BMessage *ioExtension, 414 translator_info *outInfo, uint32 outType) 415 { 416 status_t result = BitsCheck(inSource, ioExtension, outType); 417 if (result == B_OK) { 418 TranslatorBitmap bitmap; 419 result = identify_bits_header(inSource, outInfo, &bitmap); 420 if (result == B_OK) 421 result = DerivedCanHandleImageSize(bitmap.bounds.Width() + 1.0, 422 bitmap.bounds.Height() + 1.0); 423 } else if (result >= B_OK) { 424 // if NOT B_TRANSLATOR_BITMAP, it could be an image in the 425 // derived format 426 result = DerivedIdentify(inSource, inFormat, ioExtension, 427 outInfo, outType); 428 } 429 return result; 430 } 431 432 433 // --------------------------------------------------------------- 434 // Identify 435 // 436 // Examines the data from inSource and determines if it is in a 437 // format that this translator knows how to work with. 438 // 439 // Preconditions: 440 // 441 // Parameters: inSource, where the data to examine is 442 // 443 // inFormat, a hint about the data in inSource, 444 // it is ignored since it is only a hint 445 // 446 // ioExtension, configuration settings for the 447 // translator 448 // 449 // outInfo, information about what data is in 450 // inSource and how well this translator 451 // can handle that data is stored here 452 // 453 // outType, The format that the user wants 454 // the data in inSource to be 455 // converted to 456 // 457 // Postconditions: 458 // 459 // Returns: B_NO_TRANSLATOR, if this translator can't handle 460 // the data in inSource 461 // 462 // B_ERROR, if there was an error converting the data to the host 463 // format 464 // 465 // B_BAD_VALUE, if the settings in ioExtension are bad 466 // 467 // B_OK, if this translator understand the data and there were 468 // no errors found 469 // --------------------------------------------------------------- 470 status_t 471 BaseTranslator::Identify(BPositionIO *inSource, 472 const translation_format *inFormat, BMessage *ioExtension, 473 translator_info *outInfo, uint32 outType) 474 { 475 switch (fTranGroup) { 476 case B_TRANSLATOR_BITMAP: 477 return BitsIdentify(inSource, inFormat, ioExtension, 478 outInfo, outType); 479 480 default: 481 return DerivedIdentify(inSource, inFormat, ioExtension, 482 outInfo, outType); 483 } 484 } 485 486 487 // --------------------------------------------------------------- 488 // translate_from_bits_to_bits 489 // 490 // Convert the data in inSource from the Be Bitmap format ('bits') 491 // to the format specified in outType (either bits or Base). 492 // 493 // Preconditions: 494 // 495 // Parameters: inSource, the bits data to translate 496 // 497 // amtread, the amount of data already read from 498 // inSource 499 // 500 // read, pointer to the data already read from 501 // inSource 502 // 503 // outType, the type of data to convert to 504 // 505 // outDestination, where the output is written to 506 // 507 // Postconditions: 508 // 509 // Returns: B_NO_TRANSLATOR, if the data is not in a supported 510 // format 511 // 512 // B_ERROR, if there was an error allocating memory or some other 513 // error 514 // 515 // B_OK, if successfully translated the data from the bits format 516 // --------------------------------------------------------------- 517 status_t 518 BaseTranslator::translate_from_bits_to_bits(BPositionIO *inSource, 519 uint32 outType, BPositionIO *outDestination) 520 { 521 TranslatorBitmap bitsHeader; 522 bool bheaderonly = false, bdataonly = false; 523 524 status_t result; 525 result = identify_bits_header(inSource, NULL, &bitsHeader); 526 if (result != B_OK) 527 return result; 528 529 // Translate B_TRANSLATOR_BITMAP to B_TRANSLATOR_BITMAP, easy enough :) 530 if (outType == B_TRANSLATOR_BITMAP) { 531 // write out bitsHeader (only if configured to) 532 if (bheaderonly || (!bheaderonly && !bdataonly)) { 533 if (swap_data(B_UINT32_TYPE, &bitsHeader, 534 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) 535 return B_ERROR; 536 if (outDestination->Write(&bitsHeader, 537 sizeof(TranslatorBitmap)) != sizeof(TranslatorBitmap)) 538 return B_ERROR; 539 } 540 541 // write out the data (only if configured to) 542 if (bdataonly || (!bheaderonly && !bdataonly)) { 543 uint8 buf[1024]; 544 uint32 remaining = B_BENDIAN_TO_HOST_INT32(bitsHeader.dataSize); 545 ssize_t rd, writ; 546 rd = inSource->Read(buf, 1024); 547 while (rd > 0) { 548 writ = outDestination->Write(buf, rd); 549 if (writ < 0) 550 break; 551 remaining -= static_cast<uint32>(writ); 552 rd = inSource->Read(buf, std::min((uint32)1024, 553 remaining)); 554 } 555 556 if (remaining > 0) 557 return B_ERROR; 558 else 559 return B_OK; 560 } else 561 return B_OK; 562 563 } else 564 return B_NO_TRANSLATOR; 565 } 566 567 568 status_t 569 BaseTranslator::BitsTranslate(BPositionIO *inSource, 570 const translator_info *inInfo, BMessage *ioExtension, uint32 outType, 571 BPositionIO *outDestination) 572 { 573 status_t result = BitsCheck(inSource, ioExtension, outType); 574 if (result == B_OK && outType == B_TRANSLATOR_BITMAP) { 575 result = translate_from_bits_to_bits(inSource, outType, 576 outDestination); 577 } else if (result >= B_OK) { 578 // If NOT B_TRANSLATOR_BITMAP type it could be the derived format 579 result = DerivedTranslate(inSource, inInfo, ioExtension, outType, 580 outDestination, (result == B_OK)); 581 } 582 return result; 583 } 584 585 586 // --------------------------------------------------------------- 587 // Translate 588 // 589 // Translates the data in inSource to the type outType and stores 590 // the translated data in outDestination. 591 // 592 // Preconditions: 593 // 594 // Parameters: inSource, the data to be translated 595 // 596 // inInfo, hint about the data in inSource (not used) 597 // 598 // ioExtension, configuration options for the 599 // translator 600 // 601 // outType, the type to convert inSource to 602 // 603 // outDestination, where the translated data is 604 // put 605 // 606 // Postconditions: 607 // 608 // Returns: B_BAD_VALUE, if the options in ioExtension are bad 609 // 610 // B_NO_TRANSLATOR, if this translator doesn't understand the data 611 // 612 // B_ERROR, if there was an error allocating memory or converting 613 // data 614 // 615 // B_OK, if all went well 616 // --------------------------------------------------------------- 617 status_t 618 BaseTranslator::Translate(BPositionIO *inSource, 619 const translator_info *inInfo, BMessage *ioExtension, uint32 outType, 620 BPositionIO *outDestination) 621 { 622 switch (fTranGroup) { 623 case B_TRANSLATOR_BITMAP: 624 return BitsTranslate(inSource, inInfo, ioExtension, outType, 625 outDestination); 626 627 default: 628 return DerivedTranslate(inSource, inInfo, ioExtension, outType, 629 outDestination, -1); 630 } 631 } 632 633 634 // returns the current translator settings into ioExtension 635 status_t 636 BaseTranslator::GetConfigurationMessage(BMessage *ioExtension) 637 { 638 return fSettings->GetConfigurationMessage(ioExtension); 639 } 640 641 642 // --------------------------------------------------------------- 643 // MakeConfigurationView 644 // 645 // Makes a BView object for configuring / displaying info about 646 // this translator. 647 // 648 // Preconditions: 649 // 650 // Parameters: ioExtension, configuration options for the 651 // translator 652 // 653 // outView, the view to configure the 654 // translator is stored here 655 // 656 // outExtent, the bounds of the view are 657 // stored here 658 // 659 // Postconditions: 660 // 661 // Returns: 662 // --------------------------------------------------------------- 663 status_t 664 BaseTranslator::MakeConfigurationView(BMessage *ioExtension, BView **outView, 665 BRect *outExtent) 666 { 667 if (!outView || !outExtent) 668 return B_BAD_VALUE; 669 if (ioExtension && fSettings->LoadSettings(ioExtension) != B_OK) 670 return B_BAD_VALUE; 671 672 BView *view = NewConfigView(AcquireSettings()); 673 // implemented in derived class 674 675 if (view) { 676 *outView = view; 677 if ((view->Flags() & B_SUPPORTS_LAYOUT) != 0) 678 view->ResizeTo(view->ExplicitPreferredSize()); 679 680 *outExtent = view->Bounds(); 681 682 return B_OK; 683 } else 684 return BTranslator::MakeConfigurationView(ioExtension, outView, 685 outExtent); 686 } 687 688 689 TranslatorSettings * 690 BaseTranslator::AcquireSettings() 691 { 692 return fSettings->Acquire(); 693 } 694 695 696 /////////////////////////////////////////////////////////// 697 // Functions to be implemented by derived classes 698 699 status_t 700 BaseTranslator::DerivedIdentify(BPositionIO *inSource, 701 const translation_format *inFormat, BMessage *ioExtension, 702 translator_info *outInfo, uint32 outType) 703 { 704 return B_NO_TRANSLATOR; 705 } 706 707 708 status_t 709 BaseTranslator::DerivedTranslate(BPositionIO *inSource, 710 const translator_info *inInfo, BMessage *ioExtension, uint32 outType, 711 BPositionIO *outDestination, int32 baseType) 712 { 713 return B_NO_TRANSLATOR; 714 } 715 716 717 status_t 718 BaseTranslator::DerivedCanHandleImageSize(float width, float height) const 719 { 720 return B_OK; 721 } 722 723 724 BView * 725 BaseTranslator::NewConfigView(TranslatorSettings *settings) 726 { 727 return NULL; 728 } 729 730 731 void 732 translate_direct_copy(BPositionIO *inSource, BPositionIO *outDestination) 733 { 734 const size_t kbufsize = 2048; 735 uint8 buffer[kbufsize]; 736 ssize_t ret = inSource->Read(buffer, kbufsize); 737 while (ret > 0) { 738 outDestination->Write(buffer, ret); 739 ret = inSource->Read(buffer, kbufsize); 740 } 741 } 742