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