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