From 5cd33b22ca4a60775430743097fa429c13012ca7 Mon Sep 17 00:00:00 2001 From: Rupert Date: Sun, 25 May 2025 23:00:29 +0200 Subject: [PATCH] Add support for OS/2 BA bitmap arrays --- bmp-common.h | 12 ++ bmp-read-icons.c | 353 +++++++++++++++++++++++++++++++++++++++++++ bmp-read-icons.h | 28 ++++ bmp-read-loadimage.c | 5 + bmp-read.c | 183 +++++----------------- bmplib.h | 8 +- meson.build | 4 + 7 files changed, 444 insertions(+), 149 deletions(-) create mode 100644 bmp-read-icons.c create mode 100644 bmp-read-icons.h diff --git a/bmp-common.h b/bmp-common.h index 8866dd9..cb11722 100644 --- a/bmp-common.h +++ b/bmp-common.h @@ -102,6 +102,7 @@ enum ReadState { RS_DIMENSIONS_QUERIED, RS_LOAD_STARTED, RS_LOAD_DONE, + RS_ARRAY, RS_FATAL, }; @@ -111,6 +112,9 @@ struct Bmpread { size_t bytes_read; /* number of bytes we have read from the file */ struct Bmpfile *fh; struct Bmpinfo *ih; + struct Arraylist *arrayimgs; + int narrayimgs; + bool is_arrayimg; unsigned int insanity_limit; int width; int height; @@ -337,6 +341,14 @@ struct Bmpinfo { enum BmpInfoVer version; }; +struct Bmparray { + uint16_t type; + uint32_t size; + uint32_t offsetnext; + uint16_t screenwidth; + uint16_t screenheight; +}; + #define IH_PROFILEDATA_OFFSET (14L + 112L) #define MAX_ICCPROFILE_SIZE (1UL << 20) diff --git a/bmp-read-icons.c b/bmp-read-icons.c new file mode 100644 index 0000000..bf8096b --- /dev/null +++ b/bmp-read-icons.c @@ -0,0 +1,353 @@ +/* bmplib - bmp-read-icons.c + * + * Copyright (c) 2025, Rupert Weber. + * + * This file is part of bmplib. + * bmplib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see + */ + +#include +#include +#include +#include +#include +#include + +#define BMPLIB_LIB + +#include "config.h" +#include "bmplib.h" +#include "logging.h" +#include "bmp-common.h" +#include "bmp-read-icons.h" + + + + +/******************************************************** + * bmpread_array_num + *******************************************************/ + +API int bmpread_array_num(BMPHANDLE h) +{ + BMPREAD rp; + + if (!(rp = cm_read_handle(h))) + return BMP_RESULT_ERROR; + + if (rp->read_state != RS_ARRAY) { + logerr(rp->c.log, "Not a bitmap array"); + return -1; + } + + return rp->narrayimgs; +} + + +/******************************************************** + * bmpread_array_info + *******************************************************/ + +API BMPRESULT bmpread_array_info(BMPHANDLE h, struct BmpArrayInfo *ai, int idx) +{ + BMPREAD rp; + + if (!(rp = cm_read_handle(h))) + return BMP_RESULT_ERROR; + + if (rp->read_state != RS_ARRAY) { + logerr(rp->c.log, "Not a bitmap array"); + return BMP_RESULT_ERROR; + } + + if (idx < 0 || idx >= rp->narrayimgs) { + logerr(rp->c.log, "Invalid array index %d. Max is %d", idx, rp->narrayimgs - 1); + return BMP_RESULT_ERROR; + } + + if (!ai) { + logerr(rp->c.log, "Invalid array info pointer (NULL)"); + return BMP_RESULT_ERROR; + } + + struct Arraylist *img = &rp->arrayimgs[idx]; + BMPREAD imgrp = (BMPREAD)img->handle; + + memset(ai, 0, sizeof *ai); + + ai->type = imgrp->fh->type; + ai->handle = img->handle; + ai->width = imgrp->width; + ai->height = imgrp->height; + if (imgrp->ih->bitcount <= 8) + ai->ncolors = 1 << imgrp->ih->bitcount; + else + ai->ncolors = 0; + ai->screenwidth = img->ah.screenwidth; + ai->screenheight = img->ah.screenheight; + + return BMP_RESULT_OK; +} + + +/******************************************************** + * icon_read_array + *******************************************************/ +static bool s_read_array_header(BMPREAD_R rp, struct Bmparray *ah); +static void s_array_header_from_file_header(struct Bmparray *ah, struct Bmpfile *fh); + +bool icon_read_array(BMPREAD_R rp) +{ + struct Arraylist *imgs = NULL; + struct Bmparray ah = { 0 }; + int n = 0; + const int nmax = 16; + bool invalid = false; + + if (!(imgs = calloc(nmax, sizeof *imgs))) { + logsyserr(rp->c.log, "Allocating bitmap array list"); + rp->lasterr = BMP_ERR_MEMORY; + return false; + } + + s_array_header_from_file_header(&ah, rp->fh); + + while (n < nmax) { + if (ah.type != BMPFILE_BA) + break; + + memcpy(&imgs[n].ah, &ah, sizeof ah); + + imgs[n].handle = bmpread_new(rp->file); + if (imgs[n].handle) { + if (BMP_RESULT_OK == bmpread_load_info(imgs[n].handle)) { + ((BMPREAD)imgs[n].handle)->is_arrayimg = true; + n++; + } else { + bmp_free(imgs[n].handle); + invalid = true; + rp->lasterr = BMP_ERR_HEADER; + } + } else { + invalid = true; + rp->lasterr = BMP_ERR_HEADER; + } + + if (!ah.offsetnext) + break; + +#if ( LONG_MAX <= 0x7fffffffL ) + if (ah.offsetnext > (unsigned long)LONG_MAX) { + logerr(rp->c.log, "Invalid offset to next array image: %lu", (unsigned long)ah.offsetnext); + invalid = true; + rp->lasterr = BMP_ERR_HEADER; + break; + } +#endif + if (fseek(rp->file, ah.offsetnext, SEEK_SET)) { + logsyserr(rp->c.log, "Seeking next array header"); + invalid = true; + rp->lasterr = BMP_ERR_FILEIO; + break; + } + + if (!s_read_array_header(rp, &ah)) { + invalid = true; + break; + } + } + + rp->arrayimgs = imgs; + rp->narrayimgs = n; + + return !invalid; +} + + +/******************************************************** + * s_read_array_header + *******************************************************/ + +static bool s_read_array_header(BMPREAD_R rp, struct Bmparray *ah) +{ + if (read_u16_le(rp->file, &ah->type) && + read_u32_le(rp->file, &ah->size) && + read_u32_le(rp->file, &ah->offsetnext) && + read_u16_le(rp->file, &ah->screenwidth) && + read_u16_le(rp->file, &ah->screenheight)) { + + return true; + } + + if (feof(rp->file)) { + logerr(rp->c.log, "unexpected end-of-file while reading " + "array header"); + rp->lasterr = BMP_ERR_TRUNCATED; + } else { + logsyserr(rp->c.log, "error reading array header"); + rp->lasterr = BMP_ERR_FILEIO; + } + + return false; +} + + +/******************************************************** + * s_array_header_from_file_header + *******************************************************/ + +static void s_array_header_from_file_header(struct Bmparray *ah, struct Bmpfile *fh) +{ + ah->type = fh->type; + ah->size = fh->size; + ah->offsetnext = (uint32_t)fh->reserved2 << 16 | fh->reserved1; + ah->screenwidth = fh->offbits & 0xffff; + ah->screenheight = (fh->offbits >> 16) & 0xffff; +} + + +/******************************************************** + * icon_load_masks + *******************************************************/ + +long icon_load_masks(BMPREAD_R rp) +{ + /* OS/2 icons and pointers contain 1-bit AND and XOR masks, stacked in a single + * image. For monochrome (IC/PT), that's all the image; for color (CI/CP), these are + * followed by a complete color image (including headers), the masks are only used + * for transparency information. + */ + + BMPHANDLE hmono = NULL; + BMPREAD rpmono; + unsigned char *monobuf = NULL; + size_t bufsize; + unsigned bmptype = rp->fh->type; + long posmono = 0, poscolor = 0; + + if (fseek(rp->file, -14, SEEK_CUR)) { + logsyserr(rp->c.log, "Seeking to start of icon/pointer"); + goto abort; + } + + if (-1 == (posmono = ftell(rp->file))) { + logsyserr(rp->c.log, "Saving file position"); + goto abort; + } + + /* first, load monochrome XOR/AND bitmap. We'll use the + * AND bitmap as alpha channel for the color bitmap + */ + + if (!(hmono = bmpread_new(rp->file))) { + logerr(rp->c.log, "Getting handle for monochrome XOR/AND map"); + goto abort; + } + rpmono = cm_read_handle(hmono); + + rpmono->read_state = RS_EXPECT_ICON_MASK; + if (BMP_RESULT_OK != bmpread_load_info(hmono)) { + logerr(rp->c.log, "%s", bmp_errmsg(hmono)); + goto abort; + } + + if (rpmono->fh->type != bmptype) { + logerr(rp->c.log, "File type mismatch. Have 0x%04x, expected 0x%04x", + (unsigned)rpmono->fh->type, bmptype); + } + + if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP) { + if (-1 == (poscolor = ftell(rp->file))) { + logsyserr(rp->c.log, "Saving position of color header"); + goto abort; + } + } + + if (!(rpmono->width > 0 && rpmono->height > 0 && rpmono->width <=512 && rpmono->height <= 512)) { + logerr(rp->c.log, "Invalid icon/pointer dimensions: %dx%d", rpmono->width, rpmono->height); + goto abort; + } + + if (rpmono->ih->bitcount != 1) { + logerr(rp->c.log, "Invalid icon/pointer monochrome bitcount: %d", rpmono->ih->bitcount); + goto abort; + } + + if (rpmono->height & 1) { + logerr(rp->c.log, "Invalid odd icon/pointer height: %d (must be even)", rpmono->height); + goto abort; + } + + int width, height, bitsperchannel, channels; + if (BMP_RESULT_OK != bmpread_dimensions(hmono, &width, &height, &channels, &bitsperchannel, NULL)) { + logerr(rp->c.log, "%s", bmp_errmsg(hmono)); + goto abort; + } + + height /= 2; /* mochrome contains two stacked bitmaps (AND and XOR) */ + + if (channels != 3 || bitsperchannel != 8) { + logerr(rp->c.log, "Unexpected result color depth for monochrome image: " + "%d channels, %d bits/channel", channels, bitsperchannel); + goto abort; + } + + /* store the AND/XOR bitmaps in the main BMPREAD struct */ + + bufsize = bmpread_buffersize(hmono); + if (BMP_RESULT_OK != bmpread_load_image(hmono, &monobuf)) { + logerr(rp->c.log, "%s", bmp_errmsg(hmono)); + goto abort; + } + + if (!(bufsize > 0 && monobuf != NULL)) { + logerr(rp->c.log, "Panic! unkown error while loading monochrome bitmap"); + goto abort; + } + + if (!(rp->icon_mono_and = malloc(width * height))) { + logsyserr(rp->c.log, "Allocating mono AND bitmap"); + goto abort; + } + if (!(rp->icon_mono_xor = malloc(width * height))) { + logsyserr(rp->c.log, "Allocating mono XOR bitmap"); + goto abort; + } + + for (int i = 0; i < width * height; i++) + rp->icon_mono_and[i] = 255 - monobuf[3 * i]; + + for (int i = 0; i < width * height; i++) + rp->icon_mono_xor[i] = monobuf[3 * (width * height + i)]; + + rp->icon_mono_width = width; + rp->icon_mono_height = height; + free(monobuf); + monobuf = NULL; + bmp_free(hmono); + hmono = NULL; + + if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP) + return poscolor; + + return posmono; + +abort: + if (hmono) + bmp_free(hmono); + if (monobuf) + free(monobuf); + return -1; +} diff --git a/bmp-read-icons.h b/bmp-read-icons.h new file mode 100644 index 0000000..dcb343a --- /dev/null +++ b/bmp-read-icons.h @@ -0,0 +1,28 @@ +/* bmplib - bmp-read-icons.h + * + * Copyright (c) 2025, Rupert Weber. + * + * This file is part of bmplib. + * bmplib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + * If not, see + */ + + +struct Arraylist { + struct Bmparray ah; + BMPHANDLE handle; +}; + +long icon_load_masks(BMPREAD_R rp); +bool icon_read_array(BMPREAD_R rp); diff --git a/bmp-read-loadimage.c b/bmp-read-loadimage.c index 720579b..6a97a7f 100644 --- a/bmp-read-loadimage.c +++ b/bmp-read-loadimage.c @@ -130,6 +130,11 @@ static BMPRESULT s_load_image_or_line(BMPREAD_R rp, unsigned char **restrict buf return BMP_RESULT_ERROR; } + if (rp->read_state >= RS_ARRAY) { + logerr(rp->c.log, "Invalid operation on bitmap array"); + return BMP_RESULT_ERROR; + } + if (rp->read_state >= RS_LOAD_DONE) { logerr(rp->c.log, "Cannot load image more than once!"); return BMP_RESULT_ERROR; diff --git a/bmp-read.c b/bmp-read.c index 764e9c9..9e19881 100644 --- a/bmp-read.c +++ b/bmp-read.c @@ -32,6 +32,7 @@ #include "bmplib.h" #include "logging.h" #include "bmp-common.h" +#include "bmp-read-icons.h" #include "bmp-read.h" @@ -92,7 +93,6 @@ abort: *****************************************************************************/ static bool s_read_file_header(BMPREAD_R rp); static bool s_read_info_header(BMPREAD_R rp); -static long s_load_icon_masks(BMPREAD_R rp); static bool s_is_bmptype_supported(BMPREAD_R rp); static struct Palette* s_read_palette(BMPREAD_R rp); static bool s_read_colormasks(BMPREAD_R rp); @@ -123,7 +123,7 @@ API BMPRESULT bmpread_load_info(BMPHANDLE h) case BMPFILE_IC: case BMPFILE_PT: if (rp->read_state < RS_EXPECT_ICON_MASK) { - pos = s_load_icon_masks(rp); + pos = icon_load_masks(rp); if (pos < 0) goto abort; @@ -151,9 +151,18 @@ API BMPRESULT bmpread_load_info(BMPHANDLE h) break; case BMPFILE_BA: - logerr(rp->c.log, "OS/2 Bitmap arrays not supported"); - rp->lasterr = BMP_ERR_UNSUPPORTED; - goto abort; + if (rp->is_arrayimg) { + logerr(rp->c.log, "Invalid nested bitmap array"); + goto abort; + } + if (!icon_read_array(rp)) { + logerr(rp->c.log, "Failed to read icon array index"); + goto abort; + } + + rp->read_state = RS_ARRAY; + return BMP_RESULT_ARRAY; + default: logerr(rp->c.log, "Unkown BMP type 0x%04x\n", (unsigned int) rp->fh->type); @@ -262,141 +271,6 @@ abort: } -/***************************************************************************** - * s_load_icon_masks - *****************************************************************************/ - -static long s_load_icon_masks(BMPREAD_R rp) -{ - /* OS/2 icons and pointers contain 1-bit AND and XOR masks, stacked in a single - * image. For monochrome (IC/PT), that's all the image; for color (CI/CP), these are - * followed by a complete color image (including headers), the masks are only used - * for transparency information. - */ - - BMPHANDLE hmono = NULL; - BMPREAD rpmono; - unsigned char *monobuf = NULL; - size_t bufsize; - unsigned bmptype = rp->fh->type; - long posmono = 0, poscolor = 0; - - if (fseek(rp->file, -14, SEEK_CUR)) { - logsyserr(rp->c.log, "Seeking to start of icon/pointer"); - goto abort; - } - - if (-1 == (posmono = ftell(rp->file))) { - logsyserr(rp->c.log, "Saving file position"); - goto abort; - } - - /* first, load monochrome XOR/AND bitmap. We'll use the - * AND bitmap as alpha channel - */ - - if (!(hmono = bmpread_new(rp->file))) { - logerr(rp->c.log, "Getting handle for monochrome XOR/AND map"); - goto abort; - } - rpmono = cm_read_handle(hmono); - - rpmono->read_state = RS_EXPECT_ICON_MASK; - if (BMP_RESULT_OK != bmpread_load_info(hmono)) { - logerr(rp->c.log, "%s", bmp_errmsg(hmono)); - goto abort; - } - - if (rpmono->fh->type != bmptype) { - logerr(rp->c.log, "File type mismatch. Have 0x%04x, expected 0x%04x", - (unsigned)rpmono->fh->type, bmptype); - } - - if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP) { - if (-1 == (poscolor = ftell(rp->file))) { - logsyserr(rp->c.log, "Saving position of color header"); - goto abort; - } - } - - if (!(rpmono->width > 0 && rpmono->height > 0 && rpmono->width <=512 && rpmono->height <= 512)) { - logerr(rp->c.log, "Invalid icon/pointer dimensions: %dx%d", rpmono->width, rpmono->height); - goto abort; - } - - if (rpmono->ih->bitcount != 1) { - logerr(rp->c.log, "Invalid icon/pointer monochrome bitcount: %d", rpmono->ih->bitcount); - goto abort; - } - - if (rpmono->height & 1) { - logerr(rp->c.log, "Invalid odd icon/pointer height: %d (must be even)", rpmono->height); - goto abort; - } - - int width, height, bitsperchannel, channels; - if (BMP_RESULT_OK != bmpread_dimensions(hmono, &width, &height, &channels, &bitsperchannel, NULL)) { - logerr(rp->c.log, "%s", bmp_errmsg(hmono)); - goto abort; - } - - height /= 2; /* mochrome contains two stacked bitmaps (AND and XOR) */ - - if (channels != 3 || bitsperchannel != 8) { - logerr(rp->c.log, "Unexpected result color depth for monochrome image: %d channels, %d bits/channel", - channels, bitsperchannel); - goto abort; - } - - /* store the AND/XOR bitmaps in the main BMPREAD struct */ - - bufsize = bmpread_buffersize(hmono); - if (BMP_RESULT_OK != bmpread_load_image(hmono, &monobuf)) { - logerr(rp->c.log, "%s", bmp_errmsg(hmono)); - goto abort; - } - - if (!(bufsize > 0 && monobuf != NULL)) { - logerr(rp->c.log, "Panic! unkown error while loading monochrome bitmap"); - goto abort; - } - - if (!(rp->icon_mono_and = malloc(width * height))) { - logsyserr(rp->c.log, "Allocating mono AND bitmap"); - goto abort; - } - if (!(rp->icon_mono_xor = malloc(width * height))) { - logsyserr(rp->c.log, "Allocating mono XOR bitmap"); - goto abort; - } - - for (int i = 0; i < width * height; i++) - rp->icon_mono_and[i] = 255 - monobuf[3 * i]; - - for (int i = 0; i < width * height; i++) - rp->icon_mono_xor[i] = monobuf[3 * (width * height + i)]; - - rp->icon_mono_width = width; - rp->icon_mono_height = height; - free(monobuf); - monobuf = NULL; - bmp_free(hmono); - hmono = NULL; - - if (rp->fh->type == BMPFILE_CI || rp->fh->type == BMPFILE_CP) - return poscolor; - - return posmono; - -abort: - if (hmono) - bmp_free(hmono); - if (monobuf) - free(monobuf); - return -1; -} - - /***************************************************************************** * bmpread_set_64bit_conv *****************************************************************************/ @@ -454,7 +328,7 @@ API int bmpread_is_64bit(BMPHANDLE h) if (!(rp = cm_read_handle(h))) return 0; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return 0; if (rp->ih->bitcount == 64) @@ -475,7 +349,7 @@ API size_t bmpread_iccprofile_size(BMPHANDLE h) if (!(rp = cm_read_handle(h))) return 0; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return 0; if (rp->ih->cstype == PROFILE_EMBEDDED && rp->ih->profilesize <= MAX_ICCPROFILE_SIZE) { @@ -501,7 +375,7 @@ API BMPRESULT bmpread_load_iccprofile(BMPHANDLE h, unsigned char **profile) if (!(rp = cm_read_handle(h))) goto abort; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) { + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) { logerr(rp->c.log, "Must load info before loading ICC profile"); goto abort; } @@ -598,7 +472,7 @@ API BMPRESULT bmpread_dimensions(BMPHANDLE h, int* restrict width, if (rp->read_state < RS_HEADER_OK) bmpread_load_info((BMPHANDLE)(void*)rp); - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return BMP_RESULT_ERROR; if (width) { @@ -643,6 +517,9 @@ BMPRESULT br_set_number_format(BMPREAD_R rp, enum BmpFormat format) return BMP_RESULT_OK; } + if (rp->read_state >= RS_ARRAY) + return BMP_RESULT_ERROR; + switch (format) { case BMP_FORMAT_INT: /* always ok */ @@ -737,7 +614,7 @@ static int s_single_dim_val(BMPHANDLE h, enum Dimint dim) if (!(rp = cm_read_handle(h))) return 0; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return 0; switch (dim) { @@ -789,7 +666,7 @@ API size_t bmpread_buffersize(BMPHANDLE h) if (!(rp = cm_read_handle(h))) return 0; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return 0; rp->read_state = MAX(RS_DIMENSIONS_QUERIED, rp->read_state); @@ -877,6 +754,16 @@ void br_free(BMPREAD rp) { rp->c.magic = 0; + if (rp->is_arrayimg) + return; + + if (rp->arrayimgs) { + for (int i = 0; i < rp->narrayimgs; i++) { + ((BMPREAD)rp->arrayimgs[i].handle)->is_arrayimg = false; + br_free((BMPREAD)rp->arrayimgs[i].handle); + } + free(rp->arrayimgs); + } if (rp->icon_mono_and) free(rp->icon_mono_and); if (rp->icon_mono_xor) @@ -1696,7 +1583,7 @@ static int s_info_int(BMPHANDLE h, enum Infoint info) if (!(rp = cm_read_handle(h))) return 0; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return 0; switch (info) { @@ -1767,7 +1654,7 @@ API BMPRESULT bmpread_info_channel_bits(BMPHANDLE h, int *r, int *g, int *b, int if (!(rp = cm_read_handle(h))) return BMP_RESULT_ERROR; - if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_FATAL) + if (rp->read_state < RS_HEADER_OK || rp->read_state >= RS_ARRAY) return BMP_RESULT_ERROR; if (rp->ih->compression == BI_OS2_RLE24) { diff --git a/bmplib.h b/bmplib.h index 054fb22..920b98e 100644 --- a/bmplib.h +++ b/bmplib.h @@ -245,9 +245,10 @@ enum BmpImagetype { typedef enum BmpImagetype BMPIMAGETYPE; struct BmpArrayInfo { + BMPHANDLE handle; BMPIMAGETYPE type; int width, height; - int ncolors; /* -1 = RGB */ + int ncolors; /* 0 = RGB */ int screenwidth, screenheight; /* typically 0, or 1024x768 for 'hi-res' */ }; @@ -290,6 +291,11 @@ APIDECL BMPRESULT bmpread_set_64bit_conv(BMPHANDLE h, BMPCONV64 conv); APIDECL size_t bmpread_iccprofile_size(BMPHANDLE h); APIDECL BMPRESULT bmpread_load_iccprofile(BMPHANDLE h, unsigned char **profile); + +APIDECL int bmpread_array_num(BMPHANDLE h); +APIDECL BMPRESULT bmpread_array_info(BMPHANDLE h, struct BmpArrayInfo *ai, int idx); + + APIDECL BMPINFOVER bmpread_info_header_version(BMPHANDLE h); APIDECL const char* bmpread_info_header_name(BMPHANDLE h); APIDECL int bmpread_info_header_size(BMPHANDLE h); diff --git a/meson.build b/meson.build index 89d38f7..a85b17c 100644 --- a/meson.build +++ b/meson.build @@ -37,6 +37,7 @@ bmplib_sources = ['bmp-read.c', 'bmp-write.c', 'bmp-read-loadimage.c', 'bmp-read-loadindexed.c', + 'bmp-read-icons.c', 'bmp-common.c', 'huffman.c', 'logging.c'] @@ -74,6 +75,7 @@ test_read_conversions = executable('test_read_conversions', 'test-read-conversions.c', 'bmp-common.c', 'bmp-read.c', + 'bmp-read-icons.c', 'bmp-write.c', 'huffman.c', 'logging.c', @@ -85,6 +87,7 @@ test_read_io = executable('test_read_io', 'test-read-io.c', 'bmp-common.c', 'bmp-read.c', + 'bmp-read-icons.c', 'bmp-write.c', 'huffman.c', 'logging.c', @@ -97,6 +100,7 @@ test_write_io = executable('test_write_io', 'test-write-io.c', 'bmp-common.c', 'bmp-read.c', + 'bmp-read-icons.c', 'bmp-read-loadimage.c', 'huffman.c', 'logging.c',