2005-02-04 07:04:52 +03:00
|
|
|
/*
|
2007-04-05 18:26:06 +04:00
|
|
|
* Copyright 2003-2007, Haiku. All Rights Reserved.
|
2005-02-04 07:04:52 +03:00
|
|
|
* Distributed under the terms of the MIT license.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Axel Dörfler, axeld@pinc-software.de
|
|
|
|
* jonas.sundstrom@kirilla.com
|
|
|
|
*/
|
2003-11-05 14:03:24 +03:00
|
|
|
|
|
|
|
|
|
|
|
#include <TranslationKit.h>
|
|
|
|
#include <Application.h>
|
|
|
|
#include <String.h>
|
|
|
|
#include <File.h>
|
2005-02-04 07:04:52 +03:00
|
|
|
#include <Path.h>
|
|
|
|
#include <Entry.h>
|
2003-11-05 14:03:24 +03:00
|
|
|
#include <Mime.h>
|
2005-02-11 07:37:01 +03:00
|
|
|
#include <NodeInfo.h>
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
#include <stdio.h>
|
2006-05-19 19:52:21 +04:00
|
|
|
#include <stdlib.h>
|
2005-02-04 07:04:52 +03:00
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
|
|
extern const char *__progname;
|
|
|
|
const char *gProgramName = __progname;
|
|
|
|
bool gVerbose = false;
|
|
|
|
|
|
|
|
|
|
|
|
class TypeList {
|
2003-11-05 14:03:24 +03:00
|
|
|
public:
|
2005-02-04 07:04:52 +03:00
|
|
|
void Add(uint32 type);
|
|
|
|
bool Remove(uint32 type);
|
|
|
|
bool FindType(uint32 type);
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
void SetTo(TypeList &types);
|
|
|
|
int32 Count();
|
|
|
|
uint32 TypeAt(int32 index);
|
2003-11-05 14:03:24 +03:00
|
|
|
|
|
|
|
private:
|
2005-02-04 07:04:52 +03:00
|
|
|
BList fList;
|
|
|
|
};
|
|
|
|
|
|
|
|
class RemovingFile : public BFile {
|
|
|
|
public:
|
|
|
|
RemovingFile(const char *path);
|
|
|
|
~RemovingFile();
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
void Keep();
|
|
|
|
|
|
|
|
private:
|
|
|
|
BEntry fEntry;
|
2003-11-05 14:03:24 +03:00
|
|
|
};
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
class Translator {
|
|
|
|
public:
|
|
|
|
Translator(const char *inPath, const char *outPath, uint32 outFormat);
|
|
|
|
~Translator();
|
|
|
|
|
|
|
|
status_t Translate();
|
|
|
|
|
|
|
|
private:
|
|
|
|
status_t Directly(BFile &input, translator_info &info, BFile &output);
|
|
|
|
status_t Indirectly(BFile &input, BFile &output);
|
|
|
|
status_t FindPath(const translation_format *info, BPositionIO &stream,
|
|
|
|
TypeList &typesSeen, TypeList &path, double &pathQuality);
|
2005-02-11 07:37:01 +03:00
|
|
|
status_t GetMimeTypeFromCode(uint32 type, char *mimeType);
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
BTranslatorRoster *fRoster;
|
|
|
|
BPath fInputPath, fOutputPath;
|
|
|
|
uint32 fOutputFormat;
|
|
|
|
};
|
|
|
|
|
|
|
|
class TranslateApp : public BApplication {
|
|
|
|
public:
|
|
|
|
TranslateApp(void);
|
|
|
|
virtual ~TranslateApp();
|
|
|
|
|
|
|
|
virtual void ReadyToRun(void);
|
|
|
|
virtual void ArgvReceived(int32 argc, char **argv);
|
|
|
|
|
|
|
|
private:
|
|
|
|
void PrintUsage(void);
|
|
|
|
void ListTranslators(uint32 type);
|
|
|
|
|
|
|
|
uint32 GetTypeCodeForOutputMime(const char *mime);
|
|
|
|
uint32 GetTypeCodeFromString(const char *string);
|
|
|
|
status_t Translate(BFile &input, translator_info &translator, BFile &output, uint32 type);
|
|
|
|
status_t Translate(BFile &input, BFile &output, uint32 type);
|
|
|
|
status_t Translate(const char *inPath, const char *outPath, uint32 type);
|
|
|
|
|
|
|
|
bool fGotArguments;
|
|
|
|
BTranslatorRoster *fTranslatorRoster;
|
|
|
|
int32 fTranslatorCount;
|
|
|
|
translator_id *fTranslatorArray;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_tupel(const char *format, uint32 value)
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
char tupel[5];
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
for (int32 i = 0; i < 4; i++) {
|
|
|
|
tupel[i] = (value >> (24 - i * 8)) & 0xff;
|
|
|
|
if (!isprint(tupel[i]))
|
|
|
|
tupel[i] = '.';
|
|
|
|
}
|
|
|
|
tupel[4] = '\0';
|
|
|
|
|
|
|
|
printf(format, tupel);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
static void
|
|
|
|
print_translation_format(const translation_format &format)
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
print_tupel("'%s' ", format.type);
|
|
|
|
print_tupel("(%s) ", format.group);
|
|
|
|
|
|
|
|
printf("%.1f %.1f %s ; %s\n", format.quality, format.capability,
|
|
|
|
format.MIME, format.name);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
TypeList::Add(uint32 type)
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
fList.AddItem((void *)type, 0);
|
|
|
|
}
|
2003-11-05 14:03:24 +03:00
|
|
|
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
bool
|
|
|
|
TypeList::Remove(uint32 type)
|
|
|
|
{
|
|
|
|
return fList.RemoveItem((void *)type);
|
|
|
|
}
|
2003-11-05 14:03:24 +03:00
|
|
|
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
bool
|
|
|
|
TypeList::FindType(uint32 type)
|
|
|
|
{
|
|
|
|
return fList.IndexOf((void *)type) >= 0;
|
|
|
|
}
|
|
|
|
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
void
|
|
|
|
TypeList::SetTo(TypeList &types)
|
|
|
|
{
|
|
|
|
fList.MakeEmpty();
|
|
|
|
|
|
|
|
for (int32 i = 0; i < types.Count(); i++)
|
|
|
|
fList.AddItem((void *)types.TypeAt(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int32
|
|
|
|
TypeList::Count()
|
|
|
|
{
|
|
|
|
return fList.CountItems();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32
|
|
|
|
TypeList::TypeAt(int32 index)
|
|
|
|
{
|
|
|
|
return (uint32)fList.ItemAt(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
RemovingFile::RemovingFile(const char *path)
|
|
|
|
: BFile(path, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE),
|
|
|
|
fEntry(path)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RemovingFile::~RemovingFile()
|
|
|
|
{
|
|
|
|
fEntry.Remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
RemovingFile::Keep()
|
|
|
|
{
|
|
|
|
fEntry.Unset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
Translator::Translator(const char *inPath, const char *outPath, uint32 outputFormat)
|
|
|
|
:
|
|
|
|
fRoster(BTranslatorRoster::Default()),
|
|
|
|
fInputPath(inPath),
|
|
|
|
fOutputPath(outPath),
|
|
|
|
fOutputFormat(outputFormat)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Translator::~Translator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
Translator::Translate()
|
|
|
|
{
|
2003-11-05 14:03:24 +03:00
|
|
|
// input file
|
2005-02-04 07:04:52 +03:00
|
|
|
BFile input;
|
|
|
|
status_t status = input.SetTo(fInputPath.Path(), B_READ_ONLY);
|
|
|
|
if (status != B_OK) {
|
|
|
|
fprintf(stderr, "%s: could not open \"%s\": %s\n",
|
|
|
|
gProgramName, fInputPath.Path(), strerror(status));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find a direct translator
|
|
|
|
bool direct = true;
|
|
|
|
translator_info translator;
|
|
|
|
status = fRoster->Identify(&input, NULL, &translator, 0, NULL, fOutputFormat);
|
|
|
|
if (status < B_OK) {
|
|
|
|
// no direct translator found - let's try with something else
|
|
|
|
status = fRoster->Identify(&input, NULL, &translator);
|
|
|
|
if (status < B_OK) {
|
|
|
|
fprintf(stderr, "%s: identifying \"%s\" failed: %s\n",
|
|
|
|
gProgramName, fInputPath.Path(), strerror(status));
|
|
|
|
return status;
|
|
|
|
}
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
direct = false;
|
|
|
|
}
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
// output file
|
|
|
|
RemovingFile output(fOutputPath.Path());
|
|
|
|
if ((status = output.InitCheck()) != B_OK) {
|
|
|
|
fprintf(stderr, "%s: Could not create \"%s\": %s\n",
|
|
|
|
gProgramName, fOutputPath.Path(), strerror(status));
|
|
|
|
return status;
|
|
|
|
}
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
if (direct)
|
|
|
|
status = Directly(input, translator, output);
|
|
|
|
else
|
|
|
|
status = Indirectly(input, output);
|
|
|
|
|
|
|
|
if (status == B_OK) {
|
|
|
|
output.Keep();
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
// add filetype attribute
|
|
|
|
update_mime_info(fOutputPath.Path(), false, true, false);
|
2005-02-11 07:37:01 +03:00
|
|
|
|
|
|
|
char mimeType[B_ATTR_NAME_LENGTH];
|
|
|
|
BNode node(fOutputPath.Path());
|
|
|
|
BNodeInfo info(&node);
|
|
|
|
if (info.GetType(mimeType) != B_OK || !strcasecmp(mimeType, B_FILE_MIME_TYPE)) {
|
|
|
|
// the Registrar couldn't find a type for this file
|
|
|
|
// so let's use the information we have from the
|
|
|
|
// translator
|
|
|
|
if (GetMimeTypeFromCode(fOutputFormat, mimeType) == B_OK)
|
|
|
|
info.SetType(mimeType);
|
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s: translating failed: %s\n",
|
|
|
|
gProgramName, strerror(status));
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Converts the input file to the output file using the
|
|
|
|
* specified translator.
|
|
|
|
*/
|
|
|
|
|
|
|
|
status_t
|
|
|
|
Translator::Directly(BFile &input, translator_info &info, BFile &output)
|
|
|
|
{
|
|
|
|
if (gVerbose)
|
|
|
|
printf("Direct translation from \"%s\"\n", info.name);
|
|
|
|
|
|
|
|
return fRoster->Translate(&input, &info, NULL, &output, fOutputFormat);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Converts the input file to the output file by computing the best
|
|
|
|
* quality path between the input type and the output type, and then
|
|
|
|
* applies as many translators as needed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
status_t
|
|
|
|
Translator::Indirectly(BFile &input, BFile &output)
|
|
|
|
{
|
|
|
|
TypeList translatorPath;
|
|
|
|
TypeList handledTypes;
|
|
|
|
double quality;
|
|
|
|
|
|
|
|
if (FindPath(NULL, input, handledTypes, translatorPath, quality) != B_OK)
|
|
|
|
return B_NO_TRANSLATOR;
|
|
|
|
|
|
|
|
// The initial input stream is the input file which gets translated into
|
|
|
|
// the first buffer. After that, the two buffers fill each other, until
|
|
|
|
// the end is reached and the output file is the translation target
|
|
|
|
|
|
|
|
BMallocIO buffer[2];
|
|
|
|
BPositionIO *inputStream = &input;
|
|
|
|
BPositionIO *outputStream = &buffer[0];
|
|
|
|
|
|
|
|
for (int32 i = 0; i < translatorPath.Count(); i++) {
|
|
|
|
uint32 type = translatorPath.TypeAt(i);
|
|
|
|
if (type == fOutputFormat)
|
|
|
|
outputStream = &output;
|
2003-11-05 14:03:24 +03:00
|
|
|
else
|
2005-02-04 07:04:52 +03:00
|
|
|
outputStream->SetSize(0);
|
|
|
|
|
|
|
|
inputStream->Seek(0, SEEK_SET);
|
|
|
|
// rewind the input stream
|
|
|
|
|
|
|
|
status_t status = fRoster->Translate(inputStream, NULL, NULL, outputStream, type);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
// switch buffers
|
|
|
|
inputStream = &buffer[i % 2];
|
|
|
|
outputStream = &buffer[(i + 1) % 2];
|
|
|
|
|
|
|
|
if (gVerbose)
|
|
|
|
print_tupel(" '%s'\n", type);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
Translator::FindPath(const translation_format *format, BPositionIO &stream,
|
|
|
|
TypeList &typesSeen, TypeList &path, double &pathQuality)
|
|
|
|
{
|
|
|
|
translator_info *infos = NULL;
|
|
|
|
translator_id *ids = NULL;
|
|
|
|
int32 count;
|
|
|
|
uint32 inFormat = 0;
|
|
|
|
uint32 group = 0;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
// Get a list of capable translators (or all of them)
|
|
|
|
|
|
|
|
if (format == NULL) {
|
|
|
|
status = fRoster->GetTranslators(&stream, NULL, &infos, &count);
|
|
|
|
if (status == B_OK && count > 0) {
|
|
|
|
inFormat = infos[0].type;
|
|
|
|
group = infos[0].group;
|
|
|
|
|
|
|
|
if (gVerbose) {
|
|
|
|
puts("Indirect translation:");
|
|
|
|
print_tupel(" '%s', ", inFormat);
|
|
|
|
printf("%s\n", infos[0].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status = fRoster->GetAllTranslators(&ids, &count);
|
|
|
|
inFormat = format->type;
|
|
|
|
group = format->group;
|
|
|
|
}
|
|
|
|
if (status != B_OK || count == 0) {
|
|
|
|
delete[] infos;
|
|
|
|
delete[] ids;
|
|
|
|
return status;
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
// build the best path to get from here to fOutputFormat recursively
|
|
|
|
// (via depth search, best quality/capability wins)
|
|
|
|
|
|
|
|
TypeList bestPath;
|
|
|
|
double bestQuality = -1;
|
|
|
|
status = B_NO_TRANSLATOR;
|
|
|
|
|
|
|
|
for (int32 i = 0; i < count; i++) {
|
|
|
|
const translation_format *formats;
|
|
|
|
int32 formatCount;
|
|
|
|
bool matches = false;
|
|
|
|
int32 id = ids ? ids[i] : infos[i].translator;
|
|
|
|
if (fRoster->GetInputFormats(id, &formats, &formatCount) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// see if this translator is good enough for us
|
|
|
|
for (int32 j = 0; j < formatCount; j++) {
|
|
|
|
if (formats[j].type == inFormat) {
|
|
|
|
matches = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
if (!matches)
|
|
|
|
continue;
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
// search output formats
|
|
|
|
|
|
|
|
if (fRoster->GetOutputFormats(id, &formats, &formatCount) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
typesSeen.Add(inFormat);
|
|
|
|
|
|
|
|
for (int32 j = 0; j < formatCount; j++) {
|
|
|
|
if (formats[j].group != group || typesSeen.FindType(formats[j].type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
double formatQuality = formats[j].quality * formats[j].capability;
|
|
|
|
|
|
|
|
if (formats[j].type == fOutputFormat) {
|
|
|
|
// we've found our target type, so we can stop the path here
|
|
|
|
bestPath.Add(formats[j].type);
|
|
|
|
bestQuality = formatQuality;
|
|
|
|
status = B_OK;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeList path;
|
|
|
|
double quality;
|
|
|
|
if (FindPath(&formats[j], stream, typesSeen, path, quality) == B_OK) {
|
|
|
|
if (bestQuality < quality * formatQuality) {
|
|
|
|
bestQuality = quality * formatQuality;
|
|
|
|
bestPath.SetTo(path);
|
|
|
|
bestPath.Add(formats[j].type);
|
|
|
|
status = B_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typesSeen.Remove(inFormat);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
if (status == B_OK) {
|
|
|
|
pathQuality = bestQuality;
|
|
|
|
path.SetTo(bestPath);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
delete[] infos;
|
|
|
|
delete[] ids;
|
|
|
|
return status;
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
|
2005-02-11 07:37:01 +03:00
|
|
|
status_t
|
|
|
|
Translator::GetMimeTypeFromCode(uint32 type, char *mimeType)
|
|
|
|
{
|
|
|
|
translator_id *ids = NULL;
|
|
|
|
int32 count;
|
|
|
|
status_t status = fRoster->GetAllTranslators(&ids, &count);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = B_NO_TRANSLATOR;
|
|
|
|
|
|
|
|
for (int32 i = 0; i < count; i++) {
|
|
|
|
const translation_format *format = NULL;
|
|
|
|
int32 formatCount = 0;
|
|
|
|
fRoster->GetOutputFormats(ids[i], &format, &formatCount);
|
|
|
|
|
|
|
|
for (int32 j = 0; j < formatCount; j++) {
|
|
|
|
if (type == format[j].type) {
|
|
|
|
strcpy(mimeType, format[j].MIME);
|
|
|
|
status = B_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] ids;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
TranslateApp::TranslateApp(void)
|
|
|
|
: BApplication("application/x-vnd.haiku-translate"),
|
|
|
|
fGotArguments(false),
|
|
|
|
fTranslatorRoster(BTranslatorRoster::Default()),
|
|
|
|
fTranslatorCount(0),
|
|
|
|
fTranslatorArray(NULL)
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
fTranslatorRoster->GetAllTranslators(&fTranslatorArray, &fTranslatorCount);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
TranslateApp::~TranslateApp()
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
delete[] fTranslatorArray;
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
TranslateApp::ArgvReceived(int32 argc, char **argv)
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
if (argc < 2
|
|
|
|
|| !strcmp(argv[1], "--help"))
|
|
|
|
return;
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
if (!strcmp(argv[1], "--list")) {
|
|
|
|
fGotArguments = true;
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
uint32 type = B_TRANSLATOR_ANY_TYPE;
|
|
|
|
if (argc > 2)
|
|
|
|
type = GetTypeCodeFromString(argv[2]);
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
ListTranslators(type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(argv[1], "--verbose")) {
|
|
|
|
fGotArguments = true;
|
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
gVerbose = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc != 4)
|
|
|
|
return;
|
|
|
|
|
|
|
|
fGotArguments = true;
|
|
|
|
|
|
|
|
// get typecode of output format
|
|
|
|
uint32 outputFormat = 0;
|
|
|
|
BMimeType mime(argv[3]);
|
|
|
|
|
|
|
|
if (mime.IsValid() && !mime.IsSupertypeOnly()) {
|
|
|
|
// MIME-string
|
|
|
|
outputFormat = GetTypeCodeForOutputMime(argv[3]);
|
|
|
|
} else
|
|
|
|
outputFormat = GetTypeCodeFromString(argv[3]);
|
|
|
|
|
|
|
|
if (outputFormat == 0) {
|
|
|
|
fprintf(stderr, "%s: bad format: %s\nformat is 4-byte type code or full MIME type\n",
|
|
|
|
gProgramName, argv[3]);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Translator translator(argv[1], argv[2], outputFormat);
|
|
|
|
status_t status = translator.Translate();
|
|
|
|
if (status < B_OK)
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
TranslateApp::ReadyToRun(void)
|
|
|
|
{
|
|
|
|
if (fGotArguments == false)
|
|
|
|
PrintUsage();
|
|
|
|
|
|
|
|
PostMessage(B_QUIT_REQUESTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
TranslateApp::PrintUsage(void)
|
|
|
|
{
|
|
|
|
printf("usage: %s { --list [type] | input output format }\n"
|
|
|
|
"\t\"format\" can expressed as 4-byte type code (ie. 'TEXT') or as MIME type.\n",
|
|
|
|
gProgramName);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
TranslateApp::ListTranslators(uint32 type)
|
|
|
|
{
|
|
|
|
for (int32 i = 0; i < fTranslatorCount; i++) {
|
|
|
|
const char *name = NULL;
|
|
|
|
const char *info = NULL;
|
|
|
|
int32 version = 0;
|
|
|
|
if (fTranslatorRoster->GetTranslatorInfo(fTranslatorArray[i], &name, &info, &version) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const translation_format *inputFormats = NULL;
|
|
|
|
const translation_format *outputFormats = NULL;
|
|
|
|
int32 inCount = 0, outCount = 0;
|
|
|
|
fTranslatorRoster->GetInputFormats(fTranslatorArray[i], &inputFormats, &inCount);
|
|
|
|
fTranslatorRoster->GetOutputFormats(fTranslatorArray[i], &outputFormats, &outCount);
|
|
|
|
|
|
|
|
// test if the translator has formats of the specified type
|
2003-11-05 14:03:24 +03:00
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
if (type != B_TRANSLATOR_ANY_TYPE) {
|
|
|
|
bool matches = false;
|
|
|
|
|
|
|
|
for (int32 j = 0; j < inCount; j++) {
|
|
|
|
if (inputFormats[j].group == type || inputFormats[j].type == type) {
|
|
|
|
matches = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int32 j = 0; j < outCount; j++) {
|
|
|
|
if (outputFormats[j].group == type || outputFormats[j].type == type) {
|
|
|
|
matches = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!matches)
|
|
|
|
continue;
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
printf("name: %s\ninfo: %s\nversion: %ld.%ld.%ld\n", name, info,
|
2005-02-06 00:12:22 +03:00
|
|
|
B_TRANSLATION_MAJOR_VERSION(version),
|
|
|
|
B_TRANSLATION_MINOR_VERSION(version),
|
|
|
|
B_TRANSLATION_REVISION_VERSION(version));
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
for (int32 j = 0; j < inCount; j++) {
|
|
|
|
printf(" input:\t");
|
2007-04-05 18:26:06 +04:00
|
|
|
print_translation_format(inputFormats[j]);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
for (int32 j = 0; j < outCount; j++) {
|
|
|
|
printf(" output:\t");
|
|
|
|
print_translation_format(outputFormats[j]);
|
|
|
|
}
|
|
|
|
|
2003-11-05 14:03:24 +03:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
uint32
|
|
|
|
TranslateApp::GetTypeCodeForOutputMime(const char *mime)
|
|
|
|
{
|
|
|
|
for (int32 i = 0; i < fTranslatorCount; i++) {
|
|
|
|
const translation_format *format = NULL;
|
|
|
|
int32 count = 0;
|
|
|
|
fTranslatorRoster->GetOutputFormats(fTranslatorArray[i], &format, &count);
|
|
|
|
|
2005-02-11 07:37:01 +03:00
|
|
|
for (int32 j = 0; j < count; j++) {
|
|
|
|
if (!strcmp(mime, format[j].MIME))
|
|
|
|
return format[j].type;
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
|
2003-11-05 14:03:24 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
uint32
|
|
|
|
TranslateApp::GetTypeCodeFromString(const char *string)
|
2003-11-05 14:03:24 +03:00
|
|
|
{
|
2005-02-04 07:04:52 +03:00
|
|
|
size_t length = strlen(string);
|
|
|
|
if (length > 4)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uint8 code[4] = {' ', ' ', ' ', ' '};
|
|
|
|
|
|
|
|
for (uint32 i = 0; i < length; i++)
|
|
|
|
code[i] = (uint8)string[i];
|
|
|
|
|
|
|
|
return B_HOST_TO_BENDIAN_INT32(*(uint32 *)code);
|
2003-11-05 14:03:24 +03:00
|
|
|
}
|
2005-02-04 07:04:52 +03:00
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
main()
|
|
|
|
{
|
|
|
|
new TranslateApp();
|
|
|
|
be_app->Run();
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|