https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7f4708479dd73dad32838b2329bb7215ea897433

commit 7f4708479dd73dad32838b2329bb7215ea897433
Author:     Doug Lyons <dougly...@douglyons.com>
AuthorDate: Fri Feb 7 08:12:32 2025 -0600
Commit:     GitHub <nore...@github.com>
CommitDate: Fri Feb 7 23:12:32 2025 +0900

    [USER32][LIBPNG] Support PNG/Vista icons (#7704)
    
    Add PNG (NT6/Vista+) support.
    JIRA issue: CORE-18385
    - Change libpng to add IMPORTLIB libpng.spec
      to allow linking to it in USER32.
    - Add code into mostly cursoricon.c to support
      PNG icons.
---
 dll/3rdparty/libpng/CMakeLists.txt       |   5 +-
 dll/3rdparty/libpng/libpng.spec          | 246 +++++++++++++++++++++
 win32ss/user/user32/CMakeLists.txt       |   7 +-
 win32ss/user/user32/windows/cursoricon.c | 367 ++++++++++++++++++++++++++-----
 4 files changed, 565 insertions(+), 60 deletions(-)

diff --git a/dll/3rdparty/libpng/CMakeLists.txt 
b/dll/3rdparty/libpng/CMakeLists.txt
index e7599539562..1c304b7b446 100644
--- a/dll/3rdparty/libpng/CMakeLists.txt
+++ b/dll/3rdparty/libpng/CMakeLists.txt
@@ -27,7 +27,10 @@ list(APPEND SOURCE
     pngwutil.c
     pngpriv.h)
 
-add_library(libpng MODULE ${SOURCE})
+spec2def(libpng.dll libpng.spec ADD_IMPORTLIB)
+
+add_library(libpng MODULE ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/libpng.def)
+
 set_module_type(libpng win32dll)
 target_link_libraries(libpng zlib)
 add_importlibs(libpng msvcrt kernel32 ntdll)
diff --git a/dll/3rdparty/libpng/libpng.spec b/dll/3rdparty/libpng/libpng.spec
new file mode 100644
index 00000000000..f35705c3e9f
--- /dev/null
+++ b/dll/3rdparty/libpng/libpng.spec
@@ -0,0 +1,246 @@
+@ cdecl png_access_version_number()
+@ cdecl png_benign_error(ptr str)
+@ cdecl png_build_grayscale_palette(ptr ptr)
+@ cdecl png_calloc(ptr long)
+@ cdecl png_chunk_benign_error(ptr str)
+@ cdecl png_chunk_error(ptr str)
+@ cdecl png_chunk_warning(ptr str)
+@ cdecl png_convert_from_struct_tm(ptr ptr)
+@ cdecl png_convert_from_time_t(ptr long)
+@ cdecl png_convert_to_rfc1123(ptr ptr)
+@ cdecl png_convert_to_rfc1123_buffer(ptr ptr)
+@ cdecl png_create_info_struct(ptr)
+@ cdecl png_create_read_struct(ptr ptr ptr ptr)
+@ cdecl png_create_read_struct_2(ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_create_write_struct(ptr ptr ptr ptr)
+@ cdecl png_create_write_struct_2(ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_data_freer(ptr ptr long long)
+@ cdecl png_destroy_info_struct(ptr ptr)
+@ cdecl png_destroy_read_struct(ptr ptr ptr)
+@ cdecl png_destroy_write_struct(ptr ptr ptr)
+@ cdecl png_error(ptr str)
+@ cdecl png_free(ptr ptr)
+@ cdecl png_free_data(ptr ptr long long)
+@ cdecl png_free_default(ptr ptr)
+@ cdecl png_get_IHDR(ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_PLTE(ptr ptr ptr ptr)
+@ cdecl png_get_bKGD(ptr ptr ptr)
+@ cdecl png_get_bit_depth(ptr ptr)
+@ cdecl png_get_cHRM(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_cHRM_XYZ(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_cHRM_XYZ_fixed(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_cHRM_fixed(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_channels(ptr ptr)
+@ cdecl png_get_chunk_cache_max(ptr)
+@ cdecl png_get_chunk_malloc_max(ptr)
+@ cdecl png_get_color_type(ptr ptr)
+@ cdecl png_get_compression_buffer_size(ptr)
+@ cdecl png_get_compression_type(ptr ptr)
+@ cdecl png_get_copyright(ptr)
+@ cdecl png_get_current_pass_number(ptr)
+@ cdecl png_get_current_row_number(ptr)
+@ cdecl png_get_eXIf(ptr ptr ptr)
+@ cdecl png_get_eXIf_1(ptr ptr ptr ptr)
+@ cdecl png_get_error_ptr(ptr)
+@ cdecl png_get_filter_type(ptr ptr)
+@ cdecl png_get_gAMA(ptr ptr ptr)
+@ cdecl png_get_gAMA_fixed(ptr ptr ptr)
+@ cdecl png_get_hIST(ptr ptr ptr)
+@ cdecl png_get_header_ver(ptr)
+@ cdecl png_get_header_version(ptr)
+@ cdecl png_get_iCCP(ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_image_height(ptr ptr)
+@ cdecl png_get_image_width(ptr ptr)
+@ cdecl png_get_int_32(ptr)
+@ cdecl png_get_interlace_type(ptr ptr)
+@ cdecl png_get_io_chunk_type(ptr)
+@ cdecl png_get_io_ptr(ptr)
+@ cdecl png_get_io_state(ptr)
+@ cdecl png_get_libpng_ver(ptr)
+@ cdecl png_get_mem_ptr(ptr)
+@ cdecl png_get_oFFs(ptr ptr ptr ptr ptr)
+@ cdecl png_get_pCAL(ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ cdecl png_get_pHYs(ptr ptr ptr ptr ptr)
+@ cdecl png_get_pHYs_dpi(ptr ptr ptr ptr ptr)
+@ cdecl png_get_palette_max(ptr ptr)
+@ cdecl png_get_pixel_aspect_ratio(ptr ptr)
+@ cdecl png_get_pixel_aspect_ratio_fixed(ptr ptr)
+@ cdecl png_get_pixels_per_inch(ptr ptr)
+@ cdecl png_get_pixels_per_meter(ptr ptr)
+@ cdecl png_get_progressive_ptr(ptr)
+@ cdecl png_get_rgb_to_gray_status(ptr)
+@ cdecl png_get_rowbytes(ptr ptr)
+@ cdecl png_get_rows(ptr ptr)
+@ cdecl png_get_sBIT(ptr ptr ptr)
+@ cdecl png_get_sCAL(ptr ptr ptr ptr ptr)
+@ cdecl png_get_sCAL_fixed(ptr ptr ptr ptr ptr)
+@ cdecl png_get_sCAL_s(ptr ptr ptr ptr ptr)
+@ cdecl png_get_sPLT(ptr ptr ptr)
+@ cdecl png_get_sRGB(ptr ptr ptr)
+@ cdecl png_get_signature(ptr ptr)
+@ cdecl png_get_tIME(ptr ptr ptr)
+@ cdecl png_get_tRNS(ptr ptr ptr ptr ptr)
+@ cdecl png_get_text(ptr ptr ptr ptr)
+@ cdecl png_get_uint_16(ptr)
+@ cdecl png_get_uint_31(ptr ptr)
+@ cdecl png_get_uint_32(ptr)
+@ cdecl png_get_unknown_chunks(ptr ptr ptr)
+@ cdecl png_get_user_chunk_ptr(ptr)
+@ cdecl png_get_user_height_max(ptr)
+@ cdecl png_get_user_transform_ptr(ptr)
+@ cdecl png_get_user_width_max(ptr)
+@ cdecl png_get_valid(ptr ptr long)
+@ cdecl png_get_x_offset_inches(ptr ptr)
+@ cdecl png_get_x_offset_inches_fixed(ptr ptr ptr ptr ptr)
+@ cdecl png_get_x_offset_microns(ptr ptr)
+@ cdecl png_get_x_offset_pixels(ptr ptr)
+@ cdecl png_get_x_pixels_per_inch(ptr ptr)
+@ cdecl png_get_x_pixels_per_meter(ptr ptr)
+@ cdecl png_get_y_offset_inches(ptr ptr)
+@ cdecl png_get_y_offset_inches_fixed(ptr ptr)
+@ cdecl png_get_y_offset_microns(ptr ptr)
+@ cdecl png_get_y_offset_pixels(ptr ptr)
+@ cdecl png_get_y_pixels_per_inch(ptr ptr)
+@ cdecl png_get_y_pixels_per_meter(ptr ptr)
+@ cdecl png_handle_as_unknown(ptr str)
+@ cdecl png_image_begin_read_from_file(ptr str)
+@ cdecl png_image_begin_read_from_memory(ptr ptr long)
+@ cdecl png_image_begin_read_from_stdio(ptr ptr)
+@ cdecl png_image_finish_read(ptr ptr ptr long ptr)
+@ cdecl png_image_free(ptr)
+@ cdecl png_image_write_to_file(ptr str long ptr long ptr)
+@ cdecl png_image_write_to_memory(ptr ptr ptr long ptr long ptr)
+@ cdecl png_image_write_to_stdio(ptr ptr long ptr long ptr)
+@ cdecl png_info_init_3(ptr long)
+@ cdecl png_init_io(ptr ptr)
+@ cdecl png_longjmp(ptr long)
+@ cdecl png_malloc(ptr long)
+@ cdecl png_malloc_default(ptr long)
+@ cdecl png_malloc_warn(ptr long)
+@ cdecl png_permit_mng_features(ptr long)
+@ cdecl png_process_data(ptr ptr ptr long)
+@ cdecl png_process_data_pause(ptr long)
+@ cdecl png_process_data_skip(ptr)
+@ cdecl png_progressive_combine_row(ptr ptr ptr)
+@ cdecl png_read_end(ptr ptr)
+@ cdecl png_read_image(ptr ptr)
+@ cdecl png_read_info(ptr ptr)
+@ cdecl png_read_png(ptr ptr ptr ptr)
+@ cdecl png_read_row(ptr ptr ptr)
+@ cdecl png_read_rows(ptr ptr ptr long)
+@ cdecl png_read_update_info(ptr ptr)
+@ cdecl png_reset_zstream(ptr)
+@ cdecl png_save_int_32(ptr long)
+@ cdecl png_save_uint_16(ptr long)
+@ cdecl png_save_uint_32(ptr long)
+@ cdecl png_set_IHDR(ptr ptr long long long long long long long)
+@ cdecl png_set_PLTE(ptr ptr ptr long)
+@ cdecl png_set_add_alpha(ptr long long)
+@ cdecl png_set_alpha_mode(ptr long double)
+@ cdecl png_set_alpha_mode_fixed(ptr long long)
+@ cdecl png_set_bKGD(ptr ptr ptr)
+@ cdecl png_set_background(ptr ptr long long double)
+@ cdecl png_set_background_fixed(ptr ptr long long long)
+@ cdecl png_set_benign_errors(ptr long)
+@ cdecl png_set_bgr(ptr)
+@ cdecl png_set_cHRM(ptr ptr double double double double double double double 
double)
+@ cdecl png_set_cHRM_XYZ(ptr ptr double double double double double double 
double double double double)
+@ cdecl png_set_cHRM_XYZ_fixed(ptr ptr long long long long long long long long 
long)
+@ cdecl png_set_cHRM_fixed(ptr ptr long long long long long long long long)
+@ cdecl png_set_check_for_invalid_index(ptr long)
+@ cdecl png_set_chunk_cache_max(ptr long)
+@ cdecl png_set_chunk_malloc_max(ptr long)
+@ cdecl png_set_compression_buffer_size(ptr long)
+@ cdecl png_set_compression_level(ptr long)
+@ cdecl png_set_compression_mem_level(ptr long)
+@ cdecl png_set_compression_method(ptr long)
+@ cdecl png_set_compression_strategy(ptr long)
+@ cdecl png_set_compression_window_bits(ptr long)
+@ cdecl png_set_crc_action(ptr long long)
+@ cdecl png_set_eXIf(ptr ptr ptr)
+@ cdecl png_set_eXIf_1(ptr ptr long ptr)
+@ cdecl png_set_error_fn(ptr ptr ptr ptr)
+@ cdecl png_set_expand(ptr)
+@ cdecl png_set_expand_16(ptr)
+@ cdecl png_set_expand_gray_1_2_4_to_8(ptr)
+@ cdecl png_set_filler(ptr long long)
+@ cdecl png_set_filter(ptr long long)
+@ cdecl png_set_filter_heuristics(ptr long long ptr ptr)
+@ cdecl png_set_filter_heuristics_fixed(ptr long long ptr ptr)
+@ cdecl png_set_flush(ptr long)
+@ cdecl png_set_gAMA(ptr ptr double)
+@ cdecl png_set_gAMA_fixed(ptr ptr long)
+@ cdecl png_set_gamma(ptr long long)
+@ cdecl png_set_gamma_fixed(ptr long long)
+@ cdecl png_set_gray_to_rgb(ptr)
+@ cdecl png_set_hIST(ptr ptr ptr)
+@ cdecl png_set_iCCP(ptr ptr str long ptr long)
+@ cdecl png_set_interlace_handling(ptr)
+@ cdecl png_set_invalid(ptr ptr long)
+@ cdecl png_set_invert_alpha(ptr)
+@ cdecl png_set_invert_mono(ptr)
+@ cdecl png_set_keep_unknown_chunks(ptr long str long)
+@ cdecl png_set_longjmp_fn(ptr ptr long)
+@ cdecl png_set_mem_fn(ptr ptr ptr ptr)
+@ cdecl png_set_oFFs(ptr ptr long long long)
+@ cdecl png_set_option(ptr long long)
+@ cdecl png_set_pCAL(ptr ptr str long long long long str ptr)
+@ cdecl png_set_pHYs(ptr ptr long long long)
+@ cdecl png_set_packing(ptr)
+@ cdecl png_set_packswap(ptr)
+@ cdecl png_set_palette_to_rgb(ptr)
+@ cdecl png_set_progressive_read_fn(ptr ptr ptr ptr ptr)
+@ cdecl png_set_quantize(ptr ptr long long ptr long)
+@ cdecl png_set_read_fn(ptr ptr ptr)
+@ cdecl png_set_read_status_fn(ptr ptr)
+@ cdecl png_set_read_user_chunk_fn(ptr ptr ptr)
+@ cdecl png_set_read_user_transform_fn(ptr ptr)
+@ cdecl png_set_rgb_to_gray(ptr long double double)
+@ cdecl png_set_rgb_to_gray_fixed(ptr long long long)
+@ cdecl png_set_rows(ptr ptr ptr)
+@ cdecl png_set_sBIT(ptr ptr ptr)
+@ cdecl png_set_sCAL(ptr ptr long double double)
+@ cdecl png_set_sCAL_fixed(ptr ptr long long long)
+@ cdecl png_set_sCAL_s(ptr ptr long str str)
+@ cdecl png_set_sPLT(ptr ptr ptr long)
+@ cdecl png_set_sRGB(ptr ptr long)
+@ cdecl png_set_sRGB_gAMA_and_cHRM(ptr ptr long)
+@ cdecl png_set_scale_16(ptr)
+@ cdecl png_set_shift(ptr ptr)
+@ cdecl png_set_sig_bytes(ptr long)
+@ cdecl png_set_strip_16(ptr)
+@ cdecl png_set_strip_alpha(ptr)
+@ cdecl png_set_swap(ptr)
+@ cdecl png_set_swap_alpha(ptr)
+@ cdecl png_set_tIME(ptr ptr ptr)
+@ cdecl png_set_tRNS(ptr ptr str long ptr)
+@ cdecl png_set_tRNS_to_alpha(ptr)
+@ cdecl png_set_text(ptr ptr ptr long)
+@ cdecl png_set_text_compression_level(ptr long)
+@ cdecl png_set_text_compression_mem_level(ptr long)
+@ cdecl png_set_text_compression_method(ptr long)
+@ cdecl png_set_text_compression_strategy(ptr long)
+@ cdecl png_set_text_compression_window_bits(ptr long)
+@ cdecl png_set_unknown_chunk_location(ptr ptr long long)
+@ cdecl png_set_unknown_chunks(ptr ptr ptr long)
+@ cdecl png_set_user_limits(ptr long long)
+@ cdecl png_set_user_transform_info(ptr ptr long long)
+@ cdecl png_set_write_fn(ptr ptr ptr ptr)
+@ cdecl png_set_write_status_fn(ptr ptr)
+@ cdecl png_set_write_user_transform_fn(ptr ptr)
+@ cdecl png_sig_cmp(ptr long long)
+@ cdecl png_start_read_image(ptr)
+@ cdecl png_warning(ptr str)
+@ cdecl png_write_chunk(ptr ptr ptr long)
+@ cdecl png_write_chunk_data(ptr ptr long)
+@ cdecl png_write_chunk_end(ptr)
+@ cdecl png_write_chunk_start(ptr ptr long)
+@ cdecl png_write_end(ptr ptr)
+@ cdecl png_write_flush(ptr)
+@ cdecl png_write_image(ptr ptr)
+@ cdecl png_write_info(ptr ptr)
+@ cdecl png_write_info_before_PLTE(ptr ptr)
+@ cdecl png_write_png(ptr ptr ptr ptr)
+@ cdecl png_write_row(ptr ptr)
+@ cdecl png_write_rows(ptr ptr long)
+@ cdecl png_write_sig(ptr)
diff --git a/win32ss/user/user32/CMakeLists.txt 
b/win32ss/user/user32/CMakeLists.txt
index ca2f2a143e2..b7cdfe3aa4d 100644
--- a/win32ss/user/user32/CMakeLists.txt
+++ b/win32ss/user/user32/CMakeLists.txt
@@ -5,7 +5,8 @@ include_directories(
     ${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys
     include
     ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine
-    ${REACTOS_SOURCE_DIR}/win32ss/include)
+    ${REACTOS_SOURCE_DIR}/win32ss/include
+    ${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/libpng)
 
 list(APPEND SOURCE
     controls/appswitch.c
@@ -88,7 +89,7 @@ if(MSVC AND (ARCH STREQUAL "i386"))
     target_sources(user32 PRIVATE $<TARGET_OBJECTS:ftol2_sse>)
 endif()
 
-add_delay_importlibs(user32 usp10)
-add_importlibs(user32 gdi32 advapi32 kernel32 ntdll)
+add_delay_importlibs(user32 usp10 libpng)
+add_importlibs(user32 gdi32 advapi32 msvcrt kernel32 ntdll)
 add_pch(user32 include/user32.h SOURCE)
 add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all)
diff --git a/win32ss/user/user32/windows/cursoricon.c 
b/win32ss/user/user32/windows/cursoricon.c
index b1d8bc7e69a..f06a1b9d540 100644
--- a/win32ss/user/user32/windows/cursoricon.c
+++ b/win32ss/user/user32/windows/cursoricon.c
@@ -1,17 +1,244 @@
 /*
- * PROJECT:         ReactOS user32.dll
- * COPYRIGHT:       GPL - See COPYING in the top level directory
- * FILE:            win32ss/user/user32/windows/cursoricon.c
- * PURPOSE:         cursor and icons implementation
- * PROGRAMMER:      Jérôme Gardou (jerome.gar...@reactos.org)
+ * PROJECT:     ReactOS user32.dll
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     cursor and icons implementation
+ * COPYRIGHT:   Copyright Jérôme Gardou (jerome.gar...@reactos.org)
+ *              Copyright 2022-2025 Doug Lyons (dougly...@douglyons.com)
+ *              Copyright 2025 Katayama Hirofumi MZ 
(katayama.hirofumi...@gmail.com)
  */
 
 #include <user32.h>
+#include "png.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
 WINE_DECLARE_DEBUG_CHANNEL(icon);
 //WINE_DECLARE_DEBUG_CHANNEL(resource);
 
+#include <pshpack1.h>
+typedef struct {
+    BYTE bWidth;
+    BYTE bHeight;
+    BYTE bColorCount;
+    BYTE bReserved;
+    union
+    {
+        WORD wPlanes; /* For icons */
+        WORD xHotspot; /* For cursors */
+    };
+    union
+    {
+        WORD wBitCount; /* For icons */
+        WORD yHotspot; /* For cursors */
+    };
+    DWORD dwDIBSize;
+    DWORD dwDIBOffset;
+} CURSORICONFILEDIRENTRY;
+
+typedef struct
+{
+    WORD idReserved;
+    WORD idType;
+    WORD idCount;
+    CURSORICONFILEDIRENTRY idEntries[1];
+} CURSORICONFILEDIR;
+#include <poppack.h>
+
+#define PNG_CHECK_SIG_SIZE 8 /* Check signature size */
+
+/* libpng helpers */
+typedef struct {
+    png_bytep buffer;
+    size_t bufSize;
+    size_t currentPos;
+} PNG_READER_STATE;
+
+/* This function will be used for reading png data from memory */
+static VOID
+ReadMemoryPng(
+    _Inout_ png_structp png_ptr,
+    _Out_ png_bytep data,
+    _In_ size_t length)
+{
+    PNG_READER_STATE *state = png_get_io_ptr(png_ptr);
+    if ((state->currentPos + length) > state->bufSize)
+    {
+        ERR("png read error\n");
+        png_error(png_ptr, "read error in ReadMemoryPng");
+        return;
+    }
+    RtlCopyMemory(data, state->buffer + state->currentPos, length);
+    state->currentPos += length;
+}
+
+static int get_dib_image_size(int width, int height, int depth);
+
+/* Convert PNG raw data to BMP icon data */
+static LPBYTE
+CURSORICON_ConvertPngToBmpIcon(
+    _In_ LPBYTE pngBits,
+    _In_ DWORD fileSize,
+    _Out_ PDWORD pBmpIconSize)
+{
+    if (!pngBits || fileSize < PNG_CHECK_SIG_SIZE || !png_check_sig(pngBits, 
PNG_CHECK_SIG_SIZE))
+        return NULL;
+
+    TRACE("pngBits %p fileSize %d\n", pngBits, fileSize);
+
+    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, 
NULL, NULL);
+    if (!png_ptr)
+    {
+        ERR("png_create_read_struct error\n");
+        return NULL;
+    }
+
+    png_infop info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr)
+    {
+        ERR("png_create_info_struct error\n");
+        png_destroy_read_struct(&png_ptr, NULL, NULL);
+        return NULL;
+    }
+
+    /* Set our own read_function */
+    PNG_READER_STATE readerState = { pngBits, fileSize, PNG_CHECK_SIG_SIZE };
+    png_set_read_fn(png_ptr, &readerState, ReadMemoryPng);
+    png_set_sig_bytes(png_ptr, PNG_CHECK_SIG_SIZE);
+
+    /* Read png info */
+    png_read_info(png_ptr, info_ptr);
+
+    /* Add translation of some PNG formats and update info */
+    int colorType = png_get_color_type(png_ptr, info_ptr);
+    if (colorType == PNG_COLOR_TYPE_PALETTE)
+        png_set_palette_to_rgb(png_ptr);
+    else if (colorType == PNG_COLOR_TYPE_GRAY || colorType == 
PNG_COLOR_TYPE_GRAY_ALPHA)
+        png_set_gray_to_rgb(png_ptr);
+    png_set_scale_16(png_ptr); /* Convert 16-bit channels to 8-bit */
+    png_read_update_info(png_ptr, info_ptr);
+
+    /* Get updated png info */
+    png_uint_32 width, height;
+    int bitDepth;
+    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, 
NULL, NULL, NULL);
+    TRACE("width %d, height %d, bitDepth %d, colorType %d\n",
+          width, height, bitDepth, colorType);
+
+    int channels = png_get_channels(png_ptr, info_ptr);
+    int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+    int imageSize = height * rowbytes;
+    TRACE("rowbytes %d, channels %d, imageSize %d\n", rowbytes, channels, 
imageSize);
+
+    /* Allocate rows data */
+    png_bytepp rows = png_malloc(png_ptr, sizeof(png_bytep) * height);
+    if (!rows)
+    {
+        ERR("png_malloc failed\n");
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        return NULL;
+    }
+
+    for (int i = 0; i < (int)height; i++)
+    {
+        rows[i] = png_malloc(png_ptr, rowbytes);
+        if (!rows[i])
+        {
+            ERR("png_malloc failed\n");
+
+            /* Clean up */
+            while (--i >= 0)
+                png_free(png_ptr, rows[i]);
+            png_free(png_ptr, rows);
+            png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+            return NULL;
+        }
+    }
+
+    /* Read png image data */
+    png_set_rows(png_ptr, info_ptr, rows);
+    png_read_image(png_ptr, rows);
+    png_read_end(png_ptr, info_ptr);
+
+    /* After reading the image, you can deal with row pointers */
+    LPBYTE imageBytes = HeapAlloc(GetProcessHeap(), 0, imageSize);
+    if (imageBytes)
+    {
+        LPBYTE pb = imageBytes;
+        for (int i = height - 1; i >= 0; i--)
+        {
+            png_bytep row = rows[i];
+            for (int j = 0; j < channels * width; j += channels)
+            {
+                *pb++ = row[j + 2]; /* Red */
+                *pb++ = row[j + 1]; /* Green */
+                *pb++ = row[j + 0]; /* Blue */
+                if (channels == 4)
+                    *pb++ = row[j + 3]; /* Alpha */
+            }
+            pb += (channels * width) % 4;
+        }
+    }
+
+    /* Clean up */
+    for (int i = 0; i < (int)height; i++)
+        png_free(png_ptr, rows[i]);
+    png_free(png_ptr, rows);
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+    if (!imageBytes)
+    {
+        ERR("HeapAlloc failed\n");
+        return NULL;
+    }
+
+    /* BPP (Bits Per Pixel) */
+    WORD bpp = (WORD)(bitDepth * channels);
+
+    /* The byte size of mask bits */
+    DWORD maskSize = get_dib_image_size(width, height, 1);
+
+    /* Build BITMAPINFOHEADER */
+    BITMAPINFOHEADER info = { sizeof(info) };
+    info.biWidth = width;
+    info.biHeight = 2 * height;
+    info.biPlanes = 1;
+    info.biBitCount = bpp;
+    info.biCompression = BI_RGB;
+
+    /* Build CURSORICONFILEDIR */
+    CURSORICONFILEDIR cifd = { 0, 1, 1 };
+    cifd.idEntries[0].bWidth = (BYTE)width;
+    cifd.idEntries[0].bHeight = (BYTE)height;
+    cifd.idEntries[0].bColorCount = 0; /* No color pallete */
+    cifd.idEntries[0].wPlanes = 1; /* Must be 1 */
+    cifd.idEntries[0].wBitCount = bpp;
+    cifd.idEntries[0].dwDIBSize = (DWORD)(sizeof(info) + imageSize + maskSize);
+    cifd.idEntries[0].dwDIBOffset = (DWORD)sizeof(cifd);
+
+    /* Allocate BMP icon data */
+    *pBmpIconSize = (DWORD)(sizeof(cifd) + sizeof(info) + imageSize + 
maskSize);
+    LPBYTE pbBmpIcon = HeapAlloc(GetProcessHeap(), 0, *pBmpIconSize);
+    if (!pbBmpIcon)
+    {
+        ERR("HeapAlloc failed\n");
+        HeapFree(GetProcessHeap(), 0, imageBytes);
+        return NULL;
+    }
+
+    /* Store data to pbBmpIcon */
+    LPBYTE pb = pbBmpIcon;
+    RtlCopyMemory(pb, &cifd, sizeof(cifd));
+    pb += sizeof(cifd);
+    RtlCopyMemory(pb, &info, sizeof(info));
+    pb += sizeof(info);
+    RtlCopyMemory(pb, imageBytes, imageSize);
+    pb += imageSize;
+    RtlFillMemory(pb, maskSize, 0xFF); /* Mask bits for AND operation */
+
+    HeapFree(GetProcessHeap(), 0, imageBytes);
+    return pbBmpIcon;
+}
+
 /* We only use Wide string functions */
 #undef MAKEINTRESOURCE
 #define MAKEINTRESOURCE MAKEINTRESOURCEW
@@ -221,7 +448,7 @@ static int DIB_GetBitmapInfo( const BITMAPINFOHEADER 
*header, LONG *width,
     }
     if (memcmp(&header->biSize, png_sig_pattern, sizeof(png_sig_pattern)) == 0)
     {
-        ERR("Cannot yet display PNG icons\n");
+        TRACE("We have a PNG icon\n");
         /* for PNG format details see https://en.wikipedia.org/wiki/PNG */
     }
     else
@@ -469,29 +696,6 @@ done:
     return alpha;
 }
 
-#include "pshpack1.h"
-
-typedef struct {
-    BYTE bWidth;
-    BYTE bHeight;
-    BYTE bColorCount;
-    BYTE bReserved;
-    WORD xHotspot;
-    WORD yHotspot;
-    DWORD dwDIBSize;
-    DWORD dwDIBOffset;
-} CURSORICONFILEDIRENTRY;
-
-typedef struct
-{
-    WORD                idReserved;
-    WORD                idType;
-    WORD                idCount;
-    CURSORICONFILEDIRENTRY  idEntries[1];
-} CURSORICONFILEDIR;
-
-#include "poppack.h"
-
 const CURSORICONFILEDIRENTRY*
 get_best_icon_file_entry(
     _In_ const CURSORICONFILEDIR* dir,
@@ -1155,6 +1359,14 @@ BITMAP_LoadImageW(
         ResSize = SizeofResource(hinst, hrsrc);
     }
 
+    if (pbmi->bmiHeader.biCompression == BI_BITFIELDS && 
pbmi->bmiHeader.biBitCount == 32)
+    {
+        SIZE_T totalSize = pbmi->bmiHeader.biSize + (3 * sizeof(DWORD)) +
+                           pbmi->bmiHeader.biSizeImage;
+        if (pbmi->bmiHeader.biSizeImage != 0 && totalSize != ResSize)
+            WARN("Possibly bad resource size provided\n");
+    }
+
     /* Fix up values */
     if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == 
-1)
         goto end;
@@ -1385,8 +1597,8 @@ CURSORICON_LoadFromFileW(
 {
     const CURSORICONFILEDIRENTRY *entry;
     const CURSORICONFILEDIR *dir;
-    DWORD filesize = 0;
-    LPBYTE bits;
+    DWORD filesize = 0, BmpIconSize;
+    LPBYTE bits, pbBmpIcon = NULL;
     HANDLE hCurIcon = NULL;
     CURSORDATA cursorData;
 
@@ -1418,15 +1630,37 @@ CURSORICON_LoadFromFileW(
         cursorData.xHotspot = entry->xHotspot;
         cursorData.yHotspot = entry->yHotspot;
     }
-    cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR));
+    cursorData.rt = LOWORD(bIcon ? RT_ICON : RT_CURSOR);
+
+    /* Try to load BMP icon */
+    DWORD dwOffset = entry->dwDIBOffset;
+    if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO 
*)(&bits[dwOffset])))
+    {
+        /* Convert PNG raw data to BMP icon if the icon was PNG icon */
+        LPBYTE pngBits = &bits[entry->dwDIBOffset];
+        pbBmpIcon = CURSORICON_ConvertPngToBmpIcon(pngBits, filesize, 
&BmpIconSize);
+        if (!pbBmpIcon)
+            goto end; /* Not PNG icon or failed */
+
+        /* Find icon entry from BMP icon */
+        dir = (CURSORICONFILEDIR *)pbBmpIcon;
+        entry = &dir->idEntries[0]; /* Only one entry */
+
+        /* A bit of preparation */
+        RtlZeroMemory(&cursorData, sizeof(cursorData));
+        cursorData.rt = LOWORD(bIcon ? RT_ICON : RT_CURSOR);
 
-    /* Do the dance */
-    if(!CURSORICON_GetCursorDataFromBMI(&cursorData, 
(BITMAPINFO*)(&bits[entry->dwDIBOffset])))
+        /* Can we load this BMP icon? */
+        dwOffset = entry->dwDIBOffset;
+        if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO 
*)(&pbBmpIcon[dwOffset])))
         {
-            ERR("Failing File is \n    '%S'.\n", lpszName);
+            ERR("Failing file: '%S'.\n", lpszName);
             goto end;
         }
 
+        TRACE("Processing PNG/Vista icon: '%S'\n", lpszName);
+    }
+
     hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
     if(!hCurIcon)
         goto end;
@@ -1435,21 +1669,16 @@ CURSORICON_LoadFromFileW(
     if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData))
     {
         NtUserDestroyCursor(hCurIcon, TRUE);
-        goto end_error;
+        hCurIcon = NULL;
+        if (cursorData.hbmMask) DeleteObject(cursorData.hbmMask);
+        if (cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
+        if (cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
     }
 
 end:
     UnmapViewOfFile(bits);
+    HeapFree(GetProcessHeap(), 0, pbBmpIcon);
     return hCurIcon;
-
-    /* Clean up */
-end_error:
-    DeleteObject(cursorData.hbmMask);
-    if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
-    if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
-    UnmapViewOfFile(bits);
-
-    return NULL;
 }
 
 static
@@ -1514,7 +1743,7 @@ CURSORICON_LoadImageW(
             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
             return NULL;
         }
-        ustrModule.Length = wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * 
sizeof(WCHAR);
+        ustrModule.Length = (USHORT)wsprintfW(ustrModule.Buffer, fakeNameFmt, 
hinst) * sizeof(WCHAR);
     }
     else if(hinst)
     {
@@ -1545,8 +1774,8 @@ CURSORICON_LoadImageW(
             }
 
             ustrModule.Buffer[ret] = UNICODE_NULL;
-            ustrModule.Length = ret * sizeof(WCHAR);
-            ustrModule.MaximumLength = size * sizeof(WCHAR);
+            ustrModule.Length = (USHORT)(ret * sizeof(WCHAR));
+            ustrModule.MaximumLength = (USHORT)(size * sizeof(WCHAR));
             break;
         }
     }
