IMG_webp.c
author Thomas Bernard <miniupnp@free.fr>
Fri, 30 Nov 2018 11:04:15 +0100
branchSDL-1.2
changeset 634 68f958f43339
parent 609 e14e00a2754d
permissions -rw-r--r--
IMG_xcf.c: Avoid infinite loop in read_xcf_header()
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /* This is a WEBP image file loading framework */
    23 
    24 #include <stdlib.h>
    25 #include <stdio.h>
    26 
    27 #include "SDL_image.h"
    28 
    29 #ifdef LOAD_WEBP
    30 
    31 /*=============================================================================
    32         File: SDL_webp.c
    33      Purpose: A WEBP loader for the SDL library      
    34     Revision: 
    35   Created by: Michael Bonfils (Murlock) (26 November 2011)
    36               murlock42@gmail.com
    37 
    38 =============================================================================*/
    39 
    40 #include "SDL_endian.h"
    41 
    42 #ifdef macintosh
    43 #define MACOS
    44 #endif
    45 #include <webp/decode.h>
    46 
    47 static struct {
    48 	int loaded;
    49 	void *handle;
    50 #if WEBP_DECODER_ABI_VERSION < 0x0100
    51 	int/*VP8StatuCode*/ (*webp_get_features_internal) (const uint8_t *data, uint32_t data_size, WebPBitstreamFeatures* const features, int decoder_abi_version);
    52 	uint8_t*	(*webp_decode_rgb_into) (const uint8_t* data, uint32_t data_size, uint8_t* output_buffer, int output_buffer_size, int output_stride);
    53 	uint8_t*	(*webp_decode_rgba_into) (const uint8_t* data, uint32_t data_size, uint8_t* output_buffer, int output_buffer_size, int output_stride);
    54 #else
    55 	VP8StatusCode (*webp_get_features_internal) (const uint8_t *data, size_t data_size, WebPBitstreamFeatures* features, int decoder_abi_version);
    56 	uint8_t*	(*webp_decode_rgb_into) (const uint8_t* data, size_t data_size, uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
    57 	uint8_t*	(*webp_decode_rgba_into) (const uint8_t* data, size_t data_size, uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
    58 #endif
    59 } lib;
    60 
    61 #ifdef LOAD_WEBP_DYNAMIC
    62 int IMG_InitWEBP()
    63 {
    64 	if ( lib.loaded == 0 ) {
    65 		lib.handle = SDL_LoadObject(LOAD_WEBP_DYNAMIC);
    66 		if ( lib.handle == NULL ) {
    67 			return -1;
    68 		}
    69 
    70 		lib.webp_get_features_internal = 
    71 			#if WEBP_DECODER_ABI_VERSION < 0x0100
    72 			( int (*) (const uint8_t *, uint32_t, WebPBitstreamFeatures* const, int) )
    73 			#else
    74 			( VP8StatusCode (*) (const uint8_t *, size_t, WebPBitstreamFeatures*, int) )
    75 			#endif
    76 			SDL_LoadFunction(lib.handle, "WebPGetFeaturesInternal" );
    77 		if ( lib.webp_get_features_internal == NULL ) {
    78 			SDL_UnloadObject(lib.handle);
    79 			return -1;
    80 		}
    81 
    82 		lib.webp_decode_rgb_into = 
    83 			#if WEBP_DECODER_ABI_VERSION < 0x0100
    84 			( uint8_t* (*) (const uint8_t*, uint32_t, uint8_t*, int, int ) )
    85 			#else
    86 			( uint8_t* (*) (const uint8_t*, size_t, uint8_t*, size_t, int ) )
    87 			#endif
    88 			SDL_LoadFunction(lib.handle, "WebPDecodeRGBInto" );
    89 		if ( lib.webp_decode_rgb_into == NULL ) {
    90 			SDL_UnloadObject(lib.handle);
    91 			return -1;
    92 		}
    93 
    94 		lib.webp_decode_rgba_into = 
    95 			#if WEBP_DECODER_ABI_VERSION < 0x0100
    96 			( uint8_t* (*) (const uint8_t*, uint32_t, uint8_t*, int, int ) )
    97 			#else
    98 			( uint8_t* (*) (const uint8_t*, size_t, uint8_t*, size_t, int ) )
    99 			#endif
   100 			SDL_LoadFunction(lib.handle, "WebPDecodeRGBAInto" );
   101 		if ( lib.webp_decode_rgba_into == NULL ) {
   102 			SDL_UnloadObject(lib.handle);
   103 			return -1;
   104 		}
   105 	}
   106 	++lib.loaded;
   107 
   108 	return 0;
   109 }
   110 void IMG_QuitWEBP()
   111 {
   112 	if ( lib.loaded == 0 ) {
   113 		return;
   114 	}
   115 	if ( lib.loaded == 1 ) {
   116 		SDL_UnloadObject(lib.handle);
   117 	}
   118 	--lib.loaded;
   119 }
   120 #else
   121 int IMG_InitWEBP()
   122 {
   123 	if ( lib.loaded == 0 ) {
   124 		lib.webp_get_features_internal = WebPGetFeaturesInternal;
   125 		lib.webp_decode_rgb_into = WebPDecodeRGBInto;
   126 		lib.webp_decode_rgba_into = WebPDecodeRGBAInto;
   127 	}
   128 	++lib.loaded;
   129 
   130 	return 0;
   131 }
   132 void IMG_QuitWEBP()
   133 {
   134 	if ( lib.loaded == 0 ) {
   135 		return;
   136 	}
   137 	if ( lib.loaded == 1 ) {
   138 	}
   139 	--lib.loaded;
   140 }
   141 #endif /* LOAD_WEBP_DYNAMIC */
   142 
   143 static int webp_getinfo( SDL_RWops *src, int *datasize ) {
   144 	int start;
   145 	int is_WEBP;
   146 	Uint8 magic[20];
   147 
   148 	if ( !src ) {
   149 		return 0;
   150 	}
   151 	start = SDL_RWtell(src);
   152 	is_WEBP = 0;
   153 	if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
   154 		if ( magic[ 0] == 'R' &&
   155 		     magic[ 1] == 'I' &&
   156 		     magic[ 2] == 'F' &&
   157 		     magic[ 3] == 'F' &&
   158 		     magic[ 8] == 'W' &&
   159 		     magic[ 9] == 'E' &&
   160 		     magic[10] == 'B' &&
   161 		     magic[11] == 'P' &&
   162 		     magic[12] == 'V' &&
   163 		     magic[13] == 'P' &&
   164 		     magic[14] == '8' &&
   165 		/* old versions don't support VP8X and VP8L */
   166 		#if (WEBP_DECODER_ABI_VERSION < 0x0003)
   167 		     magic[15] == ' '
   168 		#else
   169 		    (magic[15] == ' ' || magic[15] == 'X' || magic[15] == 'L')
   170 		#endif
   171 		 ) {
   172 			is_WEBP = 1;
   173 			if ( datasize ) {
   174 				*datasize = SDL_RWseek(src, 0, RW_SEEK_END) - start;
   175 			}
   176 		}
   177 	}
   178 	SDL_RWseek(src, start, RW_SEEK_SET);
   179 	return(is_WEBP);
   180 }
   181 
   182 /* See if an image is contained in a data source */
   183 int IMG_isWEBP(SDL_RWops *src)
   184 {
   185 	return webp_getinfo( src, NULL );
   186 }
   187 
   188 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   189 {
   190 	int start;
   191 	const char *error = NULL;
   192 	SDL_Surface *volatile surface = NULL;
   193 	Uint32 Rmask;
   194 	Uint32 Gmask;
   195 	Uint32 Bmask;
   196 	Uint32 Amask;
   197 	WebPBitstreamFeatures features;
   198 	int raw_data_size;
   199 	uint8_t *raw_data = NULL;
   200 	int r;
   201 	uint8_t *ret;
   202 
   203 	if ( !src ) {
   204 		/* The error message has been set in SDL_RWFromFile */
   205 		return NULL;
   206 	}
   207 
   208 	start = SDL_RWtell(src);
   209 
   210 	if ( (IMG_Init(IMG_INIT_WEBP) & IMG_INIT_WEBP) == 0 ) {
   211 		goto error;
   212 	}
   213 
   214 	raw_data_size = -1;
   215 	if ( !webp_getinfo( src, &raw_data_size ) ) {
   216 		error = "Invalid WEBP";
   217 		goto error;
   218 	}
   219 
   220 	raw_data = (uint8_t*) malloc( raw_data_size );
   221 	if ( raw_data == NULL ) {
   222 		error = "Failed to allocate enough buffer for WEBP";
   223 		goto error;
   224 	}
   225 
   226 	r = SDL_RWread(src, raw_data, 1, raw_data_size );
   227 	if ( r != raw_data_size ) {
   228 		error = "Failed to read WEBP";
   229 		goto error;
   230 	}
   231 	
   232 #if 0
   233 	// extract size of picture, not interesting since we don't know about alpha channel
   234 	int width = -1, height = -1;
   235 	if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) {
   236 		printf("WebPGetInfo has failed\n" );
   237 		return NULL;
   238 	}
   239 #endif
   240 
   241 	if ( lib.webp_get_features_internal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
   242 		error = "WebPGetFeatures has failed";
   243 		goto error;
   244 	}
   245 
   246 	/* Check if it's ok !*/
   247 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   248 	Rmask = 0x000000FF;
   249 	Gmask = 0x0000FF00;
   250 	Bmask = 0x00FF0000;
   251 	Amask = (features.has_alpha) ? 0xFF000000 : 0;
   252 #else
   253 	{ int s = (features.has_alpha) ? 0 : 8;
   254 	Rmask = 0xFF000000 >> s;
   255 	Gmask = 0x00FF0000 >> s;
   256 	Bmask = 0x0000FF00 >> s;
   257 	Amask = 0x000000FF >> s;
   258 	}
   259 #endif
   260 
   261 	surface = SDL_AllocSurface(SDL_SWSURFACE, features.width, features.height,
   262 			features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask);
   263 
   264 	if ( surface == NULL ) {
   265 		error = "Failed to allocate SDL_Surface";
   266 		goto error;
   267 	}
   268 
   269 	if ( features.has_alpha ) {
   270 		ret = lib.webp_decode_rgba_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
   271 	} else {
   272 		ret = lib.webp_decode_rgb_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
   273 	}
   274 
   275 	if ( !ret ) {
   276 		error = "Failed to decode WEBP";
   277 		goto error;
   278 	}
   279 
   280 	if ( raw_data ) {
   281 		free( raw_data );
   282 	}
   283 
   284 	return surface;
   285 
   286 
   287 error:
   288 
   289 	if ( raw_data ) {
   290 		free( raw_data );
   291 	}
   292 
   293 	if ( surface ) {
   294 		SDL_FreeSurface( surface );
   295 	}
   296 
   297 	if ( error ) {
   298 		IMG_SetError( error );
   299 	}
   300 
   301 	SDL_RWseek(src, start, RW_SEEK_SET);
   302 	return(NULL);
   303 }
   304 
   305 #else
   306 
   307 int IMG_InitWEBP()
   308 {
   309 	IMG_SetError("WEBP images are not supported");
   310 	return(-1);
   311 }
   312 
   313 void IMG_QuitWEBP()
   314 {
   315 }
   316 
   317 /* See if an image is contained in a data source */
   318 int IMG_isWEBP(SDL_RWops *src)
   319 {
   320 	return(0);
   321 }
   322 
   323 /* Load a WEBP type image from an SDL datasource */
   324 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   325 {
   326 	return(NULL);
   327 }
   328 
   329 #endif /* LOAD_WEBP */