diff --git a/desmume/src/libretro-common/formats/bmp/rbmp.c b/desmume/src/libretro-common/formats/bmp/rbmp.c index 01dd61403..560fed3d9 100644 --- a/desmume/src/libretro-common/formats/bmp/rbmp.c +++ b/desmume/src/libretro-common/formats/bmp/rbmp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2016 The RetroArch team +/* Copyright (C) 2010-2017 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (rbmp.c). @@ -29,32 +29,28 @@ #include #include -#include #include #include #include -typedef struct -{ - int (*read) (void *user,char *data,int size); /* fill 'data' with 'size' bytes. return number of bytes actually read */ - void (*skip) (void *user,int n); /* skip the next 'n' bytes, or 'unget' the last -n bytes if negative */ - int (*eof) (void *user); /* returns nonzero if we are at end of file/data */ -} rbmp_io_callbacks; +/* truncate int to byte without warnings */ +#define RBMP__BYTECAST(x) ((unsigned char) ((x) & 255)) + +#define RBMP_COMPUTE_Y(r, g, b) ((unsigned char) ((((r) * 77) + ((g) * 150) + (29 * (b))) >> 8)) typedef struct { - uint32_t img_x, img_y; - int img_n, img_out_n; + uint32_t img_x; + uint32_t img_y; + int img_n; + int img_out_n; - rbmp_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; int buflen; unsigned char buffer_start[128]; - unsigned char *img_buffer, *img_buffer_end; + unsigned char *img_buffer; + unsigned char *img_buffer_end; unsigned char *img_buffer_original; } rbmp__context; @@ -62,63 +58,13 @@ struct rbmp { uint8_t *buff_data; uint32_t *output_image; - void *empty; }; -static void rbmp__refill_buffer(rbmp__context *s); - -/* initialize a memory-decode context */ -static void rbmp__start_mem(rbmp__context *s, unsigned char const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (unsigned char *) buffer; - s->img_buffer_end = (unsigned char *) buffer+len; -} - -static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, int *comp, int req_comp); - -#define rbmp__err(x,y) 0 -#define rbmp__errpf(x,y) ((float *) (rbmp__err(x,y)?NULL:NULL)) -#define rbmp__errpuc(x,y) ((unsigned char *) (rbmp__err(x,y)?NULL:NULL)) - -static unsigned char *rbmp_load_from_memory(unsigned char const *buffer, int len, unsigned *x, unsigned *y, int *comp, int req_comp) -{ - rbmp__context s; - rbmp__start_mem(&s,buffer,len); - return rbmp__bmp_load(&s,x,y,comp,req_comp); -} - -static void rbmp__refill_buffer(rbmp__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) - { - /* at end of file, treat same as if from memory, but need to handle case - * where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file */ - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } - else - { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - static INLINE unsigned char rbmp__get8(rbmp__context *s) { if (s->img_buffer < s->img_buffer_end) return *s->img_buffer++; - if (s->read_from_callbacks) - { - rbmp__refill_buffer(s); - return *s->img_buffer++; - } - return 0; } @@ -130,16 +76,6 @@ static void rbmp__skip(rbmp__context *s, int n) return; } - if (s->io.read) - { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) - { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } s->img_buffer += n; } @@ -155,13 +91,6 @@ static uint32_t rbmp__get32le(rbmp__context *s) return z + (rbmp__get16le(s) << 16); } -#define RBMP__BYTECAST(x) ((unsigned char) ((x) & 255)) /* truncate int to byte without warnings */ - -static unsigned char rbmp__compute_y(int r, int g, int b) -{ - return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8); -} - static unsigned char *rbmp__convert_format( unsigned char *data, int img_n, @@ -170,17 +99,10 @@ static unsigned char *rbmp__convert_format( unsigned int y) { int i,j; - unsigned char *good; + unsigned char *good = (unsigned char *)malloc(req_comp * x * y); - if (req_comp == img_n) return data; - retro_assert(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) malloc(req_comp * x * y); - if (good == NULL) - { - free(data); - return rbmp__errpuc("outofmem", "Out of memory"); - } + if (!good) + return NULL; for (j=0; j < (int) y; ++j) { @@ -219,32 +141,30 @@ static unsigned char *rbmp__convert_format( break; case ((3)*8+(1)): for(i=x-1; i >= 0; --i, src += 3, dest += 1) - dest[0]=rbmp__compute_y(src[0],src[1],src[2]); + dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]); break; case ((3)*8+(2)): for(i=x-1; i >= 0; --i, src += 3, dest += 2) - dest[0]=rbmp__compute_y(src[0],src[1],src[2]), dest[1] = 255; + dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]), dest[1] = 255; break; case ((4)*8+(1)): for(i=x-1; i >= 0; --i, src += 4, dest += 1) - dest[0]=rbmp__compute_y(src[0],src[1],src[2]); + dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]); break; case ((4)*8+(2)): for(i=x-1; i >= 0; --i, src += 4, dest += 2) - dest[0]=rbmp__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; + dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]), dest[1] = src[3]; break; case ((4)*8+(3)): for(i=x-1; i >= 0; --i, src += 4, dest += 3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; default: - retro_assert(0); break; } } - free(data); return good; } @@ -254,7 +174,8 @@ static unsigned char *rbmp__convert_format( static int rbmp__high_bit(unsigned int z) { int n=0; - if (z == 0) return -1; + if (z == 0) + return -1; if (z >= 0x10000) n += 16, z >>= 16; if (z >= 0x00100) n += 8, z >>= 8; if (z >= 0x00010) n += 4, z >>= 4; @@ -294,24 +215,27 @@ static int rbmp__shiftsigned(int v, int shift, int bits) return result; } -static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, int *comp, int req_comp) +static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, + int *comp, int req_comp) { unsigned char *out; - unsigned int mr=0,mg=0,mb=0,ma=0; - unsigned char pal[256][4]; - int psize=0,i,j,compress=0,width; int bpp, flip_vertically, pad, target, offset, hsz; + int psize=0,i,j,width; + unsigned int mr=0,mg=0,mb=0,ma=0; + /* Corrupt BMP? */ if (rbmp__get8(s) != 'B' || rbmp__get8(s) != 'M') - return rbmp__errpuc("not BMP", "Corrupt BMP"); + return 0; rbmp__get32le(s); /* discard filesize */ rbmp__get16le(s); /* discard reserved */ rbmp__get16le(s); /* discard reserved */ offset = rbmp__get32le(s); hsz = rbmp__get32le(s); + + /* BMP type not supported? */ if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) - return rbmp__errpuc("unknown BMP", "BMP type not supported: unknown"); + return 0; if (hsz == 12) { @@ -323,13 +247,19 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, s->img_x = rbmp__get32le(s); s->img_y = rbmp__get32le(s); } + + /* Bad BMP? */ if (rbmp__get16le(s) != 1) - return rbmp__errpuc("bad BMP", "bad BMP"); + return 0; + bpp = rbmp__get16le(s); + + /* BMP 1-bit type not supported? */ if (bpp == 1) - return rbmp__errpuc("monochrome", "BMP type not supported: 1-bit"); + return 0; + flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); + s->img_y = abs((int) s->img_y); if (hsz == 12) { @@ -338,16 +268,18 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, } else { - compress = rbmp__get32le(s); + int compress = rbmp__get32le(s); + /* BMP RLE type not supported? */ if (compress == 1 || compress == 2) - return rbmp__errpuc("BMP RLE", "BMP type not supported: RLE"); + return 0; rbmp__get32le(s); /* discard sizeof */ rbmp__get32le(s); /* discard hres */ rbmp__get32le(s); /* discard vres */ rbmp__get32le(s); /* discard colors used */ rbmp__get32le(s); /* discard max important */ + if (hsz == 40 || hsz == 56) { if (hsz == 56) @@ -359,11 +291,10 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, } if (bpp == 16 || bpp == 32) { - mr = mg = mb = 0; - switch (compress) { case 0: +#if 0 if (bpp == 32) { mr = 0xffu << 16; @@ -377,57 +308,70 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, mg = 31u << 5; mb = 31u << 0; } +#endif break; case 3: mr = rbmp__get32le(s); mg = rbmp__get32le(s); mb = rbmp__get32le(s); - /* not documented, but generated by photoshop and handled by mspaint */ + /* not documented, but generated by + * Photoshop and handled by MS Paint */ + /* Bad BMP ?*/ if (mr == mg && mg == mb) - return rbmp__errpuc("bad BMP", "bad BMP"); + return 0; break; default: +#if 0 + mr = mg = mb = 0; +#endif break; } - return rbmp__errpuc("bad BMP", "bad BMP"); + + /* Bad BMP? */ + return 0; } } else { - retro_assert(hsz == 108 || hsz == 124); mr = rbmp__get32le(s); mg = rbmp__get32le(s); mb = rbmp__get32le(s); ma = rbmp__get32le(s); - rbmp__get32le(s); /* discard color space */ + rbmp__get32le(s); /* Discard color space */ for (i=0; i < 12; ++i) - rbmp__get32le(s); /* discard color space parameters */ + rbmp__get32le(s); /* Discard color space parameters */ if (hsz == 124) { - rbmp__get32le(s); /* discard rendering intent */ - rbmp__get32le(s); /* discard offset of profile data */ - rbmp__get32le(s); /* discard size of profile data */ - rbmp__get32le(s); /* discard reserved */ + rbmp__get32le(s); /* Discard rendering intent */ + rbmp__get32le(s); /* Discard offset of profile data */ + rbmp__get32le(s); /* Discard size of profile data */ + rbmp__get32le(s); /* Discard reserved */ } } if (bpp < 16) psize = (offset - 14 - hsz) >> 2; } s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) /* we can directly decode 3 or 4 */ + if (req_comp && req_comp >= 3) /* We can directly decode 3 or 4 */ target = req_comp; else - target = s->img_n; /* if they want monochrome, we'll post-convert */ + target = s->img_n; /* If they want monochrome, we'll post-convert */ + out = (unsigned char *) malloc(target * s->img_x * s->img_y); + if (!out) - return rbmp__errpuc("outofmem", "Out of memory"); + return 0; + if (bpp < 16) { + unsigned char pal[256][4]; int z=0; + + /* Corrupt BMP? */ if (psize == 0 || psize > 256) { free(out); - return rbmp__errpuc("invalid", "Corrupt BMP"); + return 0; } for (i=0; i < psize; ++i) @@ -446,9 +390,11 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, width = s->img_x; else { + /* Corrupt BMP */ free(out); - return rbmp__errpuc("bad bpp", "Corrupt BMP"); + return 0; } + pad = (-width)&3; for (j=0; j < (int) s->img_y; ++j) { @@ -463,26 +409,45 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, out[z++] = pal[v][0]; out[z++] = pal[v][1]; out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; + if (target == 4) + out[z++] = 255; + + if (i+1 == (int)s->img_x) + break; + v = (bpp == 8) ? rbmp__get8(s) : v2; out[z++] = pal[v][0]; out[z++] = pal[v][1]; out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; + + if (target == 4) + out[z++] = 255; } rbmp__skip(s, pad); } } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int rshift=0; + int gshift=0; + int bshift=0; + int ashift=0; + int rcount=0; + int gcount=0; + int bcount=0; + int acount=0; int z = 0; int easy=0; + rbmp__skip(s, offset - 14 - hsz); - if (bpp == 24) width = 3 * s->img_x; - else if (bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; + + if (bpp == 24) + width = 3 * s->img_x; + else if (bpp == 16) + width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ + width=0; + pad = (-width) & 3; switch (bpp) @@ -500,16 +465,22 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, if (!easy) { + /* Corrupt BMP? */ if (!mr || !mg || !mb) { free(out); - return rbmp__errpuc("bad masks", "Corrupt BMP"); + return 0; } + /* right shift amt to put high bit in position #7 */ - rshift = rbmp__high_bit(mr)-7; rcount = rbmp__bitcount(mr); - gshift = rbmp__high_bit(mg)-7; gcount = rbmp__bitcount(mg); - bshift = rbmp__high_bit(mb)-7; bcount = rbmp__bitcount(mb); - ashift = rbmp__high_bit(ma)-7; acount = rbmp__bitcount(ma); + rshift = rbmp__high_bit(mr)-7; + rcount = rbmp__bitcount(mr); + gshift = rbmp__high_bit(mg)-7; + gcount = rbmp__bitcount(mg); + bshift = rbmp__high_bit(mb)-7; + bcount = rbmp__bitcount(mb); + ashift = rbmp__high_bit(ma)-7; + acount = rbmp__bitcount(ma); } for (j=0; j < (int) s->img_y; ++j) { @@ -523,7 +494,8 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, out[z+0] = rbmp__get8(s); z += 3; a = (easy == 2 ? rbmp__get8(s) : 255); - if (target == 4) out[z++] = a; + if (target == 4) + out[z++] = a; } } else @@ -536,12 +508,14 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, out[z++] = RBMP__BYTECAST(rbmp__shiftsigned(v & mg, gshift, gcount)); out[z++] = RBMP__BYTECAST(rbmp__shiftsigned(v & mb, bshift, bcount)); a = (ma ? rbmp__shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = RBMP__BYTECAST(a); + if (target == 4) + out[z++] = RBMP__BYTECAST(a); } } rbmp__skip(s, pad); } } + if (flip_vertically) { unsigned char t; @@ -555,20 +529,44 @@ static unsigned char *rbmp__bmp_load(rbmp__context *s, unsigned *x, unsigned *y, } } } - - if (req_comp && req_comp != target) + + if ( + req_comp + && (req_comp >= 1 && req_comp <= 4) + && (req_comp != target)) { - out = rbmp__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) - return out; /* rbmp__convert_format frees input on failure */ + unsigned char *tmp = rbmp__convert_format(out, target, req_comp, s->img_x, s->img_y); + + free(out); + out = NULL; + + if (!tmp) + return NULL; + + out = tmp; } *x = s->img_x; *y = s->img_y; - if (comp) *comp = s->img_n; + + if (comp) + *comp = s->img_n; + return out; } +static unsigned char *rbmp_load_from_memory(unsigned char const *buffer, int len, + unsigned *x, unsigned *y, int *comp, int req_comp) +{ + rbmp__context s; + + s.img_buffer = (unsigned char*)buffer; + s.img_buffer_original = (unsigned char*)buffer; + s.img_buffer_end = (unsigned char*)buffer+len; + + return rbmp__bmp_load(&s,x,y,comp,req_comp); +} + static void rbmp_convert_frame(uint32_t *frame, unsigned width, unsigned height) { uint32_t *end = frame + (width * height * sizeof(uint32_t))/4; @@ -589,7 +587,8 @@ int rbmp_process_image(rbmp_t *rbmp, void **buf_data, if (!rbmp) return IMAGE_PROCESS_ERROR; - rbmp->output_image = (uint32_t*)rbmp_load_from_memory(rbmp->buff_data, size, width, height, &comp, 4); + rbmp->output_image = (uint32_t*)rbmp_load_from_memory(rbmp->buff_data, + (int)size, width, height, &comp, 4); *buf_data = rbmp->output_image; rbmp_convert_frame(rbmp->output_image, *width, *height); diff --git a/desmume/src/libretro-common/formats/bmp/rbmp_encode.c b/desmume/src/libretro-common/formats/bmp/rbmp_encode.c index 0bf59f101..9c2e199ab 100644 --- a/desmume/src/libretro-common/formats/bmp/rbmp_encode.c +++ b/desmume/src/libretro-common/formats/bmp/rbmp_encode.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2016 The RetroArch team +/* Copyright (C) 2010-2017 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (rbmp_encode.c). @@ -160,7 +160,7 @@ static void dump_content(RFILE *file, const void *frame, { /* BGR24 byte order input matches output. Can directly copy, but... need to make sure we pad it. */ uint32_t zeros = 0; - int pad = line_size-pitch; + int pad = (int)(line_size-pitch); for (j = 0; j < height; j++, u.u8 += pitch) { filestream_write(file, u.u8, pitch); diff --git a/desmume/src/libretro-common/include/formats/rbmp.h b/desmume/src/libretro-common/include/formats/rbmp.h index bc0702758..622d8c94d 100644 --- a/desmume/src/libretro-common/include/formats/rbmp.h +++ b/desmume/src/libretro-common/include/formats/rbmp.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2015 The RetroArch team +/* Copyright (C) 2010-2017 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (rbmp.h).