Michel Briand <michelbriand@free.fr>

mmap tga loader


SVN revision: 8987
This commit is contained in:
Carsten Haitzler 2004-02-16 03:46:39 +00:00
parent 6edd0ecd3b
commit 6a5dcff3a1
1 changed files with 45 additions and 53 deletions

View File

@ -18,6 +18,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h>
#ifndef X_DISPLAY_MISSING #ifndef X_DISPLAY_MISSING
# include <X11/Xlib.h> # include <X11/Xlib.h>
@ -213,56 +214,60 @@ char
load(ImlibImage * im, ImlibProgressFunction progress, load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load) char progress_granularity, char immediate_load)
{ {
FILE *fp; int fd;
void *seg, *filedata;
struct stat ss;
int bpp, vinverted = 0; int bpp, vinverted = 0;
int rle = 0, footer_present = 0; int rle = 0, footer_present = 0;
tga_header header; tga_header *header;
tga_footer footer; tga_footer *footer;
if (im->data) if (im->data)
return 0; return 0;
fp = fopen(im->real_file, "rb"); fd = open(im->real_file, O_RDONLY);
if (!fp) if (fd < 0)
return 0; return 0;
/* read the footer first */ if (fstat(fd, &ss) < 0)
fseek(fp, 0L - (sizeof(tga_footer)), SEEK_END);
if (fread(&footer, sizeof(tga_footer), 1, fp) != 1)
{ {
fclose(fp); close(fd);
return 0; return 0;
} }
seg = mmap(0, ss.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (seg == MAP_FAILED)
{
close(fd);
return 0;
}
filedata = seg;
header = (tga_header *) filedata;
footer = (tga_footer *) (filedata + ss.st_size - sizeof(tga_footer));
/* check the footer to see if we have a v2.0 TGA file */ /* check the footer to see if we have a v2.0 TGA file */
if (memcmp(footer.signature, TGA_SIGNATURE, sizeof(footer.signature)) == 0) if (memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature)) == 0)
footer_present = 1; footer_present = 1;
if (!footer_present) if (!footer_present)
{ {
} }
/* now read the header */ /* skip over header */
if (fseek(fp, 0, SEEK_SET) || fread(&header, sizeof(header), 1, fp) != 1) filedata += sizeof(tga_header);
{
fclose(fp);
return 0;
}
/* skip over alphanumeric ID field */ /* skip over alphanumeric ID field */
if (header.idLength && fseek(fp, header.idLength, SEEK_CUR)) if (header->idLength)
{ filedata += header->idLength;
fclose(fp);
return 0;
}
/* now parse the header */ /* now parse the header */
/* this flag indicated bottom-up pixel storage */ /* this flag indicated bottom-up pixel storage */
vinverted = !(header.descriptor & TGA_DESC_VERTICAL); vinverted = !(header->descriptor & TGA_DESC_VERTICAL);
switch (header.imageType) switch (header->imageType)
{ {
case TGA_TYPE_COLOR_RLE: case TGA_TYPE_COLOR_RLE:
case TGA_TYPE_GRAY_RLE: case TGA_TYPE_GRAY_RLE:
@ -275,27 +280,30 @@ load(ImlibImage * im, ImlibProgressFunction progress,
break; break;
default: default:
fclose(fp); munmap(seg, ss.st_size);
return 0; close(fd);
return 0;
} }
/* bits per pixel */ /* bits per pixel */
bpp = header.bpp; bpp = header->bpp;
if (!((bpp == 32) || (bpp == 24) || (bpp == 8))) if (!((bpp == 32) || (bpp == 24) || (bpp == 8)))
{ {
fclose(fp); munmap(seg, ss.st_size);
close(fd);
return 0; return 0;
} }
/* endian-safe loading of 16-bit sizes */ /* endian-safe loading of 16-bit sizes */
im->w = (header.widthHi << 8) | header.widthLo; im->w = (header->widthHi << 8) | header->widthLo;
im->h = (header.heightHi << 8) | header.heightLo; im->h = (header->heightHi << 8) | header->heightLo;
if ((im->w > 32767) || (im->w < 1) || (im->h > 32767) || (im->h < 1)) if ((im->w > 32767) || (im->w < 1) || (im->h > 32767) || (im->h < 1))
{ {
im->w = 0; im->w = 0;
fclose(fp); munmap(seg, ss.st_size);
close(fd);
return 0; return 0;
} }
@ -312,8 +320,7 @@ load(ImlibImage * im, ImlibProgressFunction progress,
if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) if (((!im->data) && (im->loader)) || (immediate_load) || (progress))
{ {
unsigned long datasize; unsigned long datasize;
struct stat ss; unsigned char *bufptr;
unsigned char *buf, *bufptr;
DATA32 *dataptr; DATA32 *dataptr;
int y, pl = 0; int y, pl = 0;
@ -324,7 +331,8 @@ load(ImlibImage * im, ImlibProgressFunction progress,
if (!im->data) if (!im->data)
{ {
im->w = 0; im->w = 0;
fclose(fp); munmap(seg, ss.st_size);
close(fd);
return 0; return 0;
} }
@ -334,29 +342,13 @@ load(ImlibImage * im, ImlibProgressFunction progress,
/* find out how much data must be read from the file */ /* find out how much data must be read from the file */
/* (this is NOT simply width*height*4, due to compression) */ /* (this is NOT simply width*height*4, due to compression) */
stat(im->real_file, &ss); datasize = ss.st_size - sizeof(tga_header) - header->idLength -
datasize = ss.st_size - sizeof(tga_header) - header.idLength -
(footer_present ? sizeof(tga_footer) : 0); (footer_present ? sizeof(tga_footer) : 0);
buf = malloc(datasize);
if (!buf)
{
im->w = 0;
fclose(fp);
return 0;
}
/* read in the pixel data */
if (fread(buf, 1, datasize, fp) != datasize)
{
fclose(fp);
return 0;
}
/* buffer is ready for parsing */ /* buffer is ready for parsing */
/* bufptr is the next byte to be read from the buffer */ /* bufptr is the next byte to be read from the buffer */
bufptr = buf; bufptr = filedata;
/* dataptr is the next 32-bit pixel to be filled in */ /* dataptr is the next 32-bit pixel to be filled in */
dataptr = im->data; dataptr = im->data;
@ -536,11 +528,11 @@ load(ImlibImage * im, ImlibProgressFunction progress,
} /* end for (each row) */ } /* end for (each row) */
} }
/* end if (image is RLE) */ /* end if (image is RLE) */
free(buf);
} }
/* end if (loading pixel data) */ /* end if (loading pixel data) */
fclose(fp); munmap(seg, ss.st_size);
close(fd);
return 1; return 1;
} }