diff --git a/DDSTextureLoader/DDSTextureLoader.cpp b/DDSTextureLoader/DDSTextureLoader.cpp index 07de0bb..3678245 100644 --- a/DDSTextureLoader/DDSTextureLoader.cpp +++ b/DDSTextureLoader/DDSTextureLoader.cpp @@ -406,7 +406,7 @@ namespace //-------------------------------------------------------------------------------------- // Get surface information for a particular format //-------------------------------------------------------------------------------------- - void GetSurfaceInfo( + HRESULT GetSurfaceInfo( _In_ size_t width, _In_ size_t height, _In_ DXGI_FORMAT fmt, @@ -414,9 +414,9 @@ namespace _Out_opt_ size_t* outRowBytes, _Out_opt_ size_t* outNumRows) { - size_t numBytes = 0; - size_t rowBytes = 0; - size_t numRows = 0; + uint64_t numBytes = 0; + uint64_t rowBytes = 0; + uint64_t numRows = 0; bool bc = false; bool packed = false; @@ -477,19 +477,22 @@ namespace planar = true; bpe = 4; break; + + default: + break; } if (bc) { - size_t numBlocksWide = 0; + uint64_t numBlocksWide = 0; if (width > 0) { - numBlocksWide = std::max(1, (width + 3) / 4); + numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u); } - size_t numBlocksHigh = 0; + uint64_t numBlocksHigh = 0; if (height > 0) { - numBlocksHigh = std::max(1, (height + 3) / 4); + numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u); } rowBytes = numBlocksWide * bpe; numRows = numBlocksHigh; @@ -497,42 +500,55 @@ namespace } else if (packed) { - rowBytes = ((width + 1) >> 1) * bpe; - numRows = height; + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numRows = uint64_t(height); numBytes = rowBytes * height; } else if (fmt == DXGI_FORMAT_NV11) { - rowBytes = ((width + 3) >> 2) * 4; - numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u; + numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numBytes = rowBytes * numRows; } else if (planar) { - rowBytes = ((width + 1) >> 1) * bpe; - numBytes = (rowBytes * height) + ((rowBytes * height + 1) >> 1); - numRows = height + ((height + 1) >> 1); + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1); + numRows = height + ((uint64_t(height) + 1u) >> 1); } else { size_t bpp = BitsPerPixel(fmt); - rowBytes = (width * bpp + 7) / 8; // round up to nearest byte - numRows = height; + if (!bpp) + return E_INVALIDARG; + + rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte + numRows = uint64_t(height); numBytes = rowBytes * height; } +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + if (outNumBytes) { - *outNumBytes = numBytes; + *outNumBytes = static_cast(numBytes); } if (outRowBytes) { - *outRowBytes = rowBytes; + *outRowBytes = static_cast(rowBytes); } if (outNumRows) { - *outNumRows = numRows; + *outNumRows = static_cast(numRows); } + + return S_OK; } @@ -851,7 +867,9 @@ namespace size_t d = depth; for (size_t i = 0; i < mipCount; i++) { - GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr); + HRESULT hr = GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr); + if (FAILED(hr)) + return hr; if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); @@ -1357,7 +1375,9 @@ namespace { size_t numBytes = 0; size_t rowBytes = 0; - GetSurfaceInfo(width, height, format, &numBytes, &rowBytes, nullptr); + hr = GetSurfaceInfo(width, height, format, &numBytes, &rowBytes, nullptr); + if (FAILED(hr)) + return hr; if (numBytes > bitSize) { diff --git a/DDSTextureLoader/DDSTextureLoader12.cpp b/DDSTextureLoader/DDSTextureLoader12.cpp index 813193b..8e18670 100644 --- a/DDSTextureLoader/DDSTextureLoader12.cpp +++ b/DDSTextureLoader/DDSTextureLoader12.cpp @@ -336,6 +336,7 @@ namespace case DXGI_FORMAT_P010: case DXGI_FORMAT_P016: + case DXGI_FORMAT_V408: return 24; case DXGI_FORMAT_R8G8_TYPELESS: @@ -354,6 +355,8 @@ namespace case DXGI_FORMAT_B5G5R5A1_UNORM: case DXGI_FORMAT_A8P8: case DXGI_FORMAT_B4G4R4A4_UNORM: + case DXGI_FORMAT_P208: + case DXGI_FORMAT_V208: return 16; case DXGI_FORMAT_NV12: @@ -409,17 +412,17 @@ namespace //-------------------------------------------------------------------------------------- // Get surface information for a particular format //-------------------------------------------------------------------------------------- - void GetSurfaceInfo( + HRESULT GetSurfaceInfo( _In_ size_t width, _In_ size_t height, _In_ DXGI_FORMAT fmt, size_t* outNumBytes, _Out_opt_ size_t* outRowBytes, - _Out_opt_ size_t* outNumRows ) + _Out_opt_ size_t* outNumRows) { - size_t numBytes = 0; - size_t rowBytes = 0; - size_t numRows = 0; + uint64_t numBytes = 0; + uint64_t rowBytes = 0; + uint64_t numRows = 0; bool bc = false; bool packed = false; @@ -433,7 +436,7 @@ namespace case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_SNORM: - bc=true; + bc = true; bpe = 8; break; @@ -471,6 +474,7 @@ namespace case DXGI_FORMAT_NV12: case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_P208: planar = true; bpe = 2; break; @@ -480,19 +484,22 @@ namespace planar = true; bpe = 4; break; + + default: + break; } if (bc) { - size_t numBlocksWide = 0; + uint64_t numBlocksWide = 0; if (width > 0) { - numBlocksWide = std::max( 1, (width + 3) / 4 ); + numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u); } - size_t numBlocksHigh = 0; + uint64_t numBlocksHigh = 0; if (height > 0) { - numBlocksHigh = std::max( 1, (height + 3) / 4 ); + numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u); } rowBytes = numBlocksWide * bpe; numRows = numBlocksHigh; @@ -500,42 +507,55 @@ namespace } else if (packed) { - rowBytes = ( ( width + 1 ) >> 1 ) * bpe; - numRows = height; + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numRows = uint64_t(height); numBytes = rowBytes * height; } - else if ( fmt == DXGI_FORMAT_NV11 ) + else if (fmt == DXGI_FORMAT_NV11) { - rowBytes = ( ( width + 3 ) >> 2 ) * 4; - numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u; + numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numBytes = rowBytes * numRows; } else if (planar) { - rowBytes = ( ( width + 1 ) >> 1 ) * bpe; - numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); - numRows = height + ( ( height + 1 ) >> 1 ); + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1); + numRows = height + ((uint64_t(height) + 1u) >> 1); } else { - size_t bpp = BitsPerPixel( fmt ); - rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte - numRows = height; + size_t bpp = BitsPerPixel(fmt); + if (!bpp) + return E_INVALIDARG; + + rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte + numRows = uint64_t(height); numBytes = rowBytes * height; } +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + if (outNumBytes) { - *outNumBytes = numBytes; + *outNumBytes = static_cast(numBytes); } if (outRowBytes) { - *outRowBytes = rowBytes; + *outRowBytes = static_cast(rowBytes); } if (outNumRows) { - *outNumRows = numRows; + *outNumRows = static_cast(numRows); } + + return S_OK; } @@ -849,12 +869,6 @@ namespace case DXGI_FORMAT_NV12: case DXGI_FORMAT_P010: case DXGI_FORMAT_P016: - -#if defined(_XBOX_ONE) && defined(_TITLE) - case DXGI_FORMAT_D16_UNORM_S8_UINT: - case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: - case DXGI_FORMAT_X16_TYPELESS_G8_UINT: -#endif if (!slicePlane) { // Plane 0 @@ -930,7 +944,9 @@ namespace size_t d = depth; for (size_t i = 0; i < mipCount; i++) { - GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr); + HRESULT hr = GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr); + if (FAILED(hr)) + return hr; if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index 4b411fe..2a2472a 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -71,7 +71,7 @@ namespace DirectX CP_FLAGS_8BPP = 0x40000, // Override with a legacy 8 bits-per-pixel format size }; - void __cdecl ComputePitch( + HRESULT __cdecl ComputePitch( _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _Out_ size_t& rowPitch, _Out_ size_t& slicePitch, _In_ DWORD flags = CP_FLAGS_NONE); diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index 8044339..7b3f8a7 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -686,7 +686,9 @@ HRESULT DirectX::_EncodeDDSHeader( } size_t rowPitch, slicePitch; - ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE); + HRESULT hr = ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; if (slicePitch > UINT32_MAX || rowPitch > UINT32_MAX) @@ -1140,7 +1142,9 @@ namespace } size_t pixelSize, nimages; - _DetermineImageArray(metadata, cpFlags, nimages, pixelSize); + if (!_DetermineImageArray(metadata, cpFlags, nimages, pixelSize)) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + if ((nimages == 0) || (nimages != image.GetImageCount())) { return E_FAIL; @@ -1741,6 +1745,12 @@ HRESULT DirectX::LoadFromDDSFile( return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); } + if (image.GetPixelsSize() > UINT32_MAX) + { + image.Release(); + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + } + if (!ReadFile(hFile.get(), image.GetPixels(), static_cast(image.GetPixelsSize()), &bytesRead, nullptr)) { image.Release(); @@ -1797,7 +1807,9 @@ HRESULT DirectX::SaveToDDSMemory( return E_FAIL; size_t ddsRowPitch, ddsSlicePitch; - ComputePitch(metadata.format, images[i].width, images[i].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + hr = ComputePitch(metadata.format, images[i].width, images[i].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; assert(images[i].rowPitch > 0); assert(images[i].slicePitch > 0); @@ -1868,7 +1880,12 @@ HRESULT DirectX::SaveToDDSMemory( else { size_t ddsRowPitch, ddsSlicePitch; - ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + { + blob.Release(); + return hr; + } size_t rowPitch = images[index].rowPitch; @@ -1937,7 +1954,12 @@ HRESULT DirectX::SaveToDDSMemory( else { size_t ddsRowPitch, ddsSlicePitch; - ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + { + blob.Release(); + return hr; + } size_t rowPitch = images[index].rowPitch; @@ -2049,9 +2071,11 @@ HRESULT DirectX::SaveToDDSFile( assert(images[index].slicePitch > 0); size_t ddsRowPitch, ddsSlicePitch; - ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; - if (images[index].slicePitch == ddsSlicePitch) + if ((images[index].slicePitch == ddsSlicePitch) && (ddsSlicePitch <= UINT32_MAX)) { if (!WriteFile(hFile.get(), images[index].pixels, static_cast(ddsSlicePitch), &bytesWritten, nullptr)) { @@ -2072,6 +2096,9 @@ HRESULT DirectX::SaveToDDSFile( return E_FAIL; } + if (ddsRowPitch > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + const uint8_t * __restrict sPtr = images[index].pixels; size_t lines = ComputeScanlines(metadata.format, images[index].height); @@ -2117,9 +2144,11 @@ HRESULT DirectX::SaveToDDSFile( assert(images[index].slicePitch > 0); size_t ddsRowPitch, ddsSlicePitch; - ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; - if (images[index].slicePitch == ddsSlicePitch) + if ((images[index].slicePitch == ddsSlicePitch) && (ddsSlicePitch <= UINT32_MAX)) { if (!WriteFile(hFile.get(), images[index].pixels, static_cast(ddsSlicePitch), &bytesWritten, nullptr)) { @@ -2140,6 +2169,9 @@ HRESULT DirectX::SaveToDDSFile( return E_FAIL; } + if (ddsRowPitch > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + const uint8_t * __restrict sPtr = images[index].pixels; size_t lines = ComputeScanlines(metadata.format, images[index].height); diff --git a/DirectXTex/DirectXTexHDR.cpp b/DirectXTex/DirectXTexHDR.cpp index 4a015c6..4d9e9fb 100644 --- a/DirectXTex/DirectXTexHDR.cpp +++ b/DirectXTex/DirectXTexHDR.cpp @@ -1011,8 +1011,13 @@ HRESULT DirectX::SaveToHDRFile(const Image& image, const wchar_t* szFile) auto_delete_file delonfail(hFile.get()); - size_t rowPitch = image.width * 4; - size_t slicePitch = image.height * rowPitch; + uint64_t pitch = uint64_t(image.width) * 4u; + uint64_t slicePitch = uint64_t(image.height) * pitch; + + if (pitch > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + size_t rowPitch = static_cast(pitch); if (slicePitch < 65535) { @@ -1088,6 +1093,9 @@ HRESULT DirectX::SaveToHDRFile(const Image& image, const wchar_t* szFile) size_t encSize = EncodeRLE(enc, rgbe, rowPitch, image.width); if (encSize > 0) { + if (encSize > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + if (!WriteFile(hFile.get(), enc, static_cast(encSize), &bytesWritten, nullptr)) { return HRESULT_FROM_WIN32(GetLastError()); diff --git a/DirectXTex/DirectXTexImage.cpp b/DirectXTex/DirectXTexImage.cpp index 4c82e94..2ebd9cd 100644 --- a/DirectXTex/DirectXTexImage.cpp +++ b/DirectXTex/DirectXTexImage.cpp @@ -24,7 +24,7 @@ using namespace DirectX; // Determines number of image array entries and pixel size //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void DirectX::_DetermineImageArray( +bool DirectX::_DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags, size_t& nImages, @@ -34,8 +34,8 @@ void DirectX::_DetermineImageArray( assert(metadata.arraySize > 0); assert(metadata.mipLevels > 0); - size_t _pixelSize = 0; - size_t _nimages = 0; + uint64_t totalPixelSize = 0; + size_t nimages = 0; switch (metadata.dimension) { @@ -49,10 +49,14 @@ void DirectX::_DetermineImageArray( for (size_t level = 0; level < metadata.mipLevels; ++level) { size_t rowPitch, slicePitch; - ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); + if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags))) + { + nImages = pixelSize = 0; + return false; + } - _pixelSize += slicePitch; - ++_nimages; + totalPixelSize += uint64_t(slicePitch); + ++nimages; if (h > 1) h >>= 1; @@ -72,12 +76,16 @@ void DirectX::_DetermineImageArray( for (size_t level = 0; level < metadata.mipLevels; ++level) { size_t rowPitch, slicePitch; - ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); + if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags))) + { + nImages = pixelSize = 0; + return false; + } for (size_t slice = 0; slice < d; ++slice) { - _pixelSize += slicePitch; - ++_nimages; + totalPixelSize += uint64_t(slicePitch); + ++nimages; } if (h > 1) @@ -93,12 +101,25 @@ void DirectX::_DetermineImageArray( break; default: - assert(false); - break; + nImages = pixelSize = 0; + return false; } - nImages = _nimages; - pixelSize = _pixelSize; +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (totalPixelSize > UINT32_MAX) + { + nImages = pixelSize = 0; + return false; + } +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + + nImages = nimages; + pixelSize = static_cast(totalPixelSize); + + return true; } @@ -147,7 +168,8 @@ bool DirectX::_SetupImageArray( } size_t rowPitch, slicePitch; - ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); + if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags))) + return false; images[index].width = w; images[index].height = h; @@ -186,7 +208,8 @@ bool DirectX::_SetupImageArray( for (size_t level = 0; level < metadata.mipLevels; ++level) { size_t rowPitch, slicePitch; - ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags); + if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags))) + return false; for (size_t slice = 0; slice < d; ++slice) { @@ -318,7 +341,8 @@ HRESULT ScratchImage::Initialize(const TexMetadata& mdata, DWORD flags) m_metadata.dimension = mdata.dimension; size_t pixelSize, nimages; - _DetermineImageArray(m_metadata, flags, nimages, pixelSize); + if (!_DetermineImageArray(m_metadata, flags, nimages, pixelSize)) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); m_image = new (std::nothrow) Image[nimages]; if (!m_image) @@ -384,7 +408,8 @@ HRESULT ScratchImage::Initialize2D(DXGI_FORMAT fmt, size_t width, size_t height, m_metadata.dimension = TEX_DIMENSION_TEXTURE2D; size_t pixelSize, nimages; - _DetermineImageArray(m_metadata, flags, nimages, pixelSize); + if (!_DetermineImageArray(m_metadata, flags, nimages, pixelSize)) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); m_image = new (std::nothrow) Image[nimages]; if (!m_image) @@ -434,7 +459,8 @@ HRESULT ScratchImage::Initialize3D(DXGI_FORMAT fmt, size_t width, size_t height, m_metadata.dimension = TEX_DIMENSION_TEXTURE3D; size_t pixelSize, nimages; - _DetermineImageArray(m_metadata, flags, nimages, pixelSize); + if (!_DetermineImageArray(m_metadata, flags, nimages, pixelSize)) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); m_image = new (std::nothrow) Image[nimages]; if (!m_image) diff --git a/DirectXTex/DirectXTexP.h b/DirectXTex/DirectXTexP.h index 76aa086..dc23846 100644 --- a/DirectXTex/DirectXTexP.h +++ b/DirectXTex/DirectXTexP.h @@ -178,7 +178,7 @@ namespace DirectX //--------------------------------------------------------------------------------- // Image helper functions - void __cdecl _DetermineImageArray( + _Success_(return != false) bool __cdecl _DetermineImageArray( _In_ const TexMetadata& metadata, _In_ DWORD cpFlags, _Out_ size_t& nImages, _Out_ size_t& pixelSize); diff --git a/DirectXTex/DirectXTexTGA.cpp b/DirectXTex/DirectXTexTGA.cpp index 09469d4..6646868 100644 --- a/DirectXTex/DirectXTexTGA.cpp +++ b/DirectXTex/DirectXTexTGA.cpp @@ -272,7 +272,9 @@ namespace else { size_t slicePitch; - ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE); + HRESULT hr = ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; } auto sPtr = static_cast(pSource); @@ -596,7 +598,9 @@ namespace else { size_t slicePitch; - ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE); + HRESULT hr = ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; } auto sPtr = static_cast(pSource); @@ -1050,6 +1054,18 @@ HRESULT DirectX::LoadFromTGAFile( if (!(convFlags & (CONV_FLAGS_RLE | CONV_FLAGS_EXPAND | CONV_FLAGS_INVERTX)) && (convFlags & CONV_FLAGS_INVERTY)) { // This case we can read directly into the image buffer in place + if (remaining < image.GetPixelsSize()) + { + image.Release(); + return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); + } + + if (image.GetPixelsSize() > UINT32_MAX) + { + image.Release(); + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + } + if (!ReadFile(hFile.get(), image.GetPixels(), static_cast(image.GetPixelsSize()), &bytesRead, nullptr)) { image.Release(); @@ -1253,7 +1269,9 @@ HRESULT DirectX::SaveToTGAMemory(const Image& image, Blob& blob) } else { - ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE); + hr = ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; } hr = blob.Initialize(sizeof(TGA_HEADER) + slicePitch); @@ -1328,12 +1346,25 @@ HRESULT DirectX::SaveToTGAFile(const Image& image, const wchar_t* szFile) size_t rowPitch, slicePitch; if (convFlags & CONV_FLAGS_888) { - rowPitch = image.width * 3; - slicePitch = image.height * rowPitch; + uint64_t pitch = uint64_t(image.width) * 3u; + uint64_t slice = uint64_t(image.height) * pitch; + +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (pitch > UINT32_MAX || slice > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + + rowPitch = static_cast(pitch); + slicePitch = static_cast(slice); } else { - ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE); + hr = ComputePitch(image.format, image.width, image.height, rowPitch, slicePitch, CP_FLAGS_NONE); + if (FAILED(hr)) + return hr; } if (slicePitch < 65535) @@ -1375,6 +1406,9 @@ HRESULT DirectX::SaveToTGAFile(const Image& image, const wchar_t* szFile) if (bytesWritten != sizeof(TGA_HEADER)) return E_FAIL; + if (rowPitch > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + // Write pixels const uint8_t* pPixels = image.pixels; diff --git a/DirectXTex/DirectXTexUtil.cpp b/DirectXTex/DirectXTexUtil.cpp index 57a936d..29fcc52 100644 --- a/DirectXTex/DirectXTexUtil.cpp +++ b/DirectXTex/DirectXTexUtil.cpp @@ -870,9 +870,12 @@ size_t DirectX::BitsPerColor(DXGI_FORMAT fmt) // based on DXGI format, width, and height //------------------------------------------------------------------------------------- _Use_decl_annotations_ -void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, +HRESULT DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, size_t& rowPitch, size_t& slicePitch, DWORD flags) { + uint64_t pitch = 0; + uint64_t slice = 0; + switch (static_cast(fmt)) { case DXGI_FORMAT_BC1_TYPELESS: @@ -887,15 +890,15 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, { size_t nbw = width >> 2; size_t nbh = height >> 2; - rowPitch = std::max(1, nbw * 8); - slicePitch = std::max(1, rowPitch * nbh); + pitch = std::max(1u, uint64_t(nbw) * 8u); + slice = std::max(1u, pitch * uint64_t(nbh)); } else { - size_t nbw = std::max(1, (width + 3) / 4); - size_t nbh = std::max(1, (height + 3) / 4); - rowPitch = nbw * 8; - slicePitch = rowPitch * nbh; + uint64_t nbw = std::max(1u, (uint64_t(width) + 3u) / 4u); + uint64_t nbh = std::max(1u, (uint64_t(height) + 3u) / 4u); + pitch = nbw * 8u; + slice = pitch * nbh; } } break; @@ -921,15 +924,15 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, { size_t nbw = width >> 2; size_t nbh = height >> 2; - rowPitch = std::max(1, nbw * 16); - slicePitch = std::max(1, rowPitch * nbh); + pitch = std::max(1u, uint64_t(nbw) * 16u); + slice = std::max(1u, pitch * uint64_t(nbh)); } else { - size_t nbw = std::max(1, (width + 3) / 4); - size_t nbh = std::max(1, (height + 3) / 4); - rowPitch = nbw * 16; - slicePitch = rowPitch * nbh; + uint64_t nbw = std::max(1u, (uint64_t(width) + 3u) / 4u); + uint64_t nbh = std::max(1u, (uint64_t(height) + 3u) / 4u); + pitch = nbw * 16u; + slice = pitch * nbh; } } break; @@ -938,22 +941,22 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, case DXGI_FORMAT_G8R8_G8B8_UNORM: case DXGI_FORMAT_YUY2: assert(IsPacked(fmt)); - rowPitch = ((width + 1) >> 1) * 4; - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) + 1u) >> 1) * 4u; + slice = pitch * uint64_t(height); break; case DXGI_FORMAT_Y210: case DXGI_FORMAT_Y216: assert(IsPacked(fmt)); - rowPitch = ((width + 1) >> 1) * 8; - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) + 1u) >> 1) * 8u; + slice = pitch * uint64_t(height); break; case DXGI_FORMAT_NV12: case DXGI_FORMAT_420_OPAQUE: assert(IsPlanar(fmt)); - rowPitch = ((width + 1) >> 1) * 2; - slicePitch = rowPitch * (height + ((height + 1) >> 1)); + pitch = ((uint64_t(width) + 1u) >> 1) * 2u; + slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1)); break; case DXGI_FORMAT_P010: @@ -962,39 +965,37 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS: case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT: assert(IsPlanar(fmt)); - rowPitch = ((width + 1) >> 1) * 4; - slicePitch = rowPitch * (height + ((height + 1) >> 1)); + pitch = ((uint64_t(width) + 1u) >> 1) * 4u; + slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1)); break; case DXGI_FORMAT_NV11: assert(IsPlanar(fmt)); - rowPitch = ((width + 3) >> 2) * 4; - slicePitch = rowPitch * height * 2; + pitch = ((uint64_t(width) + 3u) >> 2) * 4u; + slice = pitch * uint64_t(height) * 2u; break; case WIN10_DXGI_FORMAT_P208: assert(IsPlanar(fmt)); - rowPitch = ((width + 1) >> 1) * 2; - slicePitch = rowPitch * height * 2; + pitch = ((uint64_t(width) + 1u) >> 1) * 2u; + slice = pitch * uint64_t(height) * 2u; break; case WIN10_DXGI_FORMAT_V208: assert(IsPlanar(fmt)); - rowPitch = width; - slicePitch = rowPitch * (height + (((height + 1) >> 1) * 2)); + pitch = uint64_t(width); + slice = pitch * (uint64_t(height) + (((uint64_t(height) + 1u) >> 1) * 2u)); break; case WIN10_DXGI_FORMAT_V408: assert(IsPlanar(fmt)); - rowPitch = width; - slicePitch = rowPitch * (height + ((height >> 1) * 4)); + pitch = uint64_t(width); + slice = pitch * (uint64_t(height) + (uint64_t(height >> 1) * 4u)); break; default: - assert(IsValid(fmt)); assert(!IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt)); { - size_t bpp; if (flags & CP_FLAGS_24BPP) @@ -1006,45 +1007,64 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height, else bpp = BitsPerPixel(fmt); + if (!bpp) + return E_INVALIDARG; + if (flags & (CP_FLAGS_LEGACY_DWORD | CP_FLAGS_PARAGRAPH | CP_FLAGS_YMM | CP_FLAGS_ZMM | CP_FLAGS_PAGE4K)) { if (flags & CP_FLAGS_PAGE4K) { - rowPitch = ((width * bpp + 32767) / 32768) * 4096; - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) * bpp + 32767u) / 32768u) * 4096u; + slice = pitch * uint64_t(height); } else if (flags & CP_FLAGS_ZMM) { - rowPitch = ((width * bpp + 511) / 512) * 64; - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) * bpp + 511u) / 512u) * 64u; + slice = pitch * uint64_t(height); } else if (flags & CP_FLAGS_YMM) { - rowPitch = ((width * bpp + 255) / 256) * 32; - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) * bpp + 255u) / 256u) * 32u; + slice = pitch * uint64_t(height); } else if (flags & CP_FLAGS_PARAGRAPH) { - rowPitch = ((width * bpp + 127) / 128) * 16; - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) * bpp + 127u) / 128u) * 16u; + slice = pitch * uint64_t(height); } else // DWORD alignment { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment - rowPitch = ((width * bpp + 31) / 32) * sizeof(uint32_t); - slicePitch = rowPitch * height; + pitch = ((uint64_t(width) * bpp + 31u) / 32u) * sizeof(uint32_t); + slice = pitch * uint64_t(height); } } else { // Default byte alignment - rowPitch = (width * bpp + 7) / 8; - slicePitch = rowPitch * height; + pitch = (uint64_t(width) * bpp + 7u) / 8u; + slice = pitch * uint64_t(height); } } break; } + +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (pitch > UINT32_MAX || slice > UINT32_MAX) + { + rowPitch = slicePitch = 0; + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + } +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + + rowPitch = static_cast(pitch); + slicePitch = static_cast(slice); + + return S_OK; } diff --git a/ScreenGrab/ScreenGrab.cpp b/ScreenGrab/ScreenGrab.cpp index 71099f4..40f4125 100644 --- a/ScreenGrab/ScreenGrab.cpp +++ b/ScreenGrab/ScreenGrab.cpp @@ -434,17 +434,17 @@ namespace //-------------------------------------------------------------------------------------- // Get surface information for a particular format //-------------------------------------------------------------------------------------- - void GetSurfaceInfo( + HRESULT GetSurfaceInfo( _In_ size_t width, _In_ size_t height, _In_ DXGI_FORMAT fmt, _Out_opt_ size_t* outNumBytes, _Out_opt_ size_t* outRowBytes, - _Out_opt_ size_t* outNumRows ) + _Out_opt_ size_t* outNumRows) { - size_t numBytes = 0; - size_t rowBytes = 0; - size_t numRows = 0; + uint64_t numBytes = 0; + uint64_t rowBytes = 0; + uint64_t numRows = 0; bool bc = false; bool packed = false; @@ -458,7 +458,7 @@ namespace case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_SNORM: - bc=true; + bc = true; bpe = 8; break; @@ -505,19 +505,22 @@ namespace planar = true; bpe = 4; break; + + default: + break; } if (bc) { - size_t numBlocksWide = 0; + uint64_t numBlocksWide = 0; if (width > 0) { - numBlocksWide = std::max( 1, (width + 3) / 4 ); + numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u); } - size_t numBlocksHigh = 0; + uint64_t numBlocksHigh = 0; if (height > 0) { - numBlocksHigh = std::max( 1, (height + 3) / 4 ); + numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u); } rowBytes = numBlocksWide * bpe; numRows = numBlocksHigh; @@ -525,42 +528,55 @@ namespace } else if (packed) { - rowBytes = ( ( width + 1 ) >> 1 ) * bpe; - numRows = height; + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numRows = uint64_t(height); numBytes = rowBytes * height; } - else if ( fmt == DXGI_FORMAT_NV11 ) + else if (fmt == DXGI_FORMAT_NV11) { - rowBytes = ( ( width + 3 ) >> 2 ) * 4; - numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u; + numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numBytes = rowBytes * numRows; } else if (planar) { - rowBytes = ( ( width + 1 ) >> 1 ) * bpe; - numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); - numRows = height + ( ( height + 1 ) >> 1 ); + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1); + numRows = height + ((uint64_t(height) + 1u) >> 1); } else { - size_t bpp = BitsPerPixel( fmt ); - rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte - numRows = height; + size_t bpp = BitsPerPixel(fmt); + if (!bpp) + return E_INVALIDARG; + + rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte + numRows = uint64_t(height); numBytes = rowBytes * height; } +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + if (outNumBytes) { - *outNumBytes = numBytes; + *outNumBytes = static_cast(numBytes); } if (outRowBytes) { - *outRowBytes = rowBytes; + *outRowBytes = static_cast(rowBytes); } if (outNumRows) { - *outNumRows = numRows; + *outNumRows = static_cast(numRows); } + + return S_OK; } @@ -845,7 +861,9 @@ HRESULT DirectX::SaveDDSTextureToFile( } size_t rowPitch, slicePitch, rowCount; - GetSurfaceInfo( desc.Width, desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount ); + hr = GetSurfaceInfo( desc.Width, desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount ); + if (FAILED(hr)) + return hr; if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); diff --git a/ScreenGrab/ScreenGrab12.cpp b/ScreenGrab/ScreenGrab12.cpp index 4fed21b..4faffd2 100644 --- a/ScreenGrab/ScreenGrab12.cpp +++ b/ScreenGrab/ScreenGrab12.cpp @@ -325,6 +325,7 @@ namespace case DXGI_FORMAT_P010: case DXGI_FORMAT_P016: + case DXGI_FORMAT_V408: return 24; case DXGI_FORMAT_R8G8_TYPELESS: @@ -343,6 +344,8 @@ namespace case DXGI_FORMAT_B5G5R5A1_UNORM: case DXGI_FORMAT_A8P8: case DXGI_FORMAT_B4G4R4A4_UNORM: + case DXGI_FORMAT_P208: + case DXGI_FORMAT_V208: return 16; case DXGI_FORMAT_NV12: @@ -434,17 +437,17 @@ namespace //-------------------------------------------------------------------------------------- // Get surface information for a particular format //-------------------------------------------------------------------------------------- - void GetSurfaceInfo( + HRESULT GetSurfaceInfo( _In_ size_t width, _In_ size_t height, _In_ DXGI_FORMAT fmt, _Out_opt_ size_t* outNumBytes, _Out_opt_ size_t* outRowBytes, - _Out_opt_ size_t* outNumRows ) + _Out_opt_ size_t* outNumRows) { - size_t numBytes = 0; - size_t rowBytes = 0; - size_t numRows = 0; + uint64_t numBytes = 0; + uint64_t rowBytes = 0; + uint64_t numRows = 0; bool bc = false; bool packed = false; @@ -458,7 +461,7 @@ namespace case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_SNORM: - bc=true; + bc = true; bpe = 8; break; @@ -496,6 +499,7 @@ namespace case DXGI_FORMAT_NV12: case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_P208: planar = true; bpe = 2; break; @@ -505,19 +509,22 @@ namespace planar = true; bpe = 4; break; + + default: + break; } if (bc) { - size_t numBlocksWide = 0; + uint64_t numBlocksWide = 0; if (width > 0) { - numBlocksWide = std::max( 1, (width + 3) / 4 ); + numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u); } - size_t numBlocksHigh = 0; + uint64_t numBlocksHigh = 0; if (height > 0) { - numBlocksHigh = std::max( 1, (height + 3) / 4 ); + numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u); } rowBytes = numBlocksWide * bpe; numRows = numBlocksHigh; @@ -525,42 +532,55 @@ namespace } else if (packed) { - rowBytes = ( ( width + 1 ) >> 1 ) * bpe; - numRows = height; + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numRows = uint64_t(height); numBytes = rowBytes * height; } - else if ( fmt == DXGI_FORMAT_NV11 ) + else if (fmt == DXGI_FORMAT_NV11) { - rowBytes = ( ( width + 3 ) >> 2 ) * 4; - numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u; + numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data numBytes = rowBytes * numRows; } else if (planar) { - rowBytes = ( ( width + 1 ) >> 1 ) * bpe; - numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 ); - numRows = height + ( ( height + 1 ) >> 1 ); + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1); + numRows = height + ((uint64_t(height) + 1u) >> 1); } else { - size_t bpp = BitsPerPixel( fmt ); - rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte - numRows = height; + size_t bpp = BitsPerPixel(fmt); + if (!bpp) + return E_INVALIDARG; + + rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte + numRows = uint64_t(height); numBytes = rowBytes * height; } +#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); +#else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); +#endif + if (outNumBytes) { - *outNumBytes = numBytes; + *outNumBytes = static_cast(numBytes); } if (outRowBytes) { - *outRowBytes = rowBytes; + *outRowBytes = static_cast(rowBytes); } if (outNumRows) { - *outNumRows = numRows; + *outNumRows = static_cast(numRows); } + + return S_OK; } @@ -934,7 +954,9 @@ HRESULT DirectX::SaveDDSTextureToFile( } size_t rowPitch, slicePitch, rowCount; - GetSurfaceInfo(static_cast(desc.Width), desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount); + hr = GetSurfaceInfo(static_cast(desc.Width), desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount); + if (FAILED(hr)) + return hr; if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);