vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / translators / psd / PSDLoader.cpp
blob439f439db686f96b4980b7bafc47f594fde94b24
1 /*
2 * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "PSDLoader.h"
9 #include <Catalog.h>
11 #include "BaseTranslator.h"
13 #undef B_TRANSLATION_CONTEXT
14 #define B_TRANSLATION_CONTEXT "PSDLoader"
17 PSDLoader::PSDLoader(BPositionIO *src)
19 fLoaded = false;
20 fStream = src;
22 fStream->Seek(0, SEEK_END);
23 fStreamSize = fStream->Position();
24 fStream->Seek(0, SEEK_SET);
26 if (fStreamSize <= 0)
27 return;
29 fStream->Seek(0, SEEK_SET);
31 fSignature = _GetInt32FromStream(fStream);
32 if (fSignature != 0x38425053) // 8BPS
33 return;
35 fVersion = _GetInt16FromStream(fStream);
37 // Skip reserved data
38 _SkipStreamBlock(fStream, 6);
40 fChannels = _GetInt16FromStream(fStream);
41 fHeight = _GetInt32FromStream(fStream);
42 fWidth = _GetInt32FromStream(fStream);
43 fDepth = _GetInt16FromStream(fStream);
44 fColorFormat = _GetInt16FromStream(fStream);
46 fColorModeDataSize = _GetInt32FromStream(fStream);
47 fColorModeDataPos = fStream->Position();
48 _SkipStreamBlock(fStream, fColorModeDataSize);
50 fImageResourceSectionSize = _GetInt32FromStream(fStream);
51 fImageResourceSectionPos = fStream->Position();
52 _SkipStreamBlock(fStream, fImageResourceSectionSize);
54 // Skip [layer and mask] block
55 if (fVersion == PSD_FILE)
56 _SkipStreamBlock(fStream, _GetInt32FromStream(fStream));
57 else if (fVersion == PSB_FILE)
58 _SkipStreamBlock(fStream, _GetInt64FromStream(fStream));
59 else
60 return;
62 fCompression = _GetInt16FromStream(fStream);
64 fStreamPos = fStream->Position();
66 fLoaded = true;
70 PSDLoader::~PSDLoader()
75 bool
76 PSDLoader::IsLoaded(void)
78 return fLoaded;
82 bool
83 PSDLoader::IsSupported(void)
85 if (!fLoaded)
86 return false;
88 if (fVersion != PSD_FILE
89 && fVersion != PSB_FILE) {
90 return false;
93 if (fChannels < 0 || fChannels > PSD_MAX_CHANNELS)
94 return false;
96 if (fDepth > 16)
97 return false;
99 if (_ColorFormat() == PSD_COLOR_FORMAT_UNSUPPORTED)
100 return false;
102 if (fCompression != PSD_COMPRESSED_RAW
103 && fCompression != PSD_COMPRESSED_RLE) {
104 return false;
107 return true;
111 BString
112 PSDLoader::ColorFormatName(void)
114 switch (fColorFormat) {
115 case PSD_COLOR_MODE_BITS:
116 return B_TRANSLATE("Bitmap");
117 case PSD_COLOR_MODE_GRAYSCALE:
118 return B_TRANSLATE("Grayscale");
119 case PSD_COLOR_MODE_INDEXED:
120 return B_TRANSLATE("Indexed");
121 case PSD_COLOR_MODE_RGB:
122 return fChannels > 3 ? B_TRANSLATE("RGBA") : B_TRANSLATE("RGB");
123 case PSD_COLOR_MODE_CMYK:
124 return B_TRANSLATE("CMYK");
125 case PSD_COLOR_MODE_MULTICHANNEL:
126 return B_TRANSLATE("Multichannel");
127 case PSD_COLOR_MODE_LAB:
128 return B_TRANSLATE("Lab");
129 case PSD_COLOR_MODE_DUOTONE:
130 return B_TRANSLATE("Duotone");
132 return "";
136 psd_color_format
137 PSDLoader::_ColorFormat(void)
139 psd_color_format format = PSD_COLOR_FORMAT_UNSUPPORTED;
140 if (!fLoaded)
141 return format;
143 switch (fColorFormat) {
144 case PSD_COLOR_MODE_BITS:
145 format = PSD_COLOR_FORMAT_BITMAP;
146 break;
147 case PSD_COLOR_MODE_RGB:
148 if (fChannels == 3)
149 format = PSD_COLOR_FORMAT_RGB;
150 else if (fChannels >= 4)
151 format = PSD_COLOR_FORMAT_RGB_A;
152 break;
153 case PSD_COLOR_MODE_GRAYSCALE:
154 if (fChannels == 1)
155 format = PSD_COLOR_FORMAT_GRAY;
156 else if (fChannels == 2)
157 format = PSD_COLOR_FORMAT_GRAY_A;
158 break;
159 case PSD_COLOR_MODE_MULTICHANNEL:
160 if (fChannels == 3)
161 format = PSD_COLOR_FORMAT_MULTICHANNEL;
162 break;
163 case PSD_COLOR_MODE_CMYK:
164 if (fChannels == 3)
165 format = PSD_COLOR_FORMAT_MULTICHANNEL;
166 else if (fChannels == 4)
167 format = PSD_COLOR_FORMAT_CMYK;
168 else if (fChannels > 4)
169 format = PSD_COLOR_FORMAT_CMYK_A;
170 break;
171 case PSD_COLOR_MODE_LAB:
172 if (fChannels == 3)
173 format = PSD_COLOR_FORMAT_LAB;
174 else if (fChannels > 3)
175 format = PSD_COLOR_FORMAT_LAB_A;
176 break;
177 case PSD_COLOR_MODE_DUOTONE:
178 if (fChannels >= 1)
179 format = PSD_COLOR_FORMAT_DUOTONE;
180 break;
181 case PSD_COLOR_MODE_INDEXED:
182 if (fChannels >= 1 && fColorModeDataSize >= 3)
183 format = PSD_COLOR_FORMAT_INDEXED;
184 break;
185 default:
186 break;
189 return format;
193 status_t
194 PSDLoader::Decode(BPositionIO *target)
196 if (!IsSupported())
197 return B_NO_TRANSLATOR;
199 fStreamBuffer = new uint8[fStreamSize];
200 fStream->Seek(0, SEEK_SET);
201 fStream->Read(fStreamBuffer, fStreamSize);
203 int32 depthBytes = fDepth / 8;
204 int32 rowBytes = (fWidth * fDepth) / 8;
205 int32 channelBytes = rowBytes * fHeight;
207 uint8 *imageData[PSD_MAX_CHANNELS];
208 for (int i = 0; i < fChannels; i++)
209 imageData[i] = new uint8[channelBytes];
212 switch (fCompression) {
213 case PSD_COMPRESSED_RAW:
215 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
216 uint8 *ptr = imageData[channelIdx];
217 for (int i = 0; i < channelBytes; i++, ptr++)
218 *ptr = (uint8)fStreamBuffer[fStreamPos++];
220 break;
222 case PSD_COMPRESSED_RLE:
224 if (fVersion == PSD_FILE)
225 fStreamPos += fHeight * fChannels * 2;
226 else if (fVersion == PSB_FILE)
227 fStreamPos += fHeight * fChannels * 4;
229 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
230 uint8 *ptr = imageData[channelIdx];
231 // Read the RLE data.
232 int count = 0;
233 while (count < channelBytes) {
234 uint8 len = (uint8)fStreamBuffer[fStreamPos++];
235 if (len == 128) {
236 continue;
237 } else if (len < 128) {
238 len++;
239 count += len;
240 while (len) {
241 *ptr++ = (int8)fStreamBuffer[fStreamPos++];
242 len--;
244 } else if (len > 128) {
245 int8 val = (int8)fStreamBuffer[fStreamPos++];
246 len ^= 255;
247 len += 2;
248 count += len;
249 while (len) {
250 *ptr++ = val;
251 len--;
256 break;
258 default:
259 delete[] fStreamBuffer;
260 for (int i = 0; i < fChannels; i++)
261 delete[] imageData[i];
262 return B_NO_TRANSLATOR;
265 delete[] fStreamBuffer;
267 TranslatorBitmap bitsHeader;
268 bitsHeader.magic = B_TRANSLATOR_BITMAP;
269 bitsHeader.bounds.left = 0;
270 bitsHeader.bounds.top = 0;
271 bitsHeader.bounds.right = fWidth - 1;
272 bitsHeader.bounds.bottom = fHeight - 1;
274 psd_color_format colorFormat = _ColorFormat();
276 if (colorFormat == PSD_COLOR_FORMAT_BITMAP) {
277 bitsHeader.rowBytes = rowBytes;
278 bitsHeader.dataSize = channelBytes;
279 bitsHeader.colors = B_GRAY1;
280 } else {
281 bitsHeader.rowBytes = sizeof(uint32) * fWidth;
282 bitsHeader.colors = B_RGBA32;
283 bitsHeader.dataSize = bitsHeader.rowBytes * fHeight;
286 if (swap_data(B_UINT32_TYPE, &bitsHeader,
287 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
288 return B_NO_TRANSLATOR;
291 target->Write(&bitsHeader, sizeof(TranslatorBitmap));
293 uint8 *lineData = new uint8[fWidth * sizeof(uint32)];
295 switch (colorFormat) {
296 case PSD_COLOR_FORMAT_BITMAP:
298 int32 rowBytes = (fWidth / 8 ) * fHeight;
299 for (int32 i = 0; i < rowBytes; i++)
300 imageData[0][i]^=255;
301 target->Write(imageData[0], rowBytes);
302 break;
304 case PSD_COLOR_FORMAT_INDEXED:
306 int32 paletteSize = fColorModeDataSize / 3;
308 uint8 *colorData = new uint8[fColorModeDataSize];
309 fStream->Seek(fColorModeDataPos, SEEK_SET);
310 fStream->Read(colorData, fColorModeDataSize);
312 if (_ParseImageResources() != B_OK)
313 fTransparentIndex = 256;
315 uint8 *redPalette = colorData;
316 uint8 *greenPalette = colorData + paletteSize;
317 uint8 *bluePalette = colorData + paletteSize * 2;
318 int32 index = 0;
319 for (int h = 0; h < fHeight; h++) {
320 uint8 *ptr = lineData;
321 for (int w = 0; w < fWidth; w++) {
322 uint8 colorIndex = imageData[0][index];
323 ptr[0] = bluePalette[colorIndex];
324 ptr[1] = greenPalette[colorIndex];
325 ptr[2] = redPalette[colorIndex];
326 ptr[3] = colorIndex == fTransparentIndex ? 0 : 255;
328 ptr += sizeof(uint32);
329 index++;
331 target->Write(lineData, fWidth * sizeof(uint32));
333 delete[] colorData;
334 break;
336 case PSD_COLOR_FORMAT_DUOTONE:
337 case PSD_COLOR_FORMAT_GRAY:
338 case PSD_COLOR_FORMAT_GRAY_A:
340 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_GRAY_A;
341 int32 index = 0;
342 for (int h = 0; h < fHeight; h++) {
343 uint8 *ptr = lineData;
344 for (int w = 0; w < fWidth; w++) {
345 ptr[0] = imageData[0][index];
346 ptr[1] = imageData[0][index];
347 ptr[2] = imageData[0][index];
348 ptr[3] = isAlpha ? imageData[1][index] : 255;
350 ptr += sizeof(uint32);
351 index += depthBytes;
353 target->Write(lineData, fWidth * sizeof(uint32));
355 break;
357 case PSD_COLOR_FORMAT_MULTICHANNEL:
358 case PSD_COLOR_FORMAT_RGB:
359 case PSD_COLOR_FORMAT_RGB_A:
361 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_RGB_A;
362 int32 index = 0;
363 for (int h = 0; h < fHeight; h++) {
364 uint8 *ptr = lineData;
365 for (int w = 0; w < fWidth; w++) {
366 ptr[0] = imageData[2][index];
367 ptr[1] = imageData[1][index];
368 ptr[2] = imageData[0][index];
369 ptr[3] = isAlpha ? imageData[3][index] : 255;
371 ptr += sizeof(uint32);
372 index += depthBytes;
374 target->Write(lineData, fWidth * sizeof(uint32));
376 break;
378 case PSD_COLOR_FORMAT_CMYK:
379 case PSD_COLOR_FORMAT_CMYK_A:
381 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_CMYK_A;
382 int32 index = 0;
383 for (int h = 0; h < fHeight; h++) {
384 uint8 *ptr = lineData;
385 for (int w = 0; w < fWidth; w++) {
386 double c = 1.0 - imageData[0][index] / 255.0;
387 double m = 1.0 - imageData[1][index] / 255.0;
388 double y = 1.0 - imageData[2][index] / 255.0;
389 double k = 1.0 - imageData[3][index] / 255.0;
390 ptr[0] = (uint8)((1.0 - (y * (1.0 - k) + k)) * 255.0);
391 ptr[1] = (uint8)((1.0 - (m * (1.0 - k) + k)) * 255.0);
392 ptr[2] = (uint8)((1.0 - (c * (1.0 - k) + k)) * 255.0);
393 ptr[3] = isAlpha ? imageData[4][index] : 255;
395 ptr += sizeof(uint32);
396 index += depthBytes;
398 target->Write(lineData, fWidth * sizeof(uint32));
400 break;
402 case PSD_COLOR_FORMAT_LAB:
403 case PSD_COLOR_FORMAT_LAB_A:
405 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_LAB_A;
406 int32 index = 0;
407 for (int h = 0; h < fHeight; h++) {
408 uint8 *ptr = lineData;
409 for (int w = 0; w < fWidth; w++) {
410 double L = imageData[0][index] / 255.0 * 100.0;
411 double a = imageData[1][index] - 128.0;
412 double b = imageData[2][index] - 128.0;
414 double Y = L * (1.0 / 116.0) + 16.0 / 116.0;
415 double X = a * (1.0 / 500.0) + Y;
416 double Z = b * (-1.0 / 200.0) + Y;
418 X = X > 6.0 / 29.0 ? X * X * X : X * (108.0 / 841.0)
419 - (432.0 / 24389.0);
420 Y = L > 8.0 ? Y * Y * Y : L * (27.0 / 24389.0);
421 Z = Z > 6.0 / 29.0 ? Z * Z * Z : Z * (108.0 / 841.0)
422 - (432.0 / 24389.0);
424 double R = X * (1219569.0 / 395920.0)
425 + Y * (-608687.0 / 395920.0)
426 + Z * (-107481.0 / 197960.0);
427 double G = X * (-80960619.0 / 87888100.0)
428 + Y * (82435961.0 / 43944050.0)
429 + Z * (3976797.0 / 87888100.0);
430 double B = X * (93813.0 / 1774030.0)
431 + Y * (-180961.0 / 887015.0)
432 + Z * (107481.0 / 93370.0);
434 R = R > 0.0031308 ? pow(R, 1.0 / 2.4) * 1.055 - 0.055
435 : R * 12.92;
436 G = G > 0.0031308 ? pow(G, 1.0 / 2.4) * 1.055 - 0.055
437 : G * 12.92;
438 B = B > 0.0031308 ? pow(B, 1.0 / 2.4) * 1.055 - 0.055
439 : B * 12.92;
441 R = (R < 0) ? 0 : ((R > 1) ? 1 : R);
442 G = (G < 0) ? 0 : ((G > 1) ? 1 : G);
443 B = (B < 0) ? 0 : ((B > 1) ? 1 : B);
445 ptr[0] = (uint8)(B * 255.0);
446 ptr[1] = (uint8)(G * 255.0);
447 ptr[2] = (uint8)(R * 255.0);
448 ptr[3] = isAlpha ? imageData[3][index] : 255;
450 ptr += sizeof(uint32);
451 index += depthBytes;
453 target->Write(lineData, fWidth * sizeof(uint32));
455 break;
457 default:
458 break;
461 delete[] lineData;
462 for (int i = 0; i < fChannels; i++)
463 delete[] imageData[i];
465 return B_OK;
469 int64
470 PSDLoader::_GetInt64FromStream(BPositionIO *in)
472 int64 ret;
473 in->Read(&ret, sizeof(int64));
474 return B_BENDIAN_TO_HOST_INT64(ret);
478 int32
479 PSDLoader::_GetInt32FromStream(BPositionIO *in)
481 int32 ret;
482 in->Read(&ret, sizeof(int32));
483 return B_BENDIAN_TO_HOST_INT32(ret);
487 int16
488 PSDLoader::_GetInt16FromStream(BPositionIO *in)
490 int16 ret;
491 in->Read(&ret, sizeof(int16));
492 return B_BENDIAN_TO_HOST_INT16(ret);
496 int8
497 PSDLoader::_GetInt8FromStream(BPositionIO *in)
499 int8 ret;
500 in->Read(&ret, sizeof(int8));
501 return ret;
505 uint8
506 PSDLoader::_GetUInt8FromStream(BPositionIO *in)
508 uint8 ret;
509 in->Read(&ret, sizeof(uint8));
510 return ret;
514 void
515 PSDLoader::_SkipStreamBlock(BPositionIO *in, size_t count)
517 in->Seek(count, SEEK_CUR);
521 status_t
522 PSDLoader::_ParseImageResources(void)
524 if (!fLoaded && fImageResourceSectionSize == 0)
525 return B_ERROR;
527 size_t currentPos = fStream->Position();
528 fStream->Seek(fImageResourceSectionPos, SEEK_SET);
530 while (fStream->Position() < currentPos + fImageResourceSectionSize) {
531 int32 resBlockSignature = _GetInt32FromStream(fStream);
532 if (resBlockSignature != 0x3842494D) // 8BIM
533 return B_ERROR;
535 uint16 resID = _GetInt16FromStream(fStream);
537 BString resName, name;
538 int nameLength = 0;
539 while (true) {
540 int charData = _GetUInt8FromStream(fStream);
541 nameLength++;
542 if (charData == 0) {
543 if (nameLength % 2 == 1) {
544 _GetUInt8FromStream(fStream);
545 nameLength++;
547 break;
548 } else
549 name += charData;
550 resName = name;
553 uint32 resSize = _GetInt32FromStream(fStream);
555 if (resSize % 2 == 1)
556 resSize++;
558 switch (resID) {
559 case 0x0417:
560 fTransparentIndex = _GetInt16FromStream(fStream);
561 break;
562 default:
563 _SkipStreamBlock(fStream, resSize);
567 fStream->Seek(currentPos, SEEK_SET);
569 return B_OK;