IMG_pnm.c
author Ozkan Sezer <sezeroz@gmail.com>
Tue, 16 Oct 2018 20:02:02 +0300
branchSDL-1.2
changeset 607 1a1189c2978f
parent 280 ec4ae96c100c
permissions -rw-r--r--
backports of multiple bug fixes from 2.0:

3999783e (r340): bug 1413 - Fix image corruption when using ImageIO framework
5bf0f0d6 (r343), 326a6025 (r361): fixes from VS code analysis and code review
2742fe58 (r355), 1e7a55d7 (r356). dd40be56 (r358): support for webp on big endian systems
ce8091ca (r365): bug 1801 - typo in the xcf decoder, condition is always false
35beff02 (r369): bug 1831 - Memory leak issue in SDL_image-1.2.12/IMG_xpm.c file
1700d607 (r415): bug 1991 - XCF and LBM image loading [only the memory leak parts.]
e108e122 (r419): bug 2010 - Memory leaks in do_layer_surface function in IMG_xcf.c
7a360f7d (r436): bug 2295 - Memory leak in IMG_LoadWEBP_RW
ee17b8eb (r443): bug 2454 - Crash when loading some XPM files
bca82f1c (r476): proper fix for Bugzilla #2965.
fd721465 (r490): crash if some initialization succeeded and some didn't
915de300 (r492): bug 3474 - IMG_tif leaks memory on errors
b6f8fbe5 (r493): bug 3475 - Remove unnecessary loop from IMG_tif.c
d3e819a0 (r499): bug 2318 - h->cm_map resource getting leak in read_xcf_header function
1e32e1f4 (r503): bug 3008 - Compiler warnings: "warning: initialization discards 'const'
318484db (r513): security vulnerability in XCF image loader
181ef57f (r530): failing to reset the file pointer when detecting file types with ImageIO
16772bbb (r555): lbm: use correct variable to check color planes.
97f7f01e (r556): lbm: Fail to load images with unsupported/bogus color depth.
bfa08dc0 (r557): lbm: Don't overflow static colormap buffer.
a1e9b624 (r558): ico: reject obviously incorrect image sizes.
37445f61 (r559): bmp: don't overflow palette buffer with bogus biClrUsed values.
7df1580f (r560): xcf: deal with bogus data in rle tile decoding.
45e750f9 (r563): gif: report error on bogus LWZ data, instead of overflowing a buffer.
2938fc80 (r567): pcx: don't overflow buffer if bytes-per-line is less than image width.
c5f9cbb5 (r568): xcf: Prevent infinite loop and/or buffer overflow on bogus data.
fb643e37 (r569): xcf: check for some potential integer overflows.
170d7d32 (r585): potential buffer overflow on corrupt or maliciously-crafted XCF file.
19beb4a1 (r586): Don't get into infinite loops on truncated GIF files.
32a18ca0 (r587): Don't get into infinite loops on truncated PNM files.
8b4ee1d7 (r590): memory leak in IMG_xcf.c
90a531f2 (r591): PNM: Improve checks when loading a file
31263a04 (r592): XCF: check if there's sufficient data in the stream before allocating
cec9b759 (r593): More error checking, and null terminate strings...
     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 /*
    23  * PNM (portable anymap) image loader:
    24  *
    25  * Supports: PBM, PGM and PPM, ASCII and binary formats
    26  * (PBM and PGM are loaded as 8bpp surfaces)
    27  * Does not support: maximum component value > 255
    28  */
    29 
    30 #include <limits.h>
    31 #include <stdio.h>
    32 #include <stdlib.h>
    33 #include <ctype.h>
    34 #include <string.h>
    35 
    36 #include "SDL_image.h"
    37 
    38 #ifdef LOAD_PNM
    39 
    40 /* See if an image is contained in a data source */
    41 int IMG_isPNM(SDL_RWops *src)
    42 {
    43 	int start;
    44 	int is_PNM;
    45 	char magic[2];
    46 
    47 	if ( !src )
    48 		return 0;
    49 	start = SDL_RWtell(src);
    50 	is_PNM = 0;
    51 	if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
    52 		/*
    53 		 * PNM magic signatures:
    54 		 * P1	PBM, ascii format
    55 		 * P2	PGM, ascii format
    56 		 * P3	PPM, ascii format
    57 		 * P4	PBM, binary format
    58 		 * P5	PGM, binary format
    59 		 * P6	PPM, binary format
    60 		 * P7	PAM, a general wrapper for PNM data
    61 		 */
    62 		if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
    63 			is_PNM = 1;
    64 		}
    65 	}
    66 	SDL_RWseek(src, start, RW_SEEK_SET);
    67 	return(is_PNM);
    68 }
    69 
    70 /* read a non-negative integer from the source. return -1 upon error */
    71 static int ReadNumber(SDL_RWops *src)
    72 {
    73 	int number;
    74 	unsigned char ch;
    75 
    76 	/* Initialize return value */
    77 	number = 0;
    78 
    79 	/* Skip leading whitespace */
    80 	do {
    81 		if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    82 			return(-1);
    83 		}
    84 		/* Eat comments as whitespace */
    85 		if ( ch == '#' ) {  /* Comment is '#' to end of line */
    86 			do {
    87 				if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    88 					return -1;
    89 				}
    90 			} while ( (ch != '\r') && (ch != '\n') );
    91 		}
    92 	} while ( isspace(ch) );
    93 
    94 	/* Add up the number */
    95 	if (!isdigit(ch)) {
    96 		return -1;
    97 	}
    98 	do {
    99 		/* Protect from possible overflow */
   100 		if (number >= INT_MAX / 10) {
   101 			return -1;
   102 		}
   103 		number *= 10;
   104 		number += ch-'0';
   105 
   106 		if ( !SDL_RWread(src, &ch, 1, 1) ) {
   107 			return -1;
   108 		}
   109 	} while ( isdigit(ch) );
   110 
   111 	return(number);
   112 }
   113 
   114 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   115 {
   116 	int start;
   117 	SDL_Surface *surface = NULL;
   118 	int width, height;
   119 	int maxval, y, bpl;
   120 	Uint8 *row;
   121 	Uint8 *buf = NULL;
   122 	char *error = NULL;
   123 	Uint8 magic[2];
   124 	int ascii;
   125 	enum { PBM, PGM, PPM, PAM } kind;
   126 
   127 #define ERROR(s) do { error = (s); goto done; } while(0)
   128 
   129 	if ( !src ) {
   130 		/* The error message has been set in SDL_RWFromFile */
   131 		return NULL;
   132 	}
   133 	start = SDL_RWtell(src);
   134 
   135 	SDL_RWread(src, magic, 2, 1);
   136 	kind = magic[1] - '1';
   137 	ascii = 1;
   138 	if(kind >= 3) {
   139 		ascii = 0;
   140 		kind -= 3;
   141 	}
   142 
   143 	width = ReadNumber(src);
   144 	height = ReadNumber(src);
   145 	if(width <= 0 || height <= 0)
   146 		ERROR("Unable to read image width and height");
   147 
   148 	if(kind != PBM) {
   149 		maxval = ReadNumber(src);
   150 		if(maxval <= 0 || maxval > 255)
   151 			ERROR("unsupported PNM format");
   152 	} else
   153 		maxval = 255;	/* never scale PBMs */
   154 
   155 	/* binary PNM allows just a single character of whitespace after
   156 	   the last parameter, and we've already consumed it */
   157 
   158 	if(kind == PPM) {
   159 		/* 24-bit surface in R,G,B byte order */
   160 		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
   161 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   162 					   0x000000ff, 0x0000ff00, 0x00ff0000,
   163 #else
   164 					   0x00ff0000, 0x0000ff00, 0x000000ff,
   165 #endif
   166 					   0);
   167 	} else {
   168 		/* load PBM/PGM as 8-bit indexed images */
   169 		surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
   170 					   0, 0, 0, 0);
   171 	}
   172 	if ( surface == NULL )
   173 		ERROR("Out of memory");
   174 	bpl = width * surface->format->BytesPerPixel;
   175 	if(kind == PGM) {
   176 		SDL_Color *c = surface->format->palette->colors;
   177 		int i;
   178 		for(i = 0; i < 256; i++)
   179 			c[i].r = c[i].g = c[i].b = i;
   180 		surface->format->palette->ncolors = 256;
   181 	} else if(kind == PBM) {
   182 		/* for some reason PBM has 1=black, 0=white */
   183 		SDL_Color *c = surface->format->palette->colors;
   184 		c[0].r = c[0].g = c[0].b = 255;
   185 		c[1].r = c[1].g = c[1].b = 0;
   186 		surface->format->palette->ncolors = 2;
   187 		bpl = (width + 7) >> 3;
   188 		buf = (Uint8 *)malloc(bpl);
   189 		if(buf == NULL)
   190 			ERROR("Out of memory");
   191 	}
   192 
   193 	/* Read the image into the surface */
   194 	row = (Uint8 *)surface->pixels;
   195 	for(y = 0; y < height; y++) {
   196 		if(ascii) {
   197 			int i;
   198 			if(kind == PBM) {
   199 				for(i = 0; i < width; i++) {
   200 					Uint8 ch;
   201 					do {
   202 						if(!SDL_RWread(src, &ch,
   203 							       1, 1))
   204 						       ERROR("file truncated");
   205 						ch -= '0';
   206 					} while(ch > 1);
   207 					row[i] = ch;
   208 				}
   209 			} else {
   210 				for(i = 0; i < bpl; i++) {
   211 					int c;
   212 					c = ReadNumber(src);
   213 					if(c < 0)
   214 						ERROR("file truncated");
   215 					row[i] = c;
   216 				}
   217 			}
   218 		} else {
   219 			Uint8 *dst = (kind == PBM) ? buf : row;
   220 			if(!SDL_RWread(src, dst, bpl, 1))
   221 				ERROR("file truncated");
   222 			if(kind == PBM) {
   223 				/* expand bitmap to 8bpp */
   224 				int i;
   225 				for(i = 0; i < width; i++) {
   226 					int bit = 7 - (i & 7);
   227 					row[i] = (buf[i >> 3] >> bit) & 1;
   228 				}
   229 			}
   230 		}
   231 		if(maxval < 255) {
   232 			/* scale up to full dynamic range (slow) */
   233 			int i;
   234 			for(i = 0; i < bpl; i++)
   235 				row[i] = row[i] * 255 / maxval;
   236 		}
   237 		row += surface->pitch;
   238 	}
   239 done:
   240 	free(buf);
   241 	if(error) {
   242 		SDL_RWseek(src, start, RW_SEEK_SET);
   243 		if ( surface ) {
   244 			SDL_FreeSurface(surface);
   245 			surface = NULL;
   246 		}
   247 		IMG_SetError(error);
   248 	}
   249 	return(surface);
   250 }
   251 
   252 #else
   253 
   254 /* See if an image is contained in a data source */
   255 int IMG_isPNM(SDL_RWops *src)
   256 {
   257 	return(0);
   258 }
   259 
   260 /* Load a PNM type image from an SDL datasource */
   261 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   262 {
   263 	return(NULL);
   264 }
   265 
   266 #endif /* LOAD_PNM */