slouken@libsdl.org
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "SDL_image.h"
#ifdef LOAD_PNM
int IMG_isPNM(SDL_RWops *src)
{
char magic[2];
return (SDL_RWread(src, magic, 2, 1)
&& magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6');
}
static int ReadNumber(SDL_RWops *src)
{
int number;
unsigned char ch;
number = 0;
do {
if ( ! SDL_RWread(src, &ch, 1, 1) ) {
return(0);
}
if ( ch == '#' ) {
do {
if ( ! SDL_RWread(src, &ch, 1, 1) ) {
return -1;
}
} while ( (ch != '\r') && (ch != '\n') );
}
} while ( isspace(ch) );
do {
number *= 10;
number += ch-'0';
if ( !SDL_RWread(src, &ch, 1, 1) ) {
return -1;
}
} while ( isdigit(ch) );
return(number);
}
SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
{
SDL_Surface *surface = NULL;
int width, height;
int maxval, y, bpl;
Uint8 *row;
Uint8 *buf = NULL;
char *error = NULL;
Uint8 magic[2];
int ascii;
enum { PBM, PGM, PPM } kind;
#define ERROR(s) do { error = (s); goto done; } while(0)
if ( !src ) {
return NULL;
}
SDL_RWread(src, magic, 2, 1);
kind = magic[1] - '1';
ascii = 1;
if(kind >= 3) {
ascii = 0;
kind -= 3;
}
width = ReadNumber(src);
height = ReadNumber(src);
if(width <= 0 || height <= 0)
ERROR("Unable to read image width and height");
if(kind != PBM) {
maxval = ReadNumber(src);
if(maxval <= 0 || maxval > 255)
ERROR("unsupported PNM format");
} else
maxval = 255;
if(kind == PPM) {
surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x000000ff, 0x0000ff00, 0x00ff0000,
#else
0x00ff0000, 0x0000ff00, 0x000000ff,
#endif
0);
} else {
surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8,
0, 0, 0, 0);
}
if ( surface == NULL )
ERROR("Out of memory");
bpl = width * surface->format->BytesPerPixel;
if(kind == PGM) {
SDL_Color *c = surface->format->palette->colors;
int i;
for(i = 0; i < 256; i++)
c[i].r = c[i].g = c[i].b = i;
surface->format->palette->ncolors = 256;
} else if(kind == PBM) {
SDL_Color *c = surface->format->palette->colors;
c[0].r = c[0].g = c[0].b = 255;
c[1].r = c[1].g = c[1].b = 0;
surface->format->palette->ncolors = 2;
bpl = (width + 7) >> 3;
buf = malloc(bpl);
if(buf == NULL)
ERROR("Out of memory");
}
row = surface->pixels;
for(y = 0; y < height; y++) {
if(ascii) {
int i;
if(kind == PBM) {
for(i = 0; i < width; i++) {
Uint8 ch;
do {
if(!SDL_RWread(src, &ch,
1, 1))
ERROR("file truncated");
ch -= '0';
} while(ch > 1);
row[i] = ch;
}
} else {
for(i = 0; i < bpl; i++) {
int c;
c = ReadNumber(src);
if(c < 0)
ERROR("file truncated");
row[i] = c;
}
}
} else {
Uint8 *dst = (kind == PBM) ? buf : row;
if(!SDL_RWread(src, dst, bpl, 1))
ERROR("file truncated");
if(kind == PBM) {
int i;
for(i = 0; i < width; i++) {
int bit = 7 - (i & 7);
row[i] = (buf[i >> 3] >> bit) & 1;
}
}
}
if(maxval < 255) {
int i;
for(i = 0; i < bpl; i++)
row[i] = row[i] * 255 / maxval;
}
row += surface->pitch;
}
done:
free(buf);
if(error) {
SDL_FreeSurface(surface);
IMG_SetError(error);
surface = NULL;
}
return(surface);
}
#else
int IMG_isPNM(SDL_RWops *src)
{
return(0);
}
SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
{
return(NULL);
}
#endif