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 #include "STXTTranslator.h" 12 #include "STXTView.h" 13 14 #include <Catalog.h> 15 #include <CharacterSet.h> 16 #include <CharacterSetRoster.h> 17 #include <MimeType.h> 18 #include <String.h> 19 #include <TextEncoding.h> 20 #include <UTF8.h> 21 22 #include <algorithm> 23 #include <new> 24 #include <string.h> 25 #include <stdio.h> 26 #include <stdint.h> 27 28 29 using namespace BPrivate; 30 using namespace std; 31 32 #undef B_TRANSLATION_CONTEXT 33 #define B_TRANSLATION_CONTEXT "STXTTranslator" 34 35 #define READ_BUFFER_SIZE 32768 36 #define DATA_BUFFER_SIZE 2048 37 38 // The input formats that this translator supports. 39 static const translation_format sInputFormats[] = { 40 { 41 B_TRANSLATOR_TEXT, 42 B_TRANSLATOR_TEXT, 43 TEXT_IN_QUALITY, 44 TEXT_IN_CAPABILITY, 45 "text/plain", 46 "Plain text file" 47 }, 48 { 49 B_STYLED_TEXT_FORMAT, 50 B_TRANSLATOR_TEXT, 51 STXT_IN_QUALITY, 52 STXT_IN_CAPABILITY, 53 "text/x-vnd.Be-stxt", 54 "Be styled text file" 55 } 56 }; 57 58 // The output formats that this translator supports. 59 static const translation_format sOutputFormats[] = { 60 { 61 B_TRANSLATOR_TEXT, 62 B_TRANSLATOR_TEXT, 63 TEXT_OUT_QUALITY, 64 TEXT_OUT_CAPABILITY, 65 "text/plain", 66 "Plain text file" 67 }, 68 { 69 B_STYLED_TEXT_FORMAT, 70 B_TRANSLATOR_TEXT, 71 STXT_OUT_QUALITY, 72 STXT_OUT_CAPABILITY, 73 "text/x-vnd.Be-stxt", 74 "Be styled text file" 75 } 76 }; 77 78 // Default settings for the Translator 79 static const TranSetting sDefaultSettings[] = { 80 {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, 81 {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false} 82 }; 83 84 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 85 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 86 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 87 88 // --------------------------------------------------------------- 89 // make_nth_translator 90 // 91 // Creates a STXTTranslator object to be used by BTranslatorRoster 92 // 93 // Preconditions: 94 // 95 // Parameters: n, The translator to return. Since 96 // STXTTranslator only publishes one 97 // translator, it only returns a 98 // STXTTranslator if n == 0 99 // 100 // you, The image_id of the add-on that 101 // contains code (not used). 102 // 103 // flags, Has no meaning yet, should be 0. 104 // 105 // Postconditions: 106 // 107 // Returns: NULL if n is not zero, 108 // a new STXTTranslator if n is zero 109 // --------------------------------------------------------------- 110 BTranslator * 111 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 112 { 113 if (!n) 114 return new (std::nothrow) STXTTranslator(); 115 116 return NULL; 117 } 118 119 120 // #pragma mark - 121 122 123 /*! 124 Determines if the data in inSource is of the STXT format. 125 126 \param header the STXT stream header read in by Identify() or Translate() 127 \param inSource the stream with the STXT data 128 \param outInfo information about the type of data from inSource is stored here 129 \param outType the desired output type for the data in inSource 130 \param ptxtheader if this is not NULL, the TEXT header from 131 inSource is copied to it 132 */ 133 status_t 134 identify_stxt_header(const TranslatorStyledTextStreamHeader &header, 135 BPositionIO *inSource, translator_info *outInfo, uint32 outType, 136 TranslatorStyledTextTextHeader *ptxtheader = NULL) 137 { 138 const ssize_t ktxtsize = sizeof(TranslatorStyledTextTextHeader); 139 const ssize_t kstylsize = sizeof(TranslatorStyledTextStyleHeader); 140 141 uint8 buffer[max(ktxtsize, kstylsize)]; 142 143 // Check the TEXT header 144 TranslatorStyledTextTextHeader txtheader; 145 if (inSource->Read(buffer, ktxtsize) != ktxtsize) 146 return B_NO_TRANSLATOR; 147 148 memcpy(&txtheader, buffer, ktxtsize); 149 if (swap_data(B_UINT32_TYPE, &txtheader, ktxtsize, 150 B_SWAP_BENDIAN_TO_HOST) != B_OK) 151 return B_ERROR; 152 153 if (txtheader.header.magic != 'TEXT' 154 || txtheader.header.header_size != sizeof(TranslatorStyledTextTextHeader) 155 || txtheader.charset != B_UNICODE_UTF8) 156 return B_NO_TRANSLATOR; 157 158 // skip the text data 159 off_t seekresult, pos; 160 pos = header.header.header_size + txtheader.header.header_size 161 + txtheader.header.data_size; 162 seekresult = inSource->Seek(txtheader.header.data_size, 163 SEEK_CUR); 164 if (seekresult < pos) 165 return B_NO_TRANSLATOR; 166 if (seekresult > pos) 167 return B_ERROR; 168 169 // check the STYL header (not all STXT files have this) 170 ssize_t read = 0; 171 TranslatorStyledTextStyleHeader stylheader; 172 read = inSource->Read(buffer, kstylsize); 173 if (read < 0) 174 return read; 175 if (read != kstylsize && read != 0) 176 return B_NO_TRANSLATOR; 177 178 // If there is a STYL header 179 if (read == kstylsize) { 180 memcpy(&stylheader, buffer, kstylsize); 181 if (swap_data(B_UINT32_TYPE, &stylheader, kstylsize, 182 B_SWAP_BENDIAN_TO_HOST) != B_OK) 183 return B_ERROR; 184 185 if (stylheader.header.magic != 'STYL' 186 || stylheader.header.header_size != 187 sizeof(TranslatorStyledTextStyleHeader)) 188 return B_NO_TRANSLATOR; 189 } 190 191 // if output TEXT header is supplied, fill it with data 192 if (ptxtheader) { 193 ptxtheader->header.magic = txtheader.header.magic; 194 ptxtheader->header.header_size = txtheader.header.header_size; 195 ptxtheader->header.data_size = txtheader.header.data_size; 196 ptxtheader->charset = txtheader.charset; 197 } 198 199 // return information about the data in the stream 200 outInfo->type = B_STYLED_TEXT_FORMAT; 201 outInfo->group = B_TRANSLATOR_TEXT; 202 outInfo->quality = STXT_IN_QUALITY; 203 outInfo->capability = STXT_IN_CAPABILITY; 204 strlcpy(outInfo->name, B_TRANSLATE("Be styled text file"), 205 sizeof(outInfo->name)); 206 strcpy(outInfo->MIME, "text/x-vnd.Be-stxt"); 207 208 return B_OK; 209 } 210 211 212 /*! 213 Determines if the data in \a inSource is of the UTF8 plain 214 215 \param data buffer containing data already read (must be at 216 least DATA_BUFFER_SIZE bytes large) 217 \param nread number of bytes that have already been read from the stream 218 \param header the STXT stream header read in by Identify() or Translate() 219 \param inSource the stream with the STXT data 220 \param outInfo information about the type of data from inSource is stored here 221 \param outType the desired output type for the data in inSource 222 */ 223 status_t 224 identify_text(uint8* data, int32 bytesRead, BPositionIO* source, 225 translator_info* outInfo, uint32 outType, const char*& encoding) 226 { 227 ssize_t readLater = source->Read(data + bytesRead, DATA_BUFFER_SIZE - bytesRead); 228 if (readLater < B_OK) 229 return B_NO_TRANSLATOR; 230 231 bytesRead += readLater; 232 233 BPrivate::BTextEncoding textEncoding((char*)data, (size_t)bytesRead); 234 encoding = textEncoding.GetName(); 235 if (strlen(encoding) == 0) { 236 /* No valid character encoding found! */ 237 return B_NO_TRANSLATOR; 238 } 239 240 float capability = TEXT_IN_CAPABILITY; 241 if (bytesRead < 20) 242 capability = .1f; 243 244 // return information about the data in the stream 245 outInfo->type = B_TRANSLATOR_TEXT; 246 outInfo->group = B_TRANSLATOR_TEXT; 247 outInfo->quality = TEXT_IN_QUALITY; 248 outInfo->capability = capability; 249 250 strlcpy(outInfo->name, B_TRANSLATE("Plain text file"), 251 sizeof(outInfo->name)); 252 253 //strlcpy(outInfo->MIME, type.Type(), sizeof(outInfo->MIME)); 254 strcpy(outInfo->MIME, "text/plain"); 255 return B_OK; 256 } 257 258 259 // --------------------------------------------------------------- 260 // translate_from_stxt 261 // 262 // Translates the data in inSource to the type outType and stores 263 // the translated data in outDestination. 264 // 265 // Preconditions: 266 // 267 // Parameters: inSource, the data to be translated 268 // 269 // outDestination, where the translated data is 270 // put 271 // 272 // outType, the type to convert inSource to 273 // 274 // txtheader, the TEXT header from inSource 275 // 276 // 277 // Postconditions: 278 // 279 // Returns: B_BAD_VALUE, if outType is invalid 280 // 281 // B_NO_TRANSLATOR, if this translator doesn't understand the data 282 // 283 // B_ERROR, if there was an error allocating memory or converting 284 // data 285 // 286 // B_OK, if all went well 287 // --------------------------------------------------------------- 288 status_t 289 translate_from_stxt(BPositionIO *inSource, BPositionIO *outDestination, 290 uint32 outType, const TranslatorStyledTextTextHeader &txtheader) 291 { 292 if (inSource->Seek(0, SEEK_SET) != 0) 293 return B_ERROR; 294 295 const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader); 296 const ssize_t ktxtsize = sizeof(TranslatorStyledTextTextHeader); 297 298 bool btoplain; 299 if (outType == B_TRANSLATOR_TEXT) 300 btoplain = true; 301 else if (outType == B_STYLED_TEXT_FORMAT) 302 btoplain = false; 303 else 304 return B_BAD_VALUE; 305 306 uint8 buffer[READ_BUFFER_SIZE]; 307 ssize_t nread = 0, nwritten = 0, nreed = 0, ntotalread = 0; 308 309 // skip to the actual text data when outputting a 310 // plain text file 311 if (btoplain) { 312 if (inSource->Seek(kstxtsize + ktxtsize, SEEK_CUR) != 313 kstxtsize + ktxtsize) 314 return B_ERROR; 315 } 316 317 // Read data from inSource 318 // When outputing B_TRANSLATOR_TEXT, the loop stops when all of 319 // the text data has been read and written. 320 // When outputting B_STYLED_TEXT_FORMAT, the loop stops when all 321 // of the data from inSource has been read and written. 322 if (btoplain) 323 nreed = min((size_t)READ_BUFFER_SIZE, 324 (size_t)txtheader.header.data_size - ntotalread); 325 else 326 nreed = READ_BUFFER_SIZE; 327 nread = inSource->Read(buffer, nreed); 328 while (nread > 0) { 329 nwritten = outDestination->Write(buffer, nread); 330 if (nwritten != nread) 331 return B_ERROR; 332 333 if (btoplain) { 334 ntotalread += nread; 335 nreed = min((size_t)READ_BUFFER_SIZE, 336 (size_t)txtheader.header.data_size - ntotalread); 337 } else 338 nreed = READ_BUFFER_SIZE; 339 nread = inSource->Read(buffer, nreed); 340 } 341 342 if (btoplain && static_cast<ssize_t>(txtheader.header.data_size) != 343 ntotalread) 344 // If not all of the text data was able to be read... 345 return B_NO_TRANSLATOR; 346 else 347 return B_OK; 348 } 349 350 // --------------------------------------------------------------- 351 // output_headers 352 // 353 // Outputs the Stream and Text headers from the B_STYLED_TEXT_FORMAT 354 // to outDestination, setting the data_size member of the text header 355 // to text_data_size 356 // 357 // Preconditions: 358 // 359 // Parameters: outDestination, where the translated data is 360 // put 361 // 362 // text_data_size, number of bytes in data section 363 // of the TEXT header 364 // 365 // 366 // Postconditions: 367 // 368 // Returns: 369 // 370 // B_ERROR, if there was an error writing to outDestination or 371 // an error with converting the byte order 372 // 373 // B_OK, if all went well 374 // --------------------------------------------------------------- 375 status_t 376 output_headers(BPositionIO *outDestination, uint32 text_data_size) 377 { 378 const int32 kHeadersSize = sizeof(TranslatorStyledTextStreamHeader) + 379 sizeof(TranslatorStyledTextTextHeader); 380 status_t result; 381 TranslatorStyledTextStreamHeader stxtheader; 382 TranslatorStyledTextTextHeader txtheader; 383 384 uint8 buffer[kHeadersSize]; 385 386 stxtheader.header.magic = 'STXT'; 387 stxtheader.header.header_size = sizeof(TranslatorStyledTextStreamHeader); 388 stxtheader.header.data_size = 0; 389 stxtheader.version = 100; 390 memcpy(buffer, &stxtheader, stxtheader.header.header_size); 391 392 txtheader.header.magic = 'TEXT'; 393 txtheader.header.header_size = sizeof(TranslatorStyledTextTextHeader); 394 txtheader.header.data_size = text_data_size; 395 txtheader.charset = B_UNICODE_UTF8; 396 memcpy(buffer + stxtheader.header.header_size, &txtheader, 397 txtheader.header.header_size); 398 399 // write out headers in Big Endian byte order 400 result = swap_data(B_UINT32_TYPE, buffer, kHeadersSize, 401 B_SWAP_HOST_TO_BENDIAN); 402 if (result == B_OK) { 403 ssize_t nwritten = 0; 404 nwritten = outDestination->Write(buffer, kHeadersSize); 405 if (nwritten != kHeadersSize) 406 return B_ERROR; 407 else 408 return B_OK; 409 } 410 411 return result; 412 } 413 414 // --------------------------------------------------------------- 415 // output_styles 416 // 417 // Writes out the actual style information into outDestination 418 // using the data from pflatRunArray 419 // 420 // Preconditions: 421 // 422 // Parameters: outDestination, where the translated data is 423 // put 424 // 425 // text_size, size in bytes of the text in 426 // outDestination 427 // 428 // data_size, size of pflatRunArray 429 // 430 // Postconditions: 431 // 432 // Returns: 433 // 434 // B_ERROR, if there was an error writing to outDestination or 435 // an error with converting the byte order 436 // 437 // B_OK, if all went well 438 // --------------------------------------------------------------- 439 status_t 440 output_styles(BPositionIO *outDestination, uint32 text_size, 441 uint8 *pflatRunArray, ssize_t data_size) 442 { 443 const ssize_t kstylsize = sizeof(TranslatorStyledTextStyleHeader); 444 445 uint8 buffer[kstylsize]; 446 447 // output STYL header 448 TranslatorStyledTextStyleHeader stylheader; 449 stylheader.header.magic = 'STYL'; 450 stylheader.header.header_size = 451 sizeof(TranslatorStyledTextStyleHeader); 452 stylheader.header.data_size = data_size; 453 stylheader.apply_offset = 0; 454 stylheader.apply_length = text_size; 455 456 memcpy(buffer, &stylheader, kstylsize); 457 if (swap_data(B_UINT32_TYPE, buffer, kstylsize, 458 B_SWAP_HOST_TO_BENDIAN) != B_OK) 459 return B_ERROR; 460 if (outDestination->Write(buffer, kstylsize) != kstylsize) 461 return B_ERROR; 462 463 // output actual style information 464 if (outDestination->Write(pflatRunArray, 465 data_size) != data_size) 466 return B_ERROR; 467 468 return B_OK; 469 } 470 471 472 /*! 473 Convert the plain text (UTF8) from inSource to plain or 474 styled text in outDestination 475 */ 476 status_t 477 translate_from_text(BPositionIO* source, const char* outEncoding, bool forceEncoding, 478 BPositionIO* destination, uint32 outType) 479 { 480 if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT) 481 return B_BAD_VALUE; 482 483 // find the length of the text 484 off_t size = source->Seek(0, SEEK_END); 485 if (size < 0) 486 return (status_t)size; 487 if (size > UINT32_MAX && outType == B_STYLED_TEXT_FORMAT) 488 return B_NOT_SUPPORTED; 489 490 status_t status = source->Seek(0, SEEK_SET); 491 if (status < B_OK) 492 return status; 493 494 if (outType == B_STYLED_TEXT_FORMAT) { 495 // output styled text headers 496 status = output_headers(destination, (uint32)size); 497 if (status != B_OK) 498 return status; 499 } 500 501 class MallocBuffer { 502 public: 503 MallocBuffer() : fBuffer(NULL), fSize(0) {} 504 ~MallocBuffer() { free(fBuffer); } 505 506 void* Buffer() { return fBuffer; } 507 size_t Size() const { return fSize; } 508 509 status_t 510 Allocate(size_t size) 511 { 512 fBuffer = malloc(size); 513 if (fBuffer != NULL) { 514 fSize = size; 515 return B_OK; 516 } 517 return B_NO_MEMORY; 518 } 519 520 private: 521 void* fBuffer; 522 size_t fSize; 523 } encodingBuffer; 524 525 BNode* node = dynamic_cast<BNode*>(source); 526 BString encoding(outEncoding); 527 if (node != NULL) { 528 // determine encoding, if available 529 bool hasAttribute = false; 530 if (encoding.String() && !forceEncoding) { 531 attr_info info; 532 node->GetAttrInfo("be:encoding", &info); 533 534 if ((info.type == B_STRING_TYPE) && (node->ReadAttrString( 535 "be:encoding", &encoding) == B_OK)) { 536 hasAttribute = true; 537 } else if (info.type == B_INT32_TYPE) { 538 // Try the BeOS version of the atribute, which used an int32 539 // and a well-known list of encodings. 540 int32 value; 541 ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0, 542 &value, sizeof(value)); 543 if (bytesRead == (ssize_t)sizeof(value)) { 544 if (value != 65535) { 545 const BCharacterSet* characterSet 546 = BCharacterSetRoster::GetCharacterSetByConversionID(value); 547 if (characterSet != NULL) 548 encoding = characterSet->GetName(); 549 } 550 } 551 } 552 } else { 553 hasAttribute = true; 554 // we don't write the encoding in this case 555 } 556 557 if (!encoding.IsEmpty()) 558 encodingBuffer.Allocate(READ_BUFFER_SIZE * 4); 559 560 if (!hasAttribute && !encoding.IsEmpty()) { 561 // add encoding attribute, so that someone opening the file can 562 // retrieve it for persistance 563 node->WriteAttrString("be:encoding", &encoding); 564 } 565 } 566 567 off_t outputSize = 0; 568 ssize_t bytesRead; 569 570 BPrivate::BTextEncoding codec(encoding.String()); 571 572 // output the actual text part of the data 573 do { 574 uint8 buffer[READ_BUFFER_SIZE]; 575 bytesRead = source->Read(buffer, READ_BUFFER_SIZE); 576 if (bytesRead < B_OK) 577 return bytesRead; 578 if (bytesRead == 0) 579 break; 580 581 if (encodingBuffer.Size() == 0) { 582 // default, no encoding 583 ssize_t bytesWritten = destination->Write(buffer, bytesRead); 584 if (bytesWritten != bytesRead) { 585 if (bytesWritten < B_OK) 586 return bytesWritten; 587 588 return B_ERROR; 589 } 590 591 outputSize += bytesRead; 592 } else { 593 // decode text file to UTF-8 594 const char* pos = (char*)buffer; 595 size_t encodingLength; 596 int32 bytesLeft = bytesRead; 597 size_t bytes; 598 do { 599 encodingLength = READ_BUFFER_SIZE * 4; 600 bytes = bytesLeft; 601 602 status = codec.Decode(pos, bytes, 603 (char*)encodingBuffer.Buffer(), encodingLength); 604 if (status < B_OK) { 605 return status; 606 } 607 608 ssize_t bytesWritten = destination->Write(encodingBuffer.Buffer(), 609 encodingLength); 610 if (bytesWritten < (ssize_t)encodingLength) { 611 if (bytesWritten < B_OK) 612 return bytesWritten; 613 614 return B_ERROR; 615 } 616 617 pos += bytes; 618 bytesLeft -= bytes; 619 outputSize += encodingLength; 620 } while (encodingLength > 0 && bytesLeft > 0); 621 } 622 } while (bytesRead > 0); 623 624 if (outType != B_STYLED_TEXT_FORMAT) 625 return B_OK; 626 627 if (encodingBuffer.Size() != 0 && size != outputSize) { 628 if (outputSize > UINT32_MAX) 629 return B_NOT_SUPPORTED; 630 631 // we need to update the header as the decoded text size has changed 632 status = destination->Seek(0, SEEK_SET); 633 if (status == B_OK) 634 status = output_headers(destination, (uint32)outputSize); 635 if (status == B_OK) 636 status = destination->Seek(0, SEEK_END); 637 638 if (status < B_OK) 639 return status; 640 } 641 642 // Read file attributes if outputting styled data 643 // and source is a BNode object 644 645 if (node == NULL) 646 return B_OK; 647 648 // Try to read styles - we only propagate an error if the actual on-disk 649 // data is likely to be okay 650 651 const char *kAttrName = "styles"; 652 attr_info info; 653 if (node->GetAttrInfo(kAttrName, &info) != B_OK) 654 return B_OK; 655 656 if (info.type != B_RAW_TYPE || info.size < 160) { 657 // styles seem to be broken, but since we got the text, 658 // we don't propagate the error 659 return B_OK; 660 } 661 662 uint8* flatRunArray = new (std::nothrow) uint8[info.size]; 663 if (flatRunArray == NULL) 664 return B_NO_MEMORY; 665 666 bytesRead = node->ReadAttr(kAttrName, B_RAW_TYPE, 0, flatRunArray, info.size); 667 if (bytesRead != info.size) 668 return B_OK; 669 670 output_styles(destination, size, flatRunArray, info.size); 671 672 delete[] flatRunArray; 673 return B_OK; 674 } 675 676 677 // #pragma mark - 678 679 680 STXTTranslator::STXTTranslator() 681 : BaseTranslator(B_TRANSLATE("StyledEdit files"), 682 B_TRANSLATE("StyledEdit file translator"), 683 STXT_TRANSLATOR_VERSION, 684 sInputFormats, kNumInputFormats, 685 sOutputFormats, kNumOutputFormats, 686 "STXTTranslator_Settings", 687 sDefaultSettings, kNumDefaultSettings, 688 B_TRANSLATOR_TEXT, B_STYLED_TEXT_FORMAT) 689 { 690 } 691 692 693 STXTTranslator::~STXTTranslator() 694 { 695 } 696 697 698 status_t 699 STXTTranslator::Identify(BPositionIO *inSource, 700 const translation_format *inFormat, BMessage *ioExtension, 701 translator_info *outInfo, uint32 outType) 702 { 703 if (!outType) 704 outType = B_TRANSLATOR_TEXT; 705 if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT) 706 return B_NO_TRANSLATOR; 707 708 const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader); 709 710 uint8 buffer[DATA_BUFFER_SIZE]; 711 status_t nread = 0; 712 // Read in the header to determine 713 // if the data is supported 714 nread = inSource->Read(buffer, kstxtsize); 715 if (nread < 0) 716 return nread; 717 718 // read in enough data to fill the stream header 719 if (nread == kstxtsize) { 720 TranslatorStyledTextStreamHeader header; 721 memcpy(&header, buffer, kstxtsize); 722 if (swap_data(B_UINT32_TYPE, &header, kstxtsize, 723 B_SWAP_BENDIAN_TO_HOST) != B_OK) 724 return B_ERROR; 725 726 if (header.header.magic == B_STYLED_TEXT_FORMAT 727 && header.header.header_size == (int32)kstxtsize 728 && header.header.data_size == 0 729 && header.version == 100) 730 return identify_stxt_header(header, inSource, outInfo, outType); 731 } 732 733 // if the data is not styled text, check if it is plain text 734 const char* encoding; 735 return identify_text(buffer, nread, inSource, outInfo, outType, encoding); 736 } 737 738 739 status_t 740 STXTTranslator::Translate(BPositionIO* source, const translator_info* info, 741 BMessage* ioExtension, uint32 outType, BPositionIO* outDestination) 742 { 743 if (!outType) 744 outType = B_TRANSLATOR_TEXT; 745 if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT) 746 return B_NO_TRANSLATOR; 747 748 const ssize_t headerSize = sizeof(TranslatorStyledTextStreamHeader); 749 uint8 buffer[DATA_BUFFER_SIZE]; 750 status_t result; 751 translator_info outInfo; 752 // Read in the header to determine 753 // if the data is supported 754 ssize_t bytesRead = source->Read(buffer, headerSize); 755 if (bytesRead < 0) 756 return bytesRead; 757 758 // read in enough data to fill the stream header 759 if (bytesRead == headerSize) { 760 TranslatorStyledTextStreamHeader header; 761 memcpy(&header, buffer, headerSize); 762 if (swap_data(B_UINT32_TYPE, &header, headerSize, 763 B_SWAP_BENDIAN_TO_HOST) != B_OK) 764 return B_ERROR; 765 766 if (header.header.magic == B_STYLED_TEXT_FORMAT 767 && header.header.header_size == sizeof(TranslatorStyledTextStreamHeader) 768 && header.header.data_size == 0 769 && header.version == 100) { 770 TranslatorStyledTextTextHeader textHeader; 771 result = identify_stxt_header(header, source, &outInfo, outType, 772 &textHeader); 773 if (result != B_OK) 774 return result; 775 776 return translate_from_stxt(source, outDestination, outType, textHeader); 777 } 778 } 779 780 // if the data is not styled text, check if it is ASCII text 781 bool forceEncoding = false; 782 const char* encoding = NULL; 783 result = identify_text(buffer, bytesRead, source, &outInfo, outType, encoding); 784 if (result != B_OK) 785 return result; 786 787 if (ioExtension != NULL) { 788 const char* value; 789 if (ioExtension->FindString("be:encoding", &value) == B_OK 790 && value[0]) { 791 // override encoding 792 encoding = value; 793 forceEncoding = true; 794 } 795 } 796 797 return translate_from_text(source, encoding, forceEncoding, outDestination, outType); 798 } 799 800 801 BView * 802 STXTTranslator::NewConfigView(TranslatorSettings *settings) 803 { 804 return new STXTView(BRect(0, 0, 225, 175), 805 B_TRANSLATE("STXTTranslator Settings"), 806 B_FOLLOW_ALL, B_WILL_DRAW, settings); 807 } 808 809