xref: /PHP-8.4/ext/gd/libgd/gd_xbm.c (revision 01b3fc03)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Marcus Boerger <helly@php.net>                               |
14    +----------------------------------------------------------------------+
15  */
16 
17 /* $Id$ */
18 
19 #include <stdio.h>
20 #include <math.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include "gd.h"
24 #include "gdhelpers.h"
25 #include "gd_errors.h"
26 
27 #include "php.h"
28 
29 #define MAX_XBM_LINE_SIZE 255
30 
31 /* {{{ gdImagePtr gdImageCreateFromXbm */
gdImageCreateFromXbm(FILE * fd)32 gdImagePtr gdImageCreateFromXbm(FILE * fd)
33 {
34 	char fline[MAX_XBM_LINE_SIZE];
35 	char iname[MAX_XBM_LINE_SIZE];
36 	char *type;
37 	int value;
38 	unsigned int width = 0, height = 0;
39 	int fail = 0;
40 	int max_bit = 0;
41 
42 	gdImagePtr im;
43 	int bytes = 0, i;
44 	int bit, x = 0, y = 0;
45 	int ch;
46 	char h[8];
47 	unsigned int b;
48 
49 	rewind(fd);
50 	while (fgets(fline, MAX_XBM_LINE_SIZE, fd)) {
51 		fline[MAX_XBM_LINE_SIZE-1] = '\0';
52 		if (strlen(fline) == MAX_XBM_LINE_SIZE-1) {
53 			return 0;
54 		}
55 		if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
56 			if (!(type = strrchr(iname, '_'))) {
57 				type = iname;
58 			} else {
59 				type++;
60 			}
61 
62 			if (!strcmp("width", type)) {
63 				width = (unsigned int) value;
64 			}
65 			if (!strcmp("height", type)) {
66 				height = (unsigned int) value;
67 			}
68 		} else {
69 			if ( sscanf(fline, "static unsigned char %s = {", iname) == 1
70 			  || sscanf(fline, "static char %s = {", iname) == 1)
71 			{
72 				max_bit = 128;
73 			} else if (sscanf(fline, "static unsigned short %s = {", iname) == 1
74 					|| sscanf(fline, "static short %s = {", iname) == 1)
75 			{
76 				max_bit = 32768;
77 			}
78 			if (max_bit) {
79 				bytes = (width + 7) / 8 * height;
80 				if (!bytes) {
81 					return 0;
82 				}
83 				if (!(type = strrchr(iname, '_'))) {
84 					type = iname;
85 				} else {
86 					type++;
87 				}
88 				if (!strcmp("bits[]", type)) {
89 					break;
90 				}
91 			}
92  		}
93 	}
94 	if (!bytes || !max_bit) {
95 		return 0;
96 	}
97 
98 	if(!(im = gdImageCreate(width, height))) {
99 		return 0;
100 	}
101 	gdImageColorAllocate(im, 255, 255, 255);
102 	gdImageColorAllocate(im, 0, 0, 0);
103 	h[2] = '\0';
104 	h[4] = '\0';
105 	for (i = 0; i < bytes; i++) {
106 		while (1) {
107 			if ((ch=getc(fd)) == EOF) {
108 				fail = 1;
109 				break;
110 			}
111 			if (ch == 'x') {
112 				break;
113 			}
114 		}
115 		if (fail) {
116 			break;
117 		}
118 		/* Get hex value */
119 		if ((ch=getc(fd)) == EOF) {
120 			break;
121 		}
122 		h[0] = ch;
123 		if ((ch=getc(fd)) == EOF) {
124 			break;
125 		}
126 		h[1] = ch;
127 		if (max_bit == 32768) {
128 			if ((ch=getc(fd)) == EOF) {
129 				break;
130 			}
131 			h[2] = ch;
132 			if ((ch=getc(fd)) == EOF) {
133 				break;
134 			}
135 			h[3] = ch;
136 		}
137 		if (sscanf(h, "%x", &b) != 1) {
138 			gd_error("Invalid XBM");
139 			gdImageDestroy(im);
140 			return 0;
141 		}
142 		for (bit = 1; bit <= max_bit; bit = bit << 1) {
143 			gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
144 			if (x == im->sx) {
145 				x = 0;
146 				y++;
147 				if (y == im->sy) {
148 					return im;
149 				}
150 				break;
151 			}
152 		}
153 	}
154 
155 	gd_error("EOF before image was complete");
156 	gdImageDestroy(im);
157 	return 0;
158 }
159 /* }}} */
160 
161 /* {{{ gdCtxPrintf */
gdCtxPrintf(gdIOCtx * out,const char * format,...)162 void gdCtxPrintf(gdIOCtx * out, const char *format, ...)
163 {
164 	char *buf;
165 	int len;
166 	va_list args;
167 
168 	va_start(args, format);
169 	len = vspprintf(&buf, 0, format, args);
170 	va_end(args);
171 	out->putBuf(out, buf, len);
172 	efree(buf);
173 }
174 /* }}} */
175 
176 /* {{{ gdImageXbmCtx */
gdImageXbmCtx(gdImagePtr image,char * file_name,int fg,gdIOCtx * out)177 void gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtx * out)
178 {
179 	int x, y, c, b, sx, sy, p;
180 	char *name, *f;
181 	size_t i, l;
182 
183 	name = file_name;
184 	if ((f = strrchr(name, '/')) != NULL) name = f+1;
185 	if ((f = strrchr(name, '\\')) != NULL) name = f+1;
186 	name = estrdup(name);
187 	if ((f = strrchr(name, '.')) != NULL && !strcasecmp(f, ".XBM")) *f = '\0';
188 	if ((l = strlen(name)) == 0) {
189 		efree(name);
190 		name = estrdup("image");
191 	} else {
192 		for (i=0; i<l; i++) {
193 			/* only in C-locale isalnum() would work */
194 			if (!isupper(name[i]) && !islower(name[i]) && !isdigit(name[i])) {
195 				name[i] = '_';
196 			}
197 		}
198 	}
199 
200 	gdCtxPrintf(out, "#define %s_width %d\n", name, gdImageSX(image));
201 	gdCtxPrintf(out, "#define %s_height %d\n", name, gdImageSY(image));
202 	gdCtxPrintf(out, "static unsigned char %s_bits[] = {\n  ", name);
203 
204 	efree(name);
205 
206 	b = 1;
207 	p = 0;
208 	c = 0;
209 	sx = gdImageSX(image);
210 	sy = gdImageSY(image);
211 	for (y = 0; y < sy; y++) {
212 		for (x = 0; x < sx; x++) {
213 			if (gdImageGetPixel(image, x, y) == fg) {
214 				c |= b;
215 			}
216 			if ((b == 128) || (x == sx - 1)) {
217 				b = 1;
218 				if (p) {
219 					gdCtxPrintf(out, ", ");
220 					if (!(p%12)) {
221 						gdCtxPrintf(out, "\n  ");
222 						p = 12;
223 					}
224 				}
225 				p++;
226 				gdCtxPrintf(out, "0x%02X", c);
227 				c = 0;
228 			} else {
229 				b <<= 1;
230 			}
231 		}
232 	}
233 	gdCtxPrintf(out, "};\n");
234 }
235 /* }}} */
236