vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / translators / webp / WebPTranslator.cpp
blobcfc41ae8f9bcb461f5dca819f8a4536a4ca55a9e
1 /*
2 * Copyright 2010-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Philippe Houdoin
7 */
10 #include "WebPTranslator.h"
12 #include <BufferIO.h>
13 #include <Catalog.h>
14 #include <Messenger.h>
15 #include <TranslatorRoster.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
21 #include "webp/encode.h"
22 #include "webp/decode.h"
24 #include "ConfigView.h"
25 #include "TranslatorSettings.h"
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "WebPTranslator"
32 class FreeAllocation {
33 public:
34 FreeAllocation(void* buffer)
36 fBuffer(buffer)
40 ~FreeAllocation()
42 free(fBuffer);
45 private:
46 void* fBuffer;
51 // The input formats that this translator knows how to read
52 static const translation_format sInputFormats[] = {
54 WEBP_IMAGE_FORMAT,
55 B_TRANSLATOR_BITMAP,
56 WEBP_IN_QUALITY,
57 WEBP_IN_CAPABILITY,
58 "image/webp",
59 "WebP image"
62 B_TRANSLATOR_BITMAP,
63 B_TRANSLATOR_BITMAP,
64 BITS_IN_QUALITY,
65 BITS_IN_CAPABILITY,
66 "image/x-be-bitmap",
67 "Be Bitmap Format (WebPTranslator)"
71 // The output formats that this translator knows how to write
72 static const translation_format sOutputFormats[] = {
74 WEBP_IMAGE_FORMAT,
75 B_TRANSLATOR_BITMAP,
76 WEBP_OUT_QUALITY,
77 WEBP_OUT_CAPABILITY,
78 "image/webp",
79 "WebP image"
82 B_TRANSLATOR_BITMAP,
83 B_TRANSLATOR_BITMAP,
84 BITS_OUT_QUALITY,
85 BITS_OUT_CAPABILITY,
86 "image/x-be-bitmap",
87 "Be Bitmap Format (WebPTranslator)"
91 // Default settings for the Translator
92 static const TranSetting sDefaultSettings[] = {
93 { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false },
94 { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false },
95 { WEBP_SETTING_QUALITY, TRAN_SETTING_INT32, 60 },
96 { WEBP_SETTING_PRESET, TRAN_SETTING_INT32, 0 },
97 { WEBP_SETTING_METHOD, TRAN_SETTING_INT32, 2 },
98 { WEBP_SETTING_PREPROCESSING, TRAN_SETTING_BOOL, false },
101 const uint32 kNumInputFormats = sizeof(sInputFormats) /
102 sizeof(translation_format);
103 const uint32 kNumOutputFormats = sizeof(sOutputFormats) /
104 sizeof(translation_format);
105 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) /
106 sizeof(TranSetting);
109 // #pragma mark -
112 WebPTranslator::WebPTranslator()
114 BaseTranslator(B_TRANSLATE("WebP images"),
115 B_TRANSLATE("WebP image translator"),
116 WEBP_TRANSLATOR_VERSION,
117 sInputFormats, kNumInputFormats,
118 sOutputFormats, kNumOutputFormats,
119 "WebPTranslator_Settings", sDefaultSettings, kNumDefaultSettings,
120 B_TRANSLATOR_BITMAP, WEBP_IMAGE_FORMAT)
125 WebPTranslator::~WebPTranslator()
130 status_t
131 WebPTranslator::DerivedIdentify(BPositionIO* stream,
132 const translation_format* format, BMessage* settings,
133 translator_info* info, uint32 outType)
135 if (!outType)
136 outType = B_TRANSLATOR_BITMAP;
137 if (outType != B_TRANSLATOR_BITMAP)
138 return B_NO_TRANSLATOR;
140 // Read header and first chunck bytes...
141 uint32 buf[64];
142 ssize_t size = sizeof(buf);
143 if (stream->Read(buf, size) != size)
144 return B_IO_ERROR;
146 // Check it's a valid WebP format
147 if (!WebPGetInfo((const uint8_t*)buf, size, NULL, NULL))
148 return B_ILLEGAL_DATA;
150 info->type = WEBP_IMAGE_FORMAT;
151 info->group = B_TRANSLATOR_BITMAP;
152 info->quality = WEBP_IN_QUALITY;
153 info->capability = WEBP_IN_CAPABILITY;
154 snprintf(info->name, sizeof(info->name), B_TRANSLATE("WebP image"));
155 strcpy(info->MIME, "image/webp");
157 return B_OK;
161 status_t
162 WebPTranslator::DerivedTranslate(BPositionIO* stream,
163 const translator_info* info, BMessage* ioExtension, uint32 outType,
164 BPositionIO* target, int32 baseType)
166 if (baseType == 1)
167 // if stream is in bits format
168 return _TranslateFromBits(stream, ioExtension, outType, target);
169 else if (baseType == 0)
170 // if stream is NOT in bits format
171 return _TranslateFromWebP(stream, ioExtension, outType, target);
172 else
173 // if BaseTranslator dit not properly identify the data as
174 // bits or not bits
175 return B_NO_TRANSLATOR;
179 BView*
180 WebPTranslator::NewConfigView(TranslatorSettings* settings)
182 return new ConfigView(settings);
186 status_t
187 WebPTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension,
188 uint32 outType, BPositionIO* target)
190 if (!outType)
191 outType = WEBP_IMAGE_FORMAT;
192 if (outType != WEBP_IMAGE_FORMAT)
193 return B_NO_TRANSLATOR;
195 TranslatorBitmap bitsHeader;
196 status_t status;
198 status = identify_bits_header(stream, NULL, &bitsHeader);
199 if (status != B_OK)
200 return status;
202 if (bitsHeader.colors == B_CMAP8) {
203 // TODO: support whatever colospace by intermediate colorspace conversion
204 printf("Error! Colorspace not supported\n");
205 return B_NO_TRANSLATOR;
208 int32 bitsBytesPerPixel = 0;
209 switch (bitsHeader.colors) {
210 case B_RGB32:
211 case B_RGB32_BIG:
212 case B_RGBA32:
213 case B_RGBA32_BIG:
214 case B_CMY32:
215 case B_CMYA32:
216 case B_CMYK32:
217 bitsBytesPerPixel = 4;
218 break;
220 case B_RGB24:
221 case B_RGB24_BIG:
222 case B_CMY24:
223 bitsBytesPerPixel = 3;
224 break;
226 case B_RGB16:
227 case B_RGB16_BIG:
228 case B_RGBA15:
229 case B_RGBA15_BIG:
230 case B_RGB15:
231 case B_RGB15_BIG:
232 bitsBytesPerPixel = 2;
233 break;
235 case B_CMAP8:
236 case B_GRAY8:
237 bitsBytesPerPixel = 1;
238 break;
240 default:
241 return B_ERROR;
244 if (bitsBytesPerPixel < 3) {
245 // TODO support
246 return B_NO_TRANSLATOR;
249 WebPPicture picture;
250 WebPConfig config;
252 if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
253 printf("Error! Version mismatch!\n");
254 return B_ERROR;
257 WebPPreset preset = (WebPPreset)fSettings->SetGetInt32(WEBP_SETTING_PRESET);
258 config.quality = (float)fSettings->SetGetInt32(WEBP_SETTING_QUALITY);
260 if (!WebPConfigPreset(&config, (WebPPreset)preset, config.quality)) {
261 printf("Error! Could initialize configuration with preset.");
262 return B_ERROR;
265 config.method = fSettings->SetGetInt32(WEBP_SETTING_METHOD);
266 config.preprocessing = fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING);
268 if (!WebPValidateConfig(&config)) {
269 printf("Error! Invalid configuration.\n");
270 return B_ERROR;
273 picture.width = bitsHeader.bounds.IntegerWidth() + 1;
274 picture.height = bitsHeader.bounds.IntegerHeight() + 1;
276 int stride = bitsHeader.rowBytes;
277 int bitsSize = picture.height * stride;
278 uint8* bits = (uint8*)malloc(bitsSize);
279 if (bits == NULL)
280 return B_NO_MEMORY;
282 if (stream->Read(bits, bitsSize) != bitsSize) {
283 free(bits);
284 return B_IO_ERROR;
287 if (!WebPPictureImportBGRA(&picture, bits, stride)) {
288 printf("Error! WebPEncode() failed!\n");
289 free(bits);
290 return B_ERROR;
292 free(bits);
294 picture.writer = _EncodedWriter;
295 picture.custom_ptr = target;
296 picture.stats = NULL;
298 if (!WebPEncode(&config, &picture)) {
299 printf("Error! WebPEncode() failed!\n");
300 status = B_NO_TRANSLATOR;
301 } else
302 status = B_OK;
304 WebPPictureFree(&picture);
305 return status;
309 status_t
310 WebPTranslator::_TranslateFromWebP(BPositionIO* stream, BMessage* ioExtension,
311 uint32 outType, BPositionIO* target)
313 if (!outType)
314 outType = B_TRANSLATOR_BITMAP;
315 if (outType != B_TRANSLATOR_BITMAP)
316 return B_NO_TRANSLATOR;
318 off_t streamLength = 0;
319 stream->GetSize(&streamLength);
321 off_t streamSize = stream->Seek(0, SEEK_END);
322 stream->Seek(0, SEEK_SET);
324 void* streamData = malloc(streamSize);
325 if (streamData == NULL)
326 return B_NO_MEMORY;
328 if (stream->Read(streamData, streamSize) != streamSize) {
329 free(streamData);
330 return B_IO_ERROR;
333 int width, height;
334 uint8* out = WebPDecodeBGRA((const uint8*)streamData, streamSize, &width,
335 &height);
336 free(streamData);
338 if (out == NULL)
339 return B_ILLEGAL_DATA;
341 FreeAllocation _(out);
343 uint32 dataSize = width * 4 * height;
345 TranslatorBitmap bitmapHeader;
346 bitmapHeader.magic = B_TRANSLATOR_BITMAP;
347 bitmapHeader.bounds.Set(0, 0, width - 1, height - 1);
348 bitmapHeader.rowBytes = width * 4;
349 bitmapHeader.colors = B_RGBA32;
350 bitmapHeader.dataSize = width * 4 * height;
352 // write out Be's Bitmap header
353 swap_data(B_UINT32_TYPE, &bitmapHeader, sizeof(TranslatorBitmap),
354 B_SWAP_HOST_TO_BENDIAN);
355 ssize_t bytesWritten = target->Write(&bitmapHeader,
356 sizeof(TranslatorBitmap));
357 if (bytesWritten < B_OK)
358 return bytesWritten;
360 if ((size_t)bytesWritten != sizeof(TranslatorBitmap))
361 return B_IO_ERROR;
363 bool headerOnly = false;
364 if (ioExtension != NULL)
365 ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &headerOnly);
367 if (headerOnly)
368 return B_OK;
370 uint32 dataLeft = dataSize;
371 uint8* p = out;
372 while (dataLeft) {
373 bytesWritten = target->Write(p, 4);
374 if (bytesWritten < B_OK)
375 return bytesWritten;
377 if (bytesWritten != 4)
378 return B_IO_ERROR;
380 p += 4;
381 dataLeft -= 4;
384 return B_OK;
388 /* static */ int
389 WebPTranslator::_EncodedWriter(const uint8_t* data, size_t dataSize,
390 const WebPPicture* const picture)
392 BPositionIO* target = (BPositionIO*)picture->custom_ptr;
393 return dataSize ? (target->Write(data, dataSize) == (ssize_t)dataSize) : 1;
397 // #pragma mark -
400 BTranslator*
401 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
403 if (n != 0)
404 return NULL;
406 return new WebPTranslator();