diff --git a/src/add-ons/translators/pcx/PCX.cpp b/src/add-ons/translators/pcx/PCX.cpp index 264bb52f42..745a52a9bb 100644 --- a/src/add-ons/translators/pcx/PCX.cpp +++ b/src/add-ons/translators/pcx/PCX.cpp @@ -1,19 +1,21 @@ /* * Copyright 2008, Jérôme Duval, korli@users.berlios.de. All rights reserved. - * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ -#include "StreamBuffer.h" -#include "PCX.h" -#include "PCXTranslator.h" -#include +#include "PCX.h" #include #include #include +#include + +#include "StreamBuffer.h" +#include "PCXTranslator.h" + //#define TRACE_PCX #ifdef TRACE_PCX @@ -38,16 +40,16 @@ class TempAllocator { }; -bool +bool pcx_header::IsValid() const { - TRACE("manufacturer:%u version:%u encoding:%u bitsPerPixel:%u nPlanes:%u bytesPerLine:%u\n", manufacturer, version, encoding, bitsPerPixel, nPlanes, bytesPerLine); + TRACE("manufacturer:%u version:%u encoding:%u bitsPerPixel:%u numPlanes:%u bytesPerLine:%u\n", manufacturer, version, encoding, bitsPerPixel, numPlanes, bytesPerLine); return manufacturer == 10 && version == 5 && encoding == 1 && (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) - && (nPlanes == 1 || nPlanes == 3) - && (bitsPerPixel == 8 || nPlanes == 1) + && (numPlanes == 1 || numPlanes == 3) + && (bitsPerPixel == 8 || numPlanes == 1) && (bytesPerLine & 1) == 0; } @@ -75,16 +77,17 @@ convert_data_to_bits(pcx_header &header, StreamBuffer &source, { uint16 bitsPerPixel = header.bitsPerPixel; uint16 bytesPerLine = header.bytesPerLine; - uint16 width = header.xMax - header.xMin + 1; - uint16 height = header.yMax - header.yMin + 1; - uint16 nPlanes = header.nPlanes; - uint32 scanLineLength = nPlanes * bytesPerLine; - + uint32 width = header.xMax - header.xMin + 1; + uint32 height = header.yMax - header.yMin + 1; + uint16 numPlanes = header.numPlanes; + uint32 scanLineLength = numPlanes * bytesPerLine; + // allocate buffers TempAllocator scanLineAllocator; TempAllocator paletteAllocator; uint8 *scanLineData[height]; uint8 *palette = (uint8 *)paletteAllocator.Allocate(3 * 256); + status_t status = B_OK; for (uint32 row = 0; row < height; row++) { TRACE("scanline %ld\n", row); @@ -95,46 +98,68 @@ convert_data_to_bits(pcx_header &header, StreamBuffer &source, uint32 index = 0; uint8 x; do { - if (source.Read(&x, 1) != 1) - return B_IO_ERROR; + if (source.Read(&x, 1) != 1) { + status = B_IO_ERROR; + break; + } if ((x & 0xc0) == 0xc0) { uint32 count = x & 0x3f; - if (index + count - 1 > scanLineLength) - return B_IO_ERROR; - if (source.Read(&x, 1) != 1) - return B_IO_ERROR; + if (index + count - 1 > scanLineLength) { + status = B_BAD_DATA; + break; + } + if (source.Read(&x, 1) != 1) { + status = B_IO_ERROR; + break; + } for (uint32 i = 0; i < count; i++) line[index++] = x; } else { line[index++] = x; - } + } } while (index < scanLineLength); + + if (status != B_OK) { + // If we've already read more than a third of the file, display + // what we have, ie. ignore the error. + if (row < height / 3) + return status; + + memset(scanLineData + row, 0, sizeof(uint8*) * (height - row)); + break; + } } - - - if (bitsPerPixel == 8 && nPlanes == 1) { + + if (bitsPerPixel == 8 && numPlanes == 1) { TRACE("palette reading %p 8\n", palette); uint8 x; - if (source.Read(&x, 1) != 1) + if (status != B_OK || source.Read(&x, 1) != 1 || x != 12) { + // Try again by repositioning the file stream + if (source.Seek(-3 * 256 - 1, SEEK_END) < 0) + return B_BAD_DATA; + if (source.Read(&x, 1) != 1) return B_IO_ERROR; - if (x != 12) - return B_IO_ERROR; + if (x != 12) + return B_BAD_DATA; + } if (source.Read(palette, 256 * 3) != 256 * 3) - return B_IO_ERROR; + return B_IO_ERROR; } else { TRACE("palette reading %p palette\n", palette); memcpy(palette, &header.paletteInfo, 48); } - + uint8 alpha = 255; - if (bitsPerPixel == 1 && nPlanes == 1) { + if (bitsPerPixel == 1 && numPlanes == 1) { TRACE("target writing 1\n"); palette[0] = palette[1] = palette[2] = 0; - palette[3] = palette[4] = palette[5] = 0xff; + palette[3] = palette[4] = palette[5] = 0xff; for (uint32 row = 0; row < height; row++) { uint8 *line = scanLineData[row]; + if (line == NULL) + break; uint8 mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; - for (int i = 0; i < width; i++) { + for (uint32 i = 0; i < width; i++) { bool isBit = ((line[i >> 3] & mask[i & 7]) != 0) ? true : false; target.Write(&palette[!isBit ? 2 : 5], 1); target.Write(&palette[!isBit ? 1 : 4], 1); @@ -142,11 +167,13 @@ convert_data_to_bits(pcx_header &header, StreamBuffer &source, target.Write(&alpha, 1); } } - } else if (bitsPerPixel == 4 && nPlanes == 1) { + } else if (bitsPerPixel == 4 && numPlanes == 1) { TRACE("target writing 4\n"); for (uint32 row = 0; row < height; row++) { uint8 *line = scanLineData[row]; - for (int i = 0; i < width; i++) { + if (line == NULL) + break; + for (uint32 i = 0; i < width; i++) { uint16 index; if ((i & 1) == 0) index = (line[i >> 1] >> 4) & 15; @@ -160,12 +187,14 @@ convert_data_to_bits(pcx_header &header, StreamBuffer &source, target.Write(&alpha, 1); } } - } else if (bitsPerPixel == 8 && nPlanes == 1) { + } else if (bitsPerPixel == 8 && numPlanes == 1) { TRACE("target writing 8\n"); for (uint32 row = 0; row < height; row++) { TRACE("target writing 8 row %ld\n", row); uint8 *line = scanLineData[row]; - for (int i = 0; i < width; i++) { + if (line == NULL) + break; + for (uint32 i = 0; i < width; i++) { uint16 index = line[i]; index += (index + index); target.Write(&palette[index+2], 1); @@ -173,13 +202,15 @@ convert_data_to_bits(pcx_header &header, StreamBuffer &source, target.Write(&palette[index], 1); target.Write(&alpha, 1); } - + } } else { TRACE("target writing raw\n"); for (uint32 row = 0; row < height; row++) { uint8 *line = scanLineData[row]; - for (int i = 0; i < width; i++) { + if (line == NULL) + break; + for (uint32 i = 0; i < width; i++) { target.Write(&line[i + 2 * bytesPerLine], 1); target.Write(&line[i + bytesPerLine], 1); target.Write(&line[i], 1); @@ -187,7 +218,7 @@ convert_data_to_bits(pcx_header &header, StreamBuffer &source, } } } - + return B_OK; } @@ -210,9 +241,9 @@ PCX::identify(BMessage *settings, BPositionIO &stream, uint8 &type, int32 &bitsP if (!header.IsValid()) return B_BAD_VALUE; - + bitsPerPixel = header.bitsPerPixel; - + TRACE("PCX::identify OK\n"); return B_OK; @@ -228,7 +259,7 @@ PCX::convert_pcx_to_bits(BMessage *settings, BPositionIO &source, BPositionIO &t StreamBuffer sourceBuf(&source, 2048); if (sourceBuf.InitCheck() != B_OK) return B_IO_ERROR; - + pcx_header header; if (sourceBuf.Read(&header, sizeof(pcx_header)) != (ssize_t)sizeof(pcx_header)) return B_BAD_VALUE; @@ -239,10 +270,10 @@ PCX::convert_pcx_to_bits(BMessage *settings, BPositionIO &source, BPositionIO &t if (!header.IsValid()) return B_BAD_VALUE; - + uint16 width = header.xMax - header.xMin + 1; uint16 height = header.yMax - header.yMin + 1; - + TranslatorBitmap bitsHeader; bitsHeader.magic = B_TRANSLATOR_BITMAP; bitsHeader.bounds.left = 0; diff --git a/src/add-ons/translators/pcx/PCX.h b/src/add-ons/translators/pcx/PCX.h index 9bc909045d..b1bab0e27c 100644 --- a/src/add-ons/translators/pcx/PCX.h +++ b/src/add-ons/translators/pcx/PCX.h @@ -25,7 +25,7 @@ struct pcx_header { uint16 hDpi, vDpi; uint8 colormap[48]; uint8 reserved; - uint8 nPlanes; + uint8 numPlanes; uint16 bytesPerLine; uint16 paletteInfo; uint16 hScreenSize, vScreenSize;