1 /*****************************************************************************/ 2 // File: TranslationUtils.h 3 // Class: BTranslationUtils 4 // Reimplemented by: Michael Wilber, Translation Kit Team 5 // Reimplementation: 2002-04 6 // 7 // Description: Utility functions for the Translation Kit 8 // 9 // 10 // Copyright (c) 2002 OpenBeOS Project 11 // 12 // Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. 13 // Copyright 1995-1997, Jon Watte 14 // 15 // Permission is hereby granted, free of charge, to any person obtaining a 16 // copy of this software and associated documentation files (the "Software"), 17 // to deal in the Software without restriction, including without limitation 18 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 // and/or sell copies of the Software, and to permit persons to whom the 20 // Software is furnished to do so, subject to the following conditions: 21 // 22 // The above copyright notice and this permission notice shall be included 23 // in all copies or substantial portions of the Software. 24 // 25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 // DEALINGS IN THE SOFTWARE. 32 /*****************************************************************************/ 33 #include <Application.h> 34 #include <Roster.h> 35 #include <Bitmap.h> 36 #include <BitmapStream.h> 37 #include <File.h> 38 #include <MenuItem.h> 39 #include <Resources.h> 40 #include <stdlib.h> 41 #include <TextView.h> 42 #include <TranslatorFormats.h> 43 #include <TranslatorRoster.h> 44 #include <TranslationUtils.h> 45 #include <Entry.h> 46 #include <Path.h> 47 48 // --------------------------------------------------------------- 49 // Constructor 50 // 51 // Does nothing! :) This class has no data members. 52 // 53 // Preconditions: 54 // 55 // Parameters: 56 // 57 // Postconditions: 58 // 59 // Returns: 60 // --------------------------------------------------------------- 61 BTranslationUtils::BTranslationUtils() 62 { 63 } 64 65 // --------------------------------------------------------------- 66 // Desstructor 67 // 68 // Does nothing! :) This class has no data members. 69 // 70 // Preconditions: 71 // 72 // Parameters: 73 // 74 // Postconditions: 75 // 76 // Returns: 77 // --------------------------------------------------------------- 78 BTranslationUtils::~BTranslationUtils() 79 { 80 } 81 82 // --------------------------------------------------------------- 83 // Constructor 84 // 85 // Does nothing! :) This class has no data members. 86 // 87 // Preconditions: 88 // 89 // Parameters: kUtils, not used 90 // 91 // Postconditions: 92 // 93 // Returns: 94 // --------------------------------------------------------------- 95 BTranslationUtils::BTranslationUtils(const BTranslationUtils &kUtils) 96 { 97 } 98 99 // --------------------------------------------------------------- 100 // operator= 101 // 102 // Does nothing! :) This class has no data members. 103 // 104 // Preconditions: 105 // 106 // Parameters: kUtils, not used 107 // 108 // Postconditions: 109 // 110 // Returns: reference to the object 111 // --------------------------------------------------------------- 112 BTranslationUtils & 113 BTranslationUtils::operator=(const BTranslationUtils &kUtils) 114 { 115 return *this; 116 } 117 118 // --------------------------------------------------------------- 119 // GetBitmap 120 // 121 // Returns a BBitmap object for the bitmap file or resource 122 // kName. The user has to delete this object. It first tries 123 // to open kName as a file, then as a resource. 124 // 125 // Preconditions: 126 // 127 // Parameters: kName, the name of the bitmap file or resource to 128 // be returned 129 // roster, BTranslatorRoster used to do the translation 130 // 131 // Postconditions: 132 // 133 // Returns: NULL, if the file could not be opened and the 134 // resource couldn't be found or couldn't be 135 // translated to a BBitmap 136 // BBitmap * to the bitmap reference by kName 137 // --------------------------------------------------------------- 138 BBitmap * 139 BTranslationUtils::GetBitmap(const char *kName, BTranslatorRoster *roster) 140 { 141 BBitmap *pBitmap = GetBitmapFile(kName, roster); 142 // Try loading a bitmap from the file named name 143 144 // Try loading the bitmap as an application resource 145 if (pBitmap == NULL) 146 pBitmap = GetBitmap(B_TRANSLATOR_BITMAP, kName, roster); 147 148 return pBitmap; 149 } 150 151 // --------------------------------------------------------------- 152 // GetBitmap 153 // 154 // Returns a BBitmap object for the bitmap resource identified by 155 // the type type with the resource id, id. 156 // The user has to delete this object. 157 // 158 // Preconditions: 159 // 160 // Parameters: type, the type of resource to be loaded 161 // id, the id for the resource to be loaded 162 // roster, BTranslatorRoster used to do the translation 163 // 164 // Postconditions: 165 // 166 // Returns: NULL, if the resource couldn't be loaded or couldn't 167 // be translated to a BBitmap 168 // BBitmap * to the bitmap identified by type and id 169 // --------------------------------------------------------------- 170 BBitmap * 171 BTranslationUtils::GetBitmap(uint32 type, int32 id, BTranslatorRoster *roster) 172 { 173 BResources *pResources = BApplication::AppResources(); 174 // Remember: pResources must not be freed because 175 // it belongs to the application 176 if (pResources == NULL || pResources->HasResource(type, id) == false) 177 return NULL; 178 179 // Load the bitmap resource from the application file 180 // pRawData should be NULL if the resource is an 181 // unknown type or not available 182 size_t bitmapSize = 0; 183 const void *kpRawData = pResources->LoadResource(type, id, &bitmapSize); 184 if (kpRawData == NULL || bitmapSize == 0) 185 return NULL; 186 187 BMemoryIO memio(kpRawData, bitmapSize); 188 // Put the pointer to the raw image data into a BMemoryIO object 189 // so that it can be used with BTranslatorRoster->Translate() in 190 // the GetBitmap(BPositionIO *, BTranslatorRoster *) function 191 192 return GetBitmap(&memio, roster); 193 // Translate the data in memio using the BTranslatorRoster roster 194 } 195 196 // --------------------------------------------------------------- 197 // GetBitmap 198 // 199 // Returns a BBitmap object for the bitmap resource identified by 200 // the type type with the resource name, kName. 201 // The user has to delete this object. Note that a resource type 202 // and name does not uniquely identify a resource in a file. 203 // 204 // Preconditions: 205 // 206 // Parameters: type, the type of resource to be loaded 207 // kName, the name of the resource to be loaded 208 // roster, BTranslatorRoster used to do the translation 209 // 210 // Postconditions: 211 // 212 // Returns: NULL, if the resource couldn't be loaded or couldn't 213 // be translated to a BBitmap 214 // BBitmap * to the bitmap identified by type and kName 215 // --------------------------------------------------------------- 216 BBitmap * 217 BTranslationUtils::GetBitmap(uint32 type, const char *kName, 218 BTranslatorRoster *roster) 219 { 220 BResources *pResources = BApplication::AppResources(); 221 // Remember: pResources must not be freed because 222 // it belongs to the application 223 if (pResources == NULL || pResources->HasResource(type, kName) == false) 224 return NULL; 225 226 // Load the bitmap resource from the application file 227 size_t bitmapSize = 0; 228 const void *kpRawData = pResources->LoadResource(type, kName, &bitmapSize); 229 if (kpRawData == NULL || bitmapSize == 0) 230 return NULL; 231 232 BMemoryIO memio(kpRawData, bitmapSize); 233 // Put the pointer to the raw image data into a BMemoryIO object so 234 // that it can be used with BTranslatorRoster->Translate() 235 236 return GetBitmap(&memio, roster); 237 // Translate the data in memio using the BTranslatorRoster roster 238 } 239 240 // --------------------------------------------------------------- 241 // GetBitmapFile 242 // 243 // Returns a BBitmap object for the bitmap file named kName. 244 // The user has to delete this object. 245 // 246 // Preconditions: 247 // 248 // Parameters: kName, the name of the bitmap file 249 // roster, BTranslatorRoster used to do the translation 250 // 251 // Postconditions: 252 // 253 // Returns: NULL, if the file couldn't be opened or couldn't 254 // be translated to a BBitmap 255 // BBitmap * to the bitmap file named kName 256 // --------------------------------------------------------------- 257 BBitmap * 258 BTranslationUtils::GetBitmapFile(const char *kName, BTranslatorRoster *roster) 259 { 260 if (!be_app || !kName || kName[0] == '\0') 261 return NULL; 262 263 BPath path; 264 if (kName[0] != '/') { 265 // If kName is a relative path, use the path of the application's 266 // executable as the base for the relative path 267 app_info info; 268 if (be_app->GetAppInfo(&info) != B_OK) 269 return NULL; 270 BEntry appRef(&info.ref); 271 if (path.SetTo(&appRef) != B_OK) 272 return NULL; 273 if (path.GetParent(&path) != B_OK) 274 return NULL; 275 if (path.Append(kName) != B_OK) 276 return NULL; 277 278 } else if (path.SetTo(kName) != B_OK) 279 return NULL; 280 281 BFile bitmapFile(path.Path(), B_READ_ONLY); 282 if (bitmapFile.InitCheck() != B_OK) 283 return NULL; 284 285 return GetBitmap(&bitmapFile, roster); 286 // Translate the data in memio using the BTranslatorRoster roster 287 } 288 289 // --------------------------------------------------------------- 290 // GetBitmap 291 // 292 // Returns a BBitmap object for the bitmap file with the entry_ref 293 // kRef. The user has to delete this object. 294 // 295 // Preconditions: 296 // 297 // Parameters: kRef, the entry_ref for the bitmap file 298 // roster, BTranslatorRoster used to do the translation 299 // 300 // Postconditions: 301 // 302 // Returns: NULL, if the file couldn't be opened or couldn't 303 // be translated to a BBitmap 304 // BBitmap * to the bitmap file referenced by kRef 305 // --------------------------------------------------------------- 306 BBitmap * 307 BTranslationUtils::GetBitmap(const entry_ref *kRef, BTranslatorRoster *roster) 308 { 309 BFile bitmapFile(kRef, B_READ_ONLY); 310 if (bitmapFile.InitCheck() != B_OK) 311 return NULL; 312 313 return GetBitmap(&bitmapFile, roster); 314 // Translate the data in bitmapFile using the BTranslatorRoster roster 315 } 316 317 // --------------------------------------------------------------- 318 // GetBitmap 319 // 320 // Returns a BBitmap object from the BPositionIO *stream. The 321 // user must delete the returned object. This GetBitmap function 322 // is used by the other GetBitmap functions to do all of the 323 // "real" work. 324 // 325 // Preconditions: 326 // 327 // Parameters: stream, the stream with bitmap data in it 328 // roster, BTranslatorRoster used to do the translation 329 // 330 // Postconditions: 331 // 332 // Returns: NULL, if the stream couldn't be translated to a BBitmap 333 // BBitmap * for the bitmap data from pio if successful 334 // --------------------------------------------------------------- 335 BBitmap * 336 BTranslationUtils::GetBitmap(BPositionIO *stream, BTranslatorRoster *roster) 337 { 338 if (stream == NULL) 339 return NULL; 340 341 // Use default Translator if none is specified 342 if (roster == NULL) { 343 roster = BTranslatorRoster::Default(); 344 if (roster == NULL) 345 return NULL; 346 } 347 348 // Translate the file from whatever format it is in the file 349 // to the type format so that it can be stored in a BBitmap 350 BBitmapStream bitmapStream; 351 if (roster->Translate(stream, NULL, NULL, &bitmapStream, 352 B_TRANSLATOR_BITMAP) < B_OK) 353 return NULL; 354 355 // Detach the BBitmap from the BBitmapStream so the user 356 // of this function can do what they please with it. 357 BBitmap *pBitmap = NULL; 358 if (bitmapStream.DetachBitmap(&pBitmap) == B_NO_ERROR) 359 return pBitmap; 360 else 361 return NULL; 362 } 363 364 // --------------------------------------------------------------- 365 // GetStyledText 366 // 367 // This function translates the styled text in fromStream and 368 // inserts it at the end of the text in intoView, using the 369 // BTranslatorRoster *roster to do the translation. The structs 370 // that make it possible to work with the translated data are 371 // defined in 372 // /boot/develop/headers/be/translation/TranslatorFormats.h 373 // 374 // Preconditions: 375 // 376 // Parameters: fromStream, the stream with the styled text 377 // intoView, the view where the test will be inserted 378 // roster, BTranslatorRoster used to do the translation 379 // 380 // Postconditions: 381 // 382 // Returns: B_BAD_VALUE, if fromStream or intoView is NULL 383 // B_ERROR, if any other error occurred 384 // B_NO_ERROR, if successful 385 // --------------------------------------------------------------- 386 status_t 387 BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView, 388 BTranslatorRoster *roster) 389 { 390 if (fromStream == NULL || intoView == NULL) 391 return B_BAD_VALUE; 392 393 // Use default Translator if none is specified 394 if (roster == NULL) { 395 roster = BTranslatorRoster::Default(); 396 if (roster == NULL) 397 return B_ERROR; 398 } 399 400 // Translate the file from whatever format it is in the file 401 // to the B_STYLED_TEXT_FORMAT, placing the translated data into mallio 402 BMallocIO mallio; 403 if (roster->Translate(fromStream, NULL, NULL, &mallio, 404 B_STYLED_TEXT_FORMAT) < B_OK) 405 return B_ERROR; 406 407 // make sure there is enough data to fill the stream header 408 const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader); 409 if (mallio.BufferLength() < kStreamHeaderSize) 410 return B_ERROR; 411 412 // copy the stream header from the mallio buffer 413 TranslatorStyledTextStreamHeader stm_header = 414 *(reinterpret_cast<const TranslatorStyledTextStreamHeader *> (mallio.Buffer())); 415 416 // convert the stm_header.header struct to the host format 417 const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader); 418 if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, 419 B_SWAP_BENDIAN_TO_HOST) != B_OK) 420 return B_ERROR; 421 if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), 422 B_SWAP_BENDIAN_TO_HOST) != B_OK) 423 return B_ERROR; 424 if (stm_header.header.magic != 'STXT') 425 return B_ERROR; 426 427 // copy the text header from the mallio buffer 428 uint32 offset = stm_header.header.header_size + 429 stm_header.header.data_size; 430 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); 431 if (mallio.BufferLength() < offset + kTextHeaderSize) 432 return B_ERROR; 433 434 TranslatorStyledTextTextHeader txt_header = 435 *(reinterpret_cast<const TranslatorStyledTextTextHeader *> 436 (reinterpret_cast<const char *> (mallio.Buffer()) + offset)); 437 438 // convert the stm_header.header struct to the host format 439 if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, 440 B_SWAP_BENDIAN_TO_HOST) != B_OK) 441 return B_ERROR; 442 if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), 443 B_SWAP_BENDIAN_TO_HOST) != B_OK) 444 return B_ERROR; 445 if (txt_header.header.magic != 'TEXT') 446 return B_ERROR; 447 if (txt_header.charset != B_UNICODE_UTF8) 448 return B_ERROR; 449 450 offset += txt_header.header.header_size; 451 if (mallio.BufferLength() < offset + txt_header.header.data_size) 452 return B_ERROR; 453 454 const char *pTextData = 455 (reinterpret_cast<const char *> (mallio.Buffer())) + offset; 456 // point text pointer at the actual character data 457 458 if (mallio.BufferLength() > offset + txt_header.header.data_size) { 459 // If the stream contains information beyond the text data 460 // (which means that this data is probably styled text data) 461 462 offset += txt_header.header.data_size; 463 const size_t kStyleHeaderSize = 464 sizeof(TranslatorStyledTextStyleHeader); 465 if (mallio.BufferLength() < offset + kStyleHeaderSize) 466 return B_ERROR; 467 468 TranslatorStyledTextStyleHeader stl_header = 469 *(reinterpret_cast<const TranslatorStyledTextStyleHeader *> 470 (reinterpret_cast<const char *> (mallio.Buffer()) + offset)); 471 if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, 472 B_SWAP_BENDIAN_TO_HOST) != B_OK) 473 return B_ERROR; 474 if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32), 475 B_SWAP_BENDIAN_TO_HOST) != B_OK) 476 return B_ERROR; 477 if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), 478 B_SWAP_BENDIAN_TO_HOST) != B_OK) 479 return B_ERROR; 480 if (stl_header.header.magic != 'STYL') 481 return B_ERROR; 482 483 offset += stl_header.header.header_size; 484 if (mallio.BufferLength() < offset + stl_header.header.data_size) 485 return B_ERROR; 486 487 // set pRawData to the flattened run array data 488 const void *kpRawData = reinterpret_cast<const void *> 489 (reinterpret_cast<const char *> (mallio.Buffer()) + offset); 490 text_run_array *pRunArray = BTextView::UnflattenRunArray(kpRawData); 491 492 if (pRunArray) { 493 intoView->Insert(intoView->TextLength(), pTextData, 494 txt_header.header.data_size, pRunArray); 495 free(pRunArray); 496 pRunArray = NULL; 497 } else 498 return B_ERROR; 499 } else 500 intoView->Insert(intoView->TextLength(), pTextData, 501 txt_header.header.data_size); 502 503 return B_NO_ERROR; 504 } 505 506 // --------------------------------------------------------------- 507 // PutStyledText 508 // 509 // This function takes styled text data from fromView and writes it to 510 // intoStream. The plain text data and styled text data are combined 511 // when they are written to intoStream. This is different than how 512 // a save operation in StyledEdit works. With StyledEdit, it writes 513 // plain text data to the file, but puts the styled text data in 514 // the "styles" attribute. In other words, this function writes 515 // styled text data to files in a manner that isn't human readable. 516 // 517 // So, if you want to write styled text 518 // data to a file, and you want it to behave the way StyledEdit does, 519 // you want to use the BTranslationUtils::WriteStyledEditFile() function. 520 // 521 // Preconditions: 522 // 523 // Parameters: fromView, the view with the styled text in it 524 // intoStream, the stream where the styled text is put 525 // roster, not used 526 // 527 // Postconditions: 528 // 529 // Returns: B_BAD_VALUE, if fromView or intoStream is NULL 530 // B_ERROR, if anything else went wrong 531 // B_NO_ERROR, if successful 532 // --------------------------------------------------------------- 533 status_t 534 BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream, 535 BTranslatorRoster *roster) 536 { 537 if (fromView == NULL || intoStream == NULL) 538 return B_BAD_VALUE; 539 540 int32 textLength = fromView->TextLength(); 541 if (textLength < 0) 542 return B_ERROR; 543 544 const char *pTextData = fromView->Text(); 545 // its OK if the result of fromView->Text() is NULL 546 547 int32 runArrayLength = 0; 548 text_run_array *pRunArray = fromView->RunArray(0, textLength, 549 &runArrayLength); 550 if (pRunArray == NULL) 551 return B_ERROR; 552 553 int32 flatRunArrayLength = 0; 554 void *pflatRunArray = 555 BTextView::FlattenRunArray(pRunArray, &flatRunArrayLength); 556 if (pflatRunArray == NULL) { 557 free(pRunArray); 558 pRunArray = NULL; 559 560 return B_ERROR; 561 } 562 563 // Rather than use a goto, I put a whole bunch of code that 564 // could error out inside of a loop, and break out of the loop 565 // if there is an error. If there is no error, loop is set 566 // to false. This is so that I don't have to put free() 567 // calls everywhere there could be an error. 568 569 // This block of code is where I do all of the writting of the 570 // data to the stream. I've gathered all of the data that I 571 // need at this point. 572 bool loop = true; 573 while (loop) { 574 const size_t kStreamHeaderSize = 575 sizeof(TranslatorStyledTextStreamHeader); 576 TranslatorStyledTextStreamHeader stm_header; 577 stm_header.header.magic = 'STXT'; 578 stm_header.header.header_size = kStreamHeaderSize; 579 stm_header.header.data_size = 0; 580 stm_header.version = 100; 581 582 // convert the stm_header.header struct to the host format 583 const size_t kRecordHeaderSize = 584 sizeof(TranslatorStyledTextRecordHeader); 585 if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, 586 B_SWAP_HOST_TO_BENDIAN) != B_OK) 587 break; 588 if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), 589 B_SWAP_HOST_TO_BENDIAN) != B_OK) 590 break; 591 592 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); 593 TranslatorStyledTextTextHeader txt_header; 594 txt_header.header.magic = 'TEXT'; 595 txt_header.header.header_size = kTextHeaderSize; 596 txt_header.header.data_size = textLength; 597 txt_header.charset = B_UNICODE_UTF8; 598 599 // convert the stm_header.header struct to the host format 600 if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, 601 B_SWAP_HOST_TO_BENDIAN) != B_OK) 602 break; 603 if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), 604 B_SWAP_HOST_TO_BENDIAN) != B_OK) 605 break; 606 607 const size_t kStyleHeaderSize = 608 sizeof(TranslatorStyledTextStyleHeader); 609 TranslatorStyledTextStyleHeader stl_header; 610 stl_header.header.magic = 'STYL'; 611 stl_header.header.header_size = kStyleHeaderSize; 612 stl_header.header.data_size = flatRunArrayLength; 613 stl_header.apply_offset = 0; 614 stl_header.apply_length = textLength; 615 616 // convert the stl_header.header struct to the host format 617 if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, 618 B_SWAP_HOST_TO_BENDIAN) != B_OK) 619 break; 620 if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32), 621 B_SWAP_HOST_TO_BENDIAN) != B_OK) 622 break; 623 if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), 624 B_SWAP_HOST_TO_BENDIAN) != B_OK) 625 break; 626 627 // Here, you can see the structure of the styled text data by 628 // observing the order that the various structs and data are 629 // written to the stream 630 ssize_t amountWritten = 0; 631 amountWritten = intoStream->Write(&stm_header, kStreamHeaderSize); 632 if ((size_t) amountWritten != kStreamHeaderSize) 633 break; 634 amountWritten = intoStream->Write(&txt_header, kTextHeaderSize); 635 if ((size_t) amountWritten != kTextHeaderSize) 636 break; 637 amountWritten = intoStream->Write(pTextData, textLength); 638 if (amountWritten != textLength) 639 break; 640 amountWritten = intoStream->Write(&stl_header, kStyleHeaderSize); 641 if ((size_t) amountWritten != kStyleHeaderSize) 642 break; 643 amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength); 644 if (amountWritten != flatRunArrayLength) 645 break; 646 647 loop = false; 648 // gracefully break out of the loop 649 } // end of while(loop) 650 651 free(pflatRunArray); 652 pflatRunArray = NULL; 653 free(pRunArray); 654 pRunArray = NULL; 655 656 if (loop) 657 return B_ERROR; 658 else 659 return B_NO_ERROR; 660 } 661 662 // --------------------------------------------------------------- 663 // WriteStyledEditFile 664 // 665 // This function writes the styled text data from fromView 666 // and stores it in the file intoFile. 667 // 668 // This function is similar to PutStyledText() except that it 669 // only writes styled text data to files and it puts the 670 // plain text data in the file and stores the styled data as 671 // the attribute "styles". 672 // 673 // You can use PutStyledText() to write styled text data 674 // to files, but it writes the data in a format that isn't 675 // human readable. 676 // 677 // It is important to note that this function doesn't 678 // write files in exactly the same manner that you get 679 // when you do a File->Save operation in StyledEdit. 680 // This function doesn't write all of the attributes 681 // that StyledEdit does, even though it easily could. 682 // 683 // Preconditions: 684 // 685 // Parameters: fromView, the view with the styled text 686 // intoFile, the file where the styled text 687 // is written to 688 // 689 // Postconditions: 690 // 691 // Returns: B_BAD_VALUE, if either parameter is NULL 692 // B_ERROR, if anything else went wrong 693 // B_OK, if successful 694 // --------------------------------------------------------------- 695 status_t 696 BTranslationUtils::WriteStyledEditFile(BTextView *fromView, BFile *intoFile) 697 { 698 if (fromView == NULL || intoFile == NULL) 699 return B_BAD_VALUE; 700 701 int32 textLength = fromView->TextLength(); 702 if (textLength < 0) 703 return B_ERROR; 704 705 const char *kpTextData = fromView->Text(); 706 if (kpTextData == NULL && textLength != 0) 707 return B_ERROR; 708 709 // move to the start of the file if not already there 710 status_t result = B_OK; 711 result = intoFile->Seek(0,SEEK_SET); 712 if (result != B_OK) 713 return result; 714 715 // Write plain text data to file 716 ssize_t amtWritten = intoFile->Write(kpTextData, textLength); 717 if (amtWritten != textLength) 718 return B_ERROR; 719 720 // truncate any extra text 721 result = intoFile->SetSize(textLength); 722 if (result != B_OK) 723 return result; 724 725 // get the BVolume that this file is on and 726 // check the volume for the attribute support 727 node_ref nref; 728 result = intoFile->GetNodeRef(&nref); 729 if (result != B_OK) 730 return result; 731 BVolume volume(nref.device); 732 result = volume.InitCheck(); 733 if (result != B_OK) 734 return result; 735 if (!volume.KnowsAttr()) 736 return B_OK; 737 738 // Write attributes 739 // BEOS:TYPE 740 // (this is so that the BeOS will recognize this file as a text file) 741 amtWritten = intoFile->WriteAttr("BEOS:TYPE", 'MIMS', 0, "text/plain", 11); 742 if ((size_t) amtWritten != 11) 743 return B_ERROR; 744 745 // wrap 746 // word wrap setting, turned on by default 747 int32 nwrap = ((fromView->DoesWordWrap()) ? 1 : 0); 748 amtWritten = intoFile->WriteAttr("wrap", B_INT32_TYPE, 0, 749 &nwrap, sizeof(int32)); 750 if (amtWritten != sizeof(int32)) 751 return B_ERROR; 752 753 // alignment 754 // alignment, either B_ALIGN_LEFT, B_ALIGN_RIGHT or B_ALIGN_CENTER, 755 // default is B_ALIGN_LEFT 756 int32 nalignment = fromView->Alignment(); 757 amtWritten = intoFile->WriteAttr("alignment", B_INT32_TYPE, 0, 758 &nalignment, sizeof(int32)); 759 if (amtWritten != sizeof(int32)) 760 return B_ERROR; 761 762 // be:encoding 763 // how the text is encoded, StyledEdit's list of encoding options 764 // is listed under the Encoding menu in the Save As dialog box 765 // default is Unicode UTF8 (65535) 766 // note that the B_UNICODE_UTF8 constant is 0 and not appropriate 767 // for use here 768 int32 nencoding = 65535; 769 amtWritten = intoFile->WriteAttr("be:encoding", B_INT32_TYPE, 0, 770 &nencoding, sizeof(int32)); 771 if (amtWritten != sizeof(int32)) 772 return B_ERROR; 773 774 text_run_array *pRunArray = fromView->RunArray(0, fromView->TextLength()); 775 if (pRunArray == NULL) 776 return B_ERROR; 777 778 int32 runArraySize = 0; 779 void *pflatRunArray = BTextView::FlattenRunArray(pRunArray, &runArraySize); 780 if (pflatRunArray == NULL) { 781 free(pRunArray); 782 pRunArray = NULL; 783 return B_ERROR; 784 } 785 if (runArraySize < 0) { 786 free(pflatRunArray); 787 pflatRunArray = NULL; 788 free(pRunArray); 789 pRunArray = NULL; 790 return B_ERROR; 791 } 792 793 // This is how the styled text data is stored in the file 794 // (the trick is that it isn't actually stored in the file, its stored 795 // as an attribute in the file's node) 796 amtWritten = intoFile->WriteAttr("styles", B_RAW_TYPE, 0, pflatRunArray, 797 runArraySize); 798 free(pflatRunArray); 799 pflatRunArray = NULL; 800 free(pRunArray); 801 pRunArray = NULL; 802 if (amtWritten == runArraySize) 803 return B_OK; 804 else 805 return B_ERROR; 806 } 807 808 // --------------------------------------------------------------- 809 // GetDefaultSettings 810 // 811 // Each translator can have default settings, set by the 812 // "translations" control panel. You can read these settings to 813 // pass on to a translator using one of these functions. 814 // 815 // Preconditions: 816 // 817 // Parameters: forTranslator, the translator the settings are for 818 // roster, the roster used to get the settings 819 // 820 // Postconditions: 821 // 822 // Returns: NULL, if anything went wrong 823 // BMessage * of configuration data for forTranslator 824 // --------------------------------------------------------------- 825 BMessage * 826 BTranslationUtils::GetDefaultSettings(translator_id forTranslator, 827 BTranslatorRoster *roster) 828 { 829 // Use default Translator if none is specified 830 if (roster == NULL) { 831 roster = BTranslatorRoster::Default(); 832 if (roster == NULL) 833 return NULL; 834 } 835 836 BMessage *pMessage = new BMessage(); 837 if (pMessage == NULL) 838 return NULL; 839 840 status_t result = roster->GetConfigurationMessage(forTranslator, pMessage); 841 switch (result) { 842 case B_OK: 843 break; 844 845 case B_NO_TRANSLATOR: 846 // Be's version seems to just pass an empty 847 // BMessage for this case, well, in some cases anyway 848 break; 849 850 case B_NOT_INITIALIZED: 851 delete pMessage; 852 pMessage = NULL; 853 break; 854 855 case B_BAD_VALUE: 856 delete pMessage; 857 pMessage = NULL; 858 break; 859 860 default: 861 break; 862 } 863 864 return pMessage; 865 } 866 867 // --------------------------------------------------------------- 868 // GetDefaultSettings 869 // 870 // Attempts to find the translator settings for 871 // the translator named kTranslatorName with a version of 872 // translatorVersion. 873 // 874 // Preconditions: 875 // 876 // Parameters: kTranslatorName, the name of the translator 877 // the settings are for 878 // translatorVersion, the version of the translator 879 // to retrieve 880 // 881 // Postconditions: 882 // 883 // Returns: NULL, if anything went wrong 884 // BMessage * of configuration data for kTranslatorName 885 // --------------------------------------------------------------- 886 BMessage * 887 BTranslationUtils::GetDefaultSettings(const char *kTranslatorName, 888 int32 translatorVersion) 889 { 890 BTranslatorRoster *roster = BTranslatorRoster::Default(); 891 translator_id *translators = NULL; 892 int32 numTranslators = 0; 893 if (roster == NULL 894 || roster->GetAllTranslators(&translators, &numTranslators) != B_OK) 895 return NULL; 896 897 // Cycle through all of the default translators 898 // looking for a translator that matches the name and version 899 // that I was given 900 BMessage *pMessage = NULL; 901 const char *currentTranName = NULL, *currentTranInfo = NULL; 902 int32 currentTranVersion = 0; 903 for (int i = 0; i < numTranslators; i++) { 904 905 if (roster->GetTranslatorInfo(translators[i], ¤tTranName, 906 ¤tTranInfo, ¤tTranVersion) == B_OK) { 907 908 if (currentTranVersion == translatorVersion 909 && strcmp(currentTranName, kTranslatorName) == 0) { 910 pMessage = GetDefaultSettings(translators[i], roster); 911 break; 912 } 913 } 914 } 915 916 delete[] translators; 917 return pMessage; 918 } 919 920 // --------------------------------------------------------------- 921 // AddTranslationItems 922 // 923 // Envious of that "Save As" menu in ShowImage? Well, you can have your own! 924 // AddTranslationItems will add menu items for all translations from the 925 // basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc). 926 // The translator ID and format constant chosen will be added to the message 927 // that is sent to you when the menu item is selected. 928 // 929 // The following code is a modified version of code 930 // written by Jon Watte from 931 // http://www.b500.com/bepage/TranslationKit2.html 932 // 933 // Preconditions: 934 // 935 // Parameters: intoMenu, the menu where the entries are created 936 // fromType, the type of translators to put on 937 // intoMenu 938 // kModel, the BMessage model for creating the menu 939 // if NULL, B_TRANSLATION_MENU is used 940 // kTranslationIdName, the name used for 941 // translator_id in the menuitem, 942 // if NULL, be:translator is used 943 // kTranslatorTypeName, the name used for 944 // output format id in the menuitem 945 // roster, BTranslatorRoster used to find translators 946 // if NULL, the default translators are used 947 // 948 // 949 // Postconditions: 950 // 951 // Returns: B_BAD_VALUE, if intoMenu is NULL 952 // B_OK, if successful 953 // error value if not successful 954 // --------------------------------------------------------------- 955 status_t 956 BTranslationUtils::AddTranslationItems(BMenu *intoMenu, uint32 fromType, 957 const BMessage *kModel, const char *kTranslatorIdName, 958 const char *kTranslatorTypeName, BTranslatorRoster *roster) 959 { 960 if (!intoMenu) 961 return B_BAD_VALUE; 962 963 if (!roster) 964 roster = BTranslatorRoster::Default(); 965 966 if (!kTranslatorIdName) 967 kTranslatorIdName = "be:translator"; 968 969 if (!kTranslatorTypeName) 970 kTranslatorTypeName = "be:type"; 971 972 translator_id * ids = NULL; 973 int32 count = 0; 974 status_t err = roster->GetAllTranslators(&ids, &count); 975 if (err < B_OK) 976 return err; 977 978 for (int tix = 0; tix < count; tix++) { 979 const translation_format *formats = NULL; 980 int32 numFormats = 0; 981 bool ok = false; 982 err = roster->GetInputFormats(ids[tix], &formats, &numFormats); 983 if (err == B_OK) { 984 for (int iix = 0; iix < numFormats; iix++) { 985 if (formats[iix].type == fromType) { 986 ok = true; 987 break; 988 } 989 } 990 } 991 if (!ok) 992 continue; 993 994 err = roster->GetOutputFormats(ids[tix], &formats, &numFormats); 995 if (err == B_OK) { 996 for (int oix = 0; oix < numFormats; oix++) { 997 if (formats[oix].type != fromType) { 998 BMessage *itemmsg; 999 if (kModel) 1000 itemmsg = new BMessage(*kModel); 1001 else 1002 itemmsg = new BMessage(B_TRANSLATION_MENU); 1003 itemmsg->AddInt32(kTranslatorIdName, ids[tix]); 1004 itemmsg->AddInt32(kTranslatorTypeName, formats[oix].type); 1005 intoMenu->AddItem( 1006 new BMenuItem(formats[oix].name, itemmsg)); 1007 } 1008 } 1009 } 1010 } 1011 1012 delete[] ids; 1013 return B_OK; 1014 } 1015