1/*****************************************************************************/
2// BaseTranslator
3// Written by Michael Wilber, Haiku Translation Kit Team
4//
5// BaseTranslator.cpp
6//
7// The BaseTranslator class implements functionality common to most
8// Translators so that this functionality need not be implemented over and
9// over in each Translator.
10//
11//
12// Copyright (c) 2004 Haiku, Inc.
13//
14// Permission is hereby granted, free of charge, to any person obtaining a
15// copy of this software and associated documentation files (the "Software"),
16// to deal in the Software without restriction, including without limitation
17// the rights to use, copy, modify, merge, publish, distribute, sublicense,
18// and/or sell copies of the Software, and to permit persons to whom the
19// Software is furnished to do so, subject to the following conditions:
20//
21// The above copyright notice and this permission notice shall be included
22// in all copies or substantial portions of the Software.
23//
24// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30// DEALINGS IN THE SOFTWARE.
31/*****************************************************************************/
32
33#include "BaseTranslator.h"
34
35#include <string.h>
36#include <stdio.h>
37
38#include <algorithm>
39
40#include <Catalog.h>
41#include <Locale.h>
42
43
44#undef B_TRANSLATION_CONTEXT
45#define B_TRANSLATION_CONTEXT "BaseTranslator"
46
47
48// ---------------------------------------------------------------
49// Constructor
50//
51// Sets up the version info and the name of the translator so that
52// these values can be returned when they are requested.
53//
54// Preconditions:
55//
56// Parameters:
57//
58// Postconditions:
59//
60// Returns:
61// ---------------------------------------------------------------
62BaseTranslator::BaseTranslator(const char *name, const char *info,
63	const int32 version, const translation_format *inFormats,
64	int32 inCount, const translation_format *outFormats, int32 outCount,
65	const char *settingsFile, const TranSetting *defaults, int32 defCount,
66	uint32 tranGroup, uint32 tranType)
67	:
68	BTranslator()
69{
70	fSettings = new TranslatorSettings(settingsFile, defaults, defCount);
71	fSettings->LoadSettings();
72		// load settings from the Base Translator settings file
73
74	fVersion = version;
75	fName = new char[strlen(name) + 1];
76	strcpy(fName, name);
77	fInfo = new char[strlen(info) + 41];
78	sprintf(fInfo, "%s v%d.%d.%d %s", info,
79		static_cast<int>(B_TRANSLATION_MAJOR_VERSION(fVersion)),
80		static_cast<int>(B_TRANSLATION_MINOR_VERSION(fVersion)),
81		static_cast<int>(B_TRANSLATION_REVISION_VERSION(fVersion)),
82		__DATE__);
83
84	fInputFormats = inFormats;
85	fInputCount = (fInputFormats) ? inCount : 0;
86	fOutputFormats = outFormats;
87	fOutputCount = (fOutputFormats) ? outCount : 0;
88	fTranGroup = tranGroup;
89	fTranType = tranType;
90}
91
92
93// ---------------------------------------------------------------
94// Destructor
95//
96// Does nothing
97//
98// Preconditions:
99//
100// Parameters:
101//
102// Postconditions:
103//
104// Returns:
105// ---------------------------------------------------------------
106//
107// NOTE: It may be the case, that under Be's libtranslation.so,
108// that this destructor will never be called
109BaseTranslator::~BaseTranslator()
110{
111	fSettings->Release();
112	delete[] fName;
113	delete[] fInfo;
114}
115
116
117// ---------------------------------------------------------------
118// TranslatorName
119//
120// Returns the short name of the translator.
121//
122// Preconditions:
123//
124// Parameters:
125//
126// Postconditions:
127//
128// Returns: a const char * to the short name of the translator
129// ---------------------------------------------------------------
130const char *
131BaseTranslator::TranslatorName() const
132{
133	return fName;
134}
135
136
137// ---------------------------------------------------------------
138// TranslatorInfo
139//
140// Returns a more verbose name for the translator than the one
141// TranslatorName() returns. This usually includes version info.
142//
143// Preconditions:
144//
145// Parameters:
146//
147// Postconditions:
148//
149// Returns: a const char * to the verbose name of the translator
150// ---------------------------------------------------------------
151const char *
152BaseTranslator::TranslatorInfo() const
153{
154	return fInfo;
155}
156
157
158// ---------------------------------------------------------------
159// TranslatorVersion
160//
161// Returns the integer representation of the current version of
162// this translator.
163//
164// Preconditions:
165//
166// Parameters:
167//
168// Postconditions:
169//
170// Returns:
171// ---------------------------------------------------------------
172int32
173BaseTranslator::TranslatorVersion() const
174{
175	return fVersion;
176}
177
178
179// ---------------------------------------------------------------
180// InputFormats
181//
182// Returns a list of input formats supported by this translator.
183//
184// Preconditions:
185//
186// Parameters:	out_count,	The number of input formats
187//							support is returned here.
188//
189// Postconditions:
190//
191// Returns: the array of input formats and the number of input
192// formats through the out_count parameter
193// ---------------------------------------------------------------
194const translation_format *
195BaseTranslator::InputFormats(int32 *out_count) const
196{
197	if (out_count) {
198		*out_count = fInputCount;
199		return fInputFormats;
200	} else
201		return NULL;
202}
203
204
205// ---------------------------------------------------------------
206// OutputFormats
207//
208// Returns a list of output formats supported by this translator.
209//
210// Preconditions:
211//
212// Parameters:	out_count,	The number of output formats
213//							support is returned here.
214//
215// Postconditions:
216//
217// Returns: the array of output formats and the number of output
218// formats through the out_count parameter
219// ---------------------------------------------------------------
220const translation_format *
221BaseTranslator::OutputFormats(int32 *out_count) const
222{
223	if (out_count) {
224		*out_count = fOutputCount;
225		return fOutputFormats;
226	} else
227		return NULL;
228}
229
230
231// ---------------------------------------------------------------
232// identify_bits_header
233//
234// Determines if the data in inSource is in the
235// B_TRANSLATOR_BITMAP ('bits') format. If it is, it returns
236// info about the data in inSource to outInfo and pheader.
237//
238// Preconditions:
239//
240// Parameters:	inSource,	The source of the image data
241//
242//				outInfo,	Information about the translator
243//							is copied here
244//
245//				amtread,	Amount of data read from inSource
246//							before this function was called
247//
248//				read,		Pointer to the data that was read
249// 							in before this function was called
250//
251//				pheader,	The bits header is copied here after
252//							it is read in from inSource
253//
254// Postconditions:
255//
256// Returns: B_NO_TRANSLATOR,	if the data does not look like
257//								bits format data
258//
259// B_ERROR,	if the header data could not be converted to host
260//			format
261//
262// B_OK,	if the data looks like bits data and no errors were
263//			encountered
264// ---------------------------------------------------------------
265status_t
266BaseTranslator::identify_bits_header(BPositionIO *inSource,
267	translator_info *outInfo, TranslatorBitmap *pheader)
268{
269	TranslatorBitmap header;
270
271	// read in the header
272	ssize_t size = sizeof(TranslatorBitmap);
273	if (inSource->Read(
274		(reinterpret_cast<uint8 *> (&header)), size) != size)
275		return B_NO_TRANSLATOR;
276
277	// convert to host byte order
278	if (swap_data(B_UINT32_TYPE, &header, sizeof(TranslatorBitmap),
279		B_SWAP_BENDIAN_TO_HOST) != B_OK)
280		return B_ERROR;
281
282	// check if header values are reasonable
283	if (header.colors != B_RGB32 &&
284		header.colors != B_RGB32_BIG &&
285		header.colors != B_RGBA32 &&
286		header.colors != B_RGBA32_BIG &&
287		header.colors != B_RGB24 &&
288		header.colors != B_RGB24_BIG &&
289		header.colors != B_RGB16 &&
290		header.colors != B_RGB16_BIG &&
291		header.colors != B_RGB15 &&
292		header.colors != B_RGB15_BIG &&
293		header.colors != B_RGBA15 &&
294		header.colors != B_RGBA15_BIG &&
295		header.colors != B_CMAP8 &&
296		header.colors != B_GRAY8 &&
297		header.colors != B_GRAY1 &&
298		header.colors != B_CMYK32 &&
299		header.colors != B_CMY32 &&
300		header.colors != B_CMYA32 &&
301		header.colors != B_CMY24)
302		return B_NO_TRANSLATOR;
303	if (header.rowBytes * (header.bounds.Height() + 1) != header.dataSize)
304		return B_NO_TRANSLATOR;
305
306	if (outInfo) {
307		outInfo->type = B_TRANSLATOR_BITMAP;
308		outInfo->group = B_TRANSLATOR_BITMAP;
309		outInfo->quality = 0.2;
310		outInfo->capability = 0.2;
311		strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format"),
312			sizeof(outInfo->name));
313		strcpy(outInfo->MIME, "image/x-be-bitmap");
314
315		// Look for quality / capability info in fInputFormats
316		for (int32 i = 0; i < fInputCount; i++) {
317			if (fInputFormats[i].type == B_TRANSLATOR_BITMAP &&
318				fInputFormats[i].group == B_TRANSLATOR_BITMAP) {
319				outInfo->quality = fInputFormats[i].quality;
320				outInfo->capability = fInputFormats[i].capability;
321				strcpy(outInfo->name, fInputFormats[i].name);
322				break;
323			}
324		}
325	}
326
327	if (pheader) {
328		pheader->magic = header.magic;
329		pheader->bounds = header.bounds;
330		pheader->rowBytes = header.rowBytes;
331		pheader->colors = header.colors;
332		pheader->dataSize = header.dataSize;
333	}
334
335	return B_OK;
336}
337
338
339// ---------------------------------------------------------------
340// BitsCheck
341//
342// Examines the input stream for B_TRANSLATOR_BITMAP format
343// information and determines if BaseTranslator can handle
344// the translation entirely, if it must pass the task of
345// translation to the derived translator or if the stream cannot
346// be decoded by the BaseTranslator or the derived translator.
347//
348// Preconditions:
349//
350// Parameters:	inSource,	where the data to examine is
351//
352//				ioExtension,	configuration settings for the
353//								translator
354//
355//				outType,	The format that the user wants
356//							the data in inSource to be
357//							converted to. NOTE: This is passed by
358//							reference so that it can modify the
359//							outType that is seen by the
360//							BaseTranslator and the derived
361//							translator
362//
363// Postconditions:
364//
365// Returns: B_NO_TRANSLATOR,	if this translator can't handle
366//								the data in inSource
367//
368// B_ERROR,	if there was an error converting the data to the host
369//			format
370//
371// B_BAD_VALUE, if the settings in ioExtension are bad
372//
373// B_OK,	if this translator understand the data and there were
374//			no errors found
375// ---------------------------------------------------------------
376status_t
377BaseTranslator::BitsCheck(BPositionIO *inSource, BMessage *ioExtension,
378	uint32 &outType)
379{
380	if (!outType)
381		outType = B_TRANSLATOR_BITMAP;
382	if (outType != B_TRANSLATOR_BITMAP && outType != fTranType)
383		return B_NO_TRANSLATOR;
384
385	// Convert the magic numbers to the various byte orders so that
386	// I won't have to convert the data read in to see whether or not
387	// it is a supported type
388	const uint32 kBitsMagic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
389
390	// Read in the magic number and determine if it
391	// is a supported type
392	uint8 ch[4];
393	if (inSource->Read(ch, 4) != 4)
394		return B_NO_TRANSLATOR;
395	inSource->Seek(-4, SEEK_CUR);
396		// seek backward becuase functions used after this one
397		// expect the stream to be at the beginning
398
399	// Read settings from ioExtension
400	if (ioExtension && fSettings->LoadSettings(ioExtension) < B_OK)
401		return B_BAD_VALUE;
402
403	uint32 sourceMagic;
404	memcpy(&sourceMagic, ch, sizeof(uint32));
405	if (sourceMagic == kBitsMagic)
406		return B_OK;
407	return B_OK + 1;
408}
409
410
411status_t
412BaseTranslator::BitsIdentify(BPositionIO *inSource,
413	const translation_format *inFormat, BMessage *ioExtension,
414	translator_info *outInfo, uint32 outType)
415{
416	status_t result = BitsCheck(inSource, ioExtension, outType);
417	if (result == B_OK) {
418		TranslatorBitmap bitmap;
419		result = identify_bits_header(inSource, outInfo, &bitmap);
420		if (result == B_OK)
421			result = DerivedCanHandleImageSize(bitmap.bounds.Width() + 1.0,
422				bitmap.bounds.Height() + 1.0);
423	} else if (result >= B_OK) {
424		// if NOT B_TRANSLATOR_BITMAP, it could be an image in the
425		// derived format
426		result = DerivedIdentify(inSource, inFormat, ioExtension,
427			outInfo, outType);
428	}
429	return result;
430}
431
432
433// ---------------------------------------------------------------
434// Identify
435//
436// Examines the data from inSource and determines if it is in a
437// format that this translator knows how to work with.
438//
439// Preconditions:
440//
441// Parameters:	inSource,	where the data to examine is
442//
443//				inFormat,	a hint about the data in inSource,
444//							it is ignored since it is only a hint
445//
446//				ioExtension,	configuration settings for the
447//								translator
448//
449//				outInfo,	information about what data is in
450//							inSource and how well this translator
451//							can handle that data is stored here
452//
453//				outType,	The format that the user wants
454//							the data in inSource to be
455//							converted to
456//
457// Postconditions:
458//
459// Returns: B_NO_TRANSLATOR,	if this translator can't handle
460//								the data in inSource
461//
462// B_ERROR,	if there was an error converting the data to the host
463//			format
464//
465// B_BAD_VALUE, if the settings in ioExtension are bad
466//
467// B_OK,	if this translator understand the data and there were
468//			no errors found
469// ---------------------------------------------------------------
470status_t
471BaseTranslator::Identify(BPositionIO *inSource,
472	const translation_format *inFormat, BMessage *ioExtension,
473	translator_info *outInfo, uint32 outType)
474{
475	switch (fTranGroup) {
476		case B_TRANSLATOR_BITMAP:
477			return BitsIdentify(inSource, inFormat, ioExtension,
478				outInfo, outType);
479
480		default:
481			return DerivedIdentify(inSource, inFormat, ioExtension,
482				outInfo, outType);
483	}
484}
485
486
487// ---------------------------------------------------------------
488// translate_from_bits_to_bits
489//
490// Convert the data in inSource from the Be Bitmap format ('bits')
491// to the format specified in outType (either bits or Base).
492//
493// Preconditions:
494//
495// Parameters:	inSource,	the bits data to translate
496//
497// 				amtread,	the amount of data already read from
498//							inSource
499//
500//				read,		pointer to the data already read from
501//							inSource
502//
503//				outType,	the type of data to convert to
504//
505//				outDestination,	where the output is written to
506//
507// Postconditions:
508//
509// Returns: B_NO_TRANSLATOR,	if the data is not in a supported
510//								format
511//
512// B_ERROR, if there was an error allocating memory or some other
513//			error
514//
515// B_OK, if successfully translated the data from the bits format
516// ---------------------------------------------------------------
517status_t
518BaseTranslator::translate_from_bits_to_bits(BPositionIO *inSource,
519	uint32 outType,	BPositionIO *outDestination)
520{
521	TranslatorBitmap bitsHeader;
522	bool bheaderonly = false, bdataonly = false;
523
524	status_t result;
525	result = identify_bits_header(inSource, NULL, &bitsHeader);
526	if (result != B_OK)
527		return result;
528
529	// Translate B_TRANSLATOR_BITMAP to B_TRANSLATOR_BITMAP, easy enough :)
530	if (outType == B_TRANSLATOR_BITMAP) {
531		// write out bitsHeader (only if configured to)
532		if (bheaderonly || (!bheaderonly && !bdataonly)) {
533			if (swap_data(B_UINT32_TYPE, &bitsHeader,
534				sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK)
535				return B_ERROR;
536			if (outDestination->Write(&bitsHeader,
537				sizeof(TranslatorBitmap)) != sizeof(TranslatorBitmap))
538				return B_ERROR;
539		}
540
541		// write out the data (only if configured to)
542		if (bdataonly || (!bheaderonly && !bdataonly)) {
543			uint8 buf[1024];
544			uint32 remaining = B_BENDIAN_TO_HOST_INT32(bitsHeader.dataSize);
545			ssize_t rd, writ;
546			rd = inSource->Read(buf, 1024);
547			while (rd > 0) {
548				writ = outDestination->Write(buf, rd);
549				if (writ < 0)
550					break;
551				remaining -= static_cast<uint32>(writ);
552				rd = inSource->Read(buf, std::min((uint32)1024,
553					remaining));
554			}
555
556			if (remaining > 0)
557				return B_ERROR;
558			else
559				return B_OK;
560		} else
561			return B_OK;
562
563	} else
564		return B_NO_TRANSLATOR;
565}
566
567
568status_t
569BaseTranslator::BitsTranslate(BPositionIO *inSource,
570	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
571	BPositionIO *outDestination)
572{
573	status_t result = BitsCheck(inSource, ioExtension, outType);
574	if (result == B_OK && outType == B_TRANSLATOR_BITMAP) {
575		result = translate_from_bits_to_bits(inSource, outType,
576			outDestination);
577	} else if (result >= B_OK) {
578		// If NOT B_TRANSLATOR_BITMAP type it could be the derived format
579		result = DerivedTranslate(inSource, inInfo, ioExtension, outType,
580			outDestination, (result == B_OK));
581	}
582	return result;
583}
584
585
586// ---------------------------------------------------------------
587// Translate
588//
589// Translates the data in inSource to the type outType and stores
590// the translated data in outDestination.
591//
592// Preconditions:
593//
594// Parameters:	inSource,	the data to be translated
595//
596//				inInfo,	hint about the data in inSource (not used)
597//
598//				ioExtension,	configuration options for the
599//								translator
600//
601//				outType,	the type to convert inSource to
602//
603//				outDestination,	where the translated data is
604//								put
605//
606// Postconditions:
607//
608// Returns: B_BAD_VALUE, if the options in ioExtension are bad
609//
610// B_NO_TRANSLATOR, if this translator doesn't understand the data
611//
612// B_ERROR, if there was an error allocating memory or converting
613//          data
614//
615// B_OK, if all went well
616// ---------------------------------------------------------------
617status_t
618BaseTranslator::Translate(BPositionIO *inSource,
619	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
620	BPositionIO *outDestination)
621{
622	switch (fTranGroup) {
623		case B_TRANSLATOR_BITMAP:
624			return BitsTranslate(inSource, inInfo, ioExtension, outType,
625				outDestination);
626
627		default:
628			return DerivedTranslate(inSource, inInfo, ioExtension, outType,
629				outDestination, -1);
630	}
631}
632
633
634// returns the current translator settings into ioExtension
635status_t
636BaseTranslator::GetConfigurationMessage(BMessage *ioExtension)
637{
638	return fSettings->GetConfigurationMessage(ioExtension);
639}
640
641
642// ---------------------------------------------------------------
643// MakeConfigurationView
644//
645// Makes a BView object for configuring / displaying info about
646// this translator.
647//
648// Preconditions:
649//
650// Parameters:	ioExtension,	configuration options for the
651//								translator
652//
653//				outView,		the view to configure the
654//								translator is stored here
655//
656//				outExtent,		the bounds of the view are
657//								stored here
658//
659// Postconditions:
660//
661// Returns:
662// ---------------------------------------------------------------
663status_t
664BaseTranslator::MakeConfigurationView(BMessage *ioExtension, BView **outView,
665	BRect *outExtent)
666{
667	if (!outView || !outExtent)
668		return B_BAD_VALUE;
669	if (ioExtension && fSettings->LoadSettings(ioExtension) != B_OK)
670		return B_BAD_VALUE;
671
672	BView *view = NewConfigView(AcquireSettings());
673		// implemented in derived class
674
675	if (view) {
676		*outView = view;
677		if ((view->Flags() & B_SUPPORTS_LAYOUT) != 0)
678			view->ResizeTo(view->PreferredSize());
679
680		*outExtent = view->Bounds();
681
682		return B_OK;
683	} else
684		return BTranslator::MakeConfigurationView(ioExtension, outView,
685			outExtent);
686}
687
688
689TranslatorSettings *
690BaseTranslator::AcquireSettings()
691{
692	return fSettings->Acquire();
693}
694
695
696///////////////////////////////////////////////////////////
697// Functions to be implemented by derived classes
698
699status_t
700BaseTranslator::DerivedIdentify(BPositionIO *inSource,
701	const translation_format *inFormat, BMessage *ioExtension,
702	translator_info *outInfo, uint32 outType)
703{
704	return B_NO_TRANSLATOR;
705}
706
707
708status_t
709BaseTranslator::DerivedTranslate(BPositionIO *inSource,
710	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
711	BPositionIO *outDestination, int32 baseType)
712{
713	return B_NO_TRANSLATOR;
714}
715
716
717status_t
718BaseTranslator::DerivedCanHandleImageSize(float width, float height) const
719{
720	return B_OK;
721}
722
723
724BView *
725BaseTranslator::NewConfigView(TranslatorSettings *settings)
726{
727	return NULL;
728}
729
730
731void
732translate_direct_copy(BPositionIO *inSource, BPositionIO *outDestination)
733{
734	const size_t kbufsize = 2048;
735	uint8 buffer[kbufsize];
736	ssize_t ret = inSource->Read(buffer, kbufsize);
737	while (ret > 0) {
738		outDestination->Write(buffer, ret);
739		ret = inSource->Read(buffer, kbufsize);
740	}
741}
742