vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / translators / shared / BaseTranslator.cpp
blobb8eb064929820aa5b7e9f2c569eabf60703109c8
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.
12 // Copyright (c) 2004 Haiku, Inc.
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:
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
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 /*****************************************************************************/
33 #include "BaseTranslator.h"
35 #include <string.h>
36 #include <stdio.h>
38 #include <algorithm>
40 #include <Catalog.h>
41 #include <Locale.h>
44 #undef B_TRANSLATION_CONTEXT
45 #define B_TRANSLATION_CONTEXT "BaseTranslator"
48 // ---------------------------------------------------------------
49 // Constructor
51 // Sets up the version info and the name of the translator so that
52 // these values can be returned when they are requested.
54 // Preconditions:
56 // Parameters:
58 // Postconditions:
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)
68 BTranslator()
70 fSettings = new TranslatorSettings(settingsFile, defaults, defCount);
71 fSettings->LoadSettings();
72 // load settings from the Base Translator settings file
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__);
84 fInputFormats = inFormats;
85 fInputCount = (fInputFormats) ? inCount : 0;
86 fOutputFormats = outFormats;
87 fOutputCount = (fOutputFormats) ? outCount : 0;
88 fTranGroup = tranGroup;
89 fTranType = tranType;
93 // ---------------------------------------------------------------
94 // Destructor
96 // Does nothing
98 // Preconditions:
100 // Parameters:
102 // Postconditions:
104 // Returns:
105 // ---------------------------------------------------------------
107 // NOTE: It may be the case, that under Be's libtranslation.so,
108 // that this destructor will never be called
109 BaseTranslator::~BaseTranslator()
111 fSettings->Release();
112 delete[] fName;
113 delete[] fInfo;
117 // ---------------------------------------------------------------
118 // TranslatorName
120 // Returns the short name of the translator.
122 // Preconditions:
124 // Parameters:
126 // Postconditions:
128 // Returns: a const char * to the short name of the translator
129 // ---------------------------------------------------------------
130 const char *
131 BaseTranslator::TranslatorName() const
133 return fName;
137 // ---------------------------------------------------------------
138 // TranslatorInfo
140 // Returns a more verbose name for the translator than the one
141 // TranslatorName() returns. This usually includes version info.
143 // Preconditions:
145 // Parameters:
147 // Postconditions:
149 // Returns: a const char * to the verbose name of the translator
150 // ---------------------------------------------------------------
151 const char *
152 BaseTranslator::TranslatorInfo() const
154 return fInfo;
158 // ---------------------------------------------------------------
159 // TranslatorVersion
161 // Returns the integer representation of the current version of
162 // this translator.
164 // Preconditions:
166 // Parameters:
168 // Postconditions:
170 // Returns:
171 // ---------------------------------------------------------------
172 int32
173 BaseTranslator::TranslatorVersion() const
175 return fVersion;
179 // ---------------------------------------------------------------
180 // InputFormats
182 // Returns a list of input formats supported by this translator.
184 // Preconditions:
186 // Parameters: out_count, The number of input formats
187 // support is returned here.
189 // Postconditions:
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
197 if (out_count) {
198 *out_count = fInputCount;
199 return fInputFormats;
200 } else
201 return NULL;
205 // ---------------------------------------------------------------
206 // OutputFormats
208 // Returns a list of output formats supported by this translator.
210 // Preconditions:
212 // Parameters: out_count, The number of output formats
213 // support is returned here.
215 // Postconditions:
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
223 if (out_count) {
224 *out_count = fOutputCount;
225 return fOutputFormats;
226 } else
227 return NULL;
231 // ---------------------------------------------------------------
232 // identify_bits_header
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.
238 // Preconditions:
240 // Parameters: inSource, The source of the image data
242 // outInfo, Information about the translator
243 // is copied here
245 // amtread, Amount of data read from inSource
246 // before this function was called
248 // read, Pointer to the data that was read
249 // in before this function was called
251 // pheader, The bits header is copied here after
252 // it is read in from inSource
254 // Postconditions:
256 // Returns: B_NO_TRANSLATOR, if the data does not look like
257 // bits format data
259 // B_ERROR, if the header data could not be converted to host
260 // format
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)
269 TranslatorBitmap header;
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;
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;
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;
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");
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;
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;
335 return B_OK;
339 // ---------------------------------------------------------------
340 // BitsCheck
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.
348 // Preconditions:
350 // Parameters: inSource, where the data to examine is
352 // ioExtension, configuration settings for the
353 // translator
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
363 // Postconditions:
365 // Returns: B_NO_TRANSLATOR, if this translator can't handle
366 // the data in inSource
368 // B_ERROR, if there was an error converting the data to the host
369 // format
371 // B_BAD_VALUE, if the settings in ioExtension are bad
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)
380 if (!outType)
381 outType = B_TRANSLATOR_BITMAP;
382 if (outType != B_TRANSLATOR_BITMAP && outType != fTranType)
383 return B_NO_TRANSLATOR;
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);
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
399 // Read settings from ioExtension
400 if (ioExtension && fSettings->LoadSettings(ioExtension) < B_OK)
401 return B_BAD_VALUE;
403 uint32 sourceMagic;
404 memcpy(&sourceMagic, ch, sizeof(uint32));
405 if (sourceMagic == kBitsMagic)
406 return B_OK;
407 return B_OK + 1;
411 status_t
412 BaseTranslator::BitsIdentify(BPositionIO *inSource,
413 const translation_format *inFormat, BMessage *ioExtension,
414 translator_info *outInfo, uint32 outType)
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);
429 return result;
433 // ---------------------------------------------------------------
434 // Identify
436 // Examines the data from inSource and determines if it is in a
437 // format that this translator knows how to work with.
439 // Preconditions:
441 // Parameters: inSource, where the data to examine is
443 // inFormat, a hint about the data in inSource,
444 // it is ignored since it is only a hint
446 // ioExtension, configuration settings for the
447 // translator
449 // outInfo, information about what data is in
450 // inSource and how well this translator
451 // can handle that data is stored here
453 // outType, The format that the user wants
454 // the data in inSource to be
455 // converted to
457 // Postconditions:
459 // Returns: B_NO_TRANSLATOR, if this translator can't handle
460 // the data in inSource
462 // B_ERROR, if there was an error converting the data to the host
463 // format
465 // B_BAD_VALUE, if the settings in ioExtension are bad
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)
475 switch (fTranGroup) {
476 case B_TRANSLATOR_BITMAP:
477 return BitsIdentify(inSource, inFormat, ioExtension,
478 outInfo, outType);
480 default:
481 return DerivedIdentify(inSource, inFormat, ioExtension,
482 outInfo, outType);
487 // ---------------------------------------------------------------
488 // translate_from_bits_to_bits
490 // Convert the data in inSource from the Be Bitmap format ('bits')
491 // to the format specified in outType (either bits or Base).
493 // Preconditions:
495 // Parameters: inSource, the bits data to translate
497 // amtread, the amount of data already read from
498 // inSource
500 // read, pointer to the data already read from
501 // inSource
503 // outType, the type of data to convert to
505 // outDestination, where the output is written to
507 // Postconditions:
509 // Returns: B_NO_TRANSLATOR, if the data is not in a supported
510 // format
512 // B_ERROR, if there was an error allocating memory or some other
513 // error
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)
521 TranslatorBitmap bitsHeader;
522 bool bheaderonly = false, bdataonly = false;
524 status_t result;
525 result = identify_bits_header(inSource, NULL, &bitsHeader);
526 if (result != B_OK)
527 return result;
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;
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));
556 if (remaining > 0)
557 return B_ERROR;
558 else
559 return B_OK;
560 } else
561 return B_OK;
563 } else
564 return B_NO_TRANSLATOR;
568 status_t
569 BaseTranslator::BitsTranslate(BPositionIO *inSource,
570 const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
571 BPositionIO *outDestination)
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));
582 return result;
586 // ---------------------------------------------------------------
587 // Translate
589 // Translates the data in inSource to the type outType and stores
590 // the translated data in outDestination.
592 // Preconditions:
594 // Parameters: inSource, the data to be translated
596 // inInfo, hint about the data in inSource (not used)
598 // ioExtension, configuration options for the
599 // translator
601 // outType, the type to convert inSource to
603 // outDestination, where the translated data is
604 // put
606 // Postconditions:
608 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
610 // B_NO_TRANSLATOR, if this translator doesn't understand the data
612 // B_ERROR, if there was an error allocating memory or converting
613 // data
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)
622 switch (fTranGroup) {
623 case B_TRANSLATOR_BITMAP:
624 return BitsTranslate(inSource, inInfo, ioExtension, outType,
625 outDestination);
627 default:
628 return DerivedTranslate(inSource, inInfo, ioExtension, outType,
629 outDestination, -1);
634 // returns the current translator settings into ioExtension
635 status_t
636 BaseTranslator::GetConfigurationMessage(BMessage *ioExtension)
638 return fSettings->GetConfigurationMessage(ioExtension);
642 // ---------------------------------------------------------------
643 // MakeConfigurationView
645 // Makes a BView object for configuring / displaying info about
646 // this translator.
648 // Preconditions:
650 // Parameters: ioExtension, configuration options for the
651 // translator
653 // outView, the view to configure the
654 // translator is stored here
656 // outExtent, the bounds of the view are
657 // stored here
659 // Postconditions:
661 // Returns:
662 // ---------------------------------------------------------------
663 status_t
664 BaseTranslator::MakeConfigurationView(BMessage *ioExtension, BView **outView,
665 BRect *outExtent)
667 if (!outView || !outExtent)
668 return B_BAD_VALUE;
669 if (ioExtension && fSettings->LoadSettings(ioExtension) != B_OK)
670 return B_BAD_VALUE;
672 BView *view = NewConfigView(AcquireSettings());
673 // implemented in derived class
675 if (view) {
676 *outView = view;
677 if ((view->Flags() & B_SUPPORTS_LAYOUT) != 0)
678 view->ResizeTo(view->ExplicitPreferredSize());
680 *outExtent = view->Bounds();
682 return B_OK;
683 } else
684 return BTranslator::MakeConfigurationView(ioExtension, outView,
685 outExtent);
689 TranslatorSettings *
690 BaseTranslator::AcquireSettings()
692 return fSettings->Acquire();
696 ///////////////////////////////////////////////////////////
697 // Functions to be implemented by derived classes
699 status_t
700 BaseTranslator::DerivedIdentify(BPositionIO *inSource,
701 const translation_format *inFormat, BMessage *ioExtension,
702 translator_info *outInfo, uint32 outType)
704 return B_NO_TRANSLATOR;
708 status_t
709 BaseTranslator::DerivedTranslate(BPositionIO *inSource,
710 const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
711 BPositionIO *outDestination, int32 baseType)
713 return B_NO_TRANSLATOR;
717 status_t
718 BaseTranslator::DerivedCanHandleImageSize(float width, float height) const
720 return B_OK;
724 BView *
725 BaseTranslator::NewConfigView(TranslatorSettings *settings)
727 return NULL;
731 void
732 translate_direct_copy(BPositionIO *inSource, BPositionIO *outDestination)
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);