xref: /haiku/src/add-ons/translators/shared/BaseTranslator.cpp (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 /*****************************************************************************/
2 // BaseTranslator
3 // Written by Michael Wilber, OBOS 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 OpenBeOS Project
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_VER(fVersion)),
68 		static_cast<int>(B_TRANSLATION_MINOR_VER(fVersion)),
69 		static_cast<int>(B_TRANSLATION_REVSN_VER(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 = NULL)
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 	else
387 		return B_OK + 1;
388 }
389 
390 status_t
391 BaseTranslator::BitsIdentify(BPositionIO *inSource,
392 	const translation_format *inFormat, BMessage *ioExtension,
393 	translator_info *outInfo, uint32 outType)
394 {
395 	status_t result;
396 
397 	result = BitsCheck(inSource, ioExtension, outType);
398 	if (result == B_OK)
399 		result = identify_bits_header(inSource, outInfo);
400 	else if (result == B_OK + 1)
401 		// if NOT B_TRANSLATOR_BITMAP, it could be an image in the
402 		// derived format
403 		result = DerivedIdentify(inSource, inFormat, ioExtension,
404 			outInfo, outType);
405 
406 	return result;
407 }
408 
409 // ---------------------------------------------------------------
410 // Identify
411 //
412 // Examines the data from inSource and determines if it is in a
413 // format that this translator knows how to work with.
414 //
415 // Preconditions:
416 //
417 // Parameters:	inSource,	where the data to examine is
418 //
419 //				inFormat,	a hint about the data in inSource,
420 //							it is ignored since it is only a hint
421 //
422 //				ioExtension,	configuration settings for the
423 //								translator
424 //
425 //				outInfo,	information about what data is in
426 //							inSource and how well this translator
427 //							can handle that data is stored here
428 //
429 //				outType,	The format that the user wants
430 //							the data in inSource to be
431 //							converted to
432 //
433 // Postconditions:
434 //
435 // Returns: B_NO_TRANSLATOR,	if this translator can't handle
436 //								the data in inSource
437 //
438 // B_ERROR,	if there was an error converting the data to the host
439 //			format
440 //
441 // B_BAD_VALUE, if the settings in ioExtension are bad
442 //
443 // B_OK,	if this translator understand the data and there were
444 //			no errors found
445 // ---------------------------------------------------------------
446 status_t
447 BaseTranslator::Identify(BPositionIO *inSource,
448 	const translation_format *inFormat, BMessage *ioExtension,
449 	translator_info *outInfo, uint32 outType)
450 {
451 	switch (fTranGroup) {
452 		case B_TRANSLATOR_BITMAP:
453 			return BitsIdentify(inSource, inFormat, ioExtension,
454 				outInfo, outType);
455 
456 		default:
457 			return DerivedIdentify(inSource, inFormat, ioExtension,
458 				outInfo, outType);
459 	}
460 }
461 
462 // ---------------------------------------------------------------
463 // translate_from_bits_to_bits
464 //
465 // Convert the data in inSource from the Be Bitmap format ('bits')
466 // to the format specified in outType (either bits or Base).
467 //
468 // Preconditions:
469 //
470 // Parameters:	inSource,	the bits data to translate
471 //
472 // 				amtread,	the amount of data already read from
473 //							inSource
474 //
475 //				read,		pointer to the data already read from
476 //							inSource
477 //
478 //				outType,	the type of data to convert to
479 //
480 //				outDestination,	where the output is written to
481 //
482 // Postconditions:
483 //
484 // Returns: B_NO_TRANSLATOR,	if the data is not in a supported
485 //								format
486 //
487 // B_ERROR, if there was an error allocating memory or some other
488 //			error
489 //
490 // B_OK, if successfully translated the data from the bits format
491 // ---------------------------------------------------------------
492 status_t
493 BaseTranslator::translate_from_bits_to_bits(BPositionIO *inSource,
494 	uint32 outType,	BPositionIO *outDestination)
495 {
496 	TranslatorBitmap bitsHeader;
497 	bool bheaderonly = false, bdataonly = false;
498 
499 	status_t result;
500 	result = identify_bits_header(inSource, NULL, &bitsHeader);
501 	if (result != B_OK)
502 		return result;
503 
504 	// Translate B_TRANSLATOR_BITMAP to B_TRANSLATOR_BITMAP, easy enough :)
505 	if (outType == B_TRANSLATOR_BITMAP) {
506 		// write out bitsHeader (only if configured to)
507 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
508 			if (swap_data(B_UINT32_TYPE, &bitsHeader,
509 				sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK)
510 				return B_ERROR;
511 			if (outDestination->Write(&bitsHeader,
512 				sizeof(TranslatorBitmap)) != sizeof(TranslatorBitmap))
513 				return B_ERROR;
514 		}
515 
516 		// write out the data (only if configured to)
517 		if (bdataonly || (!bheaderonly && !bdataonly)) {
518 			uint8 buf[1024];
519 			uint32 remaining = B_BENDIAN_TO_HOST_INT32(bitsHeader.dataSize);
520 			ssize_t rd, writ;
521 			rd = inSource->Read(buf, 1024);
522 			while (rd > 0) {
523 				writ = outDestination->Write(buf, rd);
524 				if (writ < 0)
525 					break;
526 				remaining -= static_cast<uint32>(writ);
527 				rd = inSource->Read(buf, min(1024, remaining));
528 			}
529 
530 			if (remaining > 0)
531 				return B_ERROR;
532 			else
533 				return B_OK;
534 		} else
535 			return B_OK;
536 
537 	} else
538 		return B_NO_TRANSLATOR;
539 }
540 
541 status_t
542 BaseTranslator::BitsTranslate(BPositionIO *inSource,
543 	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
544 	BPositionIO *outDestination)
545 {
546 	status_t result;
547 
548 	result = BitsCheck(inSource, ioExtension, outType);
549 	if (result == B_OK && outType == B_TRANSLATOR_BITMAP)
550 		result = translate_from_bits_to_bits(inSource, outType,
551 			outDestination);
552 	else if (result >= B_OK)
553 		// If NOT B_TRANSLATOR_BITMAP type it could be the derived format
554 		result = DerivedTranslate(inSource, inInfo, ioExtension, outType,
555 			outDestination, (result == B_OK));
556 
557 	return result;
558 }
559 
560 // ---------------------------------------------------------------
561 // Translate
562 //
563 // Translates the data in inSource to the type outType and stores
564 // the translated data in outDestination.
565 //
566 // Preconditions:
567 //
568 // Parameters:	inSource,	the data to be translated
569 //
570 //				inInfo,	hint about the data in inSource (not used)
571 //
572 //				ioExtension,	configuration options for the
573 //								translator
574 //
575 //				outType,	the type to convert inSource to
576 //
577 //				outDestination,	where the translated data is
578 //								put
579 //
580 // Postconditions:
581 //
582 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
583 //
584 // B_NO_TRANSLATOR, if this translator doesn't understand the data
585 //
586 // B_ERROR, if there was an error allocating memory or converting
587 //          data
588 //
589 // B_OK, if all went well
590 // ---------------------------------------------------------------
591 status_t
592 BaseTranslator::Translate(BPositionIO *inSource,
593 	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
594 	BPositionIO *outDestination)
595 {
596 	switch (fTranGroup) {
597 		case B_TRANSLATOR_BITMAP:
598 			return BitsTranslate(inSource, inInfo, ioExtension, outType,
599 				outDestination);
600 
601 		default:
602 			return DerivedTranslate(inSource, inInfo, ioExtension, outType,
603 				outDestination, -1);
604 	}
605 }
606 
607 // returns the current translator settings into ioExtension
608 status_t
609 BaseTranslator::GetConfigurationMessage(BMessage *ioExtension)
610 {
611 	return fSettings->GetConfigurationMessage(ioExtension);
612 }
613 
614 // ---------------------------------------------------------------
615 // MakeConfigurationView
616 //
617 // Makes a BView object for configuring / displaying info about
618 // this translator.
619 //
620 // Preconditions:
621 //
622 // Parameters:	ioExtension,	configuration options for the
623 //								translator
624 //
625 //				outView,		the view to configure the
626 //								translator is stored here
627 //
628 //				outExtent,		the bounds of the view are
629 //								stored here
630 //
631 // Postconditions:
632 //
633 // Returns:
634 // ---------------------------------------------------------------
635 status_t
636 BaseTranslator::MakeConfigurationView(BMessage *ioExtension, BView **outView,
637 	BRect *outExtent)
638 {
639 	if (!outView || !outExtent)
640 		return B_BAD_VALUE;
641 	if (ioExtension && fSettings->LoadSettings(ioExtension) != B_OK)
642 		return B_BAD_VALUE;
643 
644 	BView *view = NewConfigView(AcquireSettings());
645 		// implemented in derived class
646 	if (view) {
647 		*outView = view;
648 		*outExtent = view->Bounds();
649 
650 		return B_OK;
651 	} else
652 		return BTranslator::MakeConfigurationView(ioExtension, outView,
653 			outExtent);
654 }
655 
656 TranslatorSettings *
657 BaseTranslator::AcquireSettings()
658 {
659 	return fSettings->Acquire();
660 }
661 
662 ///////////////////////////////////////////////////////////
663 // Functions to be implemented by derived classes
664 
665 status_t
666 BaseTranslator::DerivedIdentify(BPositionIO *inSource,
667 	const translation_format *inFormat, BMessage *ioExtension,
668 	translator_info *outInfo, uint32 outType)
669 {
670 	return B_NO_TRANSLATOR;
671 }
672 
673 status_t
674 BaseTranslator::DerivedTranslate(BPositionIO *inSource,
675 	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
676 	BPositionIO *outDestination, int32 baseType)
677 {
678 	return B_NO_TRANSLATOR;
679 }
680 
681 
682 BView *
683 BaseTranslator::NewConfigView(TranslatorSettings *settings)
684 {
685 	return NULL;
686 }
687 
688 void
689 translate_direct_copy(BPositionIO *inSource, BPositionIO *outDestination)
690 {
691 	const size_t kbufsize = 2048;
692 	uint8 buffer[kbufsize];
693 	ssize_t ret = inSource->Read(buffer, kbufsize);
694 	while (ret > 0) {
695 		outDestination->Write(buffer, ret);
696 		ret = inSource->Read(buffer, kbufsize);
697 	}
698 }
699