IMG_pnm.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 /*
    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 */