xref: /haiku/src/add-ons/translators/stxt/STXTTranslator.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
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 256
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 != sizeof(TranslatorStyledTextTextHeader)
211 		|| txtheader.charset != B_UNICODE_UTF8)
212 		return B_NO_TRANSLATOR;
213 
214 	// skip the text data
215 	off_t seekresult, pos;
216 	pos = header.header.header_size + txtheader.header.header_size
217 		+ txtheader.header.data_size;
218 	seekresult = inSource->Seek(txtheader.header.data_size,
219 		SEEK_CUR);
220 	if (seekresult < pos)
221 		return B_NO_TRANSLATOR;
222 	if (seekresult > pos)
223 		return B_ERROR;
224 
225 	// check the STYL header (not all STXT files have this)
226 	ssize_t read = 0;
227 	TranslatorStyledTextStyleHeader stylheader;
228 	read = inSource->Read(buffer, kstylsize);
229 	if (read < 0)
230 		return read;
231 	if (read != kstylsize && read != 0)
232 		return B_NO_TRANSLATOR;
233 
234 	// If there is a STYL header
235 	if (read == kstylsize) {
236 		memcpy(&stylheader, buffer, kstylsize);
237 		if (swap_data(B_UINT32_TYPE, &stylheader, kstylsize,
238 			B_SWAP_BENDIAN_TO_HOST) != B_OK)
239 			return B_ERROR;
240 
241 		if (stylheader.header.magic != 'STYL'
242 			|| stylheader.header.header_size !=
243 				sizeof(TranslatorStyledTextStyleHeader))
244 			return B_NO_TRANSLATOR;
245 	}
246 
247 	// if output TEXT header is supplied, fill it with data
248 	if (ptxtheader) {
249 		ptxtheader->header.magic = txtheader.header.magic;
250 		ptxtheader->header.header_size = txtheader.header.header_size;
251 		ptxtheader->header.data_size = txtheader.header.data_size;
252 		ptxtheader->charset = txtheader.charset;
253 	}
254 
255 	// return information about the data in the stream
256 	outInfo->type = B_STYLED_TEXT_FORMAT;
257 	outInfo->group = B_TRANSLATOR_TEXT;
258 	outInfo->quality = STXT_IN_QUALITY;
259 	outInfo->capability = STXT_IN_CAPABILITY;
260 	strcpy(outInfo->name, "Be styled text file");
261 	strcpy(outInfo->MIME, "text/x-vnd.Be-stxt");
262 
263 	return B_OK;
264 }
265 
266 
267 static bool
268 valid_utf8_char(const uint8* bytes, size_t& length)
269 {
270 	length = 1;
271 
272 	if (bytes[0] & 0x80) {
273 		if (bytes[0] & 0x40) {
274 			if (bytes[0] & 0x20) {
275 				if (bytes[0] & 0x10) {
276 					if (bytes[0] & 0x08) {
277 						// A five byte char?!
278 						return false;
279 					}
280 
281 					// A four byte char
282 					length = 4;
283 					return true;
284 				}
285 
286 				/* A three byte char */
287 				length = 3;
288 				return true;
289 			}
290 
291 			/* A two byte char */
292 			length = 2;
293 			return true;
294 		}
295 
296 		return false;
297 	}
298 
299 	if (bytes[0] == 0)
300 		return false;
301 
302 	return true;
303 }
304 
305 
306 // ---------------------------------------------------------------
307 // identify_txt_header
308 //
309 // Determines if the data in inSource is of the UTF8 plain
310 // text format.
311 //
312 // Preconditions: data must point to a buffer at least
313 // 				  DATA_BUFFER_SIZE bytes long
314 //
315 // Parameters:	data,		buffer containing data already read
316 //							from the stream
317 //
318 //				nread,		number of bytes that have already
319 //							been read from the stream
320 //
321 //				header,		the STXT stream header read in by
322 //							Identify() or Translate()
323 //
324 //				inSource,	The stream with the STXT data
325 //
326 //				outInfo,	information about the type of data
327 //							from inSource is stored here
328 //
329 //				outType		the desired output type for the
330 //							data in inSource
331 //
332 //
333 // Postconditions:
334 //
335 // Returns: B_OK, if the data appears to be in the STXT format,
336 // B_NO_TRANSLATOR, if the data is not in the STXT format or
337 // returns B_ERROR if errors were encountered in trying to
338 // determine the format
339 // ---------------------------------------------------------------
340 status_t
341 identify_txt_header(uint8 *data, int32 bytesRead,
342 	BPositionIO *inSource, translator_info *outInfo, uint32 outType)
343 {
344 	ssize_t readLater = inSource->Read(data + bytesRead, DATA_BUFFER_SIZE - bytesRead);
345 	if (readLater < 0)
346 		return B_NO_TRANSLATOR;
347 
348 	bytesRead += readLater;
349 	float capability = TEXT_IN_CAPABILITY;
350 	int32 bad = 0;
351 
352 	// TODO: use the same mechanism as the TextSnifferAddon class in the registrar
353 	//	and add support for indicating other character sets as well
354 	for (int32 i = 0; i < bytesRead; i++) {
355 		uint8 c = data[i];
356 		size_t length;
357 
358 		// if any null characters or control characters
359 		// are found, reduce our ability to handle the data
360 		if (c < 0x20
361 			&& c != 0x08	// backspace
362 			&& c != 0x09	// tab
363 			&& c != 0x0A	// line feed
364 			&& c != 0x0C	// form feed
365 			&& c != 0x0D) { // carriage return
366 			bad++;
367 		} else if ((c & 0x80) != 0 && valid_utf8_char(data + i, length)) {
368 			int32 j = 1;
369 			for (; j < (int32)length && i + j < bytesRead; j++) {
370 				if ((data[i + j] & 0xc0) != 0x80) {
371 					bad++;
372 					break;
373 				}
374 			}
375 
376 			i += j - 1;
377 		} else if (c & 0x80)
378 			bad++;
379 	}
380 
381 // TODO: enable me once bug #675 is fixed
382 #if 0
383 	// if more than 1/3 of the characters are bad, we don't accept the text
384 	if (bad > bytesRead / 3)
385 		return B_NO_TRANSLATOR;
386 #endif
387 
388 	capability *= (bytesRead - bad) / (float)bytesRead;
389 
390 	// return information about the data in the stream
391 	outInfo->type = B_TRANSLATOR_TEXT;
392 	outInfo->group = B_TRANSLATOR_TEXT;
393 	outInfo->quality = TEXT_IN_QUALITY;
394 	outInfo->capability = capability;
395 	strcpy(outInfo->name, "Plain text file");
396 	strcpy(outInfo->MIME, "text/plain");
397 
398 	return B_OK;
399 }
400 
401 // ---------------------------------------------------------------
402 // Identify
403 //
404 // Examines the data from inSource and determines if it is in a
405 // format that this translator knows how to work with.
406 //
407 // Preconditions:
408 //
409 // Parameters:	inSource,	where the data to examine is
410 //
411 //				inFormat,	a hint about the data in inSource,
412 //							it is ignored since it is only a hint
413 //
414 //				ioExtension,	configuration settings for the
415 //								translator (not used)
416 //
417 //				outInfo,	information about what data is in
418 //							inSource and how well this translator
419 //							can handle that data is stored here
420 //
421 //				outType,	The format that the user wants
422 //							the data in inSource to be
423 //							converted to
424 //
425 // Postconditions:
426 //
427 // Returns: B_NO_TRANSLATOR,	if this translator can't handle
428 //								the data in inSource
429 //
430 // B_ERROR,	if there was an error converting the data to the host
431 //			format
432 //
433 // B_BAD_VALUE, if the settings in ioExtension are bad
434 //
435 // B_OK,	if this translator understand the data and there were
436 //			no errors found
437 //
438 // Other errors if BPositionIO::Read() returned an error value
439 // ---------------------------------------------------------------
440 status_t
441 STXTTranslator::Identify(BPositionIO *inSource,
442 	const translation_format *inFormat, BMessage *ioExtension,
443 	translator_info *outInfo, uint32 outType)
444 {
445 	if (!outType)
446 		outType = B_TRANSLATOR_TEXT;
447 	if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
448 		return B_NO_TRANSLATOR;
449 
450 	const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
451 
452 	uint8 buffer[DATA_BUFFER_SIZE];
453 	status_t nread = 0;
454 	// Read in the header to determine
455 	// if the data is supported
456 	nread = inSource->Read(buffer, kstxtsize);
457 	if (nread < 0)
458 		return nread;
459 
460 	// read in enough data to fill the stream header
461 	if (nread == kstxtsize) {
462 		TranslatorStyledTextStreamHeader header;
463 		memcpy(&header, buffer, kstxtsize);
464 		if (swap_data(B_UINT32_TYPE, &header, kstxtsize,
465 				B_SWAP_BENDIAN_TO_HOST) != B_OK)
466 			return B_ERROR;
467 
468 		if (header.header.magic == B_STYLED_TEXT_FORMAT
469 			&& header.header.header_size == (int32)kstxtsize
470 			&& header.header.data_size == 0
471 			&& header.version == 100)
472 			return identify_stxt_header(header, inSource, outInfo, outType);
473 	}
474 
475 	// if the data is not styled text, check if it is plain text
476 	return identify_txt_header(buffer, nread, inSource, outInfo, outType);
477 }
478 
479 // ---------------------------------------------------------------
480 // translate_from_stxt
481 //
482 // Translates the data in inSource to the type outType and stores
483 // the translated data in outDestination.
484 //
485 // Preconditions:
486 //
487 // Parameters:	inSource,	the data to be translated
488 //
489 //				outDestination,	where the translated data is
490 //								put
491 //
492 //				outType,	the type to convert inSource to
493 //
494 //				txtheader, 	the TEXT header from inSource
495 //
496 //
497 // Postconditions:
498 //
499 // Returns: B_BAD_VALUE, if outType is invalid
500 //
501 // B_NO_TRANSLATOR, if this translator doesn't understand the data
502 //
503 // B_ERROR, if there was an error allocating memory or converting
504 //          data
505 //
506 // B_OK, if all went well
507 // ---------------------------------------------------------------
508 status_t
509 translate_from_stxt(BPositionIO *inSource, BPositionIO *outDestination,
510 		uint32 outType, const TranslatorStyledTextTextHeader &txtheader)
511 {
512 	if (inSource->Seek(0, SEEK_SET) != 0)
513 		return B_ERROR;
514 
515 	const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
516 	const ssize_t ktxtsize = sizeof(TranslatorStyledTextTextHeader);
517 
518 	bool btoplain;
519 	if (outType == B_TRANSLATOR_TEXT)
520 		btoplain = true;
521 	else if (outType == B_STYLED_TEXT_FORMAT)
522 		btoplain = false;
523 	else
524 		return B_BAD_VALUE;
525 
526 	uint8 buffer[READ_BUFFER_SIZE];
527 	ssize_t nread = 0, nwritten = 0, nreed = 0, ntotalread = 0;
528 
529 	// skip to the actual text data when outputting a
530 	// plain text file
531 	if (btoplain) {
532 		if (inSource->Seek(kstxtsize + ktxtsize, SEEK_CUR) !=
533 			kstxtsize + ktxtsize)
534 			return B_ERROR;
535 	}
536 
537 	// Read data from inSource
538 	// When outputing B_TRANSLATOR_TEXT, the loop stops when all of
539 	// the text data has been read and written.
540 	// When outputting B_STYLED_TEXT_FORMAT, the loop stops when all
541 	// of the data from inSource has been read and written.
542 	if (btoplain)
543 		nreed = min(READ_BUFFER_SIZE,
544 			txtheader.header.data_size - ntotalread);
545 	else
546 		nreed = READ_BUFFER_SIZE;
547 	nread = inSource->Read(buffer, nreed);
548 	while (nread > 0) {
549 		nwritten = outDestination->Write(buffer, nread);
550 		if (nwritten != nread)
551 			return B_ERROR;
552 
553 		if (btoplain) {
554 			ntotalread += nread;
555 			nreed = min(READ_BUFFER_SIZE,
556 				txtheader.header.data_size - ntotalread);
557 		} else
558 			nreed = READ_BUFFER_SIZE;
559 		nread = inSource->Read(buffer, nreed);
560 	}
561 
562 	if (btoplain && static_cast<ssize_t>(txtheader.header.data_size) !=
563 		ntotalread)
564 		// If not all of the text data was able to be read...
565 		return B_NO_TRANSLATOR;
566 	else
567 		return B_OK;
568 }
569 
570 // ---------------------------------------------------------------
571 // output_headers
572 //
573 // Outputs the Stream and Text headers from the B_STYLED_TEXT_FORMAT
574 // to outDestination, setting the data_size member of the text header
575 // to text_data_size
576 //
577 // Preconditions:
578 //
579 // Parameters:	outDestination,	where the translated data is
580 //								put
581 //
582 //				text_data_size, number of bytes in data section
583 //							    of the TEXT header
584 //
585 //
586 // Postconditions:
587 //
588 // Returns:
589 //
590 // B_ERROR, if there was an error writing to outDestination or
591 // 	an error with converting the byte order
592 //
593 // B_OK, if all went well
594 // ---------------------------------------------------------------
595 status_t
596 output_headers(BPositionIO *outDestination, uint32 text_data_size)
597 {
598 	const int32 kHeadersSize = sizeof(TranslatorStyledTextStreamHeader) +
599 		sizeof(TranslatorStyledTextTextHeader);
600 	status_t result;
601 	TranslatorStyledTextStreamHeader stxtheader;
602 	TranslatorStyledTextTextHeader txtheader;
603 
604 	uint8 buffer[kHeadersSize];
605 
606 	stxtheader.header.magic = 'STXT';
607 	stxtheader.header.header_size = sizeof(TranslatorStyledTextStreamHeader);
608 	stxtheader.header.data_size = 0;
609 	stxtheader.version = 100;
610 	memcpy(buffer, &stxtheader, stxtheader.header.header_size);
611 
612 	txtheader.header.magic = 'TEXT';
613 	txtheader.header.header_size = sizeof(TranslatorStyledTextTextHeader);
614 	txtheader.header.data_size = text_data_size;
615 	txtheader.charset = B_UNICODE_UTF8;
616 	memcpy(buffer + stxtheader.header.header_size, &txtheader,
617 		txtheader.header.header_size);
618 
619 	// write out headers in Big Endian byte order
620 	result = swap_data(B_UINT32_TYPE, buffer, kHeadersSize,
621 		B_SWAP_HOST_TO_BENDIAN);
622 	if (result == B_OK) {
623 		ssize_t nwritten = 0;
624 		nwritten = outDestination->Write(buffer, kHeadersSize);
625 		if (nwritten != kHeadersSize)
626 			return B_ERROR;
627 		else
628 			return B_OK;
629 	}
630 
631 	return result;
632 }
633 
634 // ---------------------------------------------------------------
635 // output_styles
636 //
637 // Writes out the actual style information into outDestination
638 // using the data from pflatRunArray
639 //
640 // Preconditions:
641 //
642 // Parameters:	outDestination,	where the translated data is
643 //								put
644 //
645 //				text_size,		size in bytes of the text in
646 //								outDestination
647 //
648 //				data_size,		size of pflatRunArray
649 //
650 // Postconditions:
651 //
652 // Returns:
653 //
654 // B_ERROR, if there was an error writing to outDestination or
655 // 	an error with converting the byte order
656 //
657 // B_OK, if all went well
658 // ---------------------------------------------------------------
659 status_t
660 output_styles(BPositionIO *outDestination, uint32 text_size,
661 	uint8 *pflatRunArray, ssize_t data_size)
662 {
663 	const ssize_t kstylsize = sizeof(TranslatorStyledTextStyleHeader);
664 
665 	uint8 buffer[kstylsize];
666 
667 	// output STYL header
668 	TranslatorStyledTextStyleHeader stylheader;
669 	stylheader.header.magic = 'STYL';
670 	stylheader.header.header_size =
671 		sizeof(TranslatorStyledTextStyleHeader);
672 	stylheader.header.data_size = data_size;
673 	stylheader.apply_offset = 0;
674 	stylheader.apply_length = text_size;
675 
676 	memcpy(buffer, &stylheader, kstylsize);
677 	if (swap_data(B_UINT32_TYPE, buffer, kstylsize,
678 		B_SWAP_HOST_TO_BENDIAN) != B_OK)
679 		return B_ERROR;
680 	if (outDestination->Write(buffer, kstylsize) != kstylsize)
681 		return B_ERROR;
682 
683 	// output actual style information
684 	if (outDestination->Write(pflatRunArray,
685 		data_size) != data_size)
686 		return B_ERROR;
687 
688 	return B_OK;
689 }
690 
691 // ---------------------------------------------------------------
692 // translate_from_text
693 //
694 // Convert the plain text (UTF8) from inSource to plain or
695 // styled text in outDestination
696 //
697 // Preconditions:
698 //
699 // Parameters:	inSource,	the data to be translated
700 //
701 //				outDestination,	where the translated data is
702 //								put
703 //
704 //				outType,	the type to convert inSource to
705 //
706 // Postconditions:
707 //
708 // Returns: B_BAD_VALUE, if outType is not supported
709 //
710 // B_NO_MEMORY, if couldn't allocate enough memory to read in
711 // 				the styled text run array
712 //
713 // B_NO_TRANSLATOR, if this translator doesn't understand the data
714 //
715 // B_ERROR, if there was an error reading or writing data or
716 //			converting data
717 //
718 // B_OK, if all went well
719 // ---------------------------------------------------------------
720 status_t
721 translate_from_text(BPositionIO *inSource, BPositionIO *outDestination,
722 	uint32 outType)
723 {
724 	// find the length of the text
725 	off_t size = 0;
726 	size = inSource->Seek(0, SEEK_END);
727 	if (size < 0)
728 		return B_ERROR;
729 
730 	if (inSource->Seek(0, SEEK_SET) != 0)
731 		return B_ERROR;
732 
733 	bool btoplain;
734 	if (outType == B_TRANSLATOR_TEXT)
735 		btoplain = true;
736 	else if (outType == B_STYLED_TEXT_FORMAT)
737 		btoplain = false;
738 	else
739 		return B_BAD_VALUE;
740 
741 	// output styled text headers if outputting
742 	// in the B_STYLED_TEXT_FORMAT
743 	if (!btoplain) {
744 		status_t headresult;
745 		headresult = output_headers(outDestination,
746 			static_cast<uint32>(size));
747 		if (headresult != B_OK)
748 			return headresult;
749 	}
750 
751 	uint8 buffer[READ_BUFFER_SIZE];
752 	ssize_t nread = 0, nwritten = 0;
753 
754 	// output the actual text part of the data
755 	nread = inSource->Read(buffer, READ_BUFFER_SIZE);
756 	while (nread > 0) {
757 		nwritten = outDestination->Write(buffer, nread);
758 		if (nwritten != nread)
759 			return B_ERROR;
760 
761 		nread = inSource->Read(buffer, READ_BUFFER_SIZE);
762 	}
763 
764 	// Read file attributes if outputting styled data
765 	// and inSource is a BFile object
766 	status_t result = B_OK;
767 	if (!btoplain) {
768 		BFile *pfile = NULL;
769 		pfile = dynamic_cast<BFile *>(inSource);
770 		if (pfile) {
771 			const char *kAttrName = "styles";
772 			attr_info info;
773 			if (pfile->GetAttrInfo(kAttrName, &info) == B_OK) {
774 				if (info.type != B_RAW_TYPE)
775 					return B_NO_TRANSLATOR;
776 				if (info.size < 160)
777 					return B_NO_TRANSLATOR;
778 
779 				uint8 *pflatRunArray = new uint8[info.size];
780 				if (pflatRunArray) {
781 					ssize_t amtread = pfile->ReadAttr(kAttrName,
782 						B_RAW_TYPE, 0, pflatRunArray, info.size);
783 
784 					// write style data
785 					if (amtread == info.size) {
786 						result = output_styles(outDestination,
787 							size, pflatRunArray, info.size);
788 					} else
789 						result = B_ERROR;
790 
791 					delete[] pflatRunArray;
792 					pflatRunArray = NULL;
793 
794 				} else
795 					result = B_NO_MEMORY;
796 			}
797 		}
798 	}
799 
800 	return result;
801 }
802 
803 // ---------------------------------------------------------------
804 // Translate
805 //
806 // Translates the data in inSource to the type outType and stores
807 // the translated data in outDestination.
808 //
809 // Preconditions:
810 //
811 // Parameters:	inSource,	the data to be translated
812 //
813 //				inInfo,	hint about the data in inSource (not used)
814 //
815 //				ioExtension,	configuration options for the
816 //								translator
817 //
818 //				outType,	the type to convert inSource to
819 //
820 //				outDestination,	where the translated data is
821 //								put
822 //
823 // Postconditions:
824 //
825 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
826 //
827 // B_NO_TRANSLATOR, if this translator doesn't understand the data
828 //
829 // B_ERROR, if there was an error allocating memory or converting
830 //          data
831 //
832 // B_OK, if all went well
833 // ---------------------------------------------------------------
834 status_t
835 STXTTranslator::Translate(BPositionIO *inSource,
836 		const translator_info *inInfo, BMessage *ioExtension,
837 		uint32 outType, BPositionIO *outDestination)
838 {
839 	if (!outType)
840 		outType = B_TRANSLATOR_TEXT;
841 	if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
842 		return B_NO_TRANSLATOR;
843 
844 	const ssize_t kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
845 	uint8 buffer[DATA_BUFFER_SIZE];
846 	status_t nread = 0, result;
847 	translator_info outInfo;
848 	// Read in the header to determine
849 	// if the data is supported
850 	nread = inSource->Read(buffer, kstxtsize);
851 	if (nread < 0)
852 		return nread;
853 
854 	// read in enough data to fill the stream header
855 	if (nread == kstxtsize) {
856 		TranslatorStyledTextStreamHeader header;
857 		memcpy(&header, buffer, kstxtsize);
858 		if (swap_data(B_UINT32_TYPE, &header, kstxtsize,
859 			B_SWAP_BENDIAN_TO_HOST) != B_OK)
860 			return B_ERROR;
861 
862 		if (header.header.magic == B_STYLED_TEXT_FORMAT &&
863 			header.header.header_size ==
864 			sizeof(TranslatorStyledTextStreamHeader) &&
865 			header.header.data_size == 0 &&
866 			header.version == 100) {
867 
868 			TranslatorStyledTextTextHeader txtheader;
869 			result = identify_stxt_header(header, inSource, &outInfo, outType,
870 				&txtheader);
871 			return translate_from_stxt(inSource, outDestination, outType,
872 				txtheader);
873 		}
874 	}
875 
876 	// if the data is not styled text, check if it is ASCII text
877 	result = identify_txt_header(buffer, nread, inSource, &outInfo, outType);
878 	if (result == B_OK)
879 		return translate_from_text(inSource, outDestination, outType);
880 	else
881 		return result;
882 }
883 
884 BView *
885 STXTTranslator::NewConfigView(TranslatorSettings *settings)
886 {
887 	return new STXTView(BRect(0, 0, 225, 175), "STXTTranslator Settings",
888 		B_FOLLOW_ALL, B_WILL_DRAW, settings);
889 }
890 
891