tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / translation / TranslationUtils.cpp
blob3e7383ec40252200a4af897b6e7e1b7a3533a675
1 /*
2 * Copyright 2002-2007, Haiku Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Wilber
7 * Axel Dörfler, axeld@pinc-software.de
8 */
10 /*! Utility functions for the Translation Kit */
13 #include <Application.h>
14 #include <Bitmap.h>
15 #include <BitmapStream.h>
16 #include <CharacterSet.h>
17 #include <CharacterSetRoster.h>
18 #include <Entry.h>
19 #include <File.h>
20 #include <MenuItem.h>
21 #include <NodeInfo.h>
22 #include <ObjectList.h>
23 #include <Path.h>
24 #include <Resources.h>
25 #include <Roster.h>
26 #include <TextView.h>
27 #include <TranslationUtils.h>
28 #include <TranslatorFormats.h>
29 #include <TranslatorRoster.h>
30 #include <UTF8.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
38 using namespace BPrivate;
41 BTranslationUtils::BTranslationUtils()
46 BTranslationUtils::~BTranslationUtils()
51 BTranslationUtils::BTranslationUtils(const BTranslationUtils &kUtils)
56 BTranslationUtils &
57 BTranslationUtils::operator=(const BTranslationUtils &kUtils)
59 return *this;
62 // ---------------------------------------------------------------
63 // GetBitmap
65 // Returns a BBitmap object for the bitmap file or resource
66 // kName. The user has to delete this object. It first tries
67 // to open kName as a file, then as a resource.
69 // Preconditions:
71 // Parameters: kName, the name of the bitmap file or resource to
72 // be returned
73 // roster, BTranslatorRoster used to do the translation
75 // Postconditions:
77 // Returns: NULL, if the file could not be opened and the
78 // resource couldn't be found or couldn't be
79 // translated to a BBitmap
80 // BBitmap * to the bitmap reference by kName
81 // ---------------------------------------------------------------
82 BBitmap *
83 BTranslationUtils::GetBitmap(const char *kName, BTranslatorRoster *roster)
85 BBitmap *pBitmap = GetBitmapFile(kName, roster);
86 // Try loading a bitmap from the file named name
88 // Try loading the bitmap as an application resource
89 if (pBitmap == NULL)
90 pBitmap = GetBitmap(B_TRANSLATOR_BITMAP, kName, roster);
92 return pBitmap;
95 // ---------------------------------------------------------------
96 // GetBitmap
98 // Returns a BBitmap object for the bitmap resource identified by
99 // the type type with the resource id, id.
100 // The user has to delete this object.
102 // Preconditions:
104 // Parameters: type, the type of resource to be loaded
105 // id, the id for the resource to be loaded
106 // roster, BTranslatorRoster used to do the translation
108 // Postconditions:
110 // Returns: NULL, if the resource couldn't be loaded or couldn't
111 // be translated to a BBitmap
112 // BBitmap * to the bitmap identified by type and id
113 // ---------------------------------------------------------------
114 BBitmap *
115 BTranslationUtils::GetBitmap(uint32 type, int32 id, BTranslatorRoster *roster)
117 BResources *pResources = BApplication::AppResources();
118 // Remember: pResources must not be freed because
119 // it belongs to the application
120 if (pResources == NULL || pResources->HasResource(type, id) == false)
121 return NULL;
123 // Load the bitmap resource from the application file
124 // pRawData should be NULL if the resource is an
125 // unknown type or not available
126 size_t bitmapSize = 0;
127 const void *kpRawData = pResources->LoadResource(type, id, &bitmapSize);
128 if (kpRawData == NULL || bitmapSize == 0)
129 return NULL;
131 BMemoryIO memio(kpRawData, bitmapSize);
132 // Put the pointer to the raw image data into a BMemoryIO object
133 // so that it can be used with BTranslatorRoster->Translate() in
134 // the GetBitmap(BPositionIO *, BTranslatorRoster *) function
136 return GetBitmap(&memio, roster);
137 // Translate the data in memio using the BTranslatorRoster roster
140 // ---------------------------------------------------------------
141 // GetBitmap
143 // Returns a BBitmap object for the bitmap resource identified by
144 // the type type with the resource name, kName.
145 // The user has to delete this object. Note that a resource type
146 // and name does not uniquely identify a resource in a file.
148 // Preconditions:
150 // Parameters: type, the type of resource to be loaded
151 // kName, the name of the resource to be loaded
152 // roster, BTranslatorRoster used to do the translation
154 // Postconditions:
156 // Returns: NULL, if the resource couldn't be loaded or couldn't
157 // be translated to a BBitmap
158 // BBitmap * to the bitmap identified by type and kName
159 // ---------------------------------------------------------------
160 BBitmap *
161 BTranslationUtils::GetBitmap(uint32 type, const char *kName,
162 BTranslatorRoster *roster)
164 BResources *pResources = BApplication::AppResources();
165 // Remember: pResources must not be freed because
166 // it belongs to the application
167 if (pResources == NULL || pResources->HasResource(type, kName) == false)
168 return NULL;
170 // Load the bitmap resource from the application file
171 size_t bitmapSize = 0;
172 const void *kpRawData = pResources->LoadResource(type, kName, &bitmapSize);
173 if (kpRawData == NULL || bitmapSize == 0)
174 return NULL;
176 BMemoryIO memio(kpRawData, bitmapSize);
177 // Put the pointer to the raw image data into a BMemoryIO object so
178 // that it can be used with BTranslatorRoster->Translate()
180 return GetBitmap(&memio, roster);
181 // Translate the data in memio using the BTranslatorRoster roster
184 // ---------------------------------------------------------------
185 // GetBitmapFile
187 // Returns a BBitmap object for the bitmap file named kName.
188 // The user has to delete this object.
190 // Preconditions:
192 // Parameters: kName, the name of the bitmap file
193 // roster, BTranslatorRoster used to do the translation
195 // Postconditions:
197 // Returns: NULL, if the file couldn't be opened or couldn't
198 // be translated to a BBitmap
199 // BBitmap * to the bitmap file named kName
200 // ---------------------------------------------------------------
201 BBitmap *
202 BTranslationUtils::GetBitmapFile(const char *kName, BTranslatorRoster *roster)
204 if (!be_app || !kName || kName[0] == '\0')
205 return NULL;
207 BPath path;
208 if (kName[0] != '/') {
209 // If kName is a relative path, use the path of the application's
210 // executable as the base for the relative path
211 app_info info;
212 if (be_app->GetAppInfo(&info) != B_OK)
213 return NULL;
214 BEntry appRef(&info.ref);
215 if (path.SetTo(&appRef) != B_OK)
216 return NULL;
217 if (path.GetParent(&path) != B_OK)
218 return NULL;
219 if (path.Append(kName) != B_OK)
220 return NULL;
222 } else if (path.SetTo(kName) != B_OK)
223 return NULL;
225 BFile bitmapFile(path.Path(), B_READ_ONLY);
226 if (bitmapFile.InitCheck() != B_OK)
227 return NULL;
229 return GetBitmap(&bitmapFile, roster);
230 // Translate the data in memio using the BTranslatorRoster roster
233 // ---------------------------------------------------------------
234 // GetBitmap
236 // Returns a BBitmap object for the bitmap file with the entry_ref
237 // kRef. The user has to delete this object.
239 // Preconditions:
241 // Parameters: kRef, the entry_ref for the bitmap file
242 // roster, BTranslatorRoster used to do the translation
244 // Postconditions:
246 // Returns: NULL, if the file couldn't be opened or couldn't
247 // be translated to a BBitmap
248 // BBitmap * to the bitmap file referenced by kRef
249 // ---------------------------------------------------------------
250 BBitmap *
251 BTranslationUtils::GetBitmap(const entry_ref *kRef, BTranslatorRoster *roster)
253 BFile bitmapFile(kRef, B_READ_ONLY);
254 if (bitmapFile.InitCheck() != B_OK)
255 return NULL;
257 return GetBitmap(&bitmapFile, roster);
258 // Translate the data in bitmapFile using the BTranslatorRoster roster
261 // ---------------------------------------------------------------
262 // GetBitmap
264 // Returns a BBitmap object from the BPositionIO *stream. The
265 // user must delete the returned object. This GetBitmap function
266 // is used by the other GetBitmap functions to do all of the
267 // "real" work.
269 // Preconditions:
271 // Parameters: stream, the stream with bitmap data in it
272 // roster, BTranslatorRoster used to do the translation
274 // Postconditions:
276 // Returns: NULL, if the stream couldn't be translated to a BBitmap
277 // BBitmap * for the bitmap data from pio if successful
278 // ---------------------------------------------------------------
279 BBitmap *
280 BTranslationUtils::GetBitmap(BPositionIO *stream, BTranslatorRoster *roster)
282 if (stream == NULL)
283 return NULL;
285 // Use default Translator if none is specified
286 if (roster == NULL) {
287 roster = BTranslatorRoster::Default();
288 if (roster == NULL)
289 return NULL;
292 // Translate the file from whatever format it is in the file
293 // to the type format so that it can be stored in a BBitmap
294 BBitmapStream bitmapStream;
295 if (roster->Translate(stream, NULL, NULL, &bitmapStream,
296 B_TRANSLATOR_BITMAP) < B_OK)
297 return NULL;
299 // Detach the BBitmap from the BBitmapStream so the user
300 // of this function can do what they please with it.
301 BBitmap *pBitmap = NULL;
302 if (bitmapStream.DetachBitmap(&pBitmap) == B_NO_ERROR)
303 return pBitmap;
304 else
305 return NULL;
310 This function translates the styled text in fromStream and
311 inserts it at the end of the text in intoView, using the
312 BTranslatorRoster *roster to do the translation. The structs
313 that make it possible to work with the translated data are
314 defined in
315 /boot/develop/headers/be/translation/TranslatorFormats.h
317 \param source the stream with the styled text
318 \param intoView the view where the test will be inserted
319 roster, BTranslatorRoster used to do the translation
320 \param the encoding to use, defaults to UTF-8
322 \return B_BAD_VALUE, if fromStream or intoView is NULL
323 \return B_ERROR, if any other error occurred
324 \return B_OK, if successful
326 status_t
327 BTranslationUtils::GetStyledText(BPositionIO* source, BTextView* intoView,
328 const char* encoding, BTranslatorRoster* roster)
330 if (source == NULL || intoView == NULL)
331 return B_BAD_VALUE;
333 // Use default Translator if none is specified
334 if (roster == NULL) {
335 roster = BTranslatorRoster::Default();
336 if (roster == NULL)
337 return B_ERROR;
340 BMessage config;
341 if (encoding != NULL && encoding[0])
342 config.AddString("be:encoding", encoding);
344 // Translate the file from whatever format it is to B_STYLED_TEXT_FORMAT
345 // we understand
346 BMallocIO mallocIO;
347 if (roster->Translate(source, NULL, &config, &mallocIO,
348 B_STYLED_TEXT_FORMAT) < B_OK)
349 return B_BAD_TYPE;
351 const uint8* buffer = (const uint8*)mallocIO.Buffer();
353 // make sure there is enough data to fill the stream header
354 const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader);
355 if (mallocIO.BufferLength() < kStreamHeaderSize)
356 return B_BAD_DATA;
358 // copy the stream header from the mallio buffer
359 TranslatorStyledTextStreamHeader header =
360 *(reinterpret_cast<const TranslatorStyledTextStreamHeader *>(buffer));
362 // convert the stm_header.header struct to the host format
363 const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader);
364 swap_data(B_UINT32_TYPE, &header.header, kRecordHeaderSize, B_SWAP_BENDIAN_TO_HOST);
365 swap_data(B_INT32_TYPE, &header.version, sizeof(int32), B_SWAP_BENDIAN_TO_HOST);
367 if (header.header.magic != 'STXT')
368 return B_BAD_TYPE;
370 // copy the text header from the mallocIO buffer
372 uint32 offset = header.header.header_size + header.header.data_size;
373 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader);
374 if (mallocIO.BufferLength() < offset + kTextHeaderSize)
375 return B_BAD_DATA;
377 TranslatorStyledTextTextHeader textHeader =
378 *(const TranslatorStyledTextTextHeader *)(buffer + offset);
380 // convert the stm_header.header struct to the host format
381 swap_data(B_UINT32_TYPE, &textHeader.header, kRecordHeaderSize, B_SWAP_BENDIAN_TO_HOST);
382 swap_data(B_INT32_TYPE, &textHeader.charset, sizeof(int32), B_SWAP_BENDIAN_TO_HOST);
384 if (textHeader.header.magic != 'TEXT' || textHeader.charset != B_UNICODE_UTF8)
385 return B_BAD_TYPE;
387 offset += textHeader.header.header_size;
388 if (mallocIO.BufferLength() < offset + textHeader.header.data_size) {
389 // text buffer misses its end; handle this gracefully
390 textHeader.header.data_size = mallocIO.BufferLength() - offset;
393 const char* text = (const char*)buffer + offset;
394 // point text pointer at the actual character data
395 bool hasStyles = false;
397 if (mallocIO.BufferLength() > offset + textHeader.header.data_size) {
398 // If the stream contains information beyond the text data
399 // (which means that this data is probably styled text data)
401 offset += textHeader.header.data_size;
402 const size_t kStyleHeaderSize =
403 sizeof(TranslatorStyledTextStyleHeader);
404 if (mallocIO.BufferLength() >= offset + kStyleHeaderSize) {
405 TranslatorStyledTextStyleHeader styleHeader =
406 *(reinterpret_cast<const TranslatorStyledTextStyleHeader *>(buffer + offset));
407 swap_data(B_UINT32_TYPE, &styleHeader.header, kRecordHeaderSize, B_SWAP_BENDIAN_TO_HOST);
408 swap_data(B_UINT32_TYPE, &styleHeader.apply_offset, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST);
409 swap_data(B_UINT32_TYPE, &styleHeader.apply_length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST);
410 if (styleHeader.header.magic == 'STYL') {
411 offset += styleHeader.header.header_size;
412 if (mallocIO.BufferLength() >= offset + styleHeader.header.data_size)
413 hasStyles = true;
418 text_run_array *runArray = NULL;
419 if (hasStyles)
420 runArray = BTextView::UnflattenRunArray(buffer + offset);
422 if (runArray != NULL) {
423 intoView->Insert(intoView->TextLength(),
424 text, textHeader.header.data_size, runArray);
425 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
426 BTextView::FreeRunArray(runArray);
427 #else
428 free(runArray);
429 #endif
430 } else {
431 intoView->Insert(intoView->TextLength(), text,
432 textHeader.header.data_size);
435 return B_OK;
439 status_t
440 BTranslationUtils::GetStyledText(BPositionIO* source, BTextView* intoView,
441 BTranslatorRoster* roster)
443 return GetStyledText(source, intoView, NULL, roster);
448 This function takes styled text data from fromView and writes it to
449 intoStream. The plain text data and styled text data are combined
450 when they are written to intoStream. This is different than how
451 a save operation in StyledEdit works. With StyledEdit, it writes
452 plain text data to the file, but puts the styled text data in
453 the "styles" attribute. In other words, this function writes
454 styled text data to files in a manner that isn't human readable.
456 So, if you want to write styled text
457 data to a file, and you want it to behave the way StyledEdit does,
458 you want to use the BTranslationUtils::WriteStyledEditFile() function.
460 \param fromView, the view with the styled text in it
461 \param intoStream, the stream where the styled text is put
462 roster, not used
464 \return B_BAD_VALUE, if fromView or intoStream is NULL
465 \return B_ERROR, if anything else went wrong
466 \return B_NO_ERROR, if successful
468 status_t
469 BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream,
470 BTranslatorRoster *roster)
472 if (fromView == NULL || intoStream == NULL)
473 return B_BAD_VALUE;
475 int32 textLength = fromView->TextLength();
476 if (textLength < 0)
477 return B_ERROR;
479 const char *pTextData = fromView->Text();
480 // its OK if the result of fromView->Text() is NULL
482 int32 runArrayLength = 0;
483 text_run_array *runArray = fromView->RunArray(0, textLength,
484 &runArrayLength);
485 if (runArray == NULL)
486 return B_ERROR;
488 int32 flatRunArrayLength = 0;
489 void *pflatRunArray =
490 BTextView::FlattenRunArray(runArray, &flatRunArrayLength);
491 if (pflatRunArray == NULL) {
492 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
493 BTextView::FreeRunArray(runArray);
494 #else
495 free(runArray);
496 #endif
497 return B_ERROR;
500 // Rather than use a goto, I put a whole bunch of code that
501 // could error out inside of a loop, and break out of the loop
502 // if there is an error.
504 // This block of code is where I do all of the writing of the
505 // data to the stream. I've gathered all of the data that I
506 // need at this point.
507 bool ok = false;
508 while (!ok) {
509 const size_t kStreamHeaderSize =
510 sizeof(TranslatorStyledTextStreamHeader);
511 TranslatorStyledTextStreamHeader stm_header;
512 stm_header.header.magic = 'STXT';
513 stm_header.header.header_size = kStreamHeaderSize;
514 stm_header.header.data_size = 0;
515 stm_header.version = 100;
517 // convert the stm_header.header struct to the host format
518 const size_t kRecordHeaderSize =
519 sizeof(TranslatorStyledTextRecordHeader);
520 if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize,
521 B_SWAP_HOST_TO_BENDIAN) != B_OK)
522 break;
523 if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32),
524 B_SWAP_HOST_TO_BENDIAN) != B_OK)
525 break;
527 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader);
528 TranslatorStyledTextTextHeader txt_header;
529 txt_header.header.magic = 'TEXT';
530 txt_header.header.header_size = kTextHeaderSize;
531 txt_header.header.data_size = textLength;
532 txt_header.charset = B_UNICODE_UTF8;
534 // convert the stm_header.header struct to the host format
535 if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize,
536 B_SWAP_HOST_TO_BENDIAN) != B_OK)
537 break;
538 if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32),
539 B_SWAP_HOST_TO_BENDIAN) != B_OK)
540 break;
542 const size_t kStyleHeaderSize =
543 sizeof(TranslatorStyledTextStyleHeader);
544 TranslatorStyledTextStyleHeader stl_header;
545 stl_header.header.magic = 'STYL';
546 stl_header.header.header_size = kStyleHeaderSize;
547 stl_header.header.data_size = flatRunArrayLength;
548 stl_header.apply_offset = 0;
549 stl_header.apply_length = textLength;
551 // convert the stl_header.header struct to the host format
552 if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize,
553 B_SWAP_HOST_TO_BENDIAN) != B_OK)
554 break;
555 if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32),
556 B_SWAP_HOST_TO_BENDIAN) != B_OK)
557 break;
558 if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32),
559 B_SWAP_HOST_TO_BENDIAN) != B_OK)
560 break;
562 // Here, you can see the structure of the styled text data by
563 // observing the order that the various structs and data are
564 // written to the stream
565 ssize_t amountWritten = 0;
566 amountWritten = intoStream->Write(&stm_header, kStreamHeaderSize);
567 if ((size_t) amountWritten != kStreamHeaderSize)
568 break;
569 amountWritten = intoStream->Write(&txt_header, kTextHeaderSize);
570 if ((size_t) amountWritten != kTextHeaderSize)
571 break;
572 amountWritten = intoStream->Write(pTextData, textLength);
573 if (amountWritten != textLength)
574 break;
575 amountWritten = intoStream->Write(&stl_header, kStyleHeaderSize);
576 if ((size_t) amountWritten != kStyleHeaderSize)
577 break;
578 amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength);
579 if (amountWritten != flatRunArrayLength)
580 break;
582 ok = true;
583 // gracefully break out of the loop
586 free(pflatRunArray);
587 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
588 BTextView::FreeRunArray(runArray);
589 #else
590 free(runArray);
591 #endif
593 return ok ? B_OK : B_ERROR;
598 \brief Writes the styled text data from \a view to the specified \a file.
600 This function is similar to PutStyledText() except that it
601 only writes styled text data to files and it puts the
602 plain text data in the file and stores the styled data as
603 the attribute "styles".
605 You can use PutStyledText() to write styled text data
606 to files, but it writes the data in a format that isn't
607 human readable.
609 \param view the view with the styled text
610 \param file the file where the styled text is written to
611 \param the encoding to use, defaults to UTF-8
613 \return B_BAD_VALUE, if either parameter is NULL
614 B_OK, if successful, and any possible file error
615 if writing failed.
617 status_t
618 BTranslationUtils::WriteStyledEditFile(BTextView* view, BFile* file, const char *encoding)
620 if (view == NULL || file == NULL)
621 return B_BAD_VALUE;
623 int32 textLength = view->TextLength();
624 if (textLength < 0)
625 return B_ERROR;
627 const char *text = view->Text();
628 if (text == NULL && textLength != 0)
629 return B_ERROR;
631 // move to the start of the file if not already there
632 status_t status = file->Seek(0, SEEK_SET);
633 if (status != B_OK)
634 return status;
636 const BCharacterSet* characterSet = NULL;
637 if (encoding != NULL && strcmp(encoding, ""))
638 characterSet = BCharacterSetRoster::FindCharacterSetByName(encoding);
639 if (characterSet == NULL) {
640 // default encoding - UTF-8
641 // Write plain text data to file
642 ssize_t bytesWritten = file->Write(text, textLength);
643 if (bytesWritten != textLength) {
644 if (bytesWritten < B_OK)
645 return bytesWritten;
647 return B_ERROR;
650 // be:encoding, defaults to UTF-8 (65535)
651 // Note that the B_UNICODE_UTF8 constant is 0 and for some reason
652 // not appropriate for use here.
653 int32 value = 65535;
654 file->WriteAttr("be:encoding", B_INT32_TYPE, 0, &value, sizeof(value));
655 } else {
656 // we need to convert the text
657 uint32 id = characterSet->GetConversionID();
658 const char* outText = view->Text();
659 int32 sourceLength = textLength;
660 int32 state = 0;
662 textLength = 0;
664 do {
665 char buffer[32768];
666 int32 length = sourceLength;
667 int32 bufferSize = sizeof(buffer);
668 status = convert_from_utf8(id, outText, &length, buffer, &bufferSize, &state);
669 if (status != B_OK)
670 return status;
672 ssize_t bytesWritten = file->Write(buffer, bufferSize);
673 if (bytesWritten < B_OK)
674 return bytesWritten;
676 sourceLength -= length;
677 textLength += bytesWritten;
678 outText += length;
679 } while (sourceLength > 0);
681 file->WriteAttr("be:encoding", B_STRING_TYPE, 0,
682 encoding, strlen(encoding));
685 // truncate any extra text
686 status = file->SetSize(textLength);
687 if (status != B_OK)
688 return status;
690 // Write attributes. We don't report an error anymore after this point,
691 // as attributes aren't that crucial - not all volumes support attributes.
692 // However, if writing one attribute fails, no further attributes are
693 // tried to be written.
695 BNodeInfo info(file);
696 char type[B_MIME_TYPE_LENGTH];
697 if (info.GetType(type) != B_OK) {
698 // This file doesn't have a file type yet, so let's set it
699 if (info.SetType("text/plain") < B_OK)
700 return B_OK;
703 // word wrap setting, turned on by default
704 int32 wordWrap = view->DoesWordWrap() ? 1 : 0;
705 ssize_t bytesWritten = file->WriteAttr("wrap", B_INT32_TYPE, 0,
706 &wordWrap, sizeof(int32));
707 if (bytesWritten != sizeof(int32))
708 return B_OK;
710 // alignment, default is B_ALIGN_LEFT
711 int32 alignment = view->Alignment();
712 bytesWritten = file->WriteAttr("alignment", B_INT32_TYPE, 0,
713 &alignment, sizeof(int32));
714 if (bytesWritten != sizeof(int32))
715 return B_OK;
717 // Write text_run_array, ie. the styles of the text
719 text_run_array *runArray = view->RunArray(0, view->TextLength());
720 if (runArray != NULL) {
721 int32 runArraySize = 0;
722 void *flattenedRunArray = BTextView::FlattenRunArray(runArray, &runArraySize);
723 if (flattenedRunArray != NULL) {
724 file->WriteAttr("styles", B_RAW_TYPE, 0, flattenedRunArray,
725 runArraySize);
728 free(flattenedRunArray);
729 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
730 BTextView::FreeRunArray(runArray);
731 #else
732 free(runArray);
733 #endif
736 return B_OK;
740 status_t
741 BTranslationUtils::WriteStyledEditFile(BTextView* view, BFile* file)
743 return WriteStyledEditFile(view, file, NULL);
748 Each translator can have default settings, set by the
749 "translations" control panel. You can read these settings to
750 pass on to a translator using one of these functions.
752 \param forTranslator, the translator the settings are for
753 roster, the roster used to get the settings
755 \return BMessage of configuration data for forTranslator - you own
756 this message and have to free it when you're done with it.
757 \return NULL, if anything went wrong
759 BMessage *
760 BTranslationUtils::GetDefaultSettings(translator_id forTranslator,
761 BTranslatorRoster *roster)
763 // Use default Translator if none is specified
764 if (roster == NULL) {
765 roster = BTranslatorRoster::Default();
766 if (roster == NULL)
767 return NULL;
770 BMessage *message = new BMessage();
771 if (message == NULL)
772 return NULL;
774 status_t result = roster->GetConfigurationMessage(forTranslator, message);
775 if (result != B_OK && result != B_NO_TRANSLATOR) {
776 // Be's version seems to just pass an empty BMessage
777 // in case of B_NO_TRANSLATOR, well, in some cases anyway
778 delete message;
779 return NULL;
782 return message;
786 // ---------------------------------------------------------------
787 // GetDefaultSettings
789 // Attempts to find the translator settings for
790 // the translator named kTranslatorName with a version of
791 // translatorVersion.
793 // Preconditions:
795 // Parameters: kTranslatorName, the name of the translator
796 // the settings are for
797 // translatorVersion, the version of the translator
798 // to retrieve
800 // Postconditions:
802 // Returns: NULL, if anything went wrong
803 // BMessage * of configuration data for kTranslatorName
804 // ---------------------------------------------------------------
805 BMessage *
806 BTranslationUtils::GetDefaultSettings(const char *kTranslatorName,
807 int32 translatorVersion)
809 BTranslatorRoster *roster = BTranslatorRoster::Default();
810 translator_id *translators = NULL;
811 int32 numTranslators = 0;
812 if (roster == NULL
813 || roster->GetAllTranslators(&translators, &numTranslators) != B_OK)
814 return NULL;
816 // Cycle through all of the default translators
817 // looking for a translator that matches the name and version
818 // that I was given
819 BMessage *pMessage = NULL;
820 const char *currentTranName = NULL, *currentTranInfo = NULL;
821 int32 currentTranVersion = 0;
822 for (int i = 0; i < numTranslators; i++) {
824 if (roster->GetTranslatorInfo(translators[i], &currentTranName,
825 &currentTranInfo, &currentTranVersion) == B_OK) {
827 if (currentTranVersion == translatorVersion
828 && strcmp(currentTranName, kTranslatorName) == 0) {
829 pMessage = GetDefaultSettings(translators[i], roster);
830 break;
835 delete[] translators;
836 return pMessage;
840 // ---------------------------------------------------------------
841 // AddTranslationItems
843 // Envious of that "Save As" menu in ShowImage? Well, you can have your own!
844 // AddTranslationItems will add menu items for all translations from the
845 // basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc).
846 // The translator ID and format constant chosen will be added to the message
847 // that is sent to you when the menu item is selected.
849 // The following code is a modified version of code
850 // written by Jon Watte from
851 // http://www.b500.com/bepage/TranslationKit2.html
853 // Preconditions:
855 // Parameters: intoMenu, the menu where the entries are created
856 // fromType, the type of translators to put on
857 // intoMenu
858 // kModel, the BMessage model for creating the menu
859 // if NULL, B_TRANSLATION_MENU is used
860 // kTranslationIdName, the name used for
861 // translator_id in the menuitem,
862 // if NULL, be:translator is used
863 // kTranslatorTypeName, the name used for
864 // output format id in the menuitem
865 // roster, BTranslatorRoster used to find translators
866 // if NULL, the default translators are used
869 // Postconditions:
871 // Returns: B_BAD_VALUE, if intoMenu is NULL
872 // B_OK, if successful
873 // error value if not successful
874 // ---------------------------------------------------------------
875 status_t
876 BTranslationUtils::AddTranslationItems(BMenu *intoMenu, uint32 fromType,
877 const BMessage *kModel, const char *kTranslatorIdName,
878 const char *kTranslatorTypeName, BTranslatorRoster *roster)
880 if (!intoMenu)
881 return B_BAD_VALUE;
883 if (!roster)
884 roster = BTranslatorRoster::Default();
886 if (!kTranslatorIdName)
887 kTranslatorIdName = "be:translator";
889 if (!kTranslatorTypeName)
890 kTranslatorTypeName = "be:type";
892 translator_id * ids = NULL;
893 int32 count = 0;
894 status_t err = roster->GetAllTranslators(&ids, &count);
895 if (err < B_OK)
896 return err;
898 BObjectList<translator_info> infoList;
900 for (int tix = 0; tix < count; tix++) {
901 const translation_format *formats = NULL;
902 int32 numFormats = 0;
903 bool ok = false;
904 err = roster->GetInputFormats(ids[tix], &formats, &numFormats);
905 if (err == B_OK) {
906 for (int iix = 0; iix < numFormats; iix++) {
907 if (formats[iix].type == fromType) {
908 ok = true;
909 break;
913 if (!ok)
914 continue;
916 // Get supported output formats
917 err = roster->GetOutputFormats(ids[tix], &formats, &numFormats);
918 if (err == B_OK) {
919 for (int oix = 0; oix < numFormats; oix++) {
920 if (formats[oix].type != fromType) {
921 infoList.AddItem(_BuildTranslatorInfo(ids[tix],
922 const_cast<translation_format*>(&formats[oix])));
928 // Sort alphabetically by name
929 infoList.SortItems(&_CompareTranslatorInfoByName);
931 // Now add the menu items
932 for (int i = 0; i < infoList.CountItems(); i++) {
933 translator_info* info = infoList.ItemAt(i);
935 BMessage *itemmsg;
936 if (kModel)
937 itemmsg = new BMessage(*kModel);
938 else
939 itemmsg = new BMessage(B_TRANSLATION_MENU);
940 itemmsg->AddInt32(kTranslatorIdName, info->translator);
941 itemmsg->AddInt32(kTranslatorTypeName, info->type);
942 intoMenu->AddItem(new BMenuItem(info->name, itemmsg));
944 // Delete object created in _BuildTranslatorInfo
945 delete info;
948 delete[] ids;
949 return B_OK;
953 translator_info*
954 BTranslationUtils::_BuildTranslatorInfo(const translator_id id, const translation_format* format)
956 // Caller must delete
957 translator_info* info = new translator_info;
959 info->translator = id;
960 info->type = format->type;
961 info->group = format->group;
962 info->quality = format->quality;
963 info->capability = format->capability;
964 strlcpy(info->name, format->name, sizeof(info->name));
965 strlcpy(info->MIME, format->MIME, sizeof(info->MIME));
967 return info;
972 BTranslationUtils::_CompareTranslatorInfoByName(const translator_info* info1, const translator_info* info2)
974 return strcasecmp(info1->name, info2->name);