xref: /haiku/src/add-ons/translators/rtf/RTF.cpp (revision 9949213a25979d177b420bc71891c2bff02a331d)
1*9949213aSStephan Aßmus /*
2*9949213aSStephan Aßmus  * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3*9949213aSStephan Aßmus  * Distributed under the terms of the MIT License.
4*9949213aSStephan Aßmus  */
5*9949213aSStephan Aßmus 
6*9949213aSStephan Aßmus 
7*9949213aSStephan Aßmus #include "RTF.h"
8*9949213aSStephan Aßmus 
9*9949213aSStephan Aßmus #include <DataIO.h>
10*9949213aSStephan Aßmus 
11*9949213aSStephan Aßmus #include <stdlib.h>
12*9949213aSStephan Aßmus #include <stdio.h>
13*9949213aSStephan Aßmus #include <string.h>
14*9949213aSStephan Aßmus #include <ctype.h>
15*9949213aSStephan Aßmus 
16*9949213aSStephan Aßmus 
17*9949213aSStephan Aßmus static const char *kDestinationControlWords[] = {
18*9949213aSStephan Aßmus 	"aftncn", "aftnsep", "aftnsepc", "annotation", "atnauthor", "atndate",
19*9949213aSStephan Aßmus 	"atnicn", "atnid", "atnparent", "atnref", "atntime", "atrfend",
20*9949213aSStephan Aßmus 	"atrfstart", "author", "background", "bkmkend", "buptim", "colortbl",
21*9949213aSStephan Aßmus 	"comment", "creatim", "do", "doccomm", "docvar", "fonttbl", "footer",
22*9949213aSStephan Aßmus 	"footerf", "footerl", "footerr", "footnote", "ftncn", "ftnsep",
23*9949213aSStephan Aßmus 	"ftnsepc", "header", "headerf", "headerl", "headerr", "info",
24*9949213aSStephan Aßmus 	"keywords", "operator", "pict", "printim", "private1", "revtim",
25*9949213aSStephan Aßmus 	"rxe", "stylesheet", "subject", "tc", "title", "txe", "xe",
26*9949213aSStephan Aßmus };
27*9949213aSStephan Aßmus 
28*9949213aSStephan Aßmus static char read_char(BDataIO &stream, bool endOfFileAllowed = false) throw (status_t);
29*9949213aSStephan Aßmus static int32 parse_integer(char first, BDataIO &stream, char &_last, int32 base = 10) throw (status_t);
30*9949213aSStephan Aßmus 
31*9949213aSStephan Aßmus 
32*9949213aSStephan Aßmus using namespace RTF;
33*9949213aSStephan Aßmus 
34*9949213aSStephan Aßmus 
35*9949213aSStephan Aßmus static char
36*9949213aSStephan Aßmus read_char(BDataIO &stream, bool endOfFileAllowed) throw (status_t)
37*9949213aSStephan Aßmus {
38*9949213aSStephan Aßmus 	char c;
39*9949213aSStephan Aßmus 	ssize_t bytesRead = stream.Read(&c, 1);
40*9949213aSStephan Aßmus 
41*9949213aSStephan Aßmus 	if (bytesRead < B_OK)
42*9949213aSStephan Aßmus 		throw (status_t)bytesRead;
43*9949213aSStephan Aßmus 
44*9949213aSStephan Aßmus 	if (bytesRead == 0 && !endOfFileAllowed)
45*9949213aSStephan Aßmus 		throw (status_t)B_ERROR;
46*9949213aSStephan Aßmus 
47*9949213aSStephan Aßmus 	return c;
48*9949213aSStephan Aßmus }
49*9949213aSStephan Aßmus 
50*9949213aSStephan Aßmus 
51*9949213aSStephan Aßmus static int32
52*9949213aSStephan Aßmus parse_integer(char first, BDataIO &stream, char &_last, int32 base) throw (status_t)
53*9949213aSStephan Aßmus {
54*9949213aSStephan Aßmus 	const char *kDigits = "0123456789abcdef";
55*9949213aSStephan Aßmus 	int32 integer = 0;
56*9949213aSStephan Aßmus 	int32 count = 0;
57*9949213aSStephan Aßmus 
58*9949213aSStephan Aßmus 	char digit = first;
59*9949213aSStephan Aßmus 
60*9949213aSStephan Aßmus 	if (digit == '\0')
61*9949213aSStephan Aßmus 		digit = read_char(stream);
62*9949213aSStephan Aßmus 
63*9949213aSStephan Aßmus 	while (true) {
64*9949213aSStephan Aßmus 		int32 pos = 0;
65*9949213aSStephan Aßmus 		for (; pos < base; pos++) {
66*9949213aSStephan Aßmus 			if (kDigits[pos] == digit) {
67*9949213aSStephan Aßmus 				integer = integer * base + pos;
68*9949213aSStephan Aßmus 				count++;
69*9949213aSStephan Aßmus 				break;
70*9949213aSStephan Aßmus 			}
71*9949213aSStephan Aßmus 		}
72*9949213aSStephan Aßmus 		if (pos == base) {
73*9949213aSStephan Aßmus 			_last = digit;
74*9949213aSStephan Aßmus 			goto out;
75*9949213aSStephan Aßmus 		}
76*9949213aSStephan Aßmus 
77*9949213aSStephan Aßmus 		digit = read_char(stream);
78*9949213aSStephan Aßmus 	}
79*9949213aSStephan Aßmus 
80*9949213aSStephan Aßmus out:
81*9949213aSStephan Aßmus 	if (count == 0)
82*9949213aSStephan Aßmus 		throw (status_t)B_BAD_TYPE;
83*9949213aSStephan Aßmus 
84*9949213aSStephan Aßmus 	return integer;
85*9949213aSStephan Aßmus }
86*9949213aSStephan Aßmus 
87*9949213aSStephan Aßmus 
88*9949213aSStephan Aßmus static int
89*9949213aSStephan Aßmus string_array_compare(const char *key, const char **array)
90*9949213aSStephan Aßmus {
91*9949213aSStephan Aßmus 	return strcmp(key, array[0]);
92*9949213aSStephan Aßmus }
93*9949213aSStephan Aßmus 
94*9949213aSStephan Aßmus 
95*9949213aSStephan Aßmus static void
96*9949213aSStephan Aßmus dump(Element &element, int32 level = 0)
97*9949213aSStephan Aßmus {
98*9949213aSStephan Aßmus 	printf("%03ld (%p):", level, &element);
99*9949213aSStephan Aßmus 	for (int32 i = 0; i < level; i++)
100*9949213aSStephan Aßmus 		printf("  ");
101*9949213aSStephan Aßmus 
102*9949213aSStephan Aßmus 	if (RTF::Header *header = dynamic_cast<RTF::Header *>(&element)) {
103*9949213aSStephan Aßmus 		printf("<RTF header, major version %ld>\n", header->Version());
104*9949213aSStephan Aßmus 	} else if (RTF::Command *command = dynamic_cast<RTF::Command *>(&element)) {
105*9949213aSStephan Aßmus 		printf("<Command: %s", command->Name());
106*9949213aSStephan Aßmus 		if (command->HasOption())
107*9949213aSStephan Aßmus 			printf(", Option %ld", command->Option());
108*9949213aSStephan Aßmus 		puts(">");
109*9949213aSStephan Aßmus 	} else if (RTF::Text *text = dynamic_cast<RTF::Text *>(&element)) {
110*9949213aSStephan Aßmus 		printf("<Text>");
111*9949213aSStephan Aßmus 		puts(text->String());
112*9949213aSStephan Aßmus 	} else if (RTF::Group *group = dynamic_cast<RTF::Group *>(&element))
113*9949213aSStephan Aßmus 		printf("<Group \"%s\">\n", group->Name());
114*9949213aSStephan Aßmus 
115*9949213aSStephan Aßmus 	if (RTF::Group *group = dynamic_cast<RTF::Group *>(&element)) {
116*9949213aSStephan Aßmus 		for (uint32 i = 0; i < group->CountElements(); i++)
117*9949213aSStephan Aßmus 			dump(*group->ElementAt(i), level + 1);
118*9949213aSStephan Aßmus 	}
119*9949213aSStephan Aßmus }
120*9949213aSStephan Aßmus 
121*9949213aSStephan Aßmus 
122*9949213aSStephan Aßmus //	#pragma mark -
123*9949213aSStephan Aßmus 
124*9949213aSStephan Aßmus 
125*9949213aSStephan Aßmus Parser::Parser(BPositionIO &stream)
126*9949213aSStephan Aßmus 	:
127*9949213aSStephan Aßmus 	fStream(&stream, 65536, false),
128*9949213aSStephan Aßmus 	fIdentified(false)
129*9949213aSStephan Aßmus {
130*9949213aSStephan Aßmus }
131*9949213aSStephan Aßmus 
132*9949213aSStephan Aßmus 
133*9949213aSStephan Aßmus status_t
134*9949213aSStephan Aßmus Parser::Identify()
135*9949213aSStephan Aßmus {
136*9949213aSStephan Aßmus 	char header[5];
137*9949213aSStephan Aßmus 	if (fStream.Read(header, sizeof(header)) < (ssize_t)sizeof(header))
138*9949213aSStephan Aßmus 		return B_IO_ERROR;
139*9949213aSStephan Aßmus 
140*9949213aSStephan Aßmus 	if (strncmp(header, "{\\rtf", 5))
141*9949213aSStephan Aßmus 		return B_BAD_TYPE;
142*9949213aSStephan Aßmus 
143*9949213aSStephan Aßmus 	fIdentified = true;
144*9949213aSStephan Aßmus 	return B_OK;
145*9949213aSStephan Aßmus }
146*9949213aSStephan Aßmus 
147*9949213aSStephan Aßmus 
148*9949213aSStephan Aßmus status_t
149*9949213aSStephan Aßmus Parser::Parse(Header &header)
150*9949213aSStephan Aßmus {
151*9949213aSStephan Aßmus 	if (!fIdentified && Identify() != B_OK)
152*9949213aSStephan Aßmus 		return B_BAD_TYPE;
153*9949213aSStephan Aßmus 
154*9949213aSStephan Aßmus 	try {
155*9949213aSStephan Aßmus 		int32 openBrackets = 1;
156*9949213aSStephan Aßmus 
157*9949213aSStephan Aßmus 		// since we already preparsed parts of the RTF header, the header
158*9949213aSStephan Aßmus 		// is handled here directly
159*9949213aSStephan Aßmus 		char last;
160*9949213aSStephan Aßmus 		header.Parse('\0', fStream, last);
161*9949213aSStephan Aßmus 
162*9949213aSStephan Aßmus 		Group *parent = &header;
163*9949213aSStephan Aßmus 		char c = last;
164*9949213aSStephan Aßmus 
165*9949213aSStephan Aßmus 		while (true) {
166*9949213aSStephan Aßmus 			Element *element = NULL;
167*9949213aSStephan Aßmus 
168*9949213aSStephan Aßmus 			// we'll just ignore the end of the stream
169*9949213aSStephan Aßmus 			if (parent == NULL)
170*9949213aSStephan Aßmus 				return B_OK;
171*9949213aSStephan Aßmus 
172*9949213aSStephan Aßmus 			switch (c) {
173*9949213aSStephan Aßmus 				case '{':
174*9949213aSStephan Aßmus 					openBrackets++;
175*9949213aSStephan Aßmus 					parent->AddElement(element = new Group());
176*9949213aSStephan Aßmus 					parent = static_cast<Group *>(element);
177*9949213aSStephan Aßmus 					break;
178*9949213aSStephan Aßmus 
179*9949213aSStephan Aßmus 				case '\\':
180*9949213aSStephan Aßmus 					parent->AddElement(element = new Command());
181*9949213aSStephan Aßmus 					break;
182*9949213aSStephan Aßmus 
183*9949213aSStephan Aßmus 				case '}':
184*9949213aSStephan Aßmus 					openBrackets--;
185*9949213aSStephan Aßmus 					parent->DetermineDestination();
186*9949213aSStephan Aßmus 					parent = parent->Parent();
187*9949213aSStephan Aßmus 					// supposed to fall through
188*9949213aSStephan Aßmus 				case '\n':
189*9949213aSStephan Aßmus 				case '\r':
190*9949213aSStephan Aßmus 				{
191*9949213aSStephan Aßmus 					ssize_t bytesRead = fStream.Read(&c, 1);
192*9949213aSStephan Aßmus 					if (bytesRead < B_OK)
193*9949213aSStephan Aßmus 						throw (status_t)bytesRead;
194*9949213aSStephan Aßmus 					else if (bytesRead != 1) {
195*9949213aSStephan Aßmus 						// this is the only valid exit status
196*9949213aSStephan Aßmus 						if (openBrackets == 0)
197*9949213aSStephan Aßmus 							return B_OK;
198*9949213aSStephan Aßmus 
199*9949213aSStephan Aßmus 						throw B_ERROR;
200*9949213aSStephan Aßmus 					}
201*9949213aSStephan Aßmus 					continue;
202*9949213aSStephan Aßmus 				}
203*9949213aSStephan Aßmus 
204*9949213aSStephan Aßmus 				default:
205*9949213aSStephan Aßmus 					parent->AddElement(element = new Text());
206*9949213aSStephan Aßmus 					break;
207*9949213aSStephan Aßmus 			}
208*9949213aSStephan Aßmus 
209*9949213aSStephan Aßmus 			if (element == NULL)
210*9949213aSStephan Aßmus 				throw (status_t)B_ERROR;
211*9949213aSStephan Aßmus 
212*9949213aSStephan Aßmus 			element->Parse(c, fStream, last);
213*9949213aSStephan Aßmus 			c = last;
214*9949213aSStephan Aßmus 		}
215*9949213aSStephan Aßmus 	} catch (status_t status) {
216*9949213aSStephan Aßmus 		return status;
217*9949213aSStephan Aßmus 	}
218*9949213aSStephan Aßmus 
219*9949213aSStephan Aßmus 	return B_OK;
220*9949213aSStephan Aßmus }
221*9949213aSStephan Aßmus 
222*9949213aSStephan Aßmus 
223*9949213aSStephan Aßmus //	#pragma mark -
224*9949213aSStephan Aßmus 
225*9949213aSStephan Aßmus 
226*9949213aSStephan Aßmus Element::Element()
227*9949213aSStephan Aßmus 	:
228*9949213aSStephan Aßmus 	fParent(NULL)
229*9949213aSStephan Aßmus {
230*9949213aSStephan Aßmus }
231*9949213aSStephan Aßmus 
232*9949213aSStephan Aßmus 
233*9949213aSStephan Aßmus Element::~Element()
234*9949213aSStephan Aßmus {
235*9949213aSStephan Aßmus }
236*9949213aSStephan Aßmus 
237*9949213aSStephan Aßmus 
238*9949213aSStephan Aßmus void
239*9949213aSStephan Aßmus Element::SetParent(Group *parent)
240*9949213aSStephan Aßmus {
241*9949213aSStephan Aßmus 	fParent = parent;
242*9949213aSStephan Aßmus }
243*9949213aSStephan Aßmus 
244*9949213aSStephan Aßmus 
245*9949213aSStephan Aßmus Group *
246*9949213aSStephan Aßmus Element::Parent() const
247*9949213aSStephan Aßmus {
248*9949213aSStephan Aßmus 	return fParent;
249*9949213aSStephan Aßmus }
250*9949213aSStephan Aßmus 
251*9949213aSStephan Aßmus 
252*9949213aSStephan Aßmus bool
253*9949213aSStephan Aßmus Element::IsDefinitionDelimiter()
254*9949213aSStephan Aßmus {
255*9949213aSStephan Aßmus 	return false;
256*9949213aSStephan Aßmus }
257*9949213aSStephan Aßmus 
258*9949213aSStephan Aßmus 
259*9949213aSStephan Aßmus void
260*9949213aSStephan Aßmus Element::PrintToStream(int32 level)
261*9949213aSStephan Aßmus {
262*9949213aSStephan Aßmus 	dump(*this, level);
263*9949213aSStephan Aßmus }
264*9949213aSStephan Aßmus 
265*9949213aSStephan Aßmus 
266*9949213aSStephan Aßmus //	#pragma mark -
267*9949213aSStephan Aßmus 
268*9949213aSStephan Aßmus 
269*9949213aSStephan Aßmus Group::Group()
270*9949213aSStephan Aßmus 	:
271*9949213aSStephan Aßmus 	fDestination(TEXT_DESTINATION)
272*9949213aSStephan Aßmus {
273*9949213aSStephan Aßmus }
274*9949213aSStephan Aßmus 
275*9949213aSStephan Aßmus 
276*9949213aSStephan Aßmus Group::~Group()
277*9949213aSStephan Aßmus {
278*9949213aSStephan Aßmus 	Element *element;
279*9949213aSStephan Aßmus 	while ((element = (Element *)fElements.RemoveItem(0L)) != NULL) {
280*9949213aSStephan Aßmus 		delete element;
281*9949213aSStephan Aßmus 	}
282*9949213aSStephan Aßmus }
283*9949213aSStephan Aßmus 
284*9949213aSStephan Aßmus 
285*9949213aSStephan Aßmus void
286*9949213aSStephan Aßmus Group::Parse(char first, BDataIO &stream, char &last) throw (status_t)
287*9949213aSStephan Aßmus {
288*9949213aSStephan Aßmus 	if (first == '\0')
289*9949213aSStephan Aßmus 		first = read_char(stream);
290*9949213aSStephan Aßmus 
291*9949213aSStephan Aßmus 	if (first != '{')
292*9949213aSStephan Aßmus 		throw (status_t)B_BAD_TYPE;
293*9949213aSStephan Aßmus 
294*9949213aSStephan Aßmus 	last = read_char(stream);
295*9949213aSStephan Aßmus }
296*9949213aSStephan Aßmus 
297*9949213aSStephan Aßmus 
298*9949213aSStephan Aßmus status_t
299*9949213aSStephan Aßmus Group::AddElement(Element *element)
300*9949213aSStephan Aßmus {
301*9949213aSStephan Aßmus 	if (element == NULL)
302*9949213aSStephan Aßmus 		return B_BAD_VALUE;
303*9949213aSStephan Aßmus 
304*9949213aSStephan Aßmus 	if (fElements.AddItem(element)) {
305*9949213aSStephan Aßmus 		element->SetParent(this);
306*9949213aSStephan Aßmus 		return B_OK;
307*9949213aSStephan Aßmus 	}
308*9949213aSStephan Aßmus 
309*9949213aSStephan Aßmus 	return B_NO_MEMORY;
310*9949213aSStephan Aßmus }
311*9949213aSStephan Aßmus 
312*9949213aSStephan Aßmus 
313*9949213aSStephan Aßmus uint32
314*9949213aSStephan Aßmus Group::CountElements() const
315*9949213aSStephan Aßmus {
316*9949213aSStephan Aßmus 	return (uint32)fElements.CountItems();
317*9949213aSStephan Aßmus }
318*9949213aSStephan Aßmus 
319*9949213aSStephan Aßmus 
320*9949213aSStephan Aßmus Element *
321*9949213aSStephan Aßmus Group::ElementAt(uint32 index) const
322*9949213aSStephan Aßmus {
323*9949213aSStephan Aßmus 	return static_cast<Element *>(fElements.ItemAt(index));
324*9949213aSStephan Aßmus }
325*9949213aSStephan Aßmus 
326*9949213aSStephan Aßmus 
327*9949213aSStephan Aßmus Element *
328*9949213aSStephan Aßmus Group::FindDefinitionStart(int32 index, int32 *_startIndex) const
329*9949213aSStephan Aßmus {
330*9949213aSStephan Aßmus 	if (index < 0)
331*9949213aSStephan Aßmus 		return NULL;
332*9949213aSStephan Aßmus 
333*9949213aSStephan Aßmus 	Element *element;
334*9949213aSStephan Aßmus 	int32 number = 0;
335*9949213aSStephan Aßmus 	for (uint32 i = 0; (element = ElementAt(i)) != NULL; i++) {
336*9949213aSStephan Aßmus 		if (number == index) {
337*9949213aSStephan Aßmus 			if (_startIndex)
338*9949213aSStephan Aßmus 				*_startIndex = i;
339*9949213aSStephan Aßmus 			return element;
340*9949213aSStephan Aßmus 		}
341*9949213aSStephan Aßmus 
342*9949213aSStephan Aßmus 		if (element->IsDefinitionDelimiter())
343*9949213aSStephan Aßmus 			number++;
344*9949213aSStephan Aßmus 	}
345*9949213aSStephan Aßmus 
346*9949213aSStephan Aßmus 	return NULL;
347*9949213aSStephan Aßmus }
348*9949213aSStephan Aßmus 
349*9949213aSStephan Aßmus 
350*9949213aSStephan Aßmus Command *
351*9949213aSStephan Aßmus Group::FindDefinition(const char *name, int32 index) const
352*9949213aSStephan Aßmus {
353*9949213aSStephan Aßmus 	int32 startIndex;
354*9949213aSStephan Aßmus 	Element *element = FindDefinitionStart(index, &startIndex);
355*9949213aSStephan Aßmus 	if (element == NULL)
356*9949213aSStephan Aßmus 		return NULL;
357*9949213aSStephan Aßmus 
358*9949213aSStephan Aßmus 	for (uint32 i = startIndex; (element = ElementAt(i)) != NULL; i++) {
359*9949213aSStephan Aßmus 		if (element->IsDefinitionDelimiter())
360*9949213aSStephan Aßmus 			break;
361*9949213aSStephan Aßmus 
362*9949213aSStephan Aßmus 		if (Command *command = dynamic_cast<Command *>(element)) {
363*9949213aSStephan Aßmus 			if (command != NULL && !strcmp(name, command->Name()))
364*9949213aSStephan Aßmus 				return command;
365*9949213aSStephan Aßmus 		}
366*9949213aSStephan Aßmus 	}
367*9949213aSStephan Aßmus 
368*9949213aSStephan Aßmus 	return NULL;
369*9949213aSStephan Aßmus }
370*9949213aSStephan Aßmus 
371*9949213aSStephan Aßmus 
372*9949213aSStephan Aßmus Group *
373*9949213aSStephan Aßmus Group::FindGroup(const char *name) const
374*9949213aSStephan Aßmus {
375*9949213aSStephan Aßmus 	Element *element;
376*9949213aSStephan Aßmus 	for (uint32 i = 0; (element = ElementAt(i)) != NULL; i++) {
377*9949213aSStephan Aßmus 		Group *group = dynamic_cast<Group *>(element);
378*9949213aSStephan Aßmus 		if (group == NULL)
379*9949213aSStephan Aßmus 			continue;
380*9949213aSStephan Aßmus 
381*9949213aSStephan Aßmus 		Command *command = dynamic_cast<Command *>(group->ElementAt(0));
382*9949213aSStephan Aßmus 		if (command != NULL && !strcmp(name, command->Name()))
383*9949213aSStephan Aßmus 			return group;
384*9949213aSStephan Aßmus 	}
385*9949213aSStephan Aßmus 
386*9949213aSStephan Aßmus 	return NULL;
387*9949213aSStephan Aßmus }
388*9949213aSStephan Aßmus 
389*9949213aSStephan Aßmus 
390*9949213aSStephan Aßmus const char *
391*9949213aSStephan Aßmus Group::Name() const
392*9949213aSStephan Aßmus {
393*9949213aSStephan Aßmus 	Command *command = dynamic_cast<Command *>(ElementAt(0));
394*9949213aSStephan Aßmus 	if (command != NULL)
395*9949213aSStephan Aßmus 		return command->Name();
396*9949213aSStephan Aßmus 
397*9949213aSStephan Aßmus 	return NULL;
398*9949213aSStephan Aßmus }
399*9949213aSStephan Aßmus 
400*9949213aSStephan Aßmus 
401*9949213aSStephan Aßmus void
402*9949213aSStephan Aßmus Group::DetermineDestination()
403*9949213aSStephan Aßmus {
404*9949213aSStephan Aßmus 	const char *name = Name();
405*9949213aSStephan Aßmus 	if (name == NULL)
406*9949213aSStephan Aßmus 		return;
407*9949213aSStephan Aßmus 
408*9949213aSStephan Aßmus 	if (!strcmp(name, "*")) {
409*9949213aSStephan Aßmus 		fDestination = COMMENT_DESTINATION;
410*9949213aSStephan Aßmus 		return;
411*9949213aSStephan Aßmus 	}
412*9949213aSStephan Aßmus 
413*9949213aSStephan Aßmus 	// binary search for destination control words
414*9949213aSStephan Aßmus 
415*9949213aSStephan Aßmus 	if (bsearch(name, kDestinationControlWords,
416*9949213aSStephan Aßmus 			sizeof(kDestinationControlWords) / sizeof(kDestinationControlWords[0]),
417*9949213aSStephan Aßmus 			sizeof(kDestinationControlWords[0]),
418*9949213aSStephan Aßmus 			(int (*)(const void *, const void *))string_array_compare) != NULL)
419*9949213aSStephan Aßmus 		fDestination = OTHER_DESTINATION;
420*9949213aSStephan Aßmus }
421*9949213aSStephan Aßmus 
422*9949213aSStephan Aßmus 
423*9949213aSStephan Aßmus group_destination
424*9949213aSStephan Aßmus Group::Destination() const
425*9949213aSStephan Aßmus {
426*9949213aSStephan Aßmus 	return fDestination;
427*9949213aSStephan Aßmus }
428*9949213aSStephan Aßmus 
429*9949213aSStephan Aßmus 
430*9949213aSStephan Aßmus //	#pragma mark -
431*9949213aSStephan Aßmus 
432*9949213aSStephan Aßmus 
433*9949213aSStephan Aßmus Header::Header()
434*9949213aSStephan Aßmus 	:
435*9949213aSStephan Aßmus 	fVersion(0)
436*9949213aSStephan Aßmus {
437*9949213aSStephan Aßmus }
438*9949213aSStephan Aßmus 
439*9949213aSStephan Aßmus 
440*9949213aSStephan Aßmus Header::~Header()
441*9949213aSStephan Aßmus {
442*9949213aSStephan Aßmus }
443*9949213aSStephan Aßmus 
444*9949213aSStephan Aßmus 
445*9949213aSStephan Aßmus void
446*9949213aSStephan Aßmus Header::Parse(char first, BDataIO &stream, char &last) throw (status_t)
447*9949213aSStephan Aßmus {
448*9949213aSStephan Aßmus 	// The stream has been peeked into by the parser already, and
449*9949213aSStephan Aßmus 	// only the version follows in the stream -- let's pick it up
450*9949213aSStephan Aßmus 
451*9949213aSStephan Aßmus 	fVersion = parse_integer(first, stream, last);
452*9949213aSStephan Aßmus 
453*9949213aSStephan Aßmus 	// recreate "rtf" command to name this group
454*9949213aSStephan Aßmus 
455*9949213aSStephan Aßmus 	Command *command = new Command();
456*9949213aSStephan Aßmus 	command->SetName("rtf");
457*9949213aSStephan Aßmus 	command->SetOption(fVersion);
458*9949213aSStephan Aßmus 
459*9949213aSStephan Aßmus 	AddElement(command);
460*9949213aSStephan Aßmus }
461*9949213aSStephan Aßmus 
462*9949213aSStephan Aßmus 
463*9949213aSStephan Aßmus int32
464*9949213aSStephan Aßmus Header::Version() const
465*9949213aSStephan Aßmus {
466*9949213aSStephan Aßmus 	return fVersion;
467*9949213aSStephan Aßmus }
468*9949213aSStephan Aßmus 
469*9949213aSStephan Aßmus 
470*9949213aSStephan Aßmus const char *
471*9949213aSStephan Aßmus Header::Charset() const
472*9949213aSStephan Aßmus {
473*9949213aSStephan Aßmus 	Command *command = dynamic_cast<Command *>(ElementAt(1));
474*9949213aSStephan Aßmus 	if (command == NULL)
475*9949213aSStephan Aßmus 		return NULL;
476*9949213aSStephan Aßmus 
477*9949213aSStephan Aßmus 	return command->Name();
478*9949213aSStephan Aßmus }
479*9949213aSStephan Aßmus 
480*9949213aSStephan Aßmus 
481*9949213aSStephan Aßmus rgb_color
482*9949213aSStephan Aßmus Header::Color(int32 index)
483*9949213aSStephan Aßmus {
484*9949213aSStephan Aßmus 	rgb_color color = {0, 0, 0, 255};
485*9949213aSStephan Aßmus 
486*9949213aSStephan Aßmus 	Group *colorTable = FindGroup("colortbl");
487*9949213aSStephan Aßmus 
488*9949213aSStephan Aßmus 	if (colorTable != NULL) {
489*9949213aSStephan Aßmus 		if (Command *gun = colorTable->FindDefinition("red", index))
490*9949213aSStephan Aßmus 			color.red = gun->Option();
491*9949213aSStephan Aßmus 		if (Command *gun = colorTable->FindDefinition("green", index))
492*9949213aSStephan Aßmus 			color.green = gun->Option();
493*9949213aSStephan Aßmus 		if (Command *gun = colorTable->FindDefinition("blue", index))
494*9949213aSStephan Aßmus 			color.blue = gun->Option();
495*9949213aSStephan Aßmus 	}
496*9949213aSStephan Aßmus 
497*9949213aSStephan Aßmus 	return color;
498*9949213aSStephan Aßmus }
499*9949213aSStephan Aßmus 
500*9949213aSStephan Aßmus 
501*9949213aSStephan Aßmus //	#pragma mark -
502*9949213aSStephan Aßmus 
503*9949213aSStephan Aßmus 
504*9949213aSStephan Aßmus Text::Text()
505*9949213aSStephan Aßmus {
506*9949213aSStephan Aßmus }
507*9949213aSStephan Aßmus 
508*9949213aSStephan Aßmus 
509*9949213aSStephan Aßmus Text::~Text()
510*9949213aSStephan Aßmus {
511*9949213aSStephan Aßmus 	SetTo(NULL);
512*9949213aSStephan Aßmus }
513*9949213aSStephan Aßmus 
514*9949213aSStephan Aßmus 
515*9949213aSStephan Aßmus bool
516*9949213aSStephan Aßmus Text::IsDefinitionDelimiter()
517*9949213aSStephan Aßmus {
518*9949213aSStephan Aßmus 	return fText == ";";
519*9949213aSStephan Aßmus }
520*9949213aSStephan Aßmus 
521*9949213aSStephan Aßmus 
522*9949213aSStephan Aßmus void
523*9949213aSStephan Aßmus Text::Parse(char first, BDataIO &stream, char &last) throw (status_t)
524*9949213aSStephan Aßmus {
525*9949213aSStephan Aßmus 	char c = first;
526*9949213aSStephan Aßmus 	if (c == '\0')
527*9949213aSStephan Aßmus 		c = read_char(stream);
528*9949213aSStephan Aßmus 
529*9949213aSStephan Aßmus 	if (c == ';') {
530*9949213aSStephan Aßmus 		// definition delimiter
531*9949213aSStephan Aßmus 		fText.SetTo(";");
532*9949213aSStephan Aßmus 		last = read_char(stream);
533*9949213aSStephan Aßmus 		return;
534*9949213aSStephan Aßmus 	}
535*9949213aSStephan Aßmus 
536*9949213aSStephan Aßmus 	const size_t kBufferSteps = 1;
537*9949213aSStephan Aßmus 	size_t maxSize = kBufferSteps;
538*9949213aSStephan Aßmus 	char *text = fText.LockBuffer(maxSize);
539*9949213aSStephan Aßmus 	if (text == NULL)
540*9949213aSStephan Aßmus 		throw (status_t)B_NO_MEMORY;
541*9949213aSStephan Aßmus 
542*9949213aSStephan Aßmus 	size_t position = 0;
543*9949213aSStephan Aßmus 
544*9949213aSStephan Aßmus 	while (true) {
545*9949213aSStephan Aßmus 		if (c == '\\' || c == '}' || c == '{' || c == ';' || c == '\n' || c == '\r')
546*9949213aSStephan Aßmus 			break;
547*9949213aSStephan Aßmus 
548*9949213aSStephan Aßmus 		if (position >= maxSize) {
549*9949213aSStephan Aßmus 			fText.UnlockBuffer(position);
550*9949213aSStephan Aßmus 			text = fText.LockBuffer(maxSize += kBufferSteps);
551*9949213aSStephan Aßmus 			if (text == NULL)
552*9949213aSStephan Aßmus 				throw (status_t)B_NO_MEMORY;
553*9949213aSStephan Aßmus 		}
554*9949213aSStephan Aßmus 
555*9949213aSStephan Aßmus 		text[position++] = c;
556*9949213aSStephan Aßmus 
557*9949213aSStephan Aßmus 		c = read_char(stream);
558*9949213aSStephan Aßmus 	}
559*9949213aSStephan Aßmus 	fText.UnlockBuffer(position);
560*9949213aSStephan Aßmus 
561*9949213aSStephan Aßmus 	// ToDo: add support for different charsets - right now, only ASCII is supported!
562*9949213aSStephan Aßmus 	//	To achieve this, we should just translate everything into UTF-8 here
563*9949213aSStephan Aßmus 
564*9949213aSStephan Aßmus 	last = c;
565*9949213aSStephan Aßmus }
566*9949213aSStephan Aßmus 
567*9949213aSStephan Aßmus 
568*9949213aSStephan Aßmus status_t
569*9949213aSStephan Aßmus Text::SetTo(const char *text)
570*9949213aSStephan Aßmus {
571*9949213aSStephan Aßmus 	return fText.SetTo(text) != NULL ? B_OK : B_NO_MEMORY;
572*9949213aSStephan Aßmus }
573*9949213aSStephan Aßmus 
574*9949213aSStephan Aßmus 
575*9949213aSStephan Aßmus const char *
576*9949213aSStephan Aßmus Text::String() const
577*9949213aSStephan Aßmus {
578*9949213aSStephan Aßmus 	return fText.String();
579*9949213aSStephan Aßmus }
580*9949213aSStephan Aßmus 
581*9949213aSStephan Aßmus 
582*9949213aSStephan Aßmus uint32
583*9949213aSStephan Aßmus Text::Length() const
584*9949213aSStephan Aßmus {
585*9949213aSStephan Aßmus 	return fText.Length();
586*9949213aSStephan Aßmus }
587*9949213aSStephan Aßmus 
588*9949213aSStephan Aßmus 
589*9949213aSStephan Aßmus //	#pragma mark -
590*9949213aSStephan Aßmus 
591*9949213aSStephan Aßmus 
592*9949213aSStephan Aßmus Command::Command()
593*9949213aSStephan Aßmus 	:
594*9949213aSStephan Aßmus 	fName(NULL),
595*9949213aSStephan Aßmus 	fHasOption(false),
596*9949213aSStephan Aßmus 	fOption(-1)
597*9949213aSStephan Aßmus {
598*9949213aSStephan Aßmus }
599*9949213aSStephan Aßmus 
600*9949213aSStephan Aßmus 
601*9949213aSStephan Aßmus Command::~Command()
602*9949213aSStephan Aßmus {
603*9949213aSStephan Aßmus }
604*9949213aSStephan Aßmus 
605*9949213aSStephan Aßmus 
606*9949213aSStephan Aßmus void
607*9949213aSStephan Aßmus Command::Parse(char first, BDataIO &stream, char &last) throw (status_t)
608*9949213aSStephan Aßmus {
609*9949213aSStephan Aßmus 	if (first == '\0')
610*9949213aSStephan Aßmus 		first = read_char(stream);
611*9949213aSStephan Aßmus 
612*9949213aSStephan Aßmus 	if (first != '\\')
613*9949213aSStephan Aßmus 		throw (status_t)B_BAD_TYPE;
614*9949213aSStephan Aßmus 
615*9949213aSStephan Aßmus 	// get name
616*9949213aSStephan Aßmus 	char name[kCommandLength];
617*9949213aSStephan Aßmus 	size_t length = 0;
618*9949213aSStephan Aßmus 	char c;
619*9949213aSStephan Aßmus 	while (isalpha(c = read_char(stream))) {
620*9949213aSStephan Aßmus 		name[length++] = c;
621*9949213aSStephan Aßmus 		if (length >= kCommandLength - 1)
622*9949213aSStephan Aßmus 			throw (status_t)B_BAD_TYPE;
623*9949213aSStephan Aßmus 	}
624*9949213aSStephan Aßmus 
625*9949213aSStephan Aßmus 	if (length == 0) {
626*9949213aSStephan Aßmus 		if (c == '\n' || c == '\r') {
627*9949213aSStephan Aßmus 			// we're a hard return
628*9949213aSStephan Aßmus 			fName.SetTo("par");
629*9949213aSStephan Aßmus 		} else
630*9949213aSStephan Aßmus 			fName.SetTo(c, 1);
631*9949213aSStephan Aßmus 
632*9949213aSStephan Aßmus 		// read over character
633*9949213aSStephan Aßmus 		c = read_char(stream);
634*9949213aSStephan Aßmus 	} else
635*9949213aSStephan Aßmus 		fName.SetTo(name, length);
636*9949213aSStephan Aßmus 
637*9949213aSStephan Aßmus 	// parse numeric option
638*9949213aSStephan Aßmus 
639*9949213aSStephan Aßmus 	if (c == '-')
640*9949213aSStephan Aßmus 		c = read_char(stream);
641*9949213aSStephan Aßmus 
642*9949213aSStephan Aßmus 	last = c;
643*9949213aSStephan Aßmus 
644*9949213aSStephan Aßmus 	if (fName == "'") {
645*9949213aSStephan Aßmus 		// hexadecimal
646*9949213aSStephan Aßmus 		char bytes[2];
647*9949213aSStephan Aßmus 		bytes[0] = read_char(stream);
648*9949213aSStephan Aßmus 		bytes[1] = '\0';
649*9949213aSStephan Aßmus 		BMemoryIO memory(bytes, 2);
650*9949213aSStephan Aßmus 
651*9949213aSStephan Aßmus 		SetOption(parse_integer(c, memory, last, 16));
652*9949213aSStephan Aßmus 		last = read_char(stream);
653*9949213aSStephan Aßmus 	} else {
654*9949213aSStephan Aßmus 		// decimal
655*9949213aSStephan Aßmus 		if (isdigit(c))
656*9949213aSStephan Aßmus 			SetOption(parse_integer(c, stream, last));
657*9949213aSStephan Aßmus 
658*9949213aSStephan Aßmus 		// a space delimiter is eaten up by the command
659*9949213aSStephan Aßmus 		if (isspace(last))
660*9949213aSStephan Aßmus 			last = read_char(stream);
661*9949213aSStephan Aßmus 	}
662*9949213aSStephan Aßmus }
663*9949213aSStephan Aßmus 
664*9949213aSStephan Aßmus 
665*9949213aSStephan Aßmus status_t
666*9949213aSStephan Aßmus Command::SetName(const char *name)
667*9949213aSStephan Aßmus {
668*9949213aSStephan Aßmus 	return fName.SetTo(name) != NULL ? B_OK : B_NO_MEMORY;
669*9949213aSStephan Aßmus }
670*9949213aSStephan Aßmus 
671*9949213aSStephan Aßmus 
672*9949213aSStephan Aßmus const char *
673*9949213aSStephan Aßmus Command::Name()
674*9949213aSStephan Aßmus {
675*9949213aSStephan Aßmus 	return fName.String();
676*9949213aSStephan Aßmus }
677*9949213aSStephan Aßmus 
678*9949213aSStephan Aßmus 
679*9949213aSStephan Aßmus void
680*9949213aSStephan Aßmus Command::UnsetOption()
681*9949213aSStephan Aßmus {
682*9949213aSStephan Aßmus 	fHasOption = false;
683*9949213aSStephan Aßmus 	fOption = -1;
684*9949213aSStephan Aßmus }
685*9949213aSStephan Aßmus 
686*9949213aSStephan Aßmus 
687*9949213aSStephan Aßmus void
688*9949213aSStephan Aßmus Command::SetOption(int32 option)
689*9949213aSStephan Aßmus {
690*9949213aSStephan Aßmus 	fOption = option;
691*9949213aSStephan Aßmus 	fHasOption = true;
692*9949213aSStephan Aßmus }
693*9949213aSStephan Aßmus 
694*9949213aSStephan Aßmus 
695*9949213aSStephan Aßmus bool
696*9949213aSStephan Aßmus Command::HasOption() const
697*9949213aSStephan Aßmus {
698*9949213aSStephan Aßmus 	return fHasOption;
699*9949213aSStephan Aßmus }
700*9949213aSStephan Aßmus 
701*9949213aSStephan Aßmus 
702*9949213aSStephan Aßmus int32
703*9949213aSStephan Aßmus Command::Option() const
704*9949213aSStephan Aßmus {
705*9949213aSStephan Aßmus 	return fOption;
706*9949213aSStephan Aßmus }
707*9949213aSStephan Aßmus 
708*9949213aSStephan Aßmus 
709*9949213aSStephan Aßmus //	#pragma mark -
710*9949213aSStephan Aßmus 
711*9949213aSStephan Aßmus 
712*9949213aSStephan Aßmus Iterator::Iterator(Element &start, group_destination destination)
713*9949213aSStephan Aßmus {
714*9949213aSStephan Aßmus 	SetTo(start, destination);
715*9949213aSStephan Aßmus }
716*9949213aSStephan Aßmus 
717*9949213aSStephan Aßmus 
718*9949213aSStephan Aßmus void
719*9949213aSStephan Aßmus Iterator::SetTo(Element &start, group_destination destination)
720*9949213aSStephan Aßmus {
721*9949213aSStephan Aßmus 	fStart = &start;
722*9949213aSStephan Aßmus 	fDestination = destination;
723*9949213aSStephan Aßmus 
724*9949213aSStephan Aßmus 	Rewind();
725*9949213aSStephan Aßmus }
726*9949213aSStephan Aßmus 
727*9949213aSStephan Aßmus 
728*9949213aSStephan Aßmus void
729*9949213aSStephan Aßmus Iterator::Rewind()
730*9949213aSStephan Aßmus {
731*9949213aSStephan Aßmus 	fStack.MakeEmpty();
732*9949213aSStephan Aßmus 	fStack.Push(fStart);
733*9949213aSStephan Aßmus }
734*9949213aSStephan Aßmus 
735*9949213aSStephan Aßmus 
736*9949213aSStephan Aßmus bool
737*9949213aSStephan Aßmus Iterator::HasNext() const
738*9949213aSStephan Aßmus {
739*9949213aSStephan Aßmus 	return !fStack.IsEmpty();
740*9949213aSStephan Aßmus }
741*9949213aSStephan Aßmus 
742*9949213aSStephan Aßmus 
743*9949213aSStephan Aßmus Element *
744*9949213aSStephan Aßmus Iterator::Next()
745*9949213aSStephan Aßmus {
746*9949213aSStephan Aßmus 	Element *element;
747*9949213aSStephan Aßmus 
748*9949213aSStephan Aßmus 	if (!fStack.Pop(&element))
749*9949213aSStephan Aßmus 		return NULL;
750*9949213aSStephan Aßmus 
751*9949213aSStephan Aßmus 	Group *group = dynamic_cast<Group *>(element);
752*9949213aSStephan Aßmus 	if (group != NULL
753*9949213aSStephan Aßmus 		&& (fDestination == ALL_DESTINATIONS
754*9949213aSStephan Aßmus 			|| fDestination == group->Destination())) {
755*9949213aSStephan Aßmus 		// put this group's children on the stack in
756*9949213aSStephan Aßmus 		// reverse order, so that we iterate over
757*9949213aSStephan Aßmus 		// the tree in in-order
758*9949213aSStephan Aßmus 
759*9949213aSStephan Aßmus 		for (int32 i = group->CountElements(); i-- > 0;) {
760*9949213aSStephan Aßmus 			fStack.Push(group->ElementAt(i));
761*9949213aSStephan Aßmus 		}
762*9949213aSStephan Aßmus 	}
763*9949213aSStephan Aßmus 
764*9949213aSStephan Aßmus 	return element;
765*9949213aSStephan Aßmus }
766*9949213aSStephan Aßmus 
767*9949213aSStephan Aßmus 
768*9949213aSStephan Aßmus //	#pragma mark -
769*9949213aSStephan Aßmus 
770*9949213aSStephan Aßmus 
771*9949213aSStephan Aßmus Worker::Worker(RTF::Header &start)
772*9949213aSStephan Aßmus 	:
773*9949213aSStephan Aßmus 	fStart(start)
774*9949213aSStephan Aßmus {
775*9949213aSStephan Aßmus }
776*9949213aSStephan Aßmus 
777*9949213aSStephan Aßmus 
778*9949213aSStephan Aßmus Worker::~Worker()
779*9949213aSStephan Aßmus {
780*9949213aSStephan Aßmus }
781*9949213aSStephan Aßmus 
782*9949213aSStephan Aßmus 
783*9949213aSStephan Aßmus void
784*9949213aSStephan Aßmus Worker::Dispatch(Element *element)
785*9949213aSStephan Aßmus {
786*9949213aSStephan Aßmus 	if (RTF::Group *group = dynamic_cast<RTF::Group *>(element)) {
787*9949213aSStephan Aßmus 		fSkip = false;
788*9949213aSStephan Aßmus 		Group(group);
789*9949213aSStephan Aßmus 
790*9949213aSStephan Aßmus 		if (fSkip)
791*9949213aSStephan Aßmus 			return;
792*9949213aSStephan Aßmus 
793*9949213aSStephan Aßmus 		for (int32 i = 0; (element = group->ElementAt(i)) != NULL; i++)
794*9949213aSStephan Aßmus 			Dispatch(element);
795*9949213aSStephan Aßmus 
796*9949213aSStephan Aßmus 		GroupEnd(group);
797*9949213aSStephan Aßmus 	} else if (RTF::Command *command = dynamic_cast<RTF::Command *>(element)) {
798*9949213aSStephan Aßmus 		Command(command);
799*9949213aSStephan Aßmus 	} else if (RTF::Text *text = dynamic_cast<RTF::Text *>(element)) {
800*9949213aSStephan Aßmus 		Text(text);
801*9949213aSStephan Aßmus 	}
802*9949213aSStephan Aßmus }
803*9949213aSStephan Aßmus 
804*9949213aSStephan Aßmus 
805*9949213aSStephan Aßmus void
806*9949213aSStephan Aßmus Worker::Work() throw (status_t)
807*9949213aSStephan Aßmus {
808*9949213aSStephan Aßmus 	Dispatch(&fStart);
809*9949213aSStephan Aßmus }
810*9949213aSStephan Aßmus 
811*9949213aSStephan Aßmus 
812*9949213aSStephan Aßmus void
813*9949213aSStephan Aßmus Worker::Group(RTF::Group *group)
814*9949213aSStephan Aßmus {
815*9949213aSStephan Aßmus }
816*9949213aSStephan Aßmus 
817*9949213aSStephan Aßmus 
818*9949213aSStephan Aßmus void
819*9949213aSStephan Aßmus Worker::GroupEnd(RTF::Group *group)
820*9949213aSStephan Aßmus {
821*9949213aSStephan Aßmus }
822*9949213aSStephan Aßmus 
823*9949213aSStephan Aßmus 
824*9949213aSStephan Aßmus void
825*9949213aSStephan Aßmus Worker::Command(RTF::Command *command)
826*9949213aSStephan Aßmus {
827*9949213aSStephan Aßmus }
828*9949213aSStephan Aßmus 
829*9949213aSStephan Aßmus 
830*9949213aSStephan Aßmus void
831*9949213aSStephan Aßmus Worker::Text(RTF::Text *text)
832*9949213aSStephan Aßmus {
833*9949213aSStephan Aßmus }
834*9949213aSStephan Aßmus 
835*9949213aSStephan Aßmus 
836*9949213aSStephan Aßmus RTF::Header &
837*9949213aSStephan Aßmus Worker::Start()
838*9949213aSStephan Aßmus {
839*9949213aSStephan Aßmus 	return fStart;
840*9949213aSStephan Aßmus }
841*9949213aSStephan Aßmus 
842*9949213aSStephan Aßmus 
843*9949213aSStephan Aßmus void
844*9949213aSStephan Aßmus Worker::Skip()
845*9949213aSStephan Aßmus {
846*9949213aSStephan Aßmus 	fSkip = true;
847*9949213aSStephan Aßmus }
848*9949213aSStephan Aßmus 
849*9949213aSStephan Aßmus 
850*9949213aSStephan Aßmus void
851*9949213aSStephan Aßmus Worker::Abort(status_t status)
852*9949213aSStephan Aßmus {
853*9949213aSStephan Aßmus 	throw status;
854*9949213aSStephan Aßmus }
855*9949213aSStephan Aßmus 
856