xref: /haiku/src/add-ons/translators/stxt/STXTTranslator.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 /*****************************************************************************/
2 // STXTTranslator
3 // Written by Michael Wilber, OBOS Translation Kit Team
4 //
5 // STXTTranslator.cpp
6 //
7 // This BTranslator based object is for opening and writing
8 // StyledEdit (STXT) files.
9 //
10 //
11 // Copyright (c) 2002 OpenBeOS Project
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 /*****************************************************************************/
31 
32 #include <string.h>
33 #include <stdio.h>
34 #include "STXTTranslator.h"
35 #include "STXTView.h"
36 
37 #define READ_BUFFER_SIZE 2048
38 #define DATA_BUFFER_SIZE 64
39 
40 // The input formats that this translator supports.
41 translation_format gInputFormats[] = {
42 	{
43 		B_TRANSLATOR_TEXT,
44 		B_TRANSLATOR_TEXT,
45 		TEXT_IN_QUALITY,
46 		TEXT_IN_CAPABILITY,
47 		"text/plain",
48 		"Plain text file"
49 	},
50 	{
51 		B_STYLED_TEXT_FORMAT,
52 		B_TRANSLATOR_TEXT,
53 		STXT_IN_QUALITY,
54 		STXT_IN_CAPABILITY,
55 		"text/x-vnd.Be-stxt",
56 		"Be styled text file"
57 	}
58 };
59 
60 // The output formats that this translator supports.
61 translation_format gOutputFormats[] = {
62 	{
63 		B_TRANSLATOR_TEXT,
64 		B_TRANSLATOR_TEXT,
65 		TEXT_OUT_QUALITY,
66 		TEXT_OUT_CAPABILITY,
67 		"text/plain",
68 		"Plain text file"
69 	},
70 	{
71 		B_STYLED_TEXT_FORMAT,
72 		B_TRANSLATOR_TEXT,
73 		STXT_OUT_QUALITY,
74 		STXT_OUT_CAPABILITY,
75 		"text/x-vnd.Be-stxt",
76 		"Be styled text file"
77 	}
78 };
79 
80 // Default settings for the Translator
81 TranSetting gDefaultSettings[] = {
82 	{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
83 	{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}
84 };
85 
86 // ---------------------------------------------------------------
87 // make_nth_translator
88 //
89 // Creates a STXTTranslator object to be used by BTranslatorRoster
90 //
91 // Preconditions:
92 //
93 // Parameters: n,		The translator to return. Since
94 //						STXTTranslator only publishes one
95 //						translator, it only returns a
96 //						STXTTranslator if n == 0
97 //
98 //             you, 	The image_id of the add-on that
99 //						contains code (not used).
100 //
101 //             flags,	Has no meaning yet, should be 0.
102 //
103 // Postconditions:
104 //
105 // Returns: NULL if n is not zero,
106 //          a new STXTTranslator if n is zero
107 // ---------------------------------------------------------------
108 BTranslator *
109 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
110 {
111 	if (!n)
112 		return new STXTTranslator();
113 	else
114 		return NULL;
115 }
116 
117 // ---------------------------------------------------------------
118 // Constructor
119 //
120 // Sets up the version info and the name of the translator so that
121 // these values can be returned when they are requested.
122 //
123 // Preconditions:
124 //
125 // Parameters:
126 //
127 // Postconditions:
128 //
129 // Returns:
130 // ---------------------------------------------------------------
131 STXTTranslator::STXTTranslator()
132 	: BaseTranslator("StyledEdit Files", "StyledEdit files translator",
133 		STXT_TRANSLATOR_VERSION,
134 		gInputFormats, sizeof(gInputFormats) / sizeof(translation_format),
135 		gOutputFormats, sizeof(gOutputFormats) / sizeof(translation_format),
136 		"STXTTranslator_Settings",
137 		gDefaultSettings, sizeof(gDefaultSettings) / sizeof(TranSetting),
138 		B_TRANSLATOR_TEXT, B_STYLED_TEXT_FORMAT)
139 {
140 }
141 
142 // ---------------------------------------------------------------
143 // Destructor
144 //
145 // Does nothing
146 //
147 // Preconditions:
148 //
149 // Parameters:
150 //
151 // Postconditions:
152 //
153 // Returns:
154 // ---------------------------------------------------------------
155 STXTTranslator::~STXTTranslator()
156 {
157 }
158 
159 // ---------------------------------------------------------------
160 // identify_stxt_header
161 //
162 // Determines if the data in inSource is of the STXT format.
163 //
164 // Preconditions:
165 //
166 // Parameters:	header,		the STXT stream header read in by
167 //							Identify() or Translate()
168 //
169 //				inSource,	The stream with the STXT data
170 //
171 //				outInfo,	information about the type of data
172 //							from inSource is stored here
173 //
174 //				outType,	the desired output type for the
175 //							data in inSource
176 //
177 //				ptxtheader	if this is not NULL, the TEXT
178 //							header from inSource is copied
179 //							to it
180 //
181 // Postconditions:
182 //
183 // Returns: B_OK, if the data appears to be in the STXT format,
184 // B_NO_TRANSLATOR, if the data is not in the STXT format or
185 // returns B_ERROR if errors were encountered in trying to
186 // determine the format, or another error code if there was an
187 // error calling BPostionIO::Read()
188 // ---------------------------------------------------------------
189 status_t
190 identify_stxt_header(const TranslatorStyledTextStreamHeader &header,
191 	BPositionIO *inSource, translator_info *outInfo, uint32 outType,
192 	TranslatorStyledTextTextHeader *ptxtheader = NULL)
193 {
194 	const ssize_t ktxtsize = sizeof(TranslatorStyledTextTextHeader);
195 	const ssize_t kstylsize = sizeof(TranslatorStyledTextStyleHeader);
196 
197 	uint8 buffer[max(ktxtsize, kstylsize)];
198 
199 	// Check the TEXT header
200 	TranslatorStyledTextTextHeader txtheader;
201 	if (inSource->Read(buffer, ktxtsize) != ktxtsize)
202 		return B_NO_TRANSLATOR;
203 
204 	memcpy(&txtheader, buffer, ktxtsize);
205 	if (swap_data(B_UINT32_TYPE, &txtheader, ktxtsize,
206 		B_SWAP_BENDIAN_TO_HOST) != B_OK)
207 		return B_ERROR;
208 
209 	if (txtheader.header.magic != 'TEXT' ||
210 		txtheader.header.header_size !=
211 			sizeof(TranslatorStyledTextTextHeader) ||
212 		txtheader.charset != B_UNICODE_UTF8)
213 		return B_NO_TRANSLATOR;
214 
215 	// skip the text data
216 	off_t seekresult, pos;
217 	pos = header.header.header_size +
218 		txtheader.header.header_size +
219 		txtheader.header.data_size;
220 	seekresult = inSource->Seek(txtheader.header.data_size,
221 		SEEK_CUR);
222 	if (seekresult < pos)
223 		return B_NO_TRANSLATOR;
224 	if (seekresult > pos)
225 		return B_ERROR;
226 
227 	// check the STYL header (not all STXT files have this)
228 	ssize_t read = 0;
229 	TranslatorStyledTextStyleHeader stylheader;
230 	read = inSource->Read(buffer, kstylsize);
231 	if (read < 0)
232 		return read;
233 	if (read != kstylsize && read != 0)
234 		return B_NO_TRANSLATOR;
235 
236 	// If there is a STYL header
237 	if (read == kstylsize) {
238 		memcpy(&stylheader, buffer, kstylsize);
239 		if (swap_data(B_UINT32_TYPE, &stylheader, kstylsize,
240 			B_SWAP_BENDIAN_TO_HOST) != B_OK)
241 			return B_ERROR;
242 
243 		if (stylheader.header.magic != 'STYL' ||
244 			stylheader.header.header_size !=
245 				sizeof(TranslatorStyledTextStyleHeader))
246 			return B_NO_TRANSLATOR;
247 	}
248 
249 	// if output TEXT header is supplied, fill it with data
250 	if (ptxtheader) {
251 		ptxtheader->header.magic = txtheader.header.magic;
252 		ptxtheader->header.header_size = txtheader.header.header_size;
253 		ptxtheader->header.data_size = txtheader.header.data_size;
254 		ptxtheader->charset = txtheader.charset;
255 	}
256 
257 	// return information about the data in the stream
258 	outInfo->type = B_STYLED_TEXT_FORMAT;
259 	outInfo->group = B_TRANSLATOR_TEXT;
260 	outInfo->quality = STXT_IN_QUALITY;
261 	outInfo->capability = STXT_IN_CAPABILITY;
262 	strcpy(outInfo->name, "Be styled text file");
263 	strcpy(outInfo->MIME, "text/x-vnd.Be-stxt");
264 
265 	return B_OK;
266 }
267 
268 // ---------------------------------------------------------------
269 // identify_txt_header
270 //
271 // Determines if the data in inSource is of the UTF8 plain
272 // text format.
273 //
274 // Preconditions: data must point to a buffer at least
275 // 				  DATA_BUFFER_SIZE bytes long
276 //
277 // Parameters:	data,		buffer containing data already read
278 //							from the stream
279 //
280 //				nread,		number of bytes that have already
281 //							been read from the stream
282 //
283 //				header,		the STXT stream header read in by
284 //							Identify() or Translate()
285 //
286 //				inSource,	The stream with the STXT data
287 //
288 //				outInfo,	information about the type of data
289 //							from inSource is stored here
290 //
291 //				outType		the desired output type for the
292 //							data in inSource
293 //
294 //
295 // Postconditions:
296 //
297 // Returns: B_OK, if the data appears to be in the STXT format,
298 // B_NO_TRANSLATOR, if the data is not in the STXT format or
299 // returns B_ERROR if errors were encountered in trying to
300 // determine the format
301 // ---------------------------------------------------------------
302 status_t
303 identify_txt_header(uint8 *data, int32 nread,
304 	BPositionIO *inSource, translator_info *outInfo, uint32 outType)
305 {
306 	float capability = TEXT_IN_CAPABILITY;
307 	uint8 ch;
308 	ssize_t readlater = 0;
309 	readlater = inSource->Read(data + nread, DATA_BUFFER_SIZE - nread);
310 	if (readlater < 0)
311 		return B_NO_TRANSLATOR;
312 
313 	nread += readlater;
314 	for (int32 i = 0; i < nread; i++) {
315 		ch = data[i];
316 		// if any null characters or control characters
317 		// are found, reduce our ability to handle the data
318 		if (ch < 0x20 &&
319 			ch != 0x08 && // backspace
320 			ch != 0x09 && // tab
321 			ch != 0x0A && // line feed
322 			ch != 0x0C && // form feed
323 			ch != 0x0D) { // carriage return
324 			capability *= 0.6;
325 			break;
326 		}
327 	}
328 
329 	// return information about the data in the stream
330 	outInfo->type = B_TRANSLATOR_TEXT;
331 	outInfo->group = B_TRANSLATOR_TEXT;
332 	outInfo->quality = TEXT_IN_QUALITY;
333 	outInfo->capability = capability;
334 	strcpy(outInfo->name, "Plain text file");
335 	strcpy(outInfo->MIME, "text/plain");
336 
337 	return B_OK;
338 }
339 
340 // ---------------------------------------------------------------
341 // Identify
342 //
343 // Examines the data from inSource and determines if it is in a
344 // format that this translator knows how to work with.
345 //
346 // Preconditions:
347 //
348 // Parameters:	inSource,	where the data to examine is
349 //
350 //				inFormat,	a hint about the data in inSource,
351 //							it is ignored since it is only a hint
352 //
353 //				ioExtension,	configuration settings for the
354 //								translator (not used)
355 //
356 //				outInfo,	information about what data is in
357 //							inSource and how well this translator
358 //							can handle that data is stored here
359 //
360 //				outType,	The format that the user wants
361 //							the data in inSource to be
362 //							converted to
363 //
364 // Postconditions:
365 //
366 // Returns: B_NO_TRANSLATOR,	if this translator can't handle
367 //								the data in inSource
368 //
369 // B_ERROR,	if there was an error converting the data to the host
370 //			format
371 //
372 // B_BAD_VALUE, if the settings in ioExtension are bad
373 //
374 // B_OK,	if this translator understand the data and there were
375 //			no errors found
376 //
377 // Other errors if BPositionIO::Read() returned an error value
378 // ---------------------------------------------------------------
379 status_t
380 STXTTranslator::Identify(BPositionIO *inSource,
381 	const translation_format *inFormat, BMessage *ioExtension,
382 	translator_info *outInfo, uint32 outType)
383 {
384 	if (!outType)
385 		outType = B_TRANSLATOR_TEXT;
386 	if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
387 		return B_NO_TRANSLATOR;
388 
389 	const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
390 
391 	uint8 buffer[DATA_BUFFER_SIZE];
392 	status_t nread = 0;
393 	// Read in the header to determine
394 	// if the data is supported
395 	nread = inSource->Read(buffer, kstxtsize);
396 	if (nread < 0)
397 		return nread;
398 
399 	// read in enough data to fill the stream header
400 	if (nread == kstxtsize) {
401 		TranslatorStyledTextStreamHeader header;
402 		memcpy(&header, buffer, kstxtsize);
403 		if (swap_data(B_UINT32_TYPE, &header, kstxtsize,
404 			B_SWAP_BENDIAN_TO_HOST) != B_OK)
405 			return B_ERROR;
406 
407 		if (header.header.magic == B_STYLED_TEXT_FORMAT &&
408 			header.header.header_size ==
409 			sizeof(TranslatorStyledTextStreamHeader) &&
410 			header.header.data_size == 0 &&
411 			header.version == 100)
412 			return identify_stxt_header(header, inSource, outInfo, outType);
413 	}
414 
415 	// if the data is not styled text, check if it is plain text
416 	return identify_txt_header(buffer, nread, inSource, outInfo, outType);
417 }
418 
419 // ---------------------------------------------------------------
420 // translate_from_stxt
421 //
422 // Translates the data in inSource to the type outType and stores
423 // the translated data in outDestination.
424 //
425 // Preconditions:
426 //
427 // Parameters:	inSource,	the data to be translated
428 //
429 //				outDestination,	where the translated data is
430 //								put
431 //
432 //				outType,	the type to convert inSource to
433 //
434 //				txtheader, 	the TEXT header from inSource
435 //
436 //
437 // Postconditions:
438 //
439 // Returns: B_BAD_VALUE, if outType is invalid
440 //
441 // B_NO_TRANSLATOR, if this translator doesn't understand the data
442 //
443 // B_ERROR, if there was an error allocating memory or converting
444 //          data
445 //
446 // B_OK, if all went well
447 // ---------------------------------------------------------------
448 status_t
449 translate_from_stxt(BPositionIO *inSource, BPositionIO *outDestination,
450 		uint32 outType, const TranslatorStyledTextTextHeader &txtheader)
451 {
452 	if (inSource->Seek(0, SEEK_SET) != 0)
453 		return B_ERROR;
454 
455 	const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
456 	const ssize_t ktxtsize = sizeof(TranslatorStyledTextTextHeader);
457 
458 	bool btoplain;
459 	if (outType == B_TRANSLATOR_TEXT)
460 		btoplain = true;
461 	else if (outType == B_STYLED_TEXT_FORMAT)
462 		btoplain = false;
463 	else
464 		return B_BAD_VALUE;
465 
466 	uint8 buffer[READ_BUFFER_SIZE];
467 	ssize_t nread = 0, nwritten = 0, nreed = 0, ntotalread = 0;
468 
469 	// skip to the actual text data when outputting a
470 	// plain text file
471 	if (btoplain) {
472 		if (inSource->Seek(kstxtsize + ktxtsize, SEEK_CUR) !=
473 			kstxtsize + ktxtsize)
474 			return B_ERROR;
475 	}
476 
477 	// Read data from inSource
478 	// When outputing B_TRANSLATOR_TEXT, the loop stops when all of
479 	// the text data has been read and written.
480 	// When outputting B_STYLED_TEXT_FORMAT, the loop stops when all
481 	// of the data from inSource has been read and written.
482 	if (btoplain)
483 		nreed = min(READ_BUFFER_SIZE,
484 			txtheader.header.data_size - ntotalread);
485 	else
486 		nreed = READ_BUFFER_SIZE;
487 	nread = inSource->Read(buffer, nreed);
488 	while (nread > 0) {
489 		nwritten = outDestination->Write(buffer, nread);
490 		if (nwritten != nread)
491 			return B_ERROR;
492 
493 		if (btoplain) {
494 			ntotalread += nread;
495 			nreed = min(READ_BUFFER_SIZE,
496 				txtheader.header.data_size - ntotalread);
497 		} else
498 			nreed = READ_BUFFER_SIZE;
499 		nread = inSource->Read(buffer, nreed);
500 	}
501 
502 	if (btoplain && static_cast<ssize_t>(txtheader.header.data_size) !=
503 		ntotalread)
504 		// If not all of the text data was able to be read...
505 		return B_NO_TRANSLATOR;
506 	else
507 		return B_OK;
508 }
509 
510 // ---------------------------------------------------------------
511 // output_headers
512 //
513 // Outputs the Stream and Text headers from the B_STYLED_TEXT_FORMAT
514 // to outDestination, setting the data_size member of the text header
515 // to text_data_size
516 //
517 // Preconditions:
518 //
519 // Parameters:	outDestination,	where the translated data is
520 //								put
521 //
522 //				text_data_size, number of bytes in data section
523 //							    of the TEXT header
524 //
525 //
526 // Postconditions:
527 //
528 // Returns:
529 //
530 // B_ERROR, if there was an error writing to outDestination or
531 // 	an error with converting the byte order
532 //
533 // B_OK, if all went well
534 // ---------------------------------------------------------------
535 status_t
536 output_headers(BPositionIO *outDestination, uint32 text_data_size)
537 {
538 	const int32 kHeadersSize = sizeof(TranslatorStyledTextStreamHeader) +
539 		sizeof(TranslatorStyledTextTextHeader);
540 	status_t result;
541 	TranslatorStyledTextStreamHeader stxtheader;
542 	TranslatorStyledTextTextHeader txtheader;
543 
544 	uint8 buffer[kHeadersSize];
545 
546 	stxtheader.header.magic = 'STXT';
547 	stxtheader.header.header_size = sizeof(TranslatorStyledTextStreamHeader);
548 	stxtheader.header.data_size = 0;
549 	stxtheader.version = 100;
550 	memcpy(buffer, &stxtheader, stxtheader.header.header_size);
551 
552 	txtheader.header.magic = 'TEXT';
553 	txtheader.header.header_size = sizeof(TranslatorStyledTextTextHeader);
554 	txtheader.header.data_size = text_data_size;
555 	txtheader.charset = B_UNICODE_UTF8;
556 	memcpy(buffer + stxtheader.header.header_size, &txtheader,
557 		txtheader.header.header_size);
558 
559 	// write out headers in Big Endian byte order
560 	result = swap_data(B_UINT32_TYPE, buffer, kHeadersSize,
561 		B_SWAP_HOST_TO_BENDIAN);
562 	if (result == B_OK) {
563 		ssize_t nwritten = 0;
564 		nwritten = outDestination->Write(buffer, kHeadersSize);
565 		if (nwritten != kHeadersSize)
566 			return B_ERROR;
567 		else
568 			return B_OK;
569 	}
570 
571 	return result;
572 }
573 
574 // ---------------------------------------------------------------
575 // output_styles
576 //
577 // Writes out the actual style information into outDestination
578 // using the data from pflatRunArray
579 //
580 // Preconditions:
581 //
582 // Parameters:	outDestination,	where the translated data is
583 //								put
584 //
585 //				text_size,		size in bytes of the text in
586 //								outDestination
587 //
588 //				data_size,		size of pflatRunArray
589 //
590 // Postconditions:
591 //
592 // Returns:
593 //
594 // B_ERROR, if there was an error writing to outDestination or
595 // 	an error with converting the byte order
596 //
597 // B_OK, if all went well
598 // ---------------------------------------------------------------
599 status_t
600 output_styles(BPositionIO *outDestination, uint32 text_size,
601 	uint8 *pflatRunArray, ssize_t data_size)
602 {
603 	const ssize_t kstylsize = sizeof(TranslatorStyledTextStyleHeader);
604 
605 	uint8 buffer[kstylsize];
606 
607 	// output STYL header
608 	TranslatorStyledTextStyleHeader stylheader;
609 	stylheader.header.magic = 'STYL';
610 	stylheader.header.header_size =
611 		sizeof(TranslatorStyledTextStyleHeader);
612 	stylheader.header.data_size = data_size;
613 	stylheader.apply_offset = 0;
614 	stylheader.apply_length = text_size;
615 
616 	memcpy(buffer, &stylheader, kstylsize);
617 	if (swap_data(B_UINT32_TYPE, buffer, kstylsize,
618 		B_SWAP_HOST_TO_BENDIAN) != B_OK)
619 		return B_ERROR;
620 	if (outDestination->Write(buffer, kstylsize) != kstylsize)
621 		return B_ERROR;
622 
623 	// output actual style information
624 	if (outDestination->Write(pflatRunArray,
625 		data_size) != data_size)
626 		return B_ERROR;
627 
628 	return B_OK;
629 }
630 
631 // ---------------------------------------------------------------
632 // translate_from_text
633 //
634 // Convert the plain text (UTF8) from inSource to plain or
635 // styled text in outDestination
636 //
637 // Preconditions:
638 //
639 // Parameters:	inSource,	the data to be translated
640 //
641 //				outDestination,	where the translated data is
642 //								put
643 //
644 //				outType,	the type to convert inSource to
645 //
646 // Postconditions:
647 //
648 // Returns: B_BAD_VALUE, if outType is not supported
649 //
650 // B_NO_MEMORY, if couldn't allocate enough memory to read in
651 // 				the styled text run array
652 //
653 // B_NO_TRANSLATOR, if this translator doesn't understand the data
654 //
655 // B_ERROR, if there was an error reading or writing data or
656 //			converting data
657 //
658 // B_OK, if all went well
659 // ---------------------------------------------------------------
660 status_t
661 translate_from_text(BPositionIO *inSource, BPositionIO *outDestination,
662 	uint32 outType)
663 {
664 	// find the length of the text
665 	off_t size = 0;
666 	size = inSource->Seek(0, SEEK_END);
667 	if (size < 0)
668 		return B_ERROR;
669 
670 	if (inSource->Seek(0, SEEK_SET) != 0)
671 		return B_ERROR;
672 
673 	bool btoplain;
674 	if (outType == B_TRANSLATOR_TEXT)
675 		btoplain = true;
676 	else if (outType == B_STYLED_TEXT_FORMAT)
677 		btoplain = false;
678 	else
679 		return B_BAD_VALUE;
680 
681 	// output styled text headers if outputting
682 	// in the B_STYLED_TEXT_FORMAT
683 	if (!btoplain) {
684 		status_t headresult;
685 		headresult = output_headers(outDestination,
686 			static_cast<uint32>(size));
687 		if (headresult != B_OK)
688 			return headresult;
689 	}
690 
691 	uint8 buffer[READ_BUFFER_SIZE];
692 	ssize_t nread = 0, nwritten = 0;
693 
694 	// output the actual text part of the data
695 	nread = inSource->Read(buffer, READ_BUFFER_SIZE);
696 	while (nread > 0) {
697 		nwritten = outDestination->Write(buffer, nread);
698 		if (nwritten != nread)
699 			return B_ERROR;
700 
701 		nread = inSource->Read(buffer, READ_BUFFER_SIZE);
702 	}
703 
704 	// Read file attributes if outputting styled data
705 	// and inSource is a BFile object
706 	status_t result = B_OK;
707 	if (!btoplain) {
708 		BFile *pfile = NULL;
709 		pfile = dynamic_cast<BFile *>(inSource);
710 		if (pfile) {
711 			const char *kAttrName = "styles";
712 			attr_info info;
713 			if (pfile->GetAttrInfo(kAttrName, &info) == B_OK) {
714 				if (info.type != B_RAW_TYPE)
715 					return B_NO_TRANSLATOR;
716 				if (info.size < 160)
717 					return B_NO_TRANSLATOR;
718 
719 				uint8 *pflatRunArray = new uint8[info.size];
720 				if (pflatRunArray) {
721 					ssize_t amtread = pfile->ReadAttr(kAttrName,
722 						B_RAW_TYPE, 0, pflatRunArray, info.size);
723 
724 					// write style data
725 					if (amtread == info.size) {
726 						result = output_styles(outDestination,
727 							size, pflatRunArray, info.size);
728 					} else
729 						result = B_ERROR;
730 
731 					delete[] pflatRunArray;
732 					pflatRunArray = NULL;
733 
734 				} else
735 					result = B_NO_MEMORY;
736 			}
737 		}
738 	}
739 
740 	return result;
741 }
742 
743 // ---------------------------------------------------------------
744 // Translate
745 //
746 // Translates the data in inSource to the type outType and stores
747 // the translated data in outDestination.
748 //
749 // Preconditions:
750 //
751 // Parameters:	inSource,	the data to be translated
752 //
753 //				inInfo,	hint about the data in inSource (not used)
754 //
755 //				ioExtension,	configuration options for the
756 //								translator
757 //
758 //				outType,	the type to convert inSource to
759 //
760 //				outDestination,	where the translated data is
761 //								put
762 //
763 // Postconditions:
764 //
765 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
766 //
767 // B_NO_TRANSLATOR, if this translator doesn't understand the data
768 //
769 // B_ERROR, if there was an error allocating memory or converting
770 //          data
771 //
772 // B_OK, if all went well
773 // ---------------------------------------------------------------
774 status_t
775 STXTTranslator::Translate(BPositionIO *inSource,
776 		const translator_info *inInfo, BMessage *ioExtension,
777 		uint32 outType, BPositionIO *outDestination)
778 {
779 	if (!outType)
780 		outType = B_TRANSLATOR_TEXT;
781 	if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
782 		return B_NO_TRANSLATOR;
783 
784 	const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
785 	uint8 buffer[DATA_BUFFER_SIZE];
786 	status_t nread = 0, result;
787 	translator_info outInfo;
788 	// Read in the header to determine
789 	// if the data is supported
790 	nread = inSource->Read(buffer, kstxtsize);
791 	if (nread < 0)
792 		return nread;
793 
794 	// read in enough data to fill the stream header
795 	if (nread == kstxtsize) {
796 		TranslatorStyledTextStreamHeader header;
797 		memcpy(&header, buffer, kstxtsize);
798 		if (swap_data(B_UINT32_TYPE, &header, kstxtsize,
799 			B_SWAP_BENDIAN_TO_HOST) != B_OK)
800 			return B_ERROR;
801 
802 		if (header.header.magic == B_STYLED_TEXT_FORMAT &&
803 			header.header.header_size ==
804 			sizeof(TranslatorStyledTextStreamHeader) &&
805 			header.header.data_size == 0 &&
806 			header.version == 100) {
807 
808 			TranslatorStyledTextTextHeader txtheader;
809 			result = identify_stxt_header(header, inSource, &outInfo, outType,
810 				&txtheader);
811 			return translate_from_stxt(inSource, outDestination, outType,
812 				txtheader);
813 		}
814 	}
815 
816 	// if the data is not styled text, check if it is ASCII text
817 	result = identify_txt_header(buffer, nread, inSource, &outInfo, outType);
818 	if (result == B_OK)
819 		return translate_from_text(inSource, outDestination, outType);
820 	else
821 		return result;
822 }
823 
824 BView *
825 STXTTranslator::NewConfigView(TranslatorSettings *settings)
826 {
827 	return new STXTView(BRect(0, 0, 225, 175), "STXTTranslator Settings",
828 		B_FOLLOW_ALL, B_WILL_DRAW, settings);
829 }
830 
831