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 8192
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 *
make_nth_translator(int32 n,image_id you,uint32 flags,...)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
identify_stxt_header(const TranslatorStyledTextStreamHeader & header,BPositionIO * inSource,translator_info * outInfo,uint32 outType,TranslatorStyledTextTextHeader * ptxtheader=NULL)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
identify_text(uint8 * data,int32 bytesRead,BPositionIO * source,translator_info * outInfo,uint32 outType,BString & encoding)224 identify_text(uint8* data, int32 bytesRead, BPositionIO* source,
225 translator_info* outInfo, uint32 outType, BString& 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 (encoding.IsEmpty()) {
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
translate_from_stxt(BPositionIO * inSource,BPositionIO * outDestination,uint32 outType,const TranslatorStyledTextTextHeader & txtheader)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
output_headers(BPositionIO * outDestination,uint32 text_data_size)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
output_styles(BPositionIO * outDestination,uint32 text_size,uint8 * pflatRunArray,ssize_t data_size)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
translate_from_text(BPositionIO * source,BString encoding,bool forceEncoding,BPositionIO * destination,uint32 outType)477 translate_from_text(BPositionIO* source, BString encoding, 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 if (node != NULL) {
527 // determine encoding, if available
528 bool hasAttribute = false;
529 if (encoding.String() && !forceEncoding) {
530 attr_info info;
531 node->GetAttrInfo("be:encoding", &info);
532
533 if ((info.type == B_STRING_TYPE) && (node->ReadAttrString(
534 "be:encoding", &encoding) == B_OK)) {
535 hasAttribute = true;
536 } else if (info.type == B_INT32_TYPE) {
537 // Try the BeOS version of the atribute, which used an int32
538 // and a well-known list of encodings.
539 int32 value;
540 ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0,
541 &value, sizeof(value));
542 if (bytesRead == (ssize_t)sizeof(value)) {
543 if (value != 65535) {
544 const BCharacterSet* characterSet
545 = BCharacterSetRoster::GetCharacterSetByConversionID(value);
546 if (characterSet != NULL)
547 encoding = characterSet->GetName();
548 }
549 }
550 }
551 } else {
552 hasAttribute = true;
553 // we don't write the encoding in this case
554 }
555
556 if (!encoding.IsEmpty())
557 encodingBuffer.Allocate(READ_BUFFER_SIZE * 4);
558
559 if (!hasAttribute && !encoding.IsEmpty()) {
560 // add encoding attribute, so that someone opening the file can
561 // retrieve it for persistance
562 node->WriteAttrString("be:encoding", &encoding);
563 }
564 }
565
566 off_t outputSize = 0;
567 ssize_t bytesRead;
568
569 BPrivate::BTextEncoding codec(encoding.String());
570
571 // output the actual text part of the data
572 do {
573 uint8 buffer[READ_BUFFER_SIZE];
574 bytesRead = source->Read(buffer, READ_BUFFER_SIZE);
575 if (bytesRead < B_OK)
576 return bytesRead;
577 if (bytesRead == 0)
578 break;
579
580 if (encodingBuffer.Size() == 0) {
581 // default, no encoding
582 ssize_t bytesWritten = destination->Write(buffer, bytesRead);
583 if (bytesWritten != bytesRead) {
584 if (bytesWritten < B_OK)
585 return bytesWritten;
586
587 return B_ERROR;
588 }
589
590 outputSize += bytesRead;
591 } else {
592 // decode text file to UTF-8
593 const char* pos = (char*)buffer;
594 size_t encodingLength;
595 int32 bytesLeft = bytesRead;
596 size_t bytes;
597 do {
598 encodingLength = READ_BUFFER_SIZE * 4;
599 bytes = bytesLeft;
600
601 status = codec.Decode(pos, bytes,
602 (char*)encodingBuffer.Buffer(), encodingLength);
603 if (status < B_OK) {
604 return status;
605 }
606
607 ssize_t bytesWritten = destination->Write(encodingBuffer.Buffer(),
608 encodingLength);
609 if (bytesWritten < (ssize_t)encodingLength) {
610 if (bytesWritten < B_OK)
611 return bytesWritten;
612
613 return B_ERROR;
614 }
615
616 pos += bytes;
617 bytesLeft -= bytes;
618 outputSize += encodingLength;
619 } while (encodingLength > 0 && bytesLeft > 0);
620 }
621 } while (bytesRead > 0);
622
623 if (outType != B_STYLED_TEXT_FORMAT)
624 return B_OK;
625
626 if (encodingBuffer.Size() != 0 && size != outputSize) {
627 if (outputSize > UINT32_MAX)
628 return B_NOT_SUPPORTED;
629
630 // we need to update the header as the decoded text size has changed
631 status = destination->Seek(0, SEEK_SET);
632 if (status == B_OK)
633 status = output_headers(destination, (uint32)outputSize);
634 if (status == B_OK)
635 status = destination->Seek(0, SEEK_END);
636
637 if (status < B_OK)
638 return status;
639 }
640
641 // Read file attributes if outputting styled data
642 // and source is a BNode object
643
644 if (node == NULL)
645 return B_OK;
646
647 // Try to read styles - we only propagate an error if the actual on-disk
648 // data is likely to be okay
649
650 const char *kAttrName = "styles";
651 attr_info info;
652 if (node->GetAttrInfo(kAttrName, &info) != B_OK)
653 return B_OK;
654
655 if (info.type != B_RAW_TYPE || info.size < 160) {
656 // styles seem to be broken, but since we got the text,
657 // we don't propagate the error
658 return B_OK;
659 }
660
661 uint8* flatRunArray = new (std::nothrow) uint8[info.size];
662 if (flatRunArray == NULL)
663 return B_NO_MEMORY;
664
665 bytesRead = node->ReadAttr(kAttrName, B_RAW_TYPE, 0, flatRunArray, info.size);
666 if (bytesRead != info.size)
667 return B_OK;
668
669 output_styles(destination, size, flatRunArray, info.size);
670
671 delete[] flatRunArray;
672 return B_OK;
673 }
674
675
676 // #pragma mark -
677
678
STXTTranslator()679 STXTTranslator::STXTTranslator()
680 : BaseTranslator(B_TRANSLATE("StyledEdit files"),
681 B_TRANSLATE("StyledEdit file translator"),
682 STXT_TRANSLATOR_VERSION,
683 sInputFormats, kNumInputFormats,
684 sOutputFormats, kNumOutputFormats,
685 "STXTTranslator_Settings",
686 sDefaultSettings, kNumDefaultSettings,
687 B_TRANSLATOR_TEXT, B_STYLED_TEXT_FORMAT)
688 {
689 }
690
691
~STXTTranslator()692 STXTTranslator::~STXTTranslator()
693 {
694 }
695
696
697 status_t
Identify(BPositionIO * inSource,const translation_format * inFormat,BMessage * ioExtension,translator_info * outInfo,uint32 outType)698 STXTTranslator::Identify(BPositionIO *inSource,
699 const translation_format *inFormat, BMessage *ioExtension,
700 translator_info *outInfo, uint32 outType)
701 {
702 if (!outType)
703 outType = B_TRANSLATOR_TEXT;
704 if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
705 return B_NO_TRANSLATOR;
706
707 const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
708
709 uint8 buffer[DATA_BUFFER_SIZE];
710 status_t nread = 0;
711 // Read in the header to determine
712 // if the data is supported
713 nread = inSource->Read(buffer, kstxtsize);
714 if (nread < 0)
715 return nread;
716
717 // read in enough data to fill the stream header
718 if (nread == kstxtsize) {
719 TranslatorStyledTextStreamHeader header;
720 memcpy(&header, buffer, kstxtsize);
721 if (swap_data(B_UINT32_TYPE, &header, kstxtsize,
722 B_SWAP_BENDIAN_TO_HOST) != B_OK)
723 return B_ERROR;
724
725 if (header.header.magic == B_STYLED_TEXT_FORMAT
726 && header.header.header_size == (int32)kstxtsize
727 && header.header.data_size == 0
728 && header.version == 100)
729 return identify_stxt_header(header, inSource, outInfo, outType);
730 }
731
732 // if the data is not styled text, check if it is plain text
733 BString encoding;
734 return identify_text(buffer, nread, inSource, outInfo, outType, encoding);
735 }
736
737
738 status_t
Translate(BPositionIO * source,const translator_info * info,BMessage * ioExtension,uint32 outType,BPositionIO * outDestination)739 STXTTranslator::Translate(BPositionIO* source, const translator_info* info,
740 BMessage* ioExtension, uint32 outType, BPositionIO* outDestination)
741 {
742 if (!outType)
743 outType = B_TRANSLATOR_TEXT;
744 if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
745 return B_NO_TRANSLATOR;
746
747 const ssize_t headerSize = sizeof(TranslatorStyledTextStreamHeader);
748 uint8 buffer[DATA_BUFFER_SIZE];
749 status_t result;
750 translator_info outInfo;
751 // Read in the header to determine
752 // if the data is supported
753 ssize_t bytesRead = source->Read(buffer, headerSize);
754 if (bytesRead < 0)
755 return bytesRead;
756
757 // read in enough data to fill the stream header
758 if (bytesRead == headerSize) {
759 TranslatorStyledTextStreamHeader header;
760 memcpy(&header, buffer, headerSize);
761 if (swap_data(B_UINT32_TYPE, &header, headerSize,
762 B_SWAP_BENDIAN_TO_HOST) != B_OK)
763 return B_ERROR;
764
765 if (header.header.magic == B_STYLED_TEXT_FORMAT
766 && header.header.header_size == sizeof(TranslatorStyledTextStreamHeader)
767 && header.header.data_size == 0
768 && header.version == 100) {
769 TranslatorStyledTextTextHeader textHeader;
770 result = identify_stxt_header(header, source, &outInfo, outType,
771 &textHeader);
772 if (result != B_OK)
773 return result;
774
775 return translate_from_stxt(source, outDestination, outType, textHeader);
776 }
777 }
778
779 // if the data is not styled text, check if it is ASCII text
780 bool forceEncoding = false;
781 BString encoding;
782 result = identify_text(buffer, bytesRead, source, &outInfo, outType, encoding);
783 if (result != B_OK)
784 return result;
785
786 if (ioExtension != NULL) {
787 const char* value;
788 if (ioExtension->FindString("be:encoding", &value) == B_OK
789 && value[0]) {
790 // override encoding
791 encoding = value;
792 forceEncoding = true;
793 }
794 }
795
796 return translate_from_text(source, encoding, forceEncoding, outDestination, outType);
797 }
798
799
800 BView *
NewConfigView(TranslatorSettings * settings)801 STXTTranslator::NewConfigView(TranslatorSettings *settings)
802 {
803 return new STXTView(BRect(0, 0, 225, 175),
804 B_TRANSLATE("STXTTranslator Settings"),
805 B_FOLLOW_ALL, B_WILL_DRAW, settings);
806 }
807
808