The parser now uses a BBufferIO stream to speed things up.
Text::Parse() now converts bigger chunks at once. Default RTF element destination is visible in text now, only known other destinations are marked that way (using a lookup table). Added virtual method IsDefinitionDelimiter() to Element to make definition iterating nicer. ";" now always forms a separated Text object - this fixes the definition handling. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10565 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -14,6 +14,17 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const char *kDestinationControlWords[] = {
|
||||||
|
"aftncn", "aftnsep", "aftnsepc", "annotation", "atnauthor", "atndate",
|
||||||
|
"atnicn", "atnid", "atnparent", "atnref", "atntime", "atrfend",
|
||||||
|
"atrfstart", "author", "background", "bkmkend", "buptim", "colortbl",
|
||||||
|
"comment", "creatim", "do", "doccomm", "docvar", "fonttbl", "footer",
|
||||||
|
"footerf", "footerl", "footerr", "footnote", "ftncn", "ftnsep",
|
||||||
|
"ftnsepc", "header", "headerf", "headerl", "headerr", "info",
|
||||||
|
"keywords", "operator", "pict", "printim", "private1", "revtim",
|
||||||
|
"rxe", "stylesheet", "subject", "tc", "title", "txe", "xe",
|
||||||
|
};
|
||||||
|
|
||||||
static char read_char(BDataIO &stream, bool endOfFileAllowed = false) throw (status_t);
|
static char read_char(BDataIO &stream, bool endOfFileAllowed = false) throw (status_t);
|
||||||
static int32 parse_integer(char first, BDataIO &stream, char &_last) throw (status_t);
|
static int32 parse_integer(char first, BDataIO &stream, char &_last) throw (status_t);
|
||||||
|
|
||||||
@@ -68,6 +79,13 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
string_array_compare(const char *key, const char **array)
|
||||||
|
{
|
||||||
|
return strcmp(key, array[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump(Element &element, int32 level = 0)
|
dump(Element &element, int32 level = 0)
|
||||||
{
|
{
|
||||||
@@ -98,9 +116,9 @@ dump(Element &element, int32 level = 0)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
Parser::Parser(BDataIO &stream)
|
Parser::Parser(BPositionIO &stream)
|
||||||
:
|
:
|
||||||
fStream(stream),
|
fStream(&stream, 65536, false),
|
||||||
fIdentified(false)
|
fIdentified(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -141,6 +159,10 @@ Parser::Parse(Header &header)
|
|||||||
while (true) {
|
while (true) {
|
||||||
Element *element = NULL;
|
Element *element = NULL;
|
||||||
|
|
||||||
|
// we'll just ignore the end of the stream
|
||||||
|
if (parent == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '{':
|
case '{':
|
||||||
openBrackets++;
|
openBrackets++;
|
||||||
@@ -221,6 +243,13 @@ Element::Parent() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Element::IsDefinitionDelimiter()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Element::PrintToStream(int32 level)
|
Element::PrintToStream(int32 level)
|
||||||
{
|
{
|
||||||
@@ -233,7 +262,7 @@ Element::PrintToStream(int32 level)
|
|||||||
|
|
||||||
Group::Group()
|
Group::Group()
|
||||||
:
|
:
|
||||||
fDestination(OTHER_DESTINATION)
|
fDestination(TEXT_DESTINATION)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,8 +318,8 @@ Group::ElementAt(uint32 index) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Command *
|
Element *
|
||||||
Group::FindDefinition(const char *name, int32 index) const
|
Group::FindDefinitionStart(int32 index, int32 *_startIndex) const
|
||||||
{
|
{
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -298,14 +327,34 @@ Group::FindDefinition(const char *name, int32 index) const
|
|||||||
Element *element;
|
Element *element;
|
||||||
int32 number = 0;
|
int32 number = 0;
|
||||||
for (uint32 i = 0; (element = ElementAt(i)) != NULL; i++) {
|
for (uint32 i = 0; (element = ElementAt(i)) != NULL; i++) {
|
||||||
if (Text *text = dynamic_cast<Text *>(element)) {
|
if (number == index) {
|
||||||
// the ';' indicates the next definition
|
if (_startIndex)
|
||||||
if (!strcmp(text->String(), ";"))
|
*_startIndex = i;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element->IsDefinitionDelimiter())
|
||||||
number++;
|
number++;
|
||||||
} else if (Command *command = dynamic_cast<Command *>(element)) {
|
}
|
||||||
if (command != NULL
|
|
||||||
&& !strcmp(name, command->Name())
|
return NULL;
|
||||||
&& number == index)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Command *
|
||||||
|
Group::FindDefinition(const char *name, int32 index) const
|
||||||
|
{
|
||||||
|
int32 startIndex;
|
||||||
|
Element *element = FindDefinitionStart(index, &startIndex);
|
||||||
|
if (element == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (uint32 i = startIndex; (element = ElementAt(i)) != NULL; i++) {
|
||||||
|
if (element->IsDefinitionDelimiter())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (Command *command = dynamic_cast<Command *>(element)) {
|
||||||
|
if (command != NULL && !strcmp(name, command->Name()))
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,24 +396,20 @@ void
|
|||||||
Group::DetermineDestination()
|
Group::DetermineDestination()
|
||||||
{
|
{
|
||||||
const char *name = Name();
|
const char *name = Name();
|
||||||
if (name == NULL) {
|
if (name == NULL)
|
||||||
fDestination = TEXT_DESTINATION;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(name, "*")) {
|
if (!strcmp(name, "*")) {
|
||||||
fDestination = COMMENT_DESTINATION;
|
fDestination = COMMENT_DESTINATION;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *texts[] = {"rtf", "sect", "par"};
|
// binary search for destination control words
|
||||||
for (uint32 i = 0; i < sizeof(texts) / sizeof(texts[0]); i++) {
|
|
||||||
if (!strcmp(name, texts[i])) {
|
|
||||||
fDestination = TEXT_DESTINATION;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (bsearch(name, kDestinationControlWords,
|
||||||
|
sizeof(kDestinationControlWords) / sizeof(kDestinationControlWords[0]),
|
||||||
|
sizeof(kDestinationControlWords[0]),
|
||||||
|
(int (*)(const void *, const void *))string_array_compare) != NULL)
|
||||||
fDestination = OTHER_DESTINATION;
|
fDestination = OTHER_DESTINATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,6 +506,13 @@ Text::~Text()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Text::IsDefinitionDelimiter()
|
||||||
|
{
|
||||||
|
return fText == ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Text::Parse(char first, BDataIO &stream, char &last) throw (status_t)
|
Text::Parse(char first, BDataIO &stream, char &last) throw (status_t)
|
||||||
{
|
{
|
||||||
@@ -468,16 +520,37 @@ Text::Parse(char first, BDataIO &stream, char &last) throw (status_t)
|
|||||||
if (c == '\0')
|
if (c == '\0')
|
||||||
c = read_char(stream);
|
c = read_char(stream);
|
||||||
|
|
||||||
fText = "";
|
if (c == ';') {
|
||||||
|
// definition delimiter
|
||||||
|
fText.SetTo(";");
|
||||||
|
last = read_char(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t kBufferSteps = 1;
|
||||||
|
size_t maxSize = kBufferSteps;
|
||||||
|
char *text = fText.LockBuffer(maxSize);
|
||||||
|
if (text == NULL)
|
||||||
|
throw (status_t)B_NO_MEMORY;
|
||||||
|
|
||||||
|
size_t position = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (c == '\\' || c == '}')
|
if (c == '\\' || c == '}' || c == '{' || c == ';')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// ToDo: this is horribly inefficient with BStrings
|
if (position >= maxSize) {
|
||||||
fText.Append(c, 1);
|
fText.UnlockBuffer(position);
|
||||||
|
text = fText.LockBuffer(maxSize += kBufferSteps);
|
||||||
|
if (text == NULL)
|
||||||
|
throw (status_t)B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
text[position++] = c;
|
||||||
|
|
||||||
c = read_char(stream);
|
c = read_char(stream);
|
||||||
}
|
}
|
||||||
|
fText.UnlockBuffer(position);
|
||||||
|
|
||||||
// ToDo: add support for different charsets - right now, only ASCII is supported!
|
// ToDo: add support for different charsets - right now, only ASCII is supported!
|
||||||
// To achieve this, we should just translate everything into UTF-8 here
|
// To achieve this, we should just translate everything into UTF-8 here
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#include <List.h>
|
#include <List.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <GraphicsDefs.h>
|
#include <GraphicsDefs.h>
|
||||||
|
#include <BufferIO.h>
|
||||||
|
|
||||||
class BDataIO;
|
|
||||||
|
|
||||||
namespace RTF {
|
namespace RTF {
|
||||||
|
|
||||||
@@ -33,13 +33,13 @@ enum group_destination {
|
|||||||
|
|
||||||
class Parser {
|
class Parser {
|
||||||
public:
|
public:
|
||||||
Parser(BDataIO &stream);
|
Parser(BPositionIO &stream);
|
||||||
|
|
||||||
status_t Identify();
|
status_t Identify();
|
||||||
status_t Parse(RTF::Header &header);
|
status_t Parse(RTF::Header &header);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BDataIO &fStream;
|
BBufferIO fStream;
|
||||||
bool fIdentified;
|
bool fIdentified;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ class Element {
|
|||||||
void SetParent(Group *parent);
|
void SetParent(Group *parent);
|
||||||
Group *Parent() const;
|
Group *Parent() const;
|
||||||
|
|
||||||
|
virtual bool IsDefinitionDelimiter();
|
||||||
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t) = 0;
|
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t) = 0;
|
||||||
virtual void PrintToStream(int32 level = 0);
|
virtual void PrintToStream(int32 level = 0);
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ class Group : public Element {
|
|||||||
uint32 CountElements() const;
|
uint32 CountElements() const;
|
||||||
Element *ElementAt(uint32 index) const;
|
Element *ElementAt(uint32 index) const;
|
||||||
|
|
||||||
|
Element *FindDefinitionStart(int32 index, int32 *_startIndex = NULL) const;
|
||||||
Command *FindDefinition(const char *name, int32 index = 0) const;
|
Command *FindDefinition(const char *name, int32 index = 0) const;
|
||||||
Group *FindGroup(const char *name) const;
|
Group *FindGroup(const char *name) const;
|
||||||
|
|
||||||
@@ -110,6 +112,7 @@ class Text : public Element {
|
|||||||
const char *String() const;
|
const char *String() const;
|
||||||
uint32 Length() const;
|
uint32 Length() const;
|
||||||
|
|
||||||
|
virtual bool IsDefinitionDelimiter();
|
||||||
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t);
|
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user