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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user