X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6e3d5828092893fa94725ecc09a6a84c9286ccda..424da8bdb9f05243d8888d78a56ab0cc3f615a6c:/src/common/imagtga.cpp diff --git a/src/common/imagtga.cpp b/src/common/imagtga.cpp index 281682cbb9..e3b5473995 100644 --- a/src/common/imagtga.cpp +++ b/src/common/imagtga.cpp @@ -30,6 +30,7 @@ #include "wx/imagtga.h" #include "wx/log.h" +#include "wx/scopeguard.h" // ---------------------------------------------------------------------------- // constants @@ -38,9 +39,10 @@ // TGA error codes. enum { - wxTGA_OK = 0, - wxTGA_INVFORMAT = 1, - wxTGA_MEMERR = 2 + wxTGA_OK, + wxTGA_INVFORMAT, + wxTGA_MEMERR, + wxTGA_IOERR }; // TGA header bytes. @@ -99,8 +101,9 @@ void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize) } } +// return wxTGA_OK or wxTGA_IOERR static -void DecodeRLE(unsigned char* imageData, unsigned long imageSize, +int DecodeRLE(unsigned char* imageData, unsigned long imageSize, short pixelSize, wxInputStream& stream) { unsigned long index = 0; @@ -110,7 +113,11 @@ void DecodeRLE(unsigned char* imageData, unsigned long imageSize, while (index < imageSize) { - current = stream.GetC(); + int ch = stream.GetC(); + if ( ch == wxEOF ) + return wxTGA_IOERR; + + current = ch; // RLE packet. if ( current & 0x80 ) @@ -125,7 +132,8 @@ void DecodeRLE(unsigned char* imageData, unsigned long imageSize, index += current * pixelSize; // Repeat the pixel length times. - stream.Read(buf, pixelSize); + if ( !stream.Read(buf, pixelSize) ) + return wxTGA_IOERR; for (unsigned int i = 0; i < length; i++) { @@ -144,11 +152,14 @@ void DecodeRLE(unsigned char* imageData, unsigned long imageSize, index += length; // Write the next length pixels directly to the image data. - stream.Read(imageData, length); + if ( !stream.Read(imageData, length) ) + return wxTGA_IOERR; imageData += length; } } + + return wxTGA_OK; } static @@ -187,6 +198,8 @@ int ReadTGA(wxImage* image, wxInputStream& stream) return wxTGA_MEMERR; } + wxON_BLOCK_EXIT1(free, imageData); + unsigned char *dst = image->GetData(); unsigned char* alpha = NULL; @@ -198,7 +211,8 @@ int ReadTGA(wxImage* image, wxInputStream& stream) } // Seek from the offset we got from the TGA header. - stream.SeekI(offset, wxFromStart); + if (stream.SeekI(offset, wxFromStart) == wxInvalidOffset) + return wxTGA_INVFORMAT; // Load a palette if we have one. if (colorType == wxTGA_MAPPED) @@ -439,7 +453,9 @@ int ReadTGA(wxImage* image, wxInputStream& stream) // Decode the RLE data. - DecodeRLE(imageData, imageSize, pixelSize, stream); + int rc = DecodeRLE(imageData, imageSize, pixelSize, stream); + if ( rc != wxTGA_OK ) + return rc; // If orientation == 0, then the image is stored upside down. // We need to store it right side up. @@ -497,7 +513,9 @@ int ReadTGA(wxImage* image, wxInputStream& stream) { // Decode the RLE data. - DecodeRLE(imageData, imageSize, pixelSize, stream); + int rc = DecodeRLE(imageData, imageSize, pixelSize, stream); + if ( rc != wxTGA_OK ) + return rc; // If orientation == 0, then the image is stored upside down. // We need to store it right side up. @@ -575,7 +593,9 @@ int ReadTGA(wxImage* image, wxInputStream& stream) { // Decode the RLE data. - DecodeRLE(imageData, imageSize, pixelSize, stream); + int rc = DecodeRLE(imageData, imageSize, pixelSize, stream); + if ( rc != wxTGA_OK ) + return rc; // If orientation == 0, then the image is stored upside down. // We need to store it right side up. @@ -626,15 +646,74 @@ int ReadTGA(wxImage* image, wxInputStream& stream) return wxTGA_INVFORMAT; } - free(imageData); - return wxTGA_OK; } static -int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream)) +int SaveTGA(const wxImage& image, wxOutputStream *stream) { - wxLogError(wxT("Saving in TGA format is not implemented.")); + bool hasAlpha = image.HasAlpha(); + unsigned bytesPerPixel = 3 + (hasAlpha ? 1 : 0); + wxSize size = image.GetSize(); + size_t scanlineSize = size.x * bytesPerPixel; + unsigned char *scanlineData = (unsigned char *) malloc(scanlineSize); + if (!scanlineData) + { + return wxTGA_MEMERR; + } + + wxON_BLOCK_EXIT1(free, scanlineData); + + // Compose and write the TGA header + unsigned char hdr[HDR_SIZE]; + (void) memset(&hdr, 0, HDR_SIZE); + + hdr[HDR_COLORTYPE] = wxTGA_UNMAPPED; + hdr[HDR_IMAGETYPE] = 2 /* Uncompressed truecolour */; + + hdr[HDR_WIDTH] = size.x & 0xFF; + hdr[HDR_WIDTH + 1] = (size.x >> 8) & 0xFF; + + hdr[HDR_HEIGHT] = size.y & 0xFF; + hdr[HDR_HEIGHT + 1] = (size.y >> 8) & 0xFF; + + hdr[HDR_BPP] = hasAlpha ? 32 : 24; + hdr[HDR_ORIENTATION] = 1 << 5; // set bit to indicate top-down order + if (hasAlpha) + { + hdr[HDR_ORIENTATION] |= 8; // number of alpha bits + } + + if ( !stream->Write(hdr, HDR_SIZE) ) + { + return wxTGA_IOERR; + } + + + // Write image data, converting RGB to BGR and adding alpha if applicable + + unsigned char *src = image.GetData(); + unsigned char *alpha = image.GetAlpha(); + for (int y = 0; y < size.y; ++y) + { + unsigned char *dst = scanlineData; + for (int x = 0; x < size.x; ++x) + { + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + if (alpha) + { + dst[3] = *(alpha++); + } + src += 3; + dst += bytesPerPixel; + } + if ( !stream->Write(scanlineData, scanlineSize) ) + { + return wxTGA_IOERR; + } + } return wxTGA_OK; } @@ -651,7 +730,9 @@ bool wxTGAHandler::LoadFile(wxImage* image, if ( !CanRead(stream) ) { if ( verbose ) + { wxLogError(wxT("TGA: this is not a TGA file.")); + } return false; } @@ -673,6 +754,10 @@ bool wxTGAHandler::LoadFile(wxImage* image, wxLogError(wxT("TGA: couldn't allocate memory.")); break; + case wxTGA_IOERR: + wxLogError(wxT("TGA: couldn't read image data.")); + break; + default: wxLogError(wxT("TGA: unknown error!")); } @@ -688,7 +773,7 @@ bool wxTGAHandler::LoadFile(wxImage* image, bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose) { - int error = SaveTGA(image, stream); + int error = SaveTGA(*image, &stream); if ( error != wxTGA_OK ) { @@ -696,14 +781,14 @@ bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose { switch ( error ) { - case wxTGA_INVFORMAT: - wxLogError(wxT("TGA: invalid image.")); - break; - case wxTGA_MEMERR: wxLogError(wxT("TGA: couldn't allocate memory.")); break; + case wxTGA_IOERR: + wxLogError(wxT("TGA: couldn't write image data.")); + break; + default: wxLogError(wxT("TGA: unknown error!")); } @@ -719,7 +804,7 @@ bool wxTGAHandler::DoCanRead(wxInputStream& stream) { // read the fixed-size TGA headers unsigned char hdr[HDR_SIZE]; - stream.Read(hdr, HDR_SIZE); + stream.Read(hdr, HDR_SIZE); // it's ok to modify the stream position here // Check wether we can read the file or not.