xref: /haiku/src/add-ons/translators/rtf/RTFTranslator.cpp (revision 0622135673834fe8fb554c0b973651264b9e7baf)
19949213aSStephan Aßmus /*
29949213aSStephan Aßmus  * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
39949213aSStephan Aßmus  * Distributed under the terms of the MIT License.
49949213aSStephan Aßmus  */
59949213aSStephan Aßmus 
69949213aSStephan Aßmus 
79949213aSStephan Aßmus #include "RTFTranslator.h"
828e5604cSJérôme Duval 
928e5604cSJérôme Duval #include <stdio.h>
1028e5604cSJérôme Duval #include <stdlib.h>
1128e5604cSJérôme Duval #include <string.h>
129949213aSStephan Aßmus 
1370d59669SSiarzhuk Zharski #include <Catalog.h>
1428e5604cSJérôme Duval 
1528e5604cSJérôme Duval #include "ConfigView.h"
1628e5604cSJérôme Duval #include "convert.h"
1728e5604cSJérôme Duval #include "RTF.h"
1828e5604cSJérôme Duval 
199949213aSStephan Aßmus 
20546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
21546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "RTFTranslator"
229949213aSStephan Aßmus 
239949213aSStephan Aßmus #define READ_BUFFER_SIZE 2048
249949213aSStephan Aßmus #define DATA_BUFFER_SIZE 64
259949213aSStephan Aßmus 
269949213aSStephan Aßmus 
27fa267963SEzo #define TEXT_IN_QUALITY 0.4
28fa267963SEzo #define TEXT_IN_CAPABILITY 0.6
29fa267963SEzo 
30fa267963SEzo #define STXT_IN_QUALITY 0.5
31fa267963SEzo #define STXT_IN_CAPABILITY 0.5
32fa267963SEzo 
33fa267963SEzo #define RTF_OUT_QUALITY RTF_IN_QUALITY
34fa267963SEzo #define RTF_OUT_CAPABILITY RTF_IN_CAPABILITY
35fa267963SEzo 
369949213aSStephan Aßmus // The input formats that this translator supports.
37bf243977SPhilippe Houdoin static const translation_format sInputFormats[] = {
389949213aSStephan Aßmus 	{
399949213aSStephan Aßmus 		RTF_TEXT_FORMAT,
409949213aSStephan Aßmus 		B_TRANSLATOR_TEXT,
419949213aSStephan Aßmus 		RTF_IN_QUALITY,
429949213aSStephan Aßmus 		RTF_IN_CAPABILITY,
439949213aSStephan Aßmus 		"text/rtf",
449949213aSStephan Aßmus 		"RichTextFormat file"
45fa267963SEzo 	},
46fa267963SEzo 	{
47fa267963SEzo 		B_TRANSLATOR_TEXT,
48fa267963SEzo 		B_TRANSLATOR_TEXT,
49fa267963SEzo 		TEXT_IN_QUALITY,
50fa267963SEzo 		TEXT_IN_CAPABILITY,
51fa267963SEzo 		"text/plain",
52fa267963SEzo 		"Plain text file"
53fa267963SEzo 	},
54fa267963SEzo 	{
55fa267963SEzo 		B_STYLED_TEXT_FORMAT,
56fa267963SEzo 		B_TRANSLATOR_TEXT,
57fa267963SEzo 		STXT_IN_QUALITY,
58fa267963SEzo 		STXT_IN_CAPABILITY,
59fa267963SEzo 		"text/x-vnd.Be-stxt",
60fa267963SEzo 		"Be styled text file"
61bf243977SPhilippe Houdoin 	}
629949213aSStephan Aßmus };
639949213aSStephan Aßmus 
649949213aSStephan Aßmus // The output formats that this translator supports.
65bf243977SPhilippe Houdoin static const translation_format sOutputFormats[] = {
669949213aSStephan Aßmus 	{
679949213aSStephan Aßmus 		B_TRANSLATOR_TEXT,
689949213aSStephan Aßmus 		B_TRANSLATOR_TEXT,
699949213aSStephan Aßmus 		TEXT_OUT_QUALITY,
709949213aSStephan Aßmus 		TEXT_OUT_CAPABILITY,
719949213aSStephan Aßmus 		"text/plain",
729949213aSStephan Aßmus 		"Plain text file"
739949213aSStephan Aßmus 	},
749949213aSStephan Aßmus 	{
759949213aSStephan Aßmus 		B_STYLED_TEXT_FORMAT,
769949213aSStephan Aßmus 		B_TRANSLATOR_TEXT,
779949213aSStephan Aßmus 		STXT_OUT_QUALITY,
789949213aSStephan Aßmus 		STXT_OUT_CAPABILITY,
799949213aSStephan Aßmus 		"text/x-vnd.Be-stxt",
809949213aSStephan Aßmus 		"Be styled text file"
81fa267963SEzo 	},
82fa267963SEzo 	{
83fa267963SEzo 		RTF_TEXT_FORMAT,
84fa267963SEzo 		B_TRANSLATOR_TEXT,
85fa267963SEzo 		RTF_OUT_QUALITY,
86fa267963SEzo 		RTF_OUT_CAPABILITY,
87fa267963SEzo 		"text/rtf",
88fa267963SEzo 		"RichTextFormat file"
899949213aSStephan Aßmus 	}
909949213aSStephan Aßmus };
919949213aSStephan Aßmus 
929949213aSStephan Aßmus 
RTFTranslator()939949213aSStephan Aßmus RTFTranslator::RTFTranslator()
949949213aSStephan Aßmus {
959949213aSStephan Aßmus 	char info[256];
9670d59669SSiarzhuk Zharski 	sprintf(info, B_TRANSLATE("Rich Text Format translator v%d.%d.%d %s"),
9770d59669SSiarzhuk Zharski 		static_cast<int>(B_TRANSLATION_MAJOR_VERSION(RTF_TRANSLATOR_VERSION)),
9870d59669SSiarzhuk Zharski 		static_cast<int>(B_TRANSLATION_MINOR_VERSION(RTF_TRANSLATOR_VERSION)),
9970d59669SSiarzhuk Zharski 		static_cast<int>(B_TRANSLATION_REVISION_VERSION(
10070d59669SSiarzhuk Zharski 			RTF_TRANSLATOR_VERSION)),
1019949213aSStephan Aßmus 		__DATE__);
1029949213aSStephan Aßmus 
1039949213aSStephan Aßmus 	fInfo = strdup(info);
1049949213aSStephan Aßmus }
1059949213aSStephan Aßmus 
1069949213aSStephan Aßmus 
~RTFTranslator()1079949213aSStephan Aßmus RTFTranslator::~RTFTranslator()
1089949213aSStephan Aßmus {
1099949213aSStephan Aßmus 	free(fInfo);
1109949213aSStephan Aßmus }
1119949213aSStephan Aßmus 
1129949213aSStephan Aßmus 
1139949213aSStephan Aßmus const char *
TranslatorName() const1149949213aSStephan Aßmus RTFTranslator::TranslatorName() const
1159949213aSStephan Aßmus {
11670d59669SSiarzhuk Zharski 	return B_TRANSLATE("RTF text files");
1179949213aSStephan Aßmus }
1189949213aSStephan Aßmus 
1199949213aSStephan Aßmus 
1209949213aSStephan Aßmus const char *
TranslatorInfo() const1219949213aSStephan Aßmus RTFTranslator::TranslatorInfo() const
1229949213aSStephan Aßmus {
123e8eb40f7SHumdinger 	return B_TRANSLATE("Rich Text Format translator");
1249949213aSStephan Aßmus }
1259949213aSStephan Aßmus 
1269949213aSStephan Aßmus 
1279949213aSStephan Aßmus int32
TranslatorVersion() const1289949213aSStephan Aßmus RTFTranslator::TranslatorVersion() const
1299949213aSStephan Aßmus {
1309949213aSStephan Aßmus 	return RTF_TRANSLATOR_VERSION;
1319949213aSStephan Aßmus }
1329949213aSStephan Aßmus 
1339949213aSStephan Aßmus 
1349949213aSStephan Aßmus const translation_format *
InputFormats(int32 * _outCount) const1359949213aSStephan Aßmus RTFTranslator::InputFormats(int32 *_outCount) const
1369949213aSStephan Aßmus {
1379949213aSStephan Aßmus 	if (_outCount == NULL)
1389949213aSStephan Aßmus 		return NULL;
1399949213aSStephan Aßmus 
1409949213aSStephan Aßmus 	*_outCount = sizeof(sInputFormats) / sizeof(translation_format);
1419949213aSStephan Aßmus 	return sInputFormats;
1429949213aSStephan Aßmus }
1439949213aSStephan Aßmus 
1449949213aSStephan Aßmus 
1459949213aSStephan Aßmus const translation_format *
OutputFormats(int32 * _outCount) const1469949213aSStephan Aßmus RTFTranslator::OutputFormats(int32 *_outCount) const
1479949213aSStephan Aßmus {
1489949213aSStephan Aßmus 	*_outCount = sizeof(sOutputFormats) / sizeof(translation_format);
1499949213aSStephan Aßmus 	return sOutputFormats;
1509949213aSStephan Aßmus }
1519949213aSStephan Aßmus 
1529949213aSStephan Aßmus 
1539949213aSStephan Aßmus status_t
Identify(BPositionIO * stream,const translation_format * format,BMessage * ioExtension,translator_info * info,uint32 outType)1549949213aSStephan Aßmus RTFTranslator::Identify(BPositionIO *stream,
1559949213aSStephan Aßmus 	const translation_format *format, BMessage *ioExtension,
1569949213aSStephan Aßmus 	translator_info *info, uint32 outType)
1579949213aSStephan Aßmus {
1589949213aSStephan Aßmus 	if (!outType)
1599949213aSStephan Aßmus 		outType = B_TRANSLATOR_TEXT;
160fa267963SEzo 	else if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT
161fa267963SEzo 		&& outType != RTF_TEXT_FORMAT)
1629949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
1639949213aSStephan Aßmus 
164fa267963SEzo 
1659949213aSStephan Aßmus 	RTF::Parser parser(*stream);
1669949213aSStephan Aßmus 	status_t status = parser.Identify();
1679949213aSStephan Aßmus 
168fa267963SEzo 	if (status == B_OK) {
169*06221356SAdrien Destugues 		// Source data is RTF. We can translate to RTF (no-op), plaintext, or
170*06221356SAdrien Destugues 		// styled text.
171*06221356SAdrien Destugues 
1729949213aSStephan Aßmus 		// return information about the data in the stream
1739949213aSStephan Aßmus 		info->type = B_TRANSLATOR_TEXT; //RTF_TEXT_FORMAT;
1749949213aSStephan Aßmus 		info->group = B_TRANSLATOR_TEXT;
1759949213aSStephan Aßmus 		info->quality = RTF_IN_QUALITY;
1769949213aSStephan Aßmus 		info->capability = RTF_IN_CAPABILITY;
177aec33db1SPhilippe Saint-Pierre 		strlcpy(info->name, B_TRANSLATE("RichTextFormat file"),
1783927bd3cSPhilippe Saint-Pierre 			sizeof(info->name));
1799949213aSStephan Aßmus 		strcpy(info->MIME, "text/rtf");
180fa267963SEzo 	} else {
181*06221356SAdrien Destugues 		// Not an RTF file. We can only work with it if we are translating to
182*06221356SAdrien Destugues 		// RTF.
183*06221356SAdrien Destugues 		if (outType != RTF_TEXT_FORMAT)
184*06221356SAdrien Destugues 			return B_NO_TRANSLATOR;
185*06221356SAdrien Destugues 
186fa267963SEzo 		stream->Seek(0, SEEK_SET);
187fa267963SEzo 		TranslatorStyledTextStreamHeader header;
188fa267963SEzo 		stream->Read(&header, sizeof(header));
189fa267963SEzo 		swap_data(B_UINT32_TYPE, &header, sizeof(header),
190fa267963SEzo 			B_SWAP_BENDIAN_TO_HOST);
191fa267963SEzo 		stream->Seek(0, SEEK_SET);
192fa267963SEzo 		if (header.header.magic == B_STYLED_TEXT_FORMAT
193fa267963SEzo 			&& header.header.header_size == (int32)sizeof(header)
194fa267963SEzo 			&& header.header.data_size == 0
195fa267963SEzo 			&& header.version == 100) {
196fa267963SEzo 			info->type = B_STYLED_TEXT_FORMAT;
197fa267963SEzo 			info->group = B_TRANSLATOR_TEXT;
198fa267963SEzo 			info->quality = STXT_IN_QUALITY;
199fa267963SEzo 			info->capability = STXT_IN_CAPABILITY;
200fa267963SEzo 			strlcpy(info->name, B_TRANSLATE("Be style text file"),
201fa267963SEzo 				sizeof(info->name));
202fa267963SEzo 			strcpy(info->MIME, "text/x-vnd.Be-stxt");
203fa267963SEzo 		} else {
204fa267963SEzo 			info->type = B_TRANSLATOR_TEXT;
205fa267963SEzo 			info->group = B_TRANSLATOR_TEXT;
206fa267963SEzo 			info->quality = TEXT_IN_QUALITY;
207fa267963SEzo 			info->capability = TEXT_IN_CAPABILITY;
208fa267963SEzo 			strlcpy(info->name, B_TRANSLATE("Plain text file"),
209fa267963SEzo 				sizeof(info->name));
210fa267963SEzo 			strcpy(info->MIME, "text/plain");
211fa267963SEzo 		}
212fa267963SEzo 	}
2139949213aSStephan Aßmus 	return B_OK;
2149949213aSStephan Aßmus }
2159949213aSStephan Aßmus 
2169949213aSStephan Aßmus 
2179949213aSStephan Aßmus status_t
Translate(BPositionIO * source,const translator_info * inInfo,BMessage * ioExtension,uint32 outType,BPositionIO * target)2189949213aSStephan Aßmus RTFTranslator::Translate(BPositionIO *source,
2199949213aSStephan Aßmus 	const translator_info *inInfo, BMessage *ioExtension,
2209949213aSStephan Aßmus 	uint32 outType, BPositionIO *target)
2219949213aSStephan Aßmus {
2229949213aSStephan Aßmus 	if (target == NULL || source == NULL)
2239949213aSStephan Aßmus 		return B_BAD_VALUE;
2249949213aSStephan Aßmus 
2259949213aSStephan Aßmus 	if (!outType)
2269949213aSStephan Aßmus 		outType = B_TRANSLATOR_TEXT;
227fa267963SEzo 	if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT
228fa267963SEzo 		&& outType != RTF_TEXT_FORMAT)
2299949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
2309949213aSStephan Aßmus 
231fa267963SEzo 	if (strncmp(inInfo->MIME, "text/rtf", 8) == 0) {
2329949213aSStephan Aßmus 		RTF::Parser parser(*source);
2339949213aSStephan Aßmus 
2349949213aSStephan Aßmus 		RTF::Header header;
2359949213aSStephan Aßmus 		status_t status = parser.Parse(header);
2369949213aSStephan Aßmus 		if (status != B_OK)
2379949213aSStephan Aßmus 			return status;
2389949213aSStephan Aßmus 
2399949213aSStephan Aßmus 		if (outType == B_TRANSLATOR_TEXT)
2409949213aSStephan Aßmus 			return convert_to_plain_text(header, *target);
241fa267963SEzo 		else
2429949213aSStephan Aßmus 			return convert_to_stxt(header, *target);
243fa267963SEzo 
244fa267963SEzo 	} else if (inInfo->type == B_TRANSLATOR_TEXT) {
245fa267963SEzo 		return convert_plain_text_to_rtf(*source, *target);
246fa267963SEzo 	} else if (inInfo->type == B_STYLED_TEXT_FORMAT) {
247fa267963SEzo 		return convert_styled_text_to_rtf(source, target);
248fa267963SEzo 	} else
249fa267963SEzo 		return B_BAD_VALUE;
250fa267963SEzo 
2519949213aSStephan Aßmus }
2529949213aSStephan Aßmus 
2539949213aSStephan Aßmus 
2549949213aSStephan Aßmus status_t
MakeConfigurationView(BMessage * ioExtension,BView ** _view,BRect * _extent)25570d59669SSiarzhuk Zharski RTFTranslator::MakeConfigurationView(BMessage *ioExtension, BView **_view,
25670d59669SSiarzhuk Zharski 	BRect *_extent)
2579949213aSStephan Aßmus {
2589949213aSStephan Aßmus 	if (_view == NULL || _extent == NULL)
2599949213aSStephan Aßmus 		return B_BAD_VALUE;
2609949213aSStephan Aßmus 
2619949213aSStephan Aßmus 	BView *view = new ConfigView(BRect(0, 0, 225, 175));
2629949213aSStephan Aßmus 	if (view == NULL)
2639949213aSStephan Aßmus 		return BTranslator::MakeConfigurationView(ioExtension, _view, _extent);
2649949213aSStephan Aßmus 
2659949213aSStephan Aßmus 	*_view = view;
2669949213aSStephan Aßmus 	*_extent = view->Bounds();
2679949213aSStephan Aßmus 	return B_OK;
2689949213aSStephan Aßmus }
2699949213aSStephan Aßmus 
2709949213aSStephan Aßmus 
2719949213aSStephan Aßmus //	#pragma mark -
2729949213aSStephan Aßmus 
2739949213aSStephan Aßmus 
2749949213aSStephan Aßmus BTranslator *
make_nth_translator(int32 n,image_id you,uint32 flags,...)2759949213aSStephan Aßmus make_nth_translator(int32 n, image_id you, uint32 flags, ...)
2769949213aSStephan Aßmus {
2779949213aSStephan Aßmus 	if (n != 0)
2789949213aSStephan Aßmus 		return NULL;
2799949213aSStephan Aßmus 
2809949213aSStephan Aßmus 	return new RTFTranslator();
2819949213aSStephan Aßmus }
2829949213aSStephan Aßmus 
283