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