xref: /haiku/src/add-ons/translators/shared/BaseTranslator.cpp (revision 0ce4c23d22fae64d10e5575687490fbdf8ee52b8)
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 // ---------------------------------------------------------------
62 BaseTranslator::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
109 BaseTranslator::~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 // ---------------------------------------------------------------
130 const char *
131 BaseTranslator::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 // ---------------------------------------------------------------
151 const char *
152 BaseTranslator::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 // ---------------------------------------------------------------
172 int32
173 BaseTranslator::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 // ---------------------------------------------------------------
194 const translation_format *
195 BaseTranslator::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 // ---------------------------------------------------------------
220 const translation_format *
221 BaseTranslator::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 // ---------------------------------------------------------------
265 status_t
266 BaseTranslator::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 // ---------------------------------------------------------------
376 status_t
377 BaseTranslator::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 
411 status_t
412 BaseTranslator::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 // ---------------------------------------------------------------
470 status_t
471 BaseTranslator::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 // ---------------------------------------------------------------
517 status_t
518 BaseTranslator::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 
568 status_t
569 BaseTranslator::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 // ---------------------------------------------------------------
617 status_t
618 BaseTranslator::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
635 status_t
636 BaseTranslator::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 // ---------------------------------------------------------------
663 status_t
664 BaseTranslator::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->ExplicitPreferredSize());
679 
680 		*outExtent = view->Bounds();
681 
682 		return B_OK;
683 	} else
684 		return BTranslator::MakeConfigurationView(ioExtension, outView,
685 			outExtent);
686 }
687 
688 
689 TranslatorSettings *
690 BaseTranslator::AcquireSettings()
691 {
692 	return fSettings->Acquire();
693 }
694 
695 
696 ///////////////////////////////////////////////////////////
697 // Functions to be implemented by derived classes
698 
699 status_t
700 BaseTranslator::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 
708 status_t
709 BaseTranslator::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 
717 status_t
718 BaseTranslator::DerivedCanHandleImageSize(float width, float height) const
719 {
720 	return B_OK;
721 }
722 
723 
724 BView *
725 BaseTranslator::NewConfigView(TranslatorSettings *settings)
726 {
727 	return NULL;
728 }
729 
730 
731 void
732 translate_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