X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/03647350fc7cd141953c72e0284e928847d30f44..88ff049184c77fd73b60c01f4f831860d2ec5cef:/src/common/imagbmp.cpp diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index 3e7a128d10..c3fcfb275e 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -2,7 +2,6 @@ // Name: src/common/imagbmp.cpp // Purpose: wxImage BMP,ICO and CUR handlers // Author: Robert Roebling, Chris Elliott -// RCS-ID: $Id$ // Copyright: (c) Robert Roebling, Chris Elliott // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -39,6 +38,16 @@ // For memcpy #include +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +#if wxUSE_ICO_CUR + +static bool CanReadICOOrCUR(wxInputStream *stream, wxUint16 resourceType); + +#endif // wxUSE_ICO_CUR + //----------------------------------------------------------------------------- // wxBMPHandler //----------------------------------------------------------------------------- @@ -81,7 +90,7 @@ bool wxBMPHandler::SaveDib(wxImage *image, { wxCHECK_MSG( image, false, wxT("invalid pointer in wxBMPHandler::SaveFile") ); - if ( !image->Ok() ) + if ( !image->IsOk() ) { if ( verbose ) { @@ -136,8 +145,8 @@ bool wxBMPHandler::SaveDib(wxImage *image, } unsigned width = image->GetWidth(); - unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword - unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row + unsigned row_padding = (4 - ((width * bpp + 7) / 8) % 4) % 4; // # bytes to pad to dword + unsigned row_width = (width * bpp + 7) / 8 + row_padding; // # of bytes per row struct { @@ -219,10 +228,10 @@ bool wxBMPHandler::SaveDib(wxImage *image, if (// VS: looks ugly but compilers tend to do ugly things with structs, // like aligning hdr.filesize's ofset to dword :( // VZ: we should add padding then... - !stream.Write(&hdr.magic, 2) || - !stream.Write(&hdr.filesize, 4) || - !stream.Write(&hdr.reserved, 4) || - !stream.Write(&hdr.data_offset, 4) + !stream.WriteAll(&hdr.magic, 2) || + !stream.WriteAll(&hdr.filesize, 4) || + !stream.WriteAll(&hdr.reserved, 4) || + !stream.WriteAll(&hdr.data_offset, 4) ) { if (verbose) @@ -235,17 +244,17 @@ bool wxBMPHandler::SaveDib(wxImage *image, if ( !IsMask ) { if ( - !stream.Write(&hdr.bih_size, 4) || - !stream.Write(&hdr.width, 4) || - !stream.Write(&hdr.height, 4) || - !stream.Write(&hdr.planes, 2) || - !stream.Write(&hdr.bpp, 2) || - !stream.Write(&hdr.compression, 4) || - !stream.Write(&hdr.size_of_bmp, 4) || - !stream.Write(&hdr.h_res, 4) || - !stream.Write(&hdr.v_res, 4) || - !stream.Write(&hdr.num_clrs, 4) || - !stream.Write(&hdr.num_signif_clrs, 4) + !stream.WriteAll(&hdr.bih_size, 4) || + !stream.WriteAll(&hdr.width, 4) || + !stream.WriteAll(&hdr.height, 4) || + !stream.WriteAll(&hdr.planes, 2) || + !stream.WriteAll(&hdr.bpp, 2) || + !stream.WriteAll(&hdr.compression, 4) || + !stream.WriteAll(&hdr.size_of_bmp, 4) || + !stream.WriteAll(&hdr.h_res, 4) || + !stream.WriteAll(&hdr.v_res, 4) || + !stream.WriteAll(&hdr.num_clrs, 4) || + !stream.WriteAll(&hdr.num_signif_clrs, 4) ) { if (verbose) @@ -322,7 +331,7 @@ bool wxBMPHandler::SaveDib(wxImage *image, { if ( !IsMask ) { - if ( !stream.Write(rgbquad, palette_size*4) ) + if ( !stream.WriteAll(rgbquad, palette_size*4) ) { if (verbose) { @@ -341,7 +350,7 @@ bool wxBMPHandler::SaveDib(wxImage *image, // pointer to the image data, use quantized if available wxUint8 *data = (wxUint8*) image->GetData(); - if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData(); + if (q_image) if (q_image->IsOk()) data = (wxUint8*) q_image->GetData(); wxUint8 *buffer = new wxUint8[row_width]; memset(buffer, 0, row_width); @@ -457,7 +466,7 @@ bool wxBMPHandler::SaveDib(wxImage *image, } } - if ( !stream.Write(buffer, row_width) ) + if ( !stream.WriteAll(buffer, row_width) ) { if (verbose) { @@ -523,6 +532,14 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, wxON_BLOCK_EXIT1(&BMPPalette::Free, cmap); + bool isUpsideDown = true; + + if (height < 0) + { + isUpsideDown = false; + height = -height; + } + // destroy existing here instead of: image->Destroy(); image->Create(width, height); @@ -568,7 +585,9 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { if (hasPalette) { - stream.Read(bbuf, 4); + if ( !stream.ReadAll(bbuf, 4) ) + return false; + cmap[j].b = bbuf[0]; cmap[j].g = bbuf[1]; cmap[j].r = bbuf[2]; @@ -600,7 +619,9 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, if ( comp == BI_BITFIELDS ) { int bit; - stream.Read(dbuf, 4 * 3); + if ( !stream.ReadAll(dbuf, 4 * 3) ) + return false; + rmask = wxINT32_SWAP_ON_BE(dbuf[0]); gmask = wxINT32_SWAP_ON_BE(dbuf[1]); bmask = wxINT32_SWAP_ON_BE(dbuf[2]); @@ -662,9 +683,10 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, // NOTE: seeking a positive amount in wxFromCurrent mode allows us to // load even non-seekable streams (see wxInputStream::SeekI docs)! const wxFileOffset pos = stream.TellI(); - if (pos != wxInvalidOffset && bmpOffset > pos) - if (stream.SeekI(bmpOffset - pos, wxFromCurrent) == wxInvalidOffset) - return false; + if ( pos == wxInvalidOffset || + (bmpOffset > pos && + stream.SeekI(bmpOffset - pos, wxFromCurrent) == wxInvalidOffset) ) + return false; //else: icon, just carry on } @@ -684,9 +706,18 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, int linesize = ((width * bpp + 31) / 32) * 4; - /* BMPs are stored upside down */ - for ( int line = (height - 1); line >= 0; line-- ) + // flag indicating if we have any not fully transparent alpha values: this + // is used to account for the bitmaps which use 32bpp format (normally + // meaning that they have alpha channel) but have only zeroes in it so that + // without this hack they appear fully transparent -- and as this is + // unlikely intentional, we consider that they don't have alpha at all in + // this case (see #10915) + bool hasValidAlpha = false; + + for ( int row = 0; row < height; row++ ) { + int line = isUpsideDown ? height - 1 - row : row; + int linepos = 0; for ( int column = 0; column < width ; ) { @@ -694,6 +725,9 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { linepos++; aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; + if ( bpp == 1 ) { for (int bit = 0; bit < 8 && column < width; bit++) @@ -712,25 +746,35 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, wxUint8 first; first = aByte; aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; + if ( first == 0 ) { if ( aByte == 0 ) { - if ( column > 0 ) - column = width; + // end of scanline marker + column = width; + row--; } else if ( aByte == 1 ) { + // end of RLE data marker, stop decoding column = width; - line = -1; + row = height; } else if ( aByte == 2 ) { + // delta marker, move in image aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; column += aByte; linepos = column * bpp / 4; aByte = stream.GetC(); - line -= aByte; // upside down + if ( !stream.IsOk() ) + return false; + row += aByte; // upside down } else { @@ -743,6 +787,8 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { ++readBytes ; aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; nibble[1] = (wxUint8)( aByte & 0x0F ) ; } @@ -754,7 +800,11 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, linepos++; } if ( readBytes & 0x01 ) + { aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; + } } } else @@ -795,24 +845,35 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, unsigned char first; first = aByte; aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; + if ( first == 0 ) { if ( aByte == 0 ) { - /* column = width; */ + // end of scanline marker + column = width; + row--; } else if ( aByte == 1 ) { + // end of RLE data marker, stop decoding column = width; - line = -1; + row = height; } else if ( aByte == 2 ) { + // delta marker, move in image aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; column += aByte; linepos = column * bpp / 8; aByte = stream.GetC(); - line += aByte; + if ( !stream.IsOk() ) + return false; + row -= aByte; } else { @@ -821,13 +882,19 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { linepos++; aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; ptr[poffset ] = cmap[aByte].r; ptr[poffset + 1] = cmap[aByte].g; ptr[poffset + 2] = cmap[aByte].b; column++; } if ( absolute & 0x01 ) + { aByte = stream.GetC(); + if ( !stream.IsOk() ) + return false; + } } } else @@ -854,7 +921,8 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, } else if ( bpp == 24 ) { - stream.Read(bbuf, 3); + if ( !stream.ReadAll(bbuf, 3) ) + return false; linepos += 3; ptr[poffset ] = (unsigned char)bbuf[2]; ptr[poffset + 1] = (unsigned char)bbuf[1]; @@ -864,7 +932,8 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, else if ( bpp == 16 ) { unsigned char temp; - stream.Read(&aWord, 2); + if ( !stream.ReadAll(&aWord, 2) ) + return false; aWord = wxUINT16_SWAP_ON_BE(aWord); linepos += 2; /* Use the masks and calculated amount of shift @@ -882,7 +951,9 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, else { unsigned char temp; - stream.Read(&aDword, 4); + if ( !stream.ReadAll(&aDword, 4) ) + return false; + aDword = wxINT32_SWAP_ON_BE(aDword); linepos += 4; temp = (unsigned char)((aDword & rmask) >> rshift); @@ -895,21 +966,30 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { temp = (unsigned char)((aDword & amask) >> ashift); alpha[line * width + column] = temp; + + if ( temp != wxALPHA_TRANSPARENT ) + hasValidAlpha = true; } column++; } } while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) { - stream.Read(&aByte, 1); - linepos += 1; - if ( !stream ) + ++linepos; + if ( !stream.ReadAll(&aByte, 1) ) break; } } image->SetMask(false); + // check if we had any valid alpha values in this bitmap + if ( alpha && !hasValidAlpha ) + { + // we didn't, so finally discard the alpha channel completely + image->ClearAlpha(); + } + const wxStreamError err = stream.GetLastError(); return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; } @@ -924,19 +1004,23 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, if ( IsBmp ) { // read the header off the .BMP format file - stream.Read(bbuf, 2); - stream.Read(dbuf, 16); + if ( !stream.ReadAll(bbuf, 2) || + !stream.ReadAll(dbuf, 16) ) + return false; } else { - stream.Read(dbuf, 4); + if ( !stream.ReadAll(dbuf, 4) ) + return false; } #if 0 // unused wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]); #endif wxFileOffset offset = wxINT32_SWAP_ON_BE(dbuf[2]); - stream.Read(dbuf, 4 * 2); + if ( !stream.ReadAll(dbuf, 4 * 2) ) + return false; + int width = wxINT32_SWAP_ON_BE((int)dbuf[0]); int height = wxINT32_SWAP_ON_BE((int)dbuf[1]); if ( !IsBmp)height = height / 2; // for icons divide by 2 @@ -958,12 +1042,16 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, return false; } - stream.Read(&aWord, 2); + if ( !stream.ReadAll(&aWord, 2) ) + return false; + /* TODO int planes = (int)wxUINT16_SWAP_ON_BE( aWord ); */ - stream.Read(&aWord, 2); + if ( !stream.ReadAll(&aWord, 2) ) + return false; + int bpp = wxUINT16_SWAP_ON_BE((int)aWord); if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) { @@ -974,7 +1062,9 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, return false; } - stream.Read(dbuf, 4 * 4); + if ( !stream.ReadAll(dbuf, 4 * 4) ) + return false; + int comp = wxINT32_SWAP_ON_BE((int)dbuf[0]); if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS ) @@ -986,7 +1076,8 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, return false; } - stream.Read(dbuf, 4 * 2); + if ( !stream.ReadAll(dbuf, 4 * 2) ) + return false; int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] ); if (ncolors == 0) @@ -1051,7 +1142,7 @@ bool wxBMPHandler::DoCanRead(wxInputStream& stream) { unsigned char hdr[2]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here + if ( !stream.ReadAll(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here return false; // do we have the BMP file signature? @@ -1133,10 +1224,9 @@ bool wxICOHandler::SaveFile(wxImage *image, IconDir.idReserved = 0; IconDir.idType = wxUINT16_SWAP_ON_BE((wxUint16)type); IconDir.idCount = wxUINT16_SWAP_ON_BE((wxUint16)images); - stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved)); - stream.Write(&IconDir.idType, sizeof(IconDir.idType)); - stream.Write(&IconDir.idCount, sizeof(IconDir.idCount)); - if ( !stream.IsOk() ) + if ( !stream.WriteAll(&IconDir.idReserved, sizeof(IconDir.idReserved)) || + !stream.WriteAll(&IconDir.idType, sizeof(IconDir.idType)) || + !stream.WriteAll(&IconDir.idCount, sizeof(IconDir.idCount)) ) { if ( verbose ) { @@ -1221,7 +1311,7 @@ bool wxICOHandler::SaveFile(wxImage *image, // wxCountingOutputStream::IsOk() always returns true for now and this // "if" provokes VC++ warnings in optimized build #if 0 - if ( !cStream.Ok() ) + if ( !cStream.IsOk() ) { if ( verbose ) { @@ -1259,15 +1349,14 @@ bool wxICOHandler::SaveFile(wxImage *image, offset += Size; // write to stream: - stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth)); - stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight)); - stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount)); - stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved)); - stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes)); - stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount)); - stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes)); - stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset)); - if ( !stream.IsOk() ) + if ( !stream.WriteAll(&icondirentry.bWidth, sizeof(icondirentry.bWidth)) || + !stream.WriteAll(&icondirentry.bHeight, sizeof(icondirentry.bHeight)) || + !stream.WriteAll(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount)) || + !stream.WriteAll(&icondirentry.bReserved, sizeof(icondirentry.bReserved)) || + !stream.WriteAll(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes)) || + !stream.WriteAll(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount)) || + !stream.WriteAll(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes)) || + !stream.WriteAll(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset)) ) { if ( verbose ) { @@ -1307,6 +1396,11 @@ bool wxICOHandler::SaveFile(wxImage *image, bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) { + if ( stream.IsSeekable() && stream.SeekI(0) == wxInvalidOffset ) + { + return false; + } + return DoLoadFile(image, stream, verbose, index); } @@ -1318,7 +1412,9 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, ICONDIR IconDir; - stream.Read(&IconDir, sizeof(IconDir)); + if ( !stream.ReadAll(&IconDir, sizeof(IconDir)) ) + return false; + wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); // nType is 1 for Icons, 2 for Cursors: @@ -1336,7 +1432,10 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, for (unsigned int i = 0; i < nIcons; i++ ) { - alreadySeeked += stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY)).LastRead(); + if ( !stream.ReadAll(pCurrentEntry, sizeof(ICONDIRENTRY)) ) + return false; + + alreadySeeked += stream.LastRead(); // bHeight and bColorCount are wxUint8 if ( pCurrentEntry->bWidth >= wMax ) @@ -1395,10 +1494,16 @@ bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, int wxICOHandler::DoGetImageCount(wxInputStream& stream) { + // It's ok to modify the stream position in this function. + + if ( stream.IsSeekable() && stream.SeekI(0) == wxInvalidOffset ) + { + return 0; + } + ICONDIR IconDir; - if (stream.Read(&IconDir, sizeof(IconDir)).LastRead() != sizeof(IconDir)) - // it's ok to modify the stream position here + if ( !stream.ReadAll(&IconDir, sizeof(IconDir)) ) return 0; return (int)wxUINT16_SWAP_ON_BE(IconDir.idCount); @@ -1406,12 +1511,8 @@ int wxICOHandler::DoGetImageCount(wxInputStream& stream) bool wxICOHandler::DoCanRead(wxInputStream& stream) { - unsigned char hdr[4]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here - return false; + return CanReadICOOrCUR(&stream, 1 /*for identifying an icon*/); - // hdr[2] is one for an icon and two for a cursor - return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0'; } #endif // wxUSE_STREAMS @@ -1427,12 +1528,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler) bool wxCURHandler::DoCanRead(wxInputStream& stream) { - unsigned char hdr[4]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) // it's ok to modify the stream position here - return false; - - // hdr[2] is one for an icon and two for a cursor - return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0'; + return CanReadICOOrCUR(&stream, 2 /*for identifying a cursor*/); } #endif // wxUSE_STREAMS @@ -1471,6 +1567,26 @@ int wxANIHandler::DoGetImageCount(wxInputStream& stream) return decoder.GetFrameCount(); } +static bool CanReadICOOrCUR(wxInputStream *stream, wxUint16 resourceType) +{ + // It's ok to modify the stream position in this function. + + if ( stream->IsSeekable() && stream->SeekI(0) == wxInvalidOffset ) + { + return false; + } + + ICONDIR iconDir; + if ( !stream->ReadAll(&iconDir, sizeof(iconDir)) ) + { + return false; + } + + return !iconDir.idReserved // reserved, must be 0 + && wxUINT16_SWAP_ON_BE(iconDir.idType) == resourceType // either 1 or 2 + && iconDir.idCount; // must contain at least one image +} + #endif // wxUSE_STREAMS #endif // wxUSE_ICO_CUR