⛏️ index : haiku.git

/*
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <Catalog.h>

#include "ConfigView.h"
#include "convert.h"
#include "RTF.h"


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "RTFTranslator"

#define READ_BUFFER_SIZE 2048
#define DATA_BUFFER_SIZE 64


#define TEXT_IN_QUALITY 0.4
#define TEXT_IN_CAPABILITY 0.6

#define STXT_IN_QUALITY 0.5
#define STXT_IN_CAPABILITY 0.5

#define RTF_OUT_QUALITY RTF_IN_QUALITY
#define RTF_OUT_CAPABILITY RTF_IN_CAPABILITY

// The input formats that this translator supports.
static const translation_format sInputFormats[] = {
	{
		RTF_TEXT_FORMAT,
		B_TRANSLATOR_TEXT,
		RTF_IN_QUALITY,
		RTF_IN_CAPABILITY,
		"text/rtf",
		"RichTextFormat file"
	},
	{
		B_TRANSLATOR_TEXT,
		B_TRANSLATOR_TEXT,
		TEXT_IN_QUALITY,
		TEXT_IN_CAPABILITY,
		"text/plain",
		"Plain text file"
	},
	{
		B_STYLED_TEXT_FORMAT,
		B_TRANSLATOR_TEXT,
		STXT_IN_QUALITY,
		STXT_IN_CAPABILITY,
		"text/x-vnd.Be-stxt",
		"Be styled text file"
	}
};

// The output formats that this translator supports.
static const 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"
	},
	{
		RTF_TEXT_FORMAT,
		B_TRANSLATOR_TEXT,
		RTF_OUT_QUALITY,
		RTF_OUT_CAPABILITY,
		"text/rtf",
		"RichTextFormat file"
	}
};


RTFTranslator::RTFTranslator()
{
	char info[256];
	sprintf(info, B_TRANSLATE("Rich Text Format translator v%d.%d.%d %s"),
		static_cast<int>(B_TRANSLATION_MAJOR_VERSION(RTF_TRANSLATOR_VERSION)),
		static_cast<int>(B_TRANSLATION_MINOR_VERSION(RTF_TRANSLATOR_VERSION)),
		static_cast<int>(B_TRANSLATION_REVISION_VERSION(
			RTF_TRANSLATOR_VERSION)),
		__DATE__);

	fInfo = strdup(info);
}


RTFTranslator::~RTFTranslator()
{
	free(fInfo);
}


const char *
RTFTranslator::TranslatorName() const
{
	return B_TRANSLATE("RTF text files");
}


const char *
RTFTranslator::TranslatorInfo() const
{
	return B_TRANSLATE("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;
	else if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT
		&& outType != RTF_TEXT_FORMAT)
		return B_NO_TRANSLATOR;


	RTF::Parser parser(*stream);
	status_t status = parser.Identify();

	if (status == B_OK) {
		// Source data is RTF. We can translate to RTF (no-op), plaintext, or
		// styled text.

		// 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;
		strlcpy(info->name, B_TRANSLATE("RichTextFormat file"),
			sizeof(info->name));
		strcpy(info->MIME, "text/rtf");
	} else {
		// Not an RTF file. We can only work with it if we are translating to
		// RTF.
		if (outType != RTF_TEXT_FORMAT)
			return B_NO_TRANSLATOR;

		stream->Seek(0, SEEK_SET);
		TranslatorStyledTextStreamHeader header;
		stream->Read(&header, sizeof(header));
		swap_data(B_UINT32_TYPE, &header, sizeof(header),
			B_SWAP_BENDIAN_TO_HOST);
		stream->Seek(0, SEEK_SET);
		if (header.header.magic == B_STYLED_TEXT_FORMAT
			&& header.header.header_size == (int32)sizeof(header)
			&& header.header.data_size == 0
			&& header.version == 100) {
			info->type = B_STYLED_TEXT_FORMAT;
			info->group = B_TRANSLATOR_TEXT;
			info->quality = STXT_IN_QUALITY;
			info->capability = STXT_IN_CAPABILITY;
			strlcpy(info->name, B_TRANSLATE("Be style text file"),
				sizeof(info->name));
			strcpy(info->MIME, "text/x-vnd.Be-stxt");
		} else {
			info->type = B_TRANSLATOR_TEXT;
			info->group = B_TRANSLATOR_TEXT;
			info->quality = TEXT_IN_QUALITY;
			info->capability = TEXT_IN_CAPABILITY;
			strlcpy(info->name, B_TRANSLATE("Plain text file"),
				sizeof(info->name));
			strcpy(info->MIME, "text/plain");
		}
	}
	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
		&& outType != RTF_TEXT_FORMAT)
		return B_NO_TRANSLATOR;

	if (strncmp(inInfo->MIME, "text/rtf", 8) == 0) {
		RTF::Parser parser(*source);

		RTF::Header header;
		status_t status = parser.Parse(header);
		if (status != B_OK)
			return status;

		if (outType == B_TRANSLATOR_TEXT)
			return convert_to_plain_text(header, *target);
		else
			return convert_to_stxt(header, *target);

	} else if (inInfo->type == B_TRANSLATOR_TEXT) {
		return convert_plain_text_to_rtf(*source, *target);
	} else if (inInfo->type == B_STYLED_TEXT_FORMAT) {
		return convert_styled_text_to_rtf(source, target);
	} else
		return B_BAD_VALUE;

}


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();
}