diff --git a/winpr/libwinpr/utils/image.c b/winpr/libwinpr/utils/image.c index ce87e7656..7c9a1f1ba 100644 --- a/winpr/libwinpr/utils/image.c +++ b/winpr/libwinpr/utils/image.c @@ -29,10 +29,77 @@ #include #include "lodepng/lodepng.h" +#include #include "../log.h" #define TAG WINPR_TAG("utils.image") +static BOOL writeBitmapFileHeader(wStream* s, const WINPR_BITMAP_FILE_HEADER* bf) +{ + if (!Stream_EnsureRemainingCapacity(s, sizeof(WINPR_BITMAP_FILE_HEADER))) + return FALSE; + + Stream_Write_UINT8(s, bf->bfType[0]); + Stream_Write_UINT8(s, bf->bfType[1]); + Stream_Write_UINT32(s, bf->bfSize); + Stream_Write_UINT16(s, bf->bfReserved1); + Stream_Write_UINT16(s, bf->bfReserved2); + Stream_Write_UINT32(s, bf->bfOffBits); + return TRUE; +} + +static BOOL readBitmapFileHeader(wStream* s, WINPR_BITMAP_FILE_HEADER* bf) +{ + if (!s || !bf || (Stream_GetRemainingLength(s) < sizeof(WINPR_BITMAP_FILE_HEADER))) + return FALSE; + + Stream_Read_UINT8(s, bf->bfType[0]); + Stream_Read_UINT8(s, bf->bfType[1]); + Stream_Read_UINT32(s, bf->bfSize); + Stream_Read_UINT16(s, bf->bfReserved1); + Stream_Read_UINT16(s, bf->bfReserved2); + Stream_Read_UINT32(s, bf->bfOffBits); + return TRUE; +} + +static BOOL writeBitmapInfoHeader(wStream* s, const WINPR_BITMAP_INFO_HEADER* bi) +{ + if (!Stream_EnsureRemainingCapacity(s, sizeof(WINPR_BITMAP_INFO_HEADER))) + return FALSE; + + Stream_Write_UINT32(s, bi->biSize); + Stream_Write_UINT32(s, bi->biWidth); + Stream_Write_UINT32(s, bi->biHeight); + Stream_Write_UINT16(s, bi->biPlanes); + Stream_Write_UINT16(s, bi->biBitCount); + Stream_Write_UINT32(s, bi->biCompression); + Stream_Write_UINT32(s, bi->biSizeImage); + Stream_Write_UINT32(s, bi->biXPelsPerMeter); + Stream_Write_UINT32(s, bi->biYPelsPerMeter); + Stream_Write_UINT32(s, bi->biClrUsed); + Stream_Write_UINT32(s, bi->biClrImportant); + return TRUE; +} + +static BOOL readBitmapInfoHeader(wStream* s, WINPR_BITMAP_INFO_HEADER* bi) +{ + if (!s || !bi || (Stream_GetRemainingLength(s) < sizeof(WINPR_BITMAP_INFO_HEADER))) + return FALSE; + + Stream_Read_UINT32(s, bi->biSize); + Stream_Read_INT32(s, bi->biWidth); + Stream_Read_INT32(s, bi->biHeight); + Stream_Read_UINT16(s, bi->biPlanes); + Stream_Read_UINT16(s, bi->biBitCount); + Stream_Read_UINT32(s, bi->biCompression); + Stream_Read_UINT32(s, bi->biSizeImage); + Stream_Read_INT32(s, bi->biXPelsPerMeter); + Stream_Read_INT32(s, bi->biYPelsPerMeter); + Stream_Read_UINT32(s, bi->biClrUsed); + Stream_Read_UINT32(s, bi->biClrImportant); + return TRUE; +} + /** * Refer to "Compressed Image File Formats: JPEG, PNG, GIF, XBM, BMP" book */ @@ -42,8 +109,8 @@ int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, FILE* fp; WINPR_BITMAP_FILE_HEADER bf; WINPR_BITMAP_INFO_HEADER bi; - int ret = 1; - + wStream* s; + int ret = -1; fp = fopen(filename, "w+b"); if (!fp) @@ -59,7 +126,6 @@ int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, bf.bfOffBits = sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER); bi.biSizeImage = width * height * (bpp / 8); bf.bfSize = bf.bfOffBits + bi.biSizeImage; - bi.biWidth = width; bi.biHeight = -1 * height; bi.biPlanes = 1; @@ -70,14 +136,27 @@ int winpr_bitmap_write(const char* filename, BYTE* data, int width, int height, bi.biClrUsed = 0; bi.biClrImportant = 0; bi.biSize = sizeof(WINPR_BITMAP_INFO_HEADER); + s = Stream_New(NULL, sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER)); - if (fwrite((void*) &bf, sizeof(WINPR_BITMAP_FILE_HEADER), 1, fp) != 1 || - fwrite((void*) &bi, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp) != 1 || - fwrite((void*) data, bi.biSizeImage, 1, fp) != 1) - ret = -1; + if (!s) + goto fail; + if (!writeBitmapFileHeader(s, &bf)) + goto fail; + + if (!writeBitmapInfoHeader(s, &bi)) + goto fail; + + Stream_SealLength(s); + + if (fwrite(Stream_Buffer(s), Stream_Length(s), 1, fp) != 1 || + fwrite((void*) data, bi.biSizeImage, 1, fp) != 1) + goto fail; + + ret = 1; +fail: fclose(fp); - + Stream_Free(s, TRUE); return ret; } @@ -87,32 +166,29 @@ int winpr_image_write(wImage* image, const char* filename) if (image->type == WINPR_IMAGE_BITMAP) { - status = winpr_bitmap_write(filename, image->data, image->width, image->height, image->bitsPerPixel); + status = winpr_bitmap_write(filename, image->data, image->width, image->height, + image->bitsPerPixel); } else { int lodepng_status; - lodepng_status = lodepng_encode32_file(filename, image->data, image->width, image->height); - status = (lodepng_status) ? -1 : 1; } return status; } -int winpr_image_png_read_fp(wImage* image, FILE* fp) +static int winpr_image_png_read_fp(wImage* image, FILE* fp) { INT64 size; BYTE* data; UINT32 width; UINT32 height; int lodepng_status; - _fseeki64(fp, 0, SEEK_END); size = _ftelli64(fp); _fseeki64(fp, 0, SEEK_SET); - data = (BYTE*) malloc(size); if (!data) @@ -125,7 +201,6 @@ int winpr_image_png_read_fp(wImage* image, FILE* fp) } lodepng_status = lodepng_decode32(&(image->data), &width, &height, data, size); - free(data); if (lodepng_status) @@ -133,20 +208,17 @@ int winpr_image_png_read_fp(wImage* image, FILE* fp) image->width = width; image->height = height; - image->bitsPerPixel = 32; image->bytesPerPixel = 4; image->scanline = image->bytesPerPixel * image->width; - return 1; } -int winpr_image_png_read_buffer(wImage* image, BYTE* buffer, int size) +static int winpr_image_png_read_buffer(wImage* image, BYTE* buffer, size_t size) { UINT32 width; UINT32 height; int lodepng_status; - lodepng_status = lodepng_decode32(&(image->data), &width, &height, buffer, size); if (lodepng_status) @@ -154,37 +226,39 @@ int winpr_image_png_read_buffer(wImage* image, BYTE* buffer, int size) image->width = width; image->height = height; - image->bitsPerPixel = 32; image->bytesPerPixel = 4; image->scanline = image->bytesPerPixel * image->width; - return 1; } -int winpr_image_bitmap_read_fp(wImage* image, FILE* fp) +static int winpr_image_bitmap_read_fp(wImage* image, FILE* fp) { + int rc = -1; int index; BOOL vFlip; BYTE* pDstData; + wStream* s; WINPR_BITMAP_FILE_HEADER bf; WINPR_BITMAP_INFO_HEADER bi; + s = Stream_New(NULL, sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER)); - if (fread((void*) &bf, sizeof(WINPR_BITMAP_FILE_HEADER), 1, fp) != 1) + if (!s) return -1; + if (fread(Stream_Buffer(s), Stream_Capacity(s), 1, fp) != 1) + goto fail; + + if (!readBitmapFileHeader(s, &bf) || !readBitmapInfoHeader(s, &bi)) + goto fail; + if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M')) - return -1; + goto fail; image->type = WINPR_IMAGE_BITMAP; - if (fread((void*) &bi, sizeof(WINPR_BITMAP_INFO_HEADER), 1, fp) != 1) - return -1; - if (_ftelli64(fp) != bf.bfOffBits) - { _fseeki64(fp, bf.bfOffBits, SEEK_SET); - } image->width = bi.biWidth; @@ -202,20 +276,15 @@ int winpr_image_bitmap_read_fp(wImage* image, FILE* fp) image->bitsPerPixel = bi.biBitCount; image->bytesPerPixel = (image->bitsPerPixel / 8); image->scanline = (bi.biSizeImage / image->height); - image->data = (BYTE*) malloc(bi.biSizeImage); if (!image->data) - return -1; + goto fail; if (!vFlip) { if (fread((void*) image->data, bi.biSizeImage, 1, fp) != 1) - { - free(image->data); - image->data = NULL; - return -1; - } + goto fail; } else { @@ -224,45 +293,50 @@ int winpr_image_bitmap_read_fp(wImage* image, FILE* fp) for (index = 0; index < image->height; index++) { if (fread((void*) pDstData, image->scanline, 1, fp) != 1) - { - free(image->data); - image->data = NULL; - return -1; - } + goto fail; + pDstData -= image->scanline; } } + rc = 1; +fail: + + if (rc < 0) + { + free(image->data); + image->data = NULL; + } + + Stream_Free(s, TRUE); return 1; } -int winpr_image_bitmap_read_buffer(wImage* image, BYTE* buffer, int size) +static int winpr_image_bitmap_read_buffer(wImage* image, BYTE* buffer, size_t size) { + int rc = -1; int index; BOOL vFlip; - BYTE* pSrcData; BYTE* pDstData; WINPR_BITMAP_FILE_HEADER bf; WINPR_BITMAP_INFO_HEADER bi; + wStream* s = Stream_New(buffer, size); - pSrcData = buffer; + if (!s) + return -1; - CopyMemory(&bf, pSrcData, sizeof(WINPR_BITMAP_FILE_HEADER)); - pSrcData += sizeof(WINPR_BITMAP_FILE_HEADER); + if (!readBitmapFileHeader(s, &bf) || !readBitmapInfoHeader(s, &bi)) + goto fail; if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M')) - return -1; + goto fail; image->type = WINPR_IMAGE_BITMAP; - CopyMemory(&bi, pSrcData, sizeof(WINPR_BITMAP_INFO_HEADER)); - pSrcData += sizeof(WINPR_BITMAP_INFO_HEADER); - - if ((pSrcData - buffer) != bf.bfOffBits) - { - pSrcData = &buffer[bf.bfOffBits]; - } + if (Stream_Capacity(s) < bf.bfOffBits + bi.biSizeImage) + goto fail; + Stream_SetPosition(s, bf.bfOffBits); image->width = bi.biWidth; if (bi.biHeight < 0) @@ -279,27 +353,35 @@ int winpr_image_bitmap_read_buffer(wImage* image, BYTE* buffer, int size) image->bitsPerPixel = bi.biBitCount; image->bytesPerPixel = (image->bitsPerPixel / 8); image->scanline = (bi.biSizeImage / image->height); - image->data = (BYTE*) malloc(bi.biSizeImage); if (!image->data) - return -1; + goto fail; if (!vFlip) - CopyMemory(image->data, pSrcData, bi.biSizeImage); + Stream_Read(s, image->data, bi.biSizeImage); else { pDstData = &(image->data[(image->height - 1) * image->scanline]); for (index = 0; index < image->height; index++) { - CopyMemory(pDstData, pSrcData, image->scanline); - pSrcData += image->scanline; + Stream_Read(s, pDstData, image->scanline); pDstData -= image->scanline; } } - return 1; + rc = 1; +fail: + + if (rc < 0) + { + free(image->data); + image->data = NULL; + } + + Stream_Free(s, FALSE); + return rc; } int winpr_image_read(wImage* image, const char* filename) @@ -307,7 +389,6 @@ int winpr_image_read(wImage* image, const char* filename) FILE* fp; BYTE sig[8]; int status = -1; - fp = fopen(filename, "rb"); if (!fp) @@ -328,13 +409,13 @@ int winpr_image_read(wImage* image, const char* filename) status = winpr_image_bitmap_read_fp(image, fp); } else if ((sig[0] == 0x89) && (sig[1] == 'P') && (sig[2] == 'N') && (sig[3] == 'G') && - (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n')) + (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n')) { image->type = WINPR_IMAGE_PNG; status = winpr_image_png_read_fp(image, fp); } - fclose(fp); + fclose(fp); return status; } @@ -354,7 +435,7 @@ int winpr_image_read_buffer(wImage* image, BYTE* buffer, int size) status = winpr_image_bitmap_read_buffer(image, buffer, size); } else if ((sig[0] == 0x89) && (sig[1] == 'P') && (sig[2] == 'N') && (sig[3] == 'G') && - (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n')) + (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n')) { image->type = WINPR_IMAGE_PNG; status = winpr_image_png_read_buffer(image, buffer, size); @@ -363,10 +444,9 @@ int winpr_image_read_buffer(wImage* image, BYTE* buffer, int size) return status; } -wImage* winpr_image_new() +wImage* winpr_image_new(void) { wImage* image; - image = (wImage*) calloc(1, sizeof(wImage)); if (!image) diff --git a/winpr/libwinpr/utils/test/TestImage.c b/winpr/libwinpr/utils/test/TestImage.c index 08937651c..0ac34a1c4 100644 --- a/winpr/libwinpr/utils/test/TestImage.c +++ b/winpr/libwinpr/utils/test/TestImage.c @@ -9,12 +9,12 @@ #define PATH_MAX 4096 #endif -static void *read_image(const char *src, size_t *size) +static void* read_image(const char* src, size_t* size) { int success = 0; - void *a = NULL; + void* a = NULL; INT64 src_size; - FILE *fsrc = fopen(src, "rb"); + FILE* fsrc = fopen(src, "rb"); if (!fsrc) { @@ -52,22 +52,24 @@ static void *read_image(const char *src, size_t *size) success = 1; *size = src_size; - cleanup: + if (a && !success) { free(a); a = NULL; } + if (fsrc) fclose(fsrc); return a; } -static int img_compare(wImage *image, wImage *image2, BOOL ignoreType) +static int img_compare(wImage* image, wImage* image2, BOOL ignoreType) { int rc = -1; + if ((image->type != image2->type) && !ignoreType) { fprintf(stderr, "Image type mismatch %d:%d\n", image->type, image2->type); @@ -100,7 +102,8 @@ static int img_compare(wImage *image, wImage *image2, BOOL ignoreType) if (image->bytesPerPixel != image2->bytesPerPixel) { - fprintf(stderr, "Image bytesPerPixel mismatch %d:%d\n", image->bytesPerPixel, image2->bytesPerPixel); + fprintf(stderr, "Image bytesPerPixel mismatch %d:%d\n", image->bytesPerPixel, + image2->bytesPerPixel); goto cleanup; } @@ -113,11 +116,10 @@ cleanup: return rc; } -static wImage *get_image(const char *src) +static wImage* get_image(const char* src) { int status; wImage* image = NULL; - image = winpr_image_new(); if (!image) @@ -136,17 +138,16 @@ static wImage *get_image(const char *src) } cleanup: - return image; } -static int create_test(const char *src, const char *dst_png, const char *dst_bmp) +static int create_test(const char* src, const char* dst_png, const char* dst_bmp) { int rc = -1; int ret = -1; int status; size_t bsize; - void *buffer = NULL; + void* buffer = NULL; wImage* image = NULL, *image2 = NULL, *image3 = NULL, *image4 = NULL; if (!PathFileExistsA(src)) @@ -182,6 +183,7 @@ static int create_test(const char *src, const char *dst_png, const char *dst_bmp /* Read image from buffer, compare. */ buffer = read_image(src, &bsize); + if (!buffer) { fprintf(stderr, "Failed to read image %s!\n", src); @@ -205,51 +207,59 @@ static int create_test(const char *src, const char *dst_png, const char *dst_bmp } rc = img_compare(image, image2, TRUE); + if (rc) goto cleanup; image3 = get_image(dst_png); + if (!image3) goto cleanup; rc = img_compare(image, image3, TRUE); + if (rc) goto cleanup; image4 = get_image(dst_bmp); + if (!image4) goto cleanup; rc = img_compare(image, image4, TRUE); + if (rc) goto cleanup; ret = 0; cleanup: + if (image) winpr_image_free(image, TRUE); + if (image2) winpr_image_free(image2, TRUE); + if (image3) winpr_image_free(image3, TRUE); + if (image4) winpr_image_free(image4, TRUE); free(buffer); - return ret; } -int test_image_png_to_bmp() +static int test_image_png_to_bmp(void) { - char *buffer = TEST_SOURCE_PATH; + char* buffer = TEST_SOURCE_PATH; char src_png[PATH_MAX]; char src_bmp[PATH_MAX]; char dst_png[PATH_MAX]; char dst_bmp[PATH_MAX]; char dst_png2[PATH_MAX]; char dst_bmp2[PATH_MAX]; - char *tmp = GetKnownPath(KNOWN_PATH_TEMP); + char* tmp = GetKnownPath(KNOWN_PATH_TEMP); if (!tmp) return -1; @@ -276,7 +286,6 @@ int test_image_png_to_bmp() int TestImage(int argc, char* argv[]) { int rc = test_image_png_to_bmp(); - return rc; }