php-src/ext/gd/libgd/xbm.c
Christoph M. Becker f67d599a01 Fix #73968: Premature failing of XBM reading
We must take into account the line padding, when we're reading XBM
files.

We deliberately ignore the potential integer overflow here, because
that would be caught by gdImageCreate() or even earlier if `bytes==0`,
what happens in libgd00094.phpt which we adapt accordingly.
2017-01-21 13:04:36 +01:00

242 lines
5.3 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "gd.h"
#include "gdhelpers.h"
#include "php.h"
#define MAX_XBM_LINE_SIZE 255
/* {{{ gdImagePtr gdImageCreateFromXbm */
gdImagePtr gdImageCreateFromXbm(FILE * fd)
{
char fline[MAX_XBM_LINE_SIZE];
char iname[MAX_XBM_LINE_SIZE];
char *type;
int value;
unsigned int width = 0, height = 0;
int fail = 0;
int max_bit = 0;
gdImagePtr im;
int bytes = 0, i;
int bit, x = 0, y = 0;
int ch;
char h[8];
unsigned int b;
rewind(fd);
while (fgets(fline, MAX_XBM_LINE_SIZE, fd)) {
fline[MAX_XBM_LINE_SIZE-1] = '\0';
if (strlen(fline) == MAX_XBM_LINE_SIZE-1) {
return 0;
}
if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
if (!(type = strrchr(iname, '_'))) {
type = iname;
} else {
type++;
}
if (!strcmp("width", type)) {
width = (unsigned int) value;
}
if (!strcmp("height", type)) {
height = (unsigned int) value;
}
} else {
if ( sscanf(fline, "static unsigned char %s = {", iname) == 1
|| sscanf(fline, "static char %s = {", iname) == 1)
{
max_bit = 128;
} else if (sscanf(fline, "static unsigned short %s = {", iname) == 1
|| sscanf(fline, "static short %s = {", iname) == 1)
{
max_bit = 32768;
}
if (max_bit) {
bytes = (width + 7) / 8 * height;
if (!bytes) {
return 0;
}
if (!(type = strrchr(iname, '_'))) {
type = iname;
} else {
type++;
}
if (!strcmp("bits[]", type)) {
break;
}
}
}
}
if (!bytes || !max_bit) {
return 0;
}
if(!(im = gdImageCreate(width, height))) {
return 0;
}
gdImageColorAllocate(im, 255, 255, 255);
gdImageColorAllocate(im, 0, 0, 0);
h[2] = '\0';
h[4] = '\0';
for (i = 0; i < bytes; i++) {
while (1) {
if ((ch=getc(fd)) == EOF) {
fail = 1;
break;
}
if (ch == 'x') {
break;
}
}
if (fail) {
break;
}
/* Get hex value */
if ((ch=getc(fd)) == EOF) {
break;
}
h[0] = ch;
if ((ch=getc(fd)) == EOF) {
break;
}
h[1] = ch;
if (max_bit == 32768) {
if ((ch=getc(fd)) == EOF) {
break;
}
h[2] = ch;
if ((ch=getc(fd)) == EOF) {
break;
}
h[3] = ch;
}
sscanf(h, "%x", &b);
for (bit = 1; bit <= max_bit; bit = bit << 1) {
gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
if (x == im->sx) {
x = 0;
y++;
if (y == im->sy) {
return im;
}
break;
}
}
}
php_gd_error("EOF before image was complete");
gdImageDestroy(im);
return 0;
}
/* }}} */
/* {{{ gdCtxPrintf */
void gdCtxPrintf(gdIOCtx * out, const char *format, ...)
{
char *buf;
int len;
va_list args;
va_start(args, format);
len = vspprintf(&buf, 0, format, args);
va_end(args);
out->putBuf(out, buf, len);
efree(buf);
}
/* }}} */
/* {{{ gdImageXbmCtx */
void gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtx * out)
{
int x, y, c, b, sx, sy, p;
char *name, *f;
size_t i, l;
name = file_name;
if ((f = strrchr(name, '/')) != NULL) name = f+1;
if ((f = strrchr(name, '\\')) != NULL) name = f+1;
name = estrdup(name);
if ((f = strrchr(name, '.')) != NULL && !strcasecmp(f, ".XBM")) *f = '\0';
if ((l = strlen(name)) == 0) {
efree(name);
name = estrdup("image");
} else {
for (i=0; i<l; i++) {
/* only in C-locale isalnum() would work */
if (!isupper(name[i]) && !islower(name[i]) && !isdigit(name[i])) {
name[i] = '_';
}
}
}
gdCtxPrintf(out, "#define %s_width %d\n", name, gdImageSX(image));
gdCtxPrintf(out, "#define %s_height %d\n", name, gdImageSY(image));
gdCtxPrintf(out, "static unsigned char %s_bits[] = {\n ", name);
efree(name);
b = 1;
p = 0;
c = 0;
sx = gdImageSX(image);
sy = gdImageSY(image);
for (y = 0; y < sy; y++) {
for (x = 0; x < sx; x++) {
if (gdImageGetPixel(image, x, y) == fg) {
c |= b;
}
if ((b == 128) || (x == sx - 1)) {
b = 1;
if (p) {
gdCtxPrintf(out, ", ");
if (!(p%12)) {
gdCtxPrintf(out, "\n ");
p = 12;
}
}
p++;
gdCtxPrintf(out, "0x%02X", c);
c = 0;
} else {
b <<= 1;
}
}
}
gdCtxPrintf(out, "};\n");
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/