IMG_tga.c
author Thomas Bernard <miniupnp@free.fr>
Fri, 30 Nov 2018 11:04:15 +0100
branchSDL-1.2
changeset 634 68f958f43339
parent 607 1a1189c2978f
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 #if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
    23 
    24 /* This is a Targa image file loading framework */
    25 
    26 #include <stdlib.h>
    27 #include <stdio.h>
    28 #include <string.h>
    29 
    30 #include "SDL_endian.h"
    31 
    32 #include "SDL_image.h"
    33 
    34 #ifdef LOAD_TGA
    35 
    36 /*
    37  * A TGA loader for the SDL library
    38  * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey,
    39  *           uncompressed or RLE encoded.
    40  *
    41  * 2000-06-10 Mattias Engdegård <f91-men@nada.kth.se>: initial version
    42  * 2000-06-26 Mattias Engdegård <f91-men@nada.kth.se>: read greyscale TGAs
    43  * 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
    44  */
    45 
    46 struct TGAheader {
    47     Uint8 infolen;		/* length of info field */
    48     Uint8 has_cmap;		/* 1 if image has colormap, 0 otherwise */
    49     Uint8 type;
    50 
    51     Uint8 cmap_start[2];	/* index of first colormap entry */
    52     Uint8 cmap_len[2];		/* number of entries in colormap */
    53     Uint8 cmap_bits;		/* bits per colormap entry */
    54 
    55     Uint8 yorigin[2];		/* image origin (ignored here) */
    56     Uint8 xorigin[2];
    57     Uint8 width[2];		/* image size */
    58     Uint8 height[2];
    59     Uint8 pixel_bits;		/* bits/pixel */
    60     Uint8 flags;
    61 };
    62 
    63 enum tga_type {
    64     TGA_TYPE_INDEXED = 1,
    65     TGA_TYPE_RGB = 2,
    66     TGA_TYPE_BW = 3,
    67     TGA_TYPE_RLE_INDEXED = 9,
    68     TGA_TYPE_RLE_RGB = 10,
    69     TGA_TYPE_RLE_BW = 11
    70 };
    71 
    72 #define TGA_INTERLEAVE_MASK	0xc0
    73 #define TGA_INTERLEAVE_NONE	0x00
    74 #define TGA_INTERLEAVE_2WAY	0x40
    75 #define TGA_INTERLEAVE_4WAY	0x80
    76 
    77 #define TGA_ORIGIN_MASK		0x30
    78 #define TGA_ORIGIN_LEFT		0x00
    79 #define TGA_ORIGIN_RIGHT	0x10
    80 #define TGA_ORIGIN_LOWER	0x00
    81 #define TGA_ORIGIN_UPPER	0x20
    82 
    83 /* read/write unaligned little-endian 16-bit ints */
    84 #define LE16(p) ((p)[0] + ((p)[1] << 8))
    85 #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8)
    86 
    87 /* Load a TGA type image from an SDL datasource */
    88 SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
    89 {
    90     int start;
    91     const char *error = NULL;
    92     struct TGAheader hdr;
    93     int rle = 0;
    94     int alpha = 0;
    95     int indexed = 0;
    96     int grey = 0;
    97     int ckey = -1;
    98     int ncols, w, h;
    99     SDL_Surface *img = NULL;
   100     Uint32 rmask, gmask, bmask, amask;
   101     Uint8 *dst;
   102     int i;
   103     int bpp;
   104     int lstep;
   105     Uint32 pixel;
   106     int count, rep;
   107 
   108     if ( !src ) {
   109         /* The error message has been set in SDL_RWFromFile */
   110         return NULL;
   111     }
   112     start = SDL_RWtell(src);
   113 
   114     if(!SDL_RWread(src, &hdr, sizeof(hdr), 1)) {
   115         error = "Error reading TGA data";
   116 	goto error;
   117     }
   118     ncols = LE16(hdr.cmap_len);
   119     switch(hdr.type) {
   120     case TGA_TYPE_RLE_INDEXED:
   121 	rle = 1;
   122 	/* fallthrough */
   123     case TGA_TYPE_INDEXED:
   124 	if(!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
   125 	    goto unsupported;
   126 	indexed = 1;
   127 	break;
   128 
   129     case TGA_TYPE_RLE_RGB:
   130 	rle = 1;
   131 	/* fallthrough */
   132     case TGA_TYPE_RGB:
   133 	indexed = 0;
   134 	break;
   135 
   136     case TGA_TYPE_RLE_BW:
   137 	rle = 1;
   138 	/* fallthrough */
   139     case TGA_TYPE_BW:
   140 	if(hdr.pixel_bits != 8)
   141 	    goto unsupported;
   142 	/* Treat greyscale as 8bpp indexed images */
   143 	indexed = grey = 1;
   144 	break;
   145 
   146     default:
   147         goto unsupported;
   148     }
   149 
   150     bpp = (hdr.pixel_bits + 7) >> 3;
   151     rmask = gmask = bmask = amask = 0;
   152     switch(hdr.pixel_bits) {
   153     case 8:
   154 	if(!indexed) {
   155             goto unsupported;
   156 	}
   157 	break;
   158 
   159     case 15:
   160     case 16:
   161 	/* 15 and 16bpp both seem to use 5 bits/plane. The extra alpha bit
   162 	   is ignored for now. */
   163 	rmask = 0x7c00;
   164 	gmask = 0x03e0;
   165 	bmask = 0x001f;
   166 	break;
   167 
   168     case 32:
   169 	alpha = 1;
   170 	/* fallthrough */
   171     case 24:
   172 	if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
   173 	    int s = alpha ? 0 : 8;
   174 	    amask = 0x000000ff >> s;
   175 	    rmask = 0x0000ff00 >> s;
   176 	    gmask = 0x00ff0000 >> s;
   177 	    bmask = 0xff000000 >> s;
   178 	} else {
   179 	    amask = alpha ? 0xff000000 : 0;
   180 	    rmask = 0x00ff0000;
   181 	    gmask = 0x0000ff00;
   182 	    bmask = 0x000000ff;
   183 	}
   184 	break;
   185 
   186     default:
   187         goto unsupported;
   188     }
   189 
   190     if((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
   191        || hdr.flags & TGA_ORIGIN_RIGHT) {
   192         goto unsupported;
   193     }
   194     
   195     SDL_RWseek(src, hdr.infolen, RW_SEEK_CUR); /* skip info field */
   196 
   197     w = LE16(hdr.width);
   198     h = LE16(hdr.height);
   199     img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
   200 			       bpp * 8,
   201 			       rmask, gmask, bmask, amask);
   202     if(img == NULL) {
   203         error = "Out of memory";
   204         goto error;
   205     }
   206 
   207     if(hdr.has_cmap) {
   208 	int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3);
   209 	if(indexed && !grey) {
   210 	    Uint8 *pal = (Uint8 *)malloc(palsiz), *p = pal;
   211 	    SDL_Color *colors = img->format->palette->colors;
   212 	    img->format->palette->ncolors = ncols;
   213 	    SDL_RWread(src, pal, palsiz, 1);
   214 	    for(i = 0; i < ncols; i++) {
   215 		switch(hdr.cmap_bits) {
   216 		case 15:
   217 		case 16:
   218 		    {
   219 			Uint16 c = p[0] + (p[1] << 8);
   220 			p += 2;
   221 			colors[i].r = (c >> 7) & 0xf8;
   222 			colors[i].g = (c >> 2) & 0xf8;
   223 			colors[i].b = c << 3;
   224 		    }
   225 		    break;
   226 		case 24:
   227 		case 32:
   228 		    colors[i].b = *p++;
   229 		    colors[i].g = *p++;
   230 		    colors[i].r = *p++;
   231 		    if(hdr.cmap_bits == 32 && *p++ < 128)
   232 			ckey = i;
   233 		    break;
   234 		}
   235 	    }
   236 	    free(pal);
   237 	    if(ckey >= 0)
   238 		SDL_SetColorKey(img, SDL_SRCCOLORKEY, ckey);
   239 	} else {
   240 	    /* skip unneeded colormap */
   241 	    SDL_RWseek(src, palsiz, RW_SEEK_CUR);
   242 	}
   243     }
   244 
   245     if(grey) {
   246 	SDL_Color *colors = img->format->palette->colors;
   247 	for(i = 0; i < 256; i++)
   248 	    colors[i].r = colors[i].g = colors[i].b = i;
   249 	img->format->palette->ncolors = 256;
   250     }
   251 
   252     if(hdr.flags & TGA_ORIGIN_UPPER) {
   253 	lstep = img->pitch;
   254 	dst = (Uint8 *)img->pixels;
   255     } else {
   256 	lstep = -img->pitch;
   257 	dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
   258     }
   259 
   260     /* The RLE decoding code is slightly convoluted since we can't rely on
   261        spans not to wrap across scan lines */
   262     count = rep = 0;
   263     for(i = 0; i < h; i++) {
   264 	if(rle) {
   265 	    int x = 0;
   266 	    for(;;) {
   267 		Uint8 c;
   268 
   269 		if(count) {
   270 		    int n = count;
   271 		    if(n > w - x)
   272 			n = w - x;
   273 		    SDL_RWread(src, dst + x * bpp, n * bpp, 1);
   274 		    count -= n;
   275 		    x += n;
   276 		    if(x == w)
   277 			break;
   278 		} else if(rep) {
   279 		    int n = rep;
   280 		    if(n > w - x)
   281 			n = w - x;
   282 		    rep -= n;
   283 		    while(n--) {
   284 			memcpy(dst + x * bpp, &pixel, bpp);
   285 			x++;
   286 		    }
   287 		    if(x == w)
   288 			break;
   289 		}
   290 
   291 		SDL_RWread(src, &c, 1, 1);
   292 		if(c & 0x80) {
   293 		    SDL_RWread(src, &pixel, bpp, 1);
   294 		    rep = (c & 0x7f) + 1;
   295 		} else {
   296 		    count = c + 1;
   297 		}
   298 	    }
   299 
   300 	} else {
   301 	    SDL_RWread(src, dst, w * bpp, 1);
   302 	}
   303 	if(SDL_BYTEORDER == SDL_BIG_ENDIAN && bpp == 2) {
   304 	    /* swap byte order */
   305 	    int x;
   306 	    Uint16 *p = (Uint16 *)dst;
   307 	    for(x = 0; x < w; x++)
   308 		p[x] = SDL_Swap16(p[x]);
   309 	}
   310 	dst += lstep;
   311     }
   312     return img;
   313 
   314 unsupported:
   315     error = "Unsupported TGA format";
   316 
   317 error:
   318     SDL_RWseek(src, start, RW_SEEK_SET);
   319     if ( img ) {
   320         SDL_FreeSurface(img);
   321     }
   322     IMG_SetError(error);
   323     return NULL;
   324 }
   325 
   326 #else
   327 
   328 /* dummy TGA load routine */
   329 SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
   330 {
   331 	return(NULL);
   332 }
   333 
   334 #endif /* LOAD_TGA */
   335 
   336 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */