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