1/*
2 * Copyright 2004-2005, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "RTFTranslator.h"
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include <Catalog.h>
14
15#include "ConfigView.h"
16#include "convert.h"
17#include "RTF.h"
18
19
20#undef B_TRANSLATION_CONTEXT
21#define B_TRANSLATION_CONTEXT "RTFTranslator"
22
23#define READ_BUFFER_SIZE 2048
24#define DATA_BUFFER_SIZE 64
25
26
27#define TEXT_IN_QUALITY 0.4
28#define TEXT_IN_CAPABILITY 0.6
29
30#define STXT_IN_QUALITY 0.5
31#define STXT_IN_CAPABILITY 0.5
32
33#define RTF_OUT_QUALITY RTF_IN_QUALITY
34#define RTF_OUT_CAPABILITY RTF_IN_CAPABILITY
35
36// The input formats that this translator supports.
37static const translation_format sInputFormats[] = {
38	{
39		RTF_TEXT_FORMAT,
40		B_TRANSLATOR_TEXT,
41		RTF_IN_QUALITY,
42		RTF_IN_CAPABILITY,
43		"text/rtf",
44		"RichTextFormat file"
45	},
46	{
47		B_TRANSLATOR_TEXT,
48		B_TRANSLATOR_TEXT,
49		TEXT_IN_QUALITY,
50		TEXT_IN_CAPABILITY,
51		"text/plain",
52		"Plain text file"
53	},
54	{
55		B_STYLED_TEXT_FORMAT,
56		B_TRANSLATOR_TEXT,
57		STXT_IN_QUALITY,
58		STXT_IN_CAPABILITY,
59		"text/x-vnd.Be-stxt",
60		"Be styled text file"
61	}
62};
63
64// The output formats that this translator supports.
65static const translation_format sOutputFormats[] = {
66	{
67		B_TRANSLATOR_TEXT,
68		B_TRANSLATOR_TEXT,
69		TEXT_OUT_QUALITY,
70		TEXT_OUT_CAPABILITY,
71		"text/plain",
72		"Plain text file"
73	},
74	{
75		B_STYLED_TEXT_FORMAT,
76		B_TRANSLATOR_TEXT,
77		STXT_OUT_QUALITY,
78		STXT_OUT_CAPABILITY,
79		"text/x-vnd.Be-stxt",
80		"Be styled text file"
81	},
82	{
83		RTF_TEXT_FORMAT,
84		B_TRANSLATOR_TEXT,
85		RTF_OUT_QUALITY,
86		RTF_OUT_CAPABILITY,
87		"text/rtf",
88		"RichTextFormat file"
89	}
90};
91
92
93RTFTranslator::RTFTranslator()
94{
95	char info[256];
96	sprintf(info, B_TRANSLATE("Rich Text Format translator v%d.%d.%d %s"),
97		static_cast<int>(B_TRANSLATION_MAJOR_VERSION(RTF_TRANSLATOR_VERSION)),
98		static_cast<int>(B_TRANSLATION_MINOR_VERSION(RTF_TRANSLATOR_VERSION)),
99		static_cast<int>(B_TRANSLATION_REVISION_VERSION(
100			RTF_TRANSLATOR_VERSION)),
101		__DATE__);
102
103	fInfo = strdup(info);
104}
105
106
107RTFTranslator::~RTFTranslator()
108{
109	free(fInfo);
110}
111
112
113const char *
114RTFTranslator::TranslatorName() const
115{
116	return B_TRANSLATE("RTF text files");
117}
118
119
120const char *
121RTFTranslator::TranslatorInfo() const
122{
123	return B_TRANSLATE("Rich Text Format translator");
124}
125
126
127int32
128RTFTranslator::TranslatorVersion() const
129{
130	return RTF_TRANSLATOR_VERSION;
131}
132
133
134const translation_format *
135RTFTranslator::InputFormats(int32 *_outCount) const
136{
137	if (_outCount == NULL)
138		return NULL;
139
140	*_outCount = sizeof(sInputFormats) / sizeof(translation_format);
141	return sInputFormats;
142}
143
144
145const translation_format *
146RTFTranslator::OutputFormats(int32 *_outCount) const
147{
148	*_outCount = sizeof(sOutputFormats) / sizeof(translation_format);
149	return sOutputFormats;
150}
151
152
153status_t
154RTFTranslator::Identify(BPositionIO *stream,
155	const translation_format *format, BMessage *ioExtension,
156	translator_info *info, uint32 outType)
157{
158	if (!outType)
159		outType = B_TRANSLATOR_TEXT;
160	else if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT
161		&& outType != RTF_TEXT_FORMAT)
162		return B_NO_TRANSLATOR;
163
164
165	RTF::Parser parser(*stream);
166	status_t status = parser.Identify();
167
168	if (status == B_OK) {
169		// Source data is RTF. We can translate to RTF (no-op), plaintext, or
170		// styled text.
171
172		// return information about the data in the stream
173		info->type = B_TRANSLATOR_TEXT; //RTF_TEXT_FORMAT;
174		info->group = B_TRANSLATOR_TEXT;
175		info->quality = RTF_IN_QUALITY;
176		info->capability = RTF_IN_CAPABILITY;
177		strlcpy(info->name, B_TRANSLATE("RichTextFormat file"),
178			sizeof(info->name));
179		strcpy(info->MIME, "text/rtf");
180	} else {
181		// Not an RTF file. We can only work with it if we are translating to
182		// RTF.
183		if (outType != RTF_TEXT_FORMAT)
184			return B_NO_TRANSLATOR;
185
186		stream->Seek(0, SEEK_SET);
187		TranslatorStyledTextStreamHeader header;
188		stream->Read(&header, sizeof(header));
189		swap_data(B_UINT32_TYPE, &header, sizeof(header),
190			B_SWAP_BENDIAN_TO_HOST);
191		stream->Seek(0, SEEK_SET);
192		if (header.header.magic == B_STYLED_TEXT_FORMAT
193			&& header.header.header_size == (int32)sizeof(header)
194			&& header.header.data_size == 0
195			&& header.version == 100) {
196			info->type = B_STYLED_TEXT_FORMAT;
197			info->group = B_TRANSLATOR_TEXT;
198			info->quality = STXT_IN_QUALITY;
199			info->capability = STXT_IN_CAPABILITY;
200			strlcpy(info->name, B_TRANSLATE("Be style text file"),
201				sizeof(info->name));
202			strcpy(info->MIME, "text/x-vnd.Be-stxt");
203		} else {
204			info->type = B_TRANSLATOR_TEXT;
205			info->group = B_TRANSLATOR_TEXT;
206			info->quality = TEXT_IN_QUALITY;
207			info->capability = TEXT_IN_CAPABILITY;
208			strlcpy(info->name, B_TRANSLATE("Plain text file"),
209				sizeof(info->name));
210			strcpy(info->MIME, "text/plain");
211		}
212	}
213	return B_OK;
214}
215
216
217status_t
218RTFTranslator::Translate(BPositionIO *source,
219	const translator_info *inInfo, BMessage *ioExtension,
220	uint32 outType, BPositionIO *target)
221{
222	if (target == NULL || source == NULL)
223		return B_BAD_VALUE;
224
225	if (!outType)
226		outType = B_TRANSLATOR_TEXT;
227	if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT
228		&& outType != RTF_TEXT_FORMAT)
229		return B_NO_TRANSLATOR;
230
231	if (strncmp(inInfo->MIME, "text/rtf", 8) == 0) {
232		RTF::Parser parser(*source);
233
234		RTF::Header header;
235		status_t status = parser.Parse(header);
236		if (status != B_OK)
237			return status;
238
239		if (outType == B_TRANSLATOR_TEXT)
240			return convert_to_plain_text(header, *target);
241		else
242			return convert_to_stxt(header, *target);
243
244	} else if (inInfo->type == B_TRANSLATOR_TEXT) {
245		return convert_plain_text_to_rtf(*source, *target);
246	} else if (inInfo->type == B_STYLED_TEXT_FORMAT) {
247		return convert_styled_text_to_rtf(source, target);
248	} else
249		return B_BAD_VALUE;
250
251}
252
253
254status_t
255RTFTranslator::MakeConfigurationView(BMessage *ioExtension, BView **_view,
256	BRect *_extent)
257{
258	if (_view == NULL || _extent == NULL)
259		return B_BAD_VALUE;
260
261	BView *view = new ConfigView(BRect(0, 0, 225, 175));
262	if (view == NULL)
263		return BTranslator::MakeConfigurationView(ioExtension, _view, _extent);
264
265	*_view = view;
266	*_extent = view->Bounds();
267	return B_OK;
268}
269
270
271//	#pragma mark -
272
273
274BTranslator *
275make_nth_translator(int32 n, image_id you, uint32 flags, ...)
276{
277	if (n != 0)
278		return NULL;
279
280	return new RTFTranslator();
281}
282
283