@@ -2539,9 +2768,17 @@ HICON WINAPI CreateIconFromResourceEx(
     CURSORDATA cursorData;
     HICON hIcon;
     BOOL isAnimated;
+    LPBYTE pbBmpIcon = NULL;
+    DWORD BmpIconSize;
 
     TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, 
dwVersion, cxDesired, cyDesired, uFlags);
 
+    if (!pbIconBits || cbIconBits < 2 * sizeof(DWORD))
+    {
+        ERR("Sanity check failed\n");
+        return NULL;
+    }
+
     if(uFlags & LR_DEFAULTSIZE)
     {
         if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : 
SM_CXCURSOR);
@@ -2551,7 +2788,7 @@ HICON WINAPI CreateIconFromResourceEx(
     ZeroMemory(&cursorData, sizeof(cursorData));
     cursorData.cx = cxDesired;
     cursorData.cy = cyDesired;
-    cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
+    cursorData.rt = LOWORD(fIcon ? RT_ICON : RT_CURSOR);
 
     /* Convert to win32k-ready data */
     if(!memcmp(pbIconBits, "RIFF", 4))
@@ -2622,15 +2859,30 @@ HICON WINAPI CreateIconFromResourceEx(
             pbIconBits = (PBYTE)pt;
         }
 
-        if (!CURSORICON_GetCursorDataFromBMI(&cursorData, 
(BITMAPINFO*)pbIconBits))
+        /* Try to load BMP icon */
+        if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO 
*)pbIconBits))
         {
-            ERR("Couldn't fill the CURSORDATA structure.\n");
-            if (ResHandle)
-                FreeResource(ResHandle);
-            return NULL;
+            /* Convert PNG raw data to BMP icon if the icon was PNG icon */
+            pbBmpIcon = CURSORICON_ConvertPngToBmpIcon(pbIconBits, cbIconBits, 
&BmpIconSize);
+            if (!pbBmpIcon)
+                goto end; /* Not PNG icon or failed */
+
+            /* Find icon entry from BMP icon */
+            CURSORICONFILEDIR *dir = (CURSORICONFILEDIR *)pbBmpIcon;
+            CURSORICONFILEDIRENTRY *entry = &dir->idEntries[0]; /* Only one 
entry */
+
+            /* A bit of preparation */
+            RtlZeroMemory(&cursorData, sizeof(cursorData));
+            cursorData.rt = LOWORD(fIcon ? RT_ICON : RT_CURSOR);
+
+            /* Can we load this BMP icon? */
+            DWORD dwOffset = entry->dwDIBOffset;
+            if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO 
*)&pbBmpIcon[dwOffset]))
+            {
+                ERR("Couldn't get cursor/icon data\n");
+                goto end;
+            }
         }
-        if (ResHandle)
-            FreeResource(ResHandle);
         isAnimated = FALSE;
     }
 
@@ -2651,10 +2903,13 @@ HICON WINAPI CreateIconFromResourceEx(
     if(isAnimated)
         HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
 
+end:
+    HeapFree(GetProcessHeap(), 0, pbBmpIcon);
     return hIcon;
 
     /* Clean up */
 end_error:
+    HeapFree(GetProcessHeap(), 0, pbBmpIcon);
     if(isAnimated)
         HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
     DeleteObject(cursorData.hbmMask);

Reply via email to