1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2015 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  * Parts Copyright (c) 2016-2020 by Thomas Loimer
7  *
8  * Any party obtaining a copy of these files is granted, free of charge, a
9  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10  * nonexclusive right and license to deal in this software and documentation
11  * files (the "Software"), including without limitation the rights to use,
12  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13  * the Software, and to permit persons who receive copies from any such
14  * party to do so, with the only requirement being that the above copyright
15  * and this permission notice remain intact.
16  *
17  */
18 
19 /*
20  * This file contains a modified version of the
21  * XReadBitmapFromFile() routine from the X11R5 distribution.
22  * Parts Copyright, 1987, Massachusetts Institute of Technology
23  * See the copyright notice below.
24  *
25  */
26 
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"		/* restrict */
30 #endif
31 
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <X11/Xlib.h>		/* Bool, True, False */
37 #include <X11/Xutil.h>
38 
39 #include "resources.h"
40 #include "object.h"
41 #include "f_picobj.h"
42 #include "w_setup.h"
43 
44 /* attempt to read a bitmap file */
45 
46 /* return codes:  PicSuccess (1) : success
47 		  FileInvalid (-2) : invalid file
48 */
49 
50 
51 static int
52 ReadDataFromBitmapFile (FILE *file, unsigned int *width,
53 				unsigned int *height, unsigned char **data_ret);
54 
55 int
read_xbm(F_pic * pic,struct xfig_stream * restrict pic_stream)56 read_xbm(F_pic *pic, struct xfig_stream *restrict pic_stream)
57 {
58 	unsigned int	x, y;
59 	/* make scale factor smaller for metric */
60 	const double	scale =
61 		(appres.INCHES ? (double)PIX_PER_INCH : 2.54*PIX_PER_CM)
62 						/ DISPLAY_PIX_PER_INCH;
63 
64 	if (!rewind_stream(pic_stream))
65 		return FileInvalid;
66 
67 	/* first try for a X Bitmap file format */
68 	if (ReadDataFromBitmapFile(pic_stream->fp, &x, &y,
69 				&pic->pic_cache->bitmap) == BitmapSuccess) {
70 		pic->pic_cache->subtype = T_PIC_XBM;
71 		pic->hw_ratio = (float) y / x;
72 		pic->pic_cache->numcols = 0;
73 		pic->pic_cache->bit_size.x = x;
74 		pic->pic_cache->bit_size.y = y;
75 		pic->pic_cache->size_x = x * scale;
76 		pic->pic_cache->size_y = y * scale;
77 		return PicSuccess;
78 	}
79 
80 	/* Non Bitmap file */
81 	return FileInvalid;
82 }
83 
84 /* The following is a modified version of the
85    XReadBitmapFromFile() routine from the X11R5 distribution.
86    This version reads the XBM file into a data array rather
87    than creating the pixmap directly.
88    Also, it will uncompress or gunzip the file if necessary.
89 */
90 
91 /* $XConsortium: XRdBitF.c,v 1.15 91/02/01 16:34:46 gildea Exp $ */
92 /* Copyright, 1987, Massachusetts Institute of Technology */
93 
94 /*
95  * Any party obtaining a copy of these files is granted, free of charge, a
96  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
97  * nonexclusive right and license to deal in this software and
98  * documentation files (the "Software"), including without limitation the
99  * rights to use, copy, modify, merge, publish and/or distribute copies of
100  * the Software, and to permit persons who receive copies from any such
101  * party to do so, with the only requirement being that this copyright
102  * notice remain intact.
103 */
104 
105 /*
106  *	Code to read bitmaps from disk files. Interprets
107  *	data from X10 and X11 bitmap files.
108  *
109  *	Modified for speedup by Jim Becker, changed image
110  *	data parsing logic (removed some fscanf()s).
111  *	Aug 5, 1988
112  *
113  * Note that this file and ../Xmu/RdBitF.c look very similar....  Keep them
114  * that way (but don't use common source code so that people can have one
115  * without the other).
116  */
117 
118 #define MAX_SIZE 255
119 
120 /* shared data for the image read/parse logic */
121 static short hexTable[256];		/* conversion value */
122 static Bool initialized = False;	/* easier to fill in at run time */
123 
124 
125 /*
126  *	Table index for the hex values. Initialized once, first time.
127  *	Used for translation value or delimiter significance lookup.
128  */
129 static void
initHexTable(void)130 initHexTable(void)
131 {
132     /*
133      * We build the table at run time for several reasons:
134      *
135      *     1.  portable to non-ASCII machines.
136      *     2.  still reentrant since we set the init flag after setting table.
137      *     3.  easier to extend.
138      *     4.  less prone to bugs.
139      */
140     hexTable['0'] = 0;	hexTable['1'] = 1;
141     hexTable['2'] = 2;	hexTable['3'] = 3;
142     hexTable['4'] = 4;	hexTable['5'] = 5;
143     hexTable['6'] = 6;	hexTable['7'] = 7;
144     hexTable['8'] = 8;	hexTable['9'] = 9;
145     hexTable['A'] = 10;	hexTable['B'] = 11;
146     hexTable['C'] = 12;	hexTable['D'] = 13;
147     hexTable['E'] = 14;	hexTable['F'] = 15;
148     hexTable['a'] = 10;	hexTable['b'] = 11;
149     hexTable['c'] = 12;	hexTable['d'] = 13;
150     hexTable['e'] = 14;	hexTable['f'] = 15;
151 
152     /* delimiters of significance are flagged w/ negative value */
153     hexTable[' '] = -1;	hexTable[','] = -1;
154     hexTable['}'] = -1;	hexTable['\n'] = -1;
155     hexTable['\t'] = -1;
156 
157     initialized = True;
158 }
159 
160 /*
161  *	read next hex value in the input stream, return -1 if EOF
162  */
163 static int
NextInt(FILE * fstream)164 NextInt(FILE *fstream)
165 {
166     int	ch;
167     int	value = 0;
168     int	ret_value = 0;
169     int gotone = 0;
170     int done = 0;
171 
172     /* loop, accumulate hex value until find delimiter  */
173     /* skip any initial delimiters found in read stream */
174 
175     while (!done) {
176 	ch = getc(fstream);
177 	if (ch == EOF) {
178 	    value	= -1;
179 	    done++;
180 	} else {
181 	    /* trim high bits, check type and accumulate */
182 	    ch &= 0xff;
183 	    if (isascii(ch) && isxdigit(ch)) {
184 		value = (value << 4) + hexTable[ch];
185 		gotone++;
186 	    } else if ((hexTable[ch]) < 0 && gotone)
187 	      done++;
188 	}
189     }
190 
191     ret_value = 0;
192     if (value & 0x80)
193 	ret_value |= 0x01;
194     if (value & 0x40)
195 	ret_value |= 0x02;
196     if (value & 0x20)
197 	ret_value |= 0x04;
198     if (value & 0x10)
199 	ret_value |= 0x08;
200     if (value & 0x08)
201 	ret_value |= 0x10;
202     if (value & 0x04)
203 	ret_value |= 0x20;
204     if (value & 0x02)
205 	ret_value |= 0x40;
206     if (value & 0x01)
207 	ret_value |= 0x80;
208     return ret_value;
209 
210 }
211 
212 int
ReadDataFromBitmapFile(FILE * file,unsigned int * width,unsigned int * height,unsigned char ** data_ret)213 ReadDataFromBitmapFile(FILE *file, unsigned int *width, unsigned int *height,
214 			unsigned char **data_ret) {
215     unsigned char *data = NULL;		/* working variable */
216     char line[MAX_SIZE];		/* input line from file */
217     int size;				/* number of bytes of data */
218     char name_and_type[MAX_SIZE];	/* an input line */
219     char *type;				/* for parsing */
220     int value;				/* from an input line */
221     int version10p;			/* boolean, old format */
222     int padding;			/* to handle alignment */
223     int bytes_per_line;			/* per scanline of data */
224     unsigned int ww = 0;		/* width */
225     unsigned int hh = 0;		/* height */
226 
227     /* first time initialization */
228     if (initialized == False)
229 	initHexTable();
230 
231     /* error cleanup and return macro	*/
232 #define	RETURN(code)  { if (data) free (data); \
233 			return code; }
234 
235     while (fgets(line, MAX_SIZE, file)) {
236 	if (strlen(line) == MAX_SIZE-1) {
237 	    RETURN (BitmapFileInvalid);
238 	}
239 	if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
240 	    if (!(type = strrchr(name_and_type, '_')))
241 	      type = name_and_type;
242 	    else
243 	      type++;
244 
245 	    if (!strcmp("width", type))
246 	      ww = (unsigned int) value;
247 	    if (!strcmp("height", type))
248 	      hh = (unsigned int) value;
249 	    continue;
250 	}
251 
252 	if (sscanf(line, "static short %s = {", name_and_type) == 1)
253 	  version10p = 1;
254 	else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
255 	  version10p = 0;
256 	else if (sscanf(line, "static char %s = {", name_and_type) == 1)
257 	  version10p = 0;
258 	else
259 	  continue;
260 
261 	if (!(type = strrchr(name_and_type, '_')))
262 	  type = name_and_type;
263 	else
264 	  type++;
265 
266 	if (strcmp("bits[]", type))
267 	  continue;
268 
269 	if (!ww || !hh)
270 	  RETURN (BitmapFileInvalid);
271 
272 	if ((ww % 16) && ((ww % 16) < 9) && version10p)
273 	  padding = 1;
274 	else
275 	  padding = 0;
276 
277 	bytes_per_line = (ww+7)/8 + padding;
278 
279 	size = bytes_per_line * hh;
280 	data = malloc ((unsigned int) size);
281 	if (!data)
282 	  RETURN (BitmapNoMemory);
283 
284 	if (version10p) {
285 	    unsigned char *ptr;
286 	    int bytes;
287 
288 	    for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
289 		if ((value = NextInt(file)) < 0)
290 		  RETURN (BitmapFileInvalid);
291 		*(ptr++) = value;
292 		if (!padding || ((bytes+2) % bytes_per_line))
293 		  *(ptr++) = value >> 8;
294 	    }
295 	} else {
296 	    unsigned char *ptr;
297 	    int bytes;
298 
299 	    for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
300 		if ((value = NextInt(file)) < 0)
301 		  RETURN (BitmapFileInvalid);
302 		*ptr=value;
303 	    }
304 	}
305     }					/* end while */
306 
307     if (data == NULL) {
308 	RETURN (BitmapFileInvalid);
309     }
310 
311     *data_ret = data;
312     *width = ww;
313     *height = hh;
314 
315     /* don't free the data pointer */
316     return (BitmapSuccess);
317 }
318