1 /* Zgv v3.0 - GIF, JPEG and PBM/PGM/PPM viewer, for VGA PCs running Linux.
2 * Copyright (C) 1993-1998 Russell Marks. See README for license details.
3 *
4 * readxbm.c - read an X bitmap.
5 */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include "zgv.h"
11 #include "readxbm.h"
12
13
14 /* for aborted_file_xbm_cleanup() */
15 static unsigned char *work_bmap,*work_pal;
16 static FILE *work_in;
17
18
read_xbm_file(char * filename,hffunc howfarfunc,unsigned char ** bmap,unsigned char ** pal,int * output_type,PICINFO * pp)19 int read_xbm_file(char *filename,hffunc howfarfunc,unsigned char **bmap,
20 unsigned char **pal,int *output_type,PICINFO *pp)
21 {
22 static unsigned char buf[1024];
23 FILE *in;
24 int w8,w,h,x,y,data;
25 unsigned char *image,*ptr;
26 int tmppos;
27 int i,mask;
28
29 *bmap=NULL;
30 *pal=NULL;
31
32 if((in=fopen(filename,"rb"))==NULL)
33 return(_PICERR_NOFILE);
34
35 /* the format as defined in "Xlib - C Language X Interface"
36 * (in subsection 16.9, "Manipulating Bitmaps") is
37 * relatively strict, and this code follows it pretty
38 * much to the letter.
39 */
40
41 /* first two lines must be:
42 * #define foo_width <width>
43 * #define foo_height <height>
44 *
45 * Inevitably, some people don't seem able to read the spec, so I've
46 * seen one or two files which don't work (they have comments in - but
47 * the spec doesn't provide for comments). :-(
48 */
49
50 if(fgets(buf,sizeof(buf),in)==NULL || strncmp(buf,"#define ",8)!=0)
51 CLOSE_AND_RET(_PICERR_CORRUPT);
52
53 /* read number after "_width" */
54 if((ptr=strstr(buf,"_width"))==NULL)
55 CLOSE_AND_RET(_PICERR_CORRUPT);
56 w=atoi(ptr+6);
57
58 /* repeat for height */
59 if(fgets(buf,sizeof(buf),in)==NULL || strncmp(buf,"#define ",8)!=0)
60 CLOSE_AND_RET(_PICERR_CORRUPT);
61
62 if((ptr=strstr(buf,"_height"))==NULL)
63 CLOSE_AND_RET(_PICERR_CORRUPT);
64 h=atoi(ptr+7);
65
66 if(w==0 || h==0)
67 CLOSE_AND_RET(_PICERR_CORRUPT);
68
69 /* ignore possible hotspot lines
70 * (the easiest way is to ignore until we get a line which doesn't
71 * start with "#define")
72 */
73 tmppos=ftell(in);
74 while(fgets(buf,sizeof(buf),in)!=NULL)
75 {
76 if(strncmp(buf,"#define ",8)!=0) break;
77 tmppos=ftell(in);
78 }
79
80 /* check for "_bits[" and `{' */
81 if(strstr(buf,"_bits[")==NULL || (ptr=strrchr(buf,'{'))==NULL)
82 CLOSE_AND_RET(_PICERR_CORRUPT);
83
84
85 /* seek to just after the brace
86 * (bit nasty but it seems like the easiest way to deal with
87 * the possibility of hex on the line with the opening brace on)
88 */
89 fseek(in,tmppos+(ptr+1-buf),SEEK_SET);
90
91
92 if((*pal=calloc(768,1))==NULL)
93 CLOSE_AND_RET(_PICERR_NOMEM);
94
95 (*pal)[0]=(*pal)[256]=(*pal)[512]=0;
96 (*pal)[1]=(*pal)[257]=(*pal)[513]=255;
97
98 w8=(w+7)/8;
99
100 if(WH_BAD(w,h) || (*bmap=image=malloc(w*h))==NULL)
101 CLOSE_AND_RET(_PICERR_NOMEM);
102
103 /* save stuff in case of abort */
104 work_in=in; work_bmap=(*bmap); work_pal=*pal;
105
106
107 for(y=0;y<h;y++)
108 {
109 for(x=0;x<w8;x++)
110 {
111 if(fscanf(in,"%x",&data)!=1)
112 {
113 y=h;
114 break;
115 }
116
117 fgetc(in); /* remove comma (or LF or whatever) */
118
119 for(i=0,mask=1;i<8;i++,mask<<=1)
120 if(x*8+i<w)
121 image[y*w+x*8+i]=((data&mask)?0:1);
122 }
123
124 if(howfarfunc!=NULL) howfarfunc(y,h);
125 }
126
127 fclose(in);
128
129 pp->width=w;
130 pp->height=h;
131 pp->numcols=2;
132
133 *output_type=1;
134
135 return(_PIC_OK);
136 }
137
138
aborted_file_xbm_cleanup()139 void aborted_file_xbm_cleanup()
140 {
141 free(work_bmap);
142 free(work_pal);
143 fclose(work_in);
144 }
145