Added a simple RTF translator.

It only supports colors and bold fonts beside plain ASCII text, but it's a
start.
The RTF* class hierarchy should get a cleanup, though (and will soon).
You'll need Haiku's StyledEdit to make use of this translator.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10562 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-01-02 23:28:30 +00:00
parent e940fe0597
commit 40d9768b92
12 changed files with 1569 additions and 0 deletions
+1
View File
@@ -7,6 +7,7 @@ SubInclude OBOS_TOP src add-ons translators jpeg2000translator ;
SubInclude OBOS_TOP src add-ons translators libtifftranslator ;
SubInclude OBOS_TOP src add-ons translators pngtranslator ;
SubInclude OBOS_TOP src add-ons translators ppmtranslator ;
SubInclude OBOS_TOP src add-ons translators rtftranslator ;
SubInclude OBOS_TOP src add-ons translators sgitranslator ;
SubInclude OBOS_TOP src add-ons translators stxttranslator ;
SubInclude OBOS_TOP src add-ons translators tgatranslator ;
@@ -0,0 +1,55 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ConfigView.h"
#include "RTFTranslator.h"
#include <StringView.h>
#include <stdio.h>
#include <string.h>
ConfigView::ConfigView(const BRect &frame, uint32 resize, uint32 flags)
: BView(frame, "RTF-Translator Settings", resize, flags)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
font_height fontHeight;
be_bold_font->GetHeight(&fontHeight);
float height = fontHeight.descent + fontHeight.ascent + fontHeight.leading;
BRect rect(10, 10, 200, 10 + height);
BStringView *stringView = new BStringView(rect, "title", "Rich Text Format (RTF) Files");
stringView->SetFont(be_bold_font);
stringView->ResizeToPreferred();
AddChild(stringView);
rect.OffsetBy(0, height + 10);
char version[256];
sprintf(version, "Version %d.%d.%d, %s",
int(B_TRANSLATION_MAJOR_VER(RTF_TRANSLATOR_VERSION)),
int(B_TRANSLATION_MINOR_VER(RTF_TRANSLATOR_VERSION)),
int(B_TRANSLATION_REVSN_VER(RTF_TRANSLATOR_VERSION)),
__DATE__);
stringView = new BStringView(rect, "version", version);
stringView->ResizeToPreferred();
AddChild(stringView);
GetFontHeight(&fontHeight);
height = fontHeight.descent + fontHeight.ascent + fontHeight.leading;
rect.OffsetBy(0, height + 5);
stringView = new BStringView(rect, "copyright", B_UTF8_COPYRIGHT "2004-2005 Haiku Inc.");
stringView->ResizeToPreferred();
AddChild(stringView);
}
ConfigView::~ConfigView()
{
}
@@ -0,0 +1,19 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef CONFIG_VIEW_H
#define CONFIG_VIEW_H
#include <View.h>
class ConfigView : public BView {
public:
ConfigView(const BRect &frame, uint32 resize = B_FOLLOW_ALL,
uint32 flags = B_WILL_DRAW);
virtual ~ConfigView();
};
#endif /* CONFIG_VIEW_H */
@@ -0,0 +1,27 @@
SubDir OBOS_TOP src add-ons translators rtftranslator ;
# Include code from shared translator directory
SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src add-ons translators shared ] ;
# It's called RTF-Translator (with a dash) to differentiate it from the
# RTFTranslator that comes with Gobe Productive (that doesn't support
# STXT or plain text files output).
Translator RTF-Translator :
# RTFTranslator classes
main.cpp
RTFTranslator.cpp
ConfigView.cpp
RTF.cpp
convert.cpp
# shared classes
TranslatorWindow.cpp
;
LinkSharedOSLibs RTF-Translator : be translation ;
Package haiku-translationkit-cvs :
RTF-Translator
: boot home config add-ons Translators
;
@@ -0,0 +1,618 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "RTF.h"
#include <DataIO.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
static void
dump(RTFElement &element, int32 level = 0)
{
printf("%03ld:", level);
for (int32 i = 0; i < level; i++)
printf(" ");
if (RTFHeader *header = dynamic_cast<RTFHeader *>(&element)) {
printf("<RTF header, major version %ld>\n", header->Version());
} else if (RTFCommand *command = dynamic_cast<RTFCommand *>(&element)) {
printf("<Command: %s", command->Name());
if (command->HasOption())
printf(", Option %ld", command->Option());
puts(">");
} else if (RTFText *text = dynamic_cast<RTFText *>(&element)) {
printf("<Text>");
puts(text->Text());
} else
puts("<Group>");
for (uint32 i = 0; i < element.CountElements(); i++)
dump(*element.ElementAt(i), level + 1);
}
// #pragma mark -
RTFElement::RTFElement()
:
fParent(NULL),
fDestination(RTF_OTHER)
{
}
RTFElement::~RTFElement()
{
RTFElement *element;
while ((element = (RTFElement *)fElements.RemoveItem(0L)) != NULL) {
delete element;
}
}
void
RTFElement::Parse(char first, BDataIO &stream, char &last) throw (status_t)
{
if (first == '\0')
first = ReadChar(stream);
if (first != '{')
throw (status_t)B_BAD_TYPE;
last = ReadChar(stream);
}
status_t
RTFElement::AddElement(RTFElement *element)
{
if (element == NULL)
return B_BAD_VALUE;
if (fElements.AddItem(element)) {
element->fParent = this;
return B_OK;
}
return B_NO_MEMORY;
}
uint32
RTFElement::CountElements() const
{
return (uint32)fElements.CountItems();
}
RTFElement *
RTFElement::ElementAt(uint32 index) const
{
return static_cast<RTFElement *>(fElements.ItemAt(index));
}
RTFCommand *
RTFElement::FindDefinition(const char *name, int32 index) const
{
if (index < 0)
return NULL;
RTFElement *element;
int32 number = 0;
for (uint32 i = 0; (element = ElementAt(i)) != NULL; i++) {
if (RTFText *text = dynamic_cast<RTFText *>(element)) {
// the ';' indicates the next definition
if (!strcmp(text->Text(), ";"))
number++;
} else if (RTFCommand *command = dynamic_cast<RTFCommand *>(element)) {
if (command != NULL
&& !strcmp(name, command->Name())
&& number == index)
return command;
}
}
return NULL;
}
RTFElement *
RTFElement::FindGroup(const char *name) const
{
RTFElement *group;
for (uint32 i = 0; (group = ElementAt(i)) != NULL; i++) {
RTFCommand *command = dynamic_cast<RTFCommand *>(group->ElementAt(0));
if (command != NULL && !strcmp(name, command->Name()))
return group;
}
return NULL;
}
const char *
RTFElement::GroupName() const
{
RTFCommand *command = dynamic_cast<RTFCommand *>(ElementAt(0));
if (command != NULL)
return command->Name();
return NULL;
}
RTFElement *
RTFElement::Parent() const
{
return fParent;
}
void
RTFElement::PrintToStream()
{
dump(*this, 0);
}
void
RTFElement::DetermineDestination()
{
const char *name = GroupName();
if (name == NULL)
fDestination = RTF_TEXT;
if (!strcmp(name, "*")) {
fDestination = RTF_COMMENT;
return;
}
const char *texts[] = {"rtf", "sect", "par"};
for (uint32 i = 0; i < sizeof(texts) / sizeof(texts[0]); i++) {
if (!strcmp(texts[i], name)) {
fDestination = RTF_TEXT;
return;
}
}
fDestination = RTF_OTHER;
}
rtf_destination
RTFElement::Destination() const
{
return fDestination;
}
/* static */
char
RTFElement::ReadChar(BDataIO &stream, bool endOfFileAllowed) throw (status_t)
{
char c;
ssize_t bytesRead = stream.Read(&c, 1);
if (bytesRead < B_OK)
throw (status_t)bytesRead;
if (bytesRead == 0 && !endOfFileAllowed)
throw (status_t)B_ERROR;
return c;
}
/* static */
int32
RTFElement::ParseInteger(char first, BDataIO &stream, char &_last) throw (status_t)
{
int32 integer = 0;
int32 count = 0;
char digit = first;
if (digit == '\0')
digit = ReadChar(stream);
while (true) {
if (isdigit(digit)) {
integer = integer * 10 + digit - '0';
count++;
} else {
_last = digit;
goto out;
}
digit = ReadChar(stream);
}
out:
if (count == 0)
throw (status_t)B_BAD_TYPE;
return integer;
}
// #pragma mark -
RTFHeader::RTFHeader()
:
fVersion(0)
{
}
RTFHeader::~RTFHeader()
{
}
void
RTFHeader::Parse(char first, BDataIO &stream, char &last) throw (status_t)
{
int32 openBrackets = 1;
// The stream has been picked up by the static RTFHeader::Parse(), so
// the version follows in the stream -- let's pick it up
fVersion = ParseInteger(first, stream, last);
RTFElement *parent = this;
char c = last;
while (true) {
RTFElement *element = NULL;
switch (c) {
case '{':
openBrackets++;
parent->AddElement(element = new RTFElement());
parent = element;
break;
case '\\':
parent->AddElement(element = new RTFCommand());
break;
case '}':
openBrackets--;
parent->DetermineDestination();
parent = parent->Parent();
case '\n':
case '\r':
{
ssize_t bytesRead = stream.Read(&c, 1);
if (bytesRead < B_OK)
throw (status_t)bytesRead;
else if (bytesRead != 1) {
// this is the only valid exit status
if (openBrackets == 0)
return;
throw B_ERROR;
}
continue;
}
default:
parent->AddElement(element = new RTFText());
break;
}
if (element == NULL)
throw (status_t)B_ERROR;
element->Parse(c, stream, last);
c = last;
}
}
int32
RTFHeader::Version() const
{
return fVersion;
}
const char *
RTFHeader::Charset() const
{
RTFCommand *command = dynamic_cast<RTFCommand *>(ElementAt(0));
if (command == NULL)
return NULL;
return command->Name();
}
rgb_color
RTFHeader::Color(int32 index)
{
rgb_color color = {0, 0, 0, 255};
RTFElement *colorTable = FindGroup("colortbl");
if (colorTable != NULL) {
if (RTFCommand *gun = colorTable->FindDefinition("red", index))
color.red = gun->Option();
if (RTFCommand *gun = colorTable->FindDefinition("green", index))
color.green = gun->Option();
if (RTFCommand *gun = colorTable->FindDefinition("blue", index))
color.blue = gun->Option();
}
return color;
}
status_t
RTFHeader::Identify(BDataIO &stream)
{
char header[5];
if (stream.Read(header, sizeof(header)) < (ssize_t)sizeof(header))
return B_IO_ERROR;
return strncmp(header, "{\\rtf", 5) ? B_BAD_TYPE : B_OK;
}
status_t
RTFHeader::Parse(BDataIO &stream, RTFHeader &header, bool identified)
{
if (!identified && Identify(stream) != B_OK)
return B_BAD_TYPE;
try {
char last;
header.Parse('\0', stream, last);
} catch (status_t status) {
return status;
}
return B_OK;
}
// #pragma mark -
RTFText::RTFText()
{
}
RTFText::~RTFText()
{
SetText(NULL);
}
void
RTFText::Parse(char first, BDataIO &stream, char &last) throw (status_t)
{
char c = first;
if (c == '\0')
c = ReadChar(stream);
fText = "";
while (true) {
if (c == '\\' || c == '}')
break;
// ToDo: this is horribly inefficient with BStrings
fText.Append(c, 1);
c = ReadChar(stream);
}
// ToDo: add support for different charsets - right now, only ASCII is supported!
// To achieve this, we should just translate everything into UTF-8 here
last = c;
}
status_t
RTFText::SetText(const char *text)
{
return fText.SetTo(text) != NULL ? B_OK : B_NO_MEMORY;
}
const char *
RTFText::Text() const
{
return fText.String();
}
uint32
RTFText::TextLength() const
{
return fText.Length();
}
// #pragma mark -
RTFCommand::RTFCommand()
:
fName(NULL),
fHasOption(false),
fOption(-1)
{
}
RTFCommand::~RTFCommand()
{
}
void
RTFCommand::Parse(char first, BDataIO &stream, char &last) throw (status_t)
{
if (first == '\0')
first = ReadChar(stream);
if (first != '\\')
throw B_BAD_TYPE;
// get name
char name[kRTFCommandLength];
size_t length = 0;
char c;
while (isalpha(c = ReadChar(stream))) {
name[length++] = c;
if (length >= kRTFCommandLength - 1)
throw B_BAD_TYPE;
}
if (length == 0) {
if (c == '*') {
// we're a comment!
name[0] = 'c';
length++;
} else if (c == '\n') {
// we're a hard return
name[0] = '\n';
length++;
}
}
fName.SetTo(name, length);
// parse numeric option
if (c == '-')
c = ReadChar(stream);
last = c;
if (isdigit(c))
SetOption(ParseInteger(c, stream, last));
// a space delimiter is eaten up by the command
if (isspace(last))
last = ReadChar(stream);
}
status_t
RTFCommand::SetName(const char *name)
{
return fName.SetTo(name) != NULL ? B_OK : B_NO_MEMORY;
}
const char *
RTFCommand::Name()
{
return fName.String();
}
void
RTFCommand::UnsetOption()
{
fHasOption = false;
fOption = -1;
}
void
RTFCommand::SetOption(int32 option)
{
fOption = option;
fHasOption = true;
}
bool
RTFCommand::HasOption() const
{
return fHasOption;
}
int32
RTFCommand::Option() const
{
return fOption;
}
// #pragma mark -
RTFIterator::RTFIterator(RTFElement &start, rtf_destination destination)
{
SetTo(start, destination);
}
void
RTFIterator::SetTo(RTFElement &start, rtf_destination destination)
{
fStart = &start;
fDestination = destination;
Rewind();
}
void
RTFIterator::Rewind()
{
fStack.MakeEmpty();
fStack.Push(fStart);
}
bool
RTFIterator::HasNext() const
{
return !fStack.IsEmpty();
}
RTFElement *
RTFIterator::Next()
{
RTFElement *element;
if (!fStack.Pop(&element))
return NULL;
// put this element's children on the stack in
// reverse order, so that we iterate over the
// tree in in-order
for (int32 i = element->CountElements(); i-- > 0;) {
RTFElement *child = element->ElementAt(i);
if (fDestination == RTF_ALL_DESTINATIONS
|| child->CountElements() == 0
|| fDestination == element->Destination())
fStack.Push(child);
}
return element;
}
+136
View File
@@ -0,0 +1,136 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef RTF_H
#define RTF_H
#include "Stack.h"
#include <List.h>
#include <String.h>
#include <GraphicsDefs.h>
class BDataIO;
class RTFCommand;
static const size_t kRTFCommandLength = 32;
enum rtf_destination {
RTF_TEXT,
RTF_COMMENT,
RTF_OTHER,
RTF_ALL_DESTINATIONS = 255
};
class RTFElement {
public:
RTFElement();
virtual ~RTFElement();
status_t AddElement(RTFElement *element);
uint32 CountElements() const;
RTFElement *ElementAt(uint32 index) const;
RTFCommand *FindDefinition(const char *name, int32 index = 0) const;
RTFElement *FindGroup(const char *name) const;
const char *GroupName() const;
RTFElement *Parent() const;
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t);
virtual void PrintToStream();
void DetermineDestination();
rtf_destination Destination() const;
protected:
static char ReadChar(BDataIO &stream, bool endOfFileAllowed = false) throw (status_t);
static int32 ParseInteger(char first, BDataIO &stream, char &last) throw (status_t);
private:
RTFElement *fParent;
BList fElements;
rtf_destination fDestination;
};
class RTFHeader : public RTFElement {
public:
RTFHeader();
virtual ~RTFHeader();
int32 Version() const;
const char *Charset() const;
rgb_color Color(int32 index);
static status_t Identify(BDataIO &stream);
static status_t Parse(BDataIO &stream, RTFHeader &header, bool identified = false);
protected:
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t);
private:
int32 fVersion;
};
class RTFText : public RTFElement {
public:
RTFText();
virtual ~RTFText();
status_t SetText(const char *text);
const char *Text() const;
uint32 TextLength() const;
protected:
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t);
private:
BString fText;
};
class RTFCommand : public RTFElement {
public:
RTFCommand();
virtual ~RTFCommand();
status_t SetName(const char *name);
const char *Name();
void UnsetOption();
void SetOption(int32 option);
bool HasOption() const;
int32 Option() const;
protected:
virtual void Parse(char first, BDataIO &stream, char &last) throw (status_t);
private:
BString fName;
bool fHasOption;
int32 fOption;
};
//---------------------------------
class RTFIterator {
public:
RTFIterator(RTFElement &start, rtf_destination destination = RTF_ALL_DESTINATIONS);
void SetTo(RTFElement &start, rtf_destination destination = RTF_ALL_DESTINATIONS);
void Rewind();
bool HasNext() const;
RTFElement *Next();
private:
RTFElement *fStart;
Stack<RTFElement *> fStack;
rtf_destination fDestination;
};
#endif /* RTF_H */
@@ -0,0 +1,193 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "RTFTranslator.h"
#include "ConfigView.h"
#include "RTF.h"
#include "convert.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define READ_BUFFER_SIZE 2048
#define DATA_BUFFER_SIZE 64
// The input formats that this translator supports.
translation_format sInputFormats[] = {
{
RTF_TEXT_FORMAT,
B_TRANSLATOR_TEXT,
RTF_IN_QUALITY,
RTF_IN_CAPABILITY,
"text/rtf",
"RichTextFormat file"
},
};
// The output formats that this translator supports.
translation_format sOutputFormats[] = {
{
B_TRANSLATOR_TEXT,
B_TRANSLATOR_TEXT,
TEXT_OUT_QUALITY,
TEXT_OUT_CAPABILITY,
"text/plain",
"Plain text file"
},
{
B_STYLED_TEXT_FORMAT,
B_TRANSLATOR_TEXT,
STXT_OUT_QUALITY,
STXT_OUT_CAPABILITY,
"text/x-vnd.Be-stxt",
"Be styled text file"
}
};
RTFTranslator::RTFTranslator()
{
char info[256];
sprintf(info, "Rich Text Format Translator v%d.%d.%d %s",
int(B_TRANSLATION_MAJOR_VER(RTF_TRANSLATOR_VERSION)),
int(B_TRANSLATION_MINOR_VER(RTF_TRANSLATOR_VERSION)),
int(B_TRANSLATION_REVSN_VER(RTF_TRANSLATOR_VERSION)),
__DATE__);
fInfo = strdup(info);
}
RTFTranslator::~RTFTranslator()
{
free(fInfo);
}
const char *
RTFTranslator::TranslatorName() const
{
return "RTF Text Files";
}
const char *
RTFTranslator::TranslatorInfo() const
{
return "Rich Text Format Translator";
}
int32
RTFTranslator::TranslatorVersion() const
{
return RTF_TRANSLATOR_VERSION;
}
const translation_format *
RTFTranslator::InputFormats(int32 *_outCount) const
{
if (_outCount == NULL)
return NULL;
*_outCount = sizeof(sInputFormats) / sizeof(translation_format);
return sInputFormats;
}
const translation_format *
RTFTranslator::OutputFormats(int32 *_outCount) const
{
*_outCount = sizeof(sOutputFormats) / sizeof(translation_format);
return sOutputFormats;
}
status_t
RTFTranslator::Identify(BPositionIO *stream,
const translation_format *format, BMessage *ioExtension,
translator_info *info, uint32 outType)
{
if (!outType)
outType = B_TRANSLATOR_TEXT;
if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
return B_NO_TRANSLATOR;
status_t status = RTFHeader::Identify(*stream);
if (status != B_OK)
return B_NO_TRANSLATOR;
// return information about the data in the stream
info->type = B_TRANSLATOR_TEXT; //RTF_TEXT_FORMAT;
info->group = B_TRANSLATOR_TEXT;
info->quality = RTF_IN_QUALITY;
info->capability = RTF_IN_CAPABILITY;
strcpy(info->name, "RichTextFormat file");
strcpy(info->MIME, "text/rtf");
return B_OK;
}
status_t
RTFTranslator::Translate(BPositionIO *source,
const translator_info *inInfo, BMessage *ioExtension,
uint32 outType, BPositionIO *target)
{
if (target == NULL || source == NULL)
return B_BAD_VALUE;
if (!outType)
outType = B_TRANSLATOR_TEXT;
if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT)
return B_NO_TRANSLATOR;
RTFHeader header;
status_t status = RTFHeader::Parse(*source, header);
if (status != B_OK)
return status;
// we support two different output formats
if (outType == B_TRANSLATOR_TEXT)
return convert_to_plain_text(header, *target);
return convert_to_stxt(header, *target);
}
status_t
RTFTranslator::MakeConfigurationView(BMessage *ioExtension, BView **_view, BRect *_extent)
{
if (_view == NULL || _extent == NULL)
return B_BAD_VALUE;
BView *view = new ConfigView(BRect(0, 0, 225, 175));
if (view == NULL)
return BTranslator::MakeConfigurationView(ioExtension, _view, _extent);
*_view = view;
*_extent = view->Bounds();
return B_OK;
}
// #pragma mark -
BTranslator *
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
{
if (n != 0)
return NULL;
return new RTFTranslator();
}
@@ -0,0 +1,64 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef RTF_TRANSLATOR_H
#define RTF_TRANSLATOR_H
#include <Translator.h>
#include <TranslatorFormats.h>
#include <TranslationDefs.h>
#include <GraphicsDefs.h>
#include <InterfaceDefs.h>
#include <DataIO.h>
#include <File.h>
#include <ByteOrder.h>
#include <fs_attr.h>
#include "BaseTranslator.h"
#define RTF_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VER(1, 0, 0)
#define RTF_TEXT_FORMAT 'RTF '
#define RTF_IN_QUALITY 0.7
#define RTF_IN_CAPABILITY 0.9
#define TEXT_OUT_QUALITY 0.3
#define TEXT_OUT_CAPABILITY 0.6
#define STXT_OUT_QUALITY 0.5
#define STXT_OUT_CAPABILITY 0.5
class RTFTranslator : public BTranslator {
public:
RTFTranslator();
virtual const char *TranslatorName() const;
virtual const char *TranslatorInfo() const;
virtual int32 TranslatorVersion() const;
virtual const translation_format *InputFormats(int32 *_outCount) const;
virtual const translation_format *OutputFormats(int32 *_outCount) const;
virtual status_t Identify(BPositionIO *inSource,
const translation_format *inFormat, BMessage *ioExtension,
translator_info *outInfo, uint32 outType);
virtual status_t Translate(BPositionIO *inSource,
const translator_info *inInfo, BMessage *ioExtension,
uint32 outType, BPositionIO *outDestination);
virtual status_t MakeConfigurationView(BMessage *ioExtension,
BView **outView, BRect *outExtent);
protected:
virtual ~RTFTranslator();
// this is protected because the object is deleted by the
// Release() function instead of being deleted directly by
// the user
private:
char *fInfo;
};
#endif /* RTF_TRANSLATOR_H */
@@ -0,0 +1,68 @@
/* Stack - a template stack class
*
* Copyright 2001-2005, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
#ifndef STACK_H
#define STACK_H
#include <SupportDefs.h>
template<class T> class Stack {
public:
Stack()
:
fArray(NULL),
fUsed(0),
fMax(0)
{
}
~Stack()
{
free(fArray);
}
bool IsEmpty() const
{
return fUsed == 0;
}
void MakeEmpty()
{
// could also free the memory
fUsed = 0;
}
status_t Push(T value)
{
if (fUsed >= fMax) {
fMax += 16;
T *newArray = (T *)realloc(fArray, fMax * sizeof(T));
if (newArray == NULL)
return B_NO_MEMORY;
fArray = newArray;
}
fArray[fUsed++] = value;
return B_OK;
}
bool Pop(T *value)
{
if (fUsed == 0)
return false;
*value = fArray[--fUsed];
return true;
}
private:
T *fArray;
int32 fUsed;
int32 fMax;
};
#endif /* STACK_H */
@@ -0,0 +1,341 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "convert.h"
#include <TranslatorFormats.h>
#include <Application.h>
#include <TextView.h>
#include <TypeConstants.h>
#include <ByteOrder.h>
#include <Node.h>
#include <Font.h>
#include <stdlib.h>
#include <string.h>
class AppServerConnection {
public:
AppServerConnection();
~AppServerConnection();
private:
BApplication *fApplication;
};
AppServerConnection::AppServerConnection()
:
fApplication(NULL)
{
// This is not nice, but it's the only we can provide all features on command
// line tools that don't create a BApplication - without a BApplicatio, we
// could not support any text styles (colors and fonts)
if (be_app == NULL)
fApplication = new BApplication("application/x-vnd.Haiku-RTF-Translator");
}
AppServerConnection::~AppServerConnection()
{
delete fApplication;
}
// #pragma mark -
static size_t
get_text_for_command(RTFCommand *command, char *text, size_t size)
{
const char *name = command->Name();
if (!strcmp(name, "\n")
|| !strcmp(name, "par")
|| !strcmp(name, "sect")) {
if (text != NULL)
strlcpy(text, "\n", size);
return 1;
}
return 0;
}
static text_run *
get_style(BList &runs, text_run *run, int32 offset)
{
if (run != NULL && offset == run->offset)
return run;
text_run *newRun = new text_run();
if (newRun == NULL)
throw (status_t)B_NO_MEMORY;
// take over previous styles
if (run != NULL)
*newRun = *run;
newRun->offset = offset;
runs.AddItem(newRun);
return newRun;
}
static text_run_array *
get_text_run_array(RTFHeader &header)
{
// collect styles
RTFIterator iterator(header, RTF_TEXT);
text_run *current = NULL;
int32 offset = 0;
BList runs;
while (iterator.HasNext()) {
RTFElement *element = iterator.Next();
if (RTFText *text = dynamic_cast<RTFText *>(element)) {
offset += text->TextLength();
continue;
}
RTFCommand *command = dynamic_cast<RTFCommand *>(element);
if (command == NULL)
continue;
if (!strcmp(command->Name(), "cf")) {
// foreground color
current = get_style(runs, current, offset);
current->color = header.Color(command->Option());
} else if (!strcmp(command->Name(), "b")) {
// bold style
current = get_style(runs, current, offset);
if (command->Option() != 0)
current->font.SetFace(B_BOLD_FACE);
else
current->font.SetFace(B_REGULAR_FACE);
} else
offset += get_text_for_command(command, NULL, 0);
}
// are there any styles?
if (runs.CountItems() == 0)
return NULL;
// create array
text_run_array *array = (text_run_array *)malloc(sizeof(text_run_array)
+ sizeof(text_run) * (runs.CountItems() - 1));
if (array == NULL)
throw (status_t)B_NO_MEMORY;
array->count = runs.CountItems();
for (int32 i = 0; i < array->count; i++) {
text_run *run = (text_run *)runs.RemoveItem(0L);
array->runs[i] = *run;
delete run;
}
return array;
}
status_t
write_plain_text(RTFHeader &header, BDataIO &target)
{
RTFIterator iterator(header, RTF_TEXT);
while (iterator.HasNext()) {
RTFElement *element = iterator.Next();
char buffer[1024];
const char *string = NULL;
size_t size = 0;
if (RTFText *text = dynamic_cast<RTFText *>(element)) {
string = text->Text();
size = text->TextLength();
} else if (RTFCommand *command = dynamic_cast<RTFCommand *>(element)) {
size = get_text_for_command(command, buffer, sizeof(buffer));
if (size != 0)
string = buffer;
}
if (size == 0)
continue;
ssize_t written = target.Write(string, size);
if (written < B_OK)
return written;
if ((size_t)written != size)
return B_IO_ERROR;
}
return B_OK;
}
// #pragma mark -
status_t
convert_to_stxt(RTFHeader &header, BDataIO &target)
{
// count text bytes
size_t textSize = 0;
RTFIterator iterator(header, RTF_TEXT);
while (iterator.HasNext()) {
RTFElement *element = iterator.Next();
if (RTFText *text = dynamic_cast<RTFText *>(element)) {
textSize += text->TextLength();
} else if (RTFCommand *command = dynamic_cast<RTFCommand *>(element)) {
textSize += get_text_for_command(command, NULL, 0);
}
}
// put out header
TranslatorStyledTextStreamHeader stxtHeader;
stxtHeader.header.magic = 'STXT';
stxtHeader.header.header_size = sizeof(TranslatorStyledTextStreamHeader);
stxtHeader.header.data_size = 0;
stxtHeader.version = 100;
status_t status = swap_data(B_UINT32_TYPE, &stxtHeader, sizeof(stxtHeader),
B_SWAP_HOST_TO_BENDIAN);
if (status != B_OK)
return status;
ssize_t written = target.Write(&stxtHeader, sizeof(stxtHeader));
if (written < B_OK)
return written;
if (written != sizeof(stxtHeader))
return B_IO_ERROR;
TranslatorStyledTextTextHeader textHeader;
textHeader.header.magic = 'TEXT';
textHeader.header.header_size = sizeof(TranslatorStyledTextTextHeader);
textHeader.header.data_size = textSize;
textHeader.charset = B_UNICODE_UTF8;
status = swap_data(B_UINT32_TYPE, &textHeader, sizeof(textHeader),
B_SWAP_HOST_TO_BENDIAN);
if (status != B_OK)
return status;
written = target.Write(&textHeader, sizeof(textHeader));
if (written < B_OK)
return written;
if (written != sizeof(textHeader))
return B_IO_ERROR;
// put out main text
status = write_plain_text(header, target);
if (status < B_OK)
return status;
// prepare styles
AppServerConnection connection;
// we need that for the the text_run/BFont stuff
text_run_array *runs = NULL;
try {
runs = get_text_run_array(header);
} catch (status_t status) {
return status;
}
if (runs == NULL)
return B_OK;
int32 flattenedSize;
void *flattenedRuns = BTextView::FlattenRunArray(runs, &flattenedSize);
if (flattenedRuns == NULL)
return B_NO_MEMORY;
// put out styles
TranslatorStyledTextStyleHeader styleHeader;
styleHeader.header.magic = 'STYL';
styleHeader.header.header_size = sizeof(TranslatorStyledTextStyleHeader);
styleHeader.header.data_size = flattenedSize;
styleHeader.apply_offset = 0;
styleHeader.apply_length = textSize;
status = swap_data(B_UINT32_TYPE, &styleHeader, sizeof(styleHeader),
B_SWAP_HOST_TO_BENDIAN);
if (status != B_OK)
return status;
written = target.Write(&styleHeader, sizeof(styleHeader));
if (written < B_OK)
return written;
if (written != sizeof(styleHeader))
return B_IO_ERROR;
// output actual style information
written = target.Write(flattenedRuns, flattenedSize);
if (written < B_OK)
return written;
if (written != flattenedSize)
return B_IO_ERROR;
return B_OK;
}
status_t
convert_to_plain_text(RTFHeader &header, BPositionIO &target)
{
// put out main text
status_t status = write_plain_text(header, target);
if (status < B_OK)
return status;
// ToDo: this is not really nice, we should adopt the BPositionIO class
// from Dano/Zeta which has meta data support
BNode *node = dynamic_cast<BNode *>(&target);
if (node == NULL) {
// we can't write the styles
return B_OK;
}
// prepare styles
AppServerConnection connection;
// we need that for the the text_run/BFont stuff
text_run_array *runs = NULL;
try {
runs = get_text_run_array(header);
} catch (status_t status) {
// doesn't matter too much if we could write the styles or not
return B_OK;
}
if (runs == NULL)
return B_OK;
int32 flattenedSize;
void *flattenedRuns = BTextView::FlattenRunArray(runs, &flattenedSize);
if (flattenedRuns == NULL)
return B_OK;
// put out styles
ssize_t written = node->WriteAttr("styles", B_RAW_TYPE, 0, flattenedRuns, flattenedSize);
if (written >= B_OK && written != flattenedSize)
node->RemoveAttr("styles");
return B_OK;
}
@@ -0,0 +1,16 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef CONVERT_H
#define CONVERT_H
#include <RTF.h>
#include <DataIO.h>
extern status_t convert_to_stxt(RTFHeader &header, BDataIO &target);
extern status_t convert_to_plain_text(RTFHeader &header, BPositionIO &target);
#endif /* CONVERT_H */
@@ -0,0 +1,31 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "RTFTranslator.h"
#include "RTF.h"
#include <TranslatorWindow.h>
#include <TranslatorRoster.h>
#include <Application.h>
#include <stdio.h>
#include <string.h>
int
main(int /*argc*/, char **/*argv*/)
{
BApplication app("application/x-vnd.haiku-rtf-translator");
status_t result;
result = LaunchTranslatorWindow(new RTFTranslator, "RTF Settings", BRect(0, 0, 225, 175));
if (result != B_OK)
return 1;
app.Run();
return 0;
}