1 
2 /*
3  *  Diverse Bristol audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 
29 #include "brightoninternals.h"
30 
31 static int hex2num(char);
32 static int xpmchar2num(brightonBitmap *,char);
33 static int convertindex(brightonBitmap *, char *, int);
34 static int convertcolor(char *);
35 
36 extern void brightonSprintColor(brightonWindow *, char *, int);
37 
38 #define BUFSIZE 8192
39 
40 #define CTAB_SIZE 2048
41 
42 /*
43  * In the next peice of code we are calling brightonfopen(), brightonfgets()
44  * and brightonfclose(), these are empty stubs that would get removed at
45  * -O3 or so however I have used them at times for debugging heap corruption
46  * and the overhead is minimal and only affects startup, not runtime.
47  */
48 brightonBitmap *
xpmread(brightonWindow * bwin,char * filename)49 xpmread(brightonWindow *bwin, char *filename)
50 {
51 	int color, width = 0, height = 0, colors = 0, bpcolor = 0, i = 1, j;
52 	int innerstatic = -1, outerstatic = -1;
53 	FILE *fd;
54 	char line[BUFSIZE];
55 	int *colormap;
56 	brightonBitmap *bitmap;
57 
58 	/*
59 	 * This code was added to allow using compressed images reducing the size
60 	 * of the installation to about 1/5th. It spools the gz to /tmp if the xpm
61 	 * is not found and gunzips.
62 	 */
63 	if ((fd = brightonfopen(filename, "r")) == (FILE *) NULL)
64 	{
65 		int status;
66 		char tfn[256];;
67 		pid_t child;
68 		char *params[10];
69 
70 		sprintf(line, "%s.gz", filename);
71 		sprintf(tfn, "/tmp/bbm_%i.xpm.gz", getpid());
72 
73 		if ((fd = brightonfopen(line, "r")) == (FILE *) NULL)
74 			return(NULL);
75 
76 		brightonfclose(fd);
77 
78 		if ((child = fork()) == 0)
79 		{
80 			params[0] = "cp";
81 			params[1] = "-f";
82 			params[2] = line;
83 			params[3] = tfn;
84 			params[4] = NULL;
85 			if ((child = execvp("cp", params)) < 0) {
86 				printf("\nCannot spool the compressed source bitmap\n\n");
87 			}
88 			exit(1);
89 		} else
90 			waitpid(child, &status, 0);
91 
92 		if (status) {
93 			printf("Error copying %s to %s: %i\n", line, tfn, status);
94 			exit(1);
95 		}
96 
97 		if ((child = fork()) == 0)
98 		{
99 			params[0] = "gunzip";
100 			params[1] = "-f";
101 			params[2] = tfn;
102 			params[3] = NULL;
103 			if ((child = execvp("gunzip", params)) < 0) {
104 				printf("\nCannot finding the gunzip binary, install it or ");
105 				printf("email author for an\nalternative resolution\n\n");
106 			}
107 			exit(1);
108 		} else
109 			waitpid(child, &status, 0);
110 
111 		if (status)
112 			exit(1);
113 
114 		unlink(tfn); /* unlink the zipped file - on error may exist */
115 		sprintf(tfn, "/tmp/bbm_%i.xpm", getpid());
116 
117 		if ((fd = brightonfopen(tfn, "r")) == (FILE *) NULL)
118 		{
119 			unlink(tfn);
120 			return(NULL);
121 		}
122 
123 		unlink(tfn);
124 	}
125 
126 	/* printf("xpmread(\"%s\")\n", filename); */
127 
128 	while ((brightonfgets(line, BUFSIZE, fd)) != 0)
129 	{
130 		/*
131 		 * We are looking for numbers:
132 		 */
133 		if (!isdigit(line[1]))
134 			continue;
135 		else {
136 			/*
137 			 * Should be able to get width, height, colors and planes from this
138 			 * line of text.
139 			 */
140 			while (isdigit(line[i]))
141 				width = width * 10 + line[i++] - '0';
142 			if (line[i++] != ' ')
143 			{
144 				brightonfclose(fd);
145 				return(0);
146 			}
147 
148 			while (isdigit(line[i]))
149 				height = height * 10 + line[i++] - '0';
150 			if (line[i++] != ' ')
151 			{
152 				brightonfclose(fd);
153 				return(0);
154 			}
155 
156 			while (isdigit(line[i]))
157 				colors = colors * 10 + line[i++] - '0';
158 			if (line[i++] != ' ')
159 			{
160 				brightonfclose(fd);
161 				return(0);
162 			}
163 
164 			while (isdigit(line[i]))
165 				bpcolor = bpcolor * 10 + line[i++] - '0';
166 
167 			if (line[i] != '"')
168 			{
169 				while (line[i] == ' ')
170 					i++;
171 				innerstatic = 0;
172 
173 				while (isdigit(line[i]))
174 					innerstatic = innerstatic * 10 + line[i++] - '0';
175 
176 				if (line[i] != '"')
177 				{
178 					while (line[i] == ' ')
179 						i++;
180 					outerstatic = 0;
181 
182 					while (isdigit(line[i]))
183 						outerstatic = outerstatic * 10 + line[i++] - '0';
184 				}
185 
186 				if (line[i] != '"')
187 				{
188 					brightonfclose(fd);
189 					return(0);
190 				}
191 			}
192 
193 			break;
194 		}
195 	}
196 
197 	bitmap = brightonCreateBitmap(bwin, width, height);
198 
199 	if (bitmap->pixels == NULL)
200 		bitmap->pixels = (int *) brightonmalloc((2 + width) * (2 + height)
201 			* sizeof(int));
202 	bitmap->width = width;
203 	bitmap->height = height;
204 	bitmap->ncolors = colors;
205 	bitmap->ctabsize = colors;
206 	bitmap->uses = 0;
207 
208 	bitmap->istatic = innerstatic;
209 	bitmap->ostatic = width > height? height / 2: width /2;
210 	if (outerstatic != -1)
211 	{
212 		if (width > height) {
213 			if (outerstatic < (height / 2))
214 				bitmap->ostatic = outerstatic;
215 		} else {
216 			if (outerstatic < (width / 2))
217 				bitmap->ostatic = outerstatic;
218 		}
219 	}
220 
221 	colormap = (int *) brightonmalloc(colors * sizeof(int));
222 	if (bitmap->colormap)
223 		brightonfree(bitmap->colormap);
224 	bitmap->colormap = colormap;
225 
226 	/*
227 	 * We now have some reasonable w, h, c and p. Need to parse c color lines.
228 	 * We have to build a table of the character indeces from the XPM file. To
229 	 * do this we need a character table and index. Rather than define them in
230 	 * this file I am going to re-use some parts of the bitmap structure.
231 	 */
232 	bitmap->name = brightonmalloc(CTAB_SIZE * sizeof(char));
233 
234 	for (i = 0; i < colors;i++)
235 	{
236 		short r, g, b;
237 
238 		if (brightonfgets(line, BUFSIZE, fd) == 0)
239 		{
240 			brightonfclose(fd);
241 			printf("e1: %s\n", filename);
242 			return(bitmap);
243 		}
244 
245 		if (((line[bpcolor + 1] != '\t') && (line[bpcolor + 1] != ' ')) ||
246 			((line[bpcolor + 2] != 'c') && (line[bpcolor + 2] != 'g')))
247 		{
248 			brightonfclose(fd);
249 			printf("e2: %s: %i %i, %s\n", filename, bpcolor, colors, line);
250 			return(bitmap);
251 		}
252 
253 		if (strncmp("None", &line[4 + bpcolor], 4) == 0)
254 		{
255 			color = convertindex(bitmap, &line[1], bpcolor);
256 			colormap[i] = brightonGetGCByName(bwin, "Blue");
257 			continue;
258 		}
259 
260 		/*
261 		 * We need to make a new convertindex that builds its own index table
262 		 * based on the characters in the xpm file.
263 		 */
264 		color = convertindex(bitmap, &line[1], bpcolor);
265 
266 		if ((color = convertcolor(&line[bpcolor + 4])) < 0)
267 		{
268 			line[strlen(line) - 3] = '\0';
269 			colormap[i] = brightonGetGCByName(bwin, &line[bpcolor + 4]);
270 		} else {
271 
272 			/*
273 			 * Call the color manager to get a GC with this color for eventual
274 			 * rendering.
275 			 *
276 			 * XPM has color from 0 to 255. getGC wants 16 bit values.
277 			 */
278 			r = (color >> 16) * 256;
279 			g = ((color >> 8) & 0xff) * 256;
280 			b = (color & 0x00ff) * 256;
281 
282 			/*
283 			 * Brighton color manager is going to find this color, and return
284 			 * it if found, return a new GC if there is space, or a best match
285 			 * if not.
286 			 */
287 			colormap[i] = brightonGetGC(bwin, r, g, b);
288 		}
289 	}
290 
291 	for (i = 0; i < height;i++)
292 	{
293 		if (brightonfgets(line, BUFSIZE, fd) == 0)
294 		{
295 			brightonfclose(fd);
296 			printf("e3: %s\n", filename);
297 			return(bitmap);
298 		}
299 		if (line[0] != '\"')
300 			continue;
301 		for (j = 0; j < width * bpcolor; j+=bpcolor)
302 		{
303 			color = convertindex(bitmap, &line[j + 1], bpcolor);
304 			if (color < 0)
305 			{
306 				brightonfclose(fd);
307 				printf("e4: %s, %i/%i\n", filename, color, colors);
308 				return(bitmap);
309 			} else if (color >= colors) {
310 //				printf("e5: %s, %i/%i\n", filename, color, colors);
311 				bitmap->pixels[i * width + j / bpcolor] = colormap[colors - 1];
312 			} else {
313 				bitmap->pixels[i * width + j / bpcolor] = colormap[color];
314 			}
315 		}
316 	}
317 
318 	/* Free this temporary holder */
319 	brightonfree(bitmap->name);
320 
321 	bitmap->name = (char *) brightonmalloc(strlen(filename) + 1);
322 	sprintf(bitmap->name, "%s", filename);
323 
324 /*	bitmap->colormap = colormap; */
325 
326 	bitmap->uses = 1;
327 
328 	brightonfclose(fd);
329 
330 	return(bitmap);
331 }
332 
333 static int
hex2num(char c)334 hex2num(char c)
335 {
336 	if (isxdigit(c))
337 	{
338 		switch (c) {
339 			case '0':
340 			case '1':
341 			case '2':
342 			case '3':
343 			case '4':
344 			case '5':
345 			case '6':
346 			case '7':
347 			case '8':
348 			case '9':
349 				return(c - '0');
350 			case 'a':
351 			case 'b':
352 			case 'c':
353 			case 'd':
354 			case 'e':
355 			case 'f':
356 				return(c - 'a' + 10);
357 			default:
358 				return(c - 'A' + 10);
359 		}
360 	}
361 	return(-1);
362 }
363 
364 static int
convertcolor(char * line)365 convertcolor(char *line)
366 {
367 	int i = 0, color = 0, digit;
368 
369 	if (strcmp(line, "none") == 0)
370 		return(0);
371 	else if (strcmp(line, "None") == 0)
372 		return(0);
373 
374 	if (line[0] != '#')
375 		return(-1);
376 
377 	line++;
378 
379 	while (line[i] != '"')
380 	{
381 		if ((digit = hex2num(line[i])) < 0)
382 			return(0);
383 
384 		color = color * 16 + digit;
385 		i++;
386 	}
387 
388 	return(color);
389 }
390 
391 static int
convertindex(brightonBitmap * bitmap,char * line,int bpc)392 convertindex(brightonBitmap *bitmap, char *line, int bpc)
393 {
394 	int cindex = 0, i = 0, j = 1;
395 
396 	while (i < bpc)
397 	{
398 		cindex = cindex + xpmchar2num(bitmap, line[i]) * j;
399 		j += 91;
400 		i++;
401 	}
402 
403 	return(cindex);
404 }
405 
406 int
xpmchar2num(brightonBitmap * bitmap,char c)407 xpmchar2num(brightonBitmap *bitmap, char c)
408 {
409 	int i;
410 
411 	for (i = 0; i < bitmap->uses; i++)
412 		if (c == bitmap->name[i])
413 			return(i);
414 
415 /*printf("", bitmap->uses, i); */
416 	/*
417 	 * If we got here then the character has not been assigned yet.
418 	 */
419 	bitmap->name[bitmap->uses] = (int) c;
420 	bitmap->uses++;
421 
422 	return(i);
423 }
424 
425 int
writeLine(int fd,char * line)426 writeLine(int fd, char *line)
427 {
428 	return(write(fd, line, strlen(line)));
429 }
430 
431 #define SAVE_IMAGE
432 #ifdef SAVE_IMAGE
433 
434 #include <sys/types.h>
435 #include <sys/stat.h>
436 #include <fcntl.h>
437 
438 int
brightonXpmWrite(brightonWindow * bwin,char * file)439 brightonXpmWrite(brightonWindow *bwin, char *file)
440 {
441 	int fd, x, y, color, lindex;
442 	int colors[4096], cindex = 0, ccnt = 0, coff = 0, cagg = 0;
443 	long *points;
444 	char *line;
445 	char cstring[16], filename[64];
446 
447 	sprintf(filename, "/tmp/%s.xpm", bwin->template->name);
448 
449 	if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0770)) < 0)
450 		return(0);
451 
452 	points = brightonmalloc(sizeof(long) * bwin->width * bwin->height);
453 	line = brightonmalloc(sizeof(char) * (bwin->width + 10) * 2);
454 
455 	writeLine(fd, "/* XPM */\n");
456 	writeLine(fd, "static char * brighton_xpm[] = {\n");
457 
458 	/*
459 	 * We need to scan the image to see how many colors it implements. From this
460 	 * we should build a character table, and then we should scan through the
461 	 * image printing these characters.
462 	 */
463 	for (y = 0; y < bwin->render->height; y++)
464 	{
465 		for (x = 0; x < bwin->render->width; x++)
466 		{
467 			color = bwin->render->pixels[x + y * bwin->render->width];
468 
469 			for (cindex = 0; cindex < ccnt; cindex++)
470 			{
471 				if (color == colors[cindex])
472 				{
473 					/*
474 					 * This can't work: points[x][y] = cindex; hence
475 					 */
476 					points[x + y * bwin->render->width] = cindex;
477 					break;
478 				}
479 			}
480 			if (cindex == ccnt)
481 			{
482 				colors[cindex] = color;
483 				ccnt++;
484 			}
485 			/*
486 			 * This can't work: points[x][y] = cindex; hence
487 			 */
488 			points[x + y * bwin->render->width] = cindex;
489 		}
490 	}
491 
492 	sprintf(line, "\"%i %i %i %i\",\n", bwin->width, bwin->height, ccnt, 2);
493 	writeLine(fd, line);
494 
495 	for (cindex = 0; cindex < ccnt; cindex++)
496 	{
497 		/*
498 		 * We have to be reasonably intelligent with the color indeces. The
499 		 * first attempt failed when we went over about 80 colors. The index
500 		 * needs to become a string. We could go for two digits immediately?
501 		 */
502 		brightonSprintColor(bwin, cstring, colors[cindex]);
503 		sprintf(line, "\"%c%c	c %s\",\n", coff + 35, cagg + 35, cstring);
504 
505 		if (++cagg >= 90)
506 		{
507 			cagg = 0;
508 			coff++;
509 		}
510 
511 		writeLine(fd, line);
512 	}
513 
514 	for (y = 0; y < bwin->height; y++)
515 	{
516 		lindex = 1;
517 		sprintf(line, "\"");
518 
519 		for (x = 0; x < bwin->width; x++)
520 		{
521 			cagg = points[x + y * bwin->render->width] % 90;
522 			coff = points[x + y * bwin->render->width] / 90;
523 			sprintf(&line[lindex], "%c%c", coff + 35, cagg + 35);
524 			lindex+=2;
525 		}
526 
527 		sprintf(&line[lindex], "\"\n");
528 		writeLine(fd, line);
529 	}
530 
531 	writeLine(fd, "};\n\n");
532 
533 	brightonfree(points);
534 	brightonfree(line);
535 
536 	close(fd);
537 
538 	printf("Image written to %s, %i colors\n", filename, ccnt);
539 	printf("Width %i, Height %i\n", bwin->width, bwin->height);
540 
541 	return(0);
542 }
543 #endif /* SAVE_IMAGE */
544 
545