1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "charset.h"
31 #include "fontP.h"
32 #include "gdraw.h"
33 #include "gfile.h"
34 #include "gresource.h"
35 #include "gresourceP.h"
36 #include "ustring.h"
37 #include "utype.h"
38 
39 char *GResourceProgramName;
40 char *usercharset_names;
41 /* int local_encoding = e_iso8859_1;*/
42 
43 static int rcur, rmax=0;
44 static int rbase = 0, rsummit=0, rskiplen=0;	/* when restricting a search */
45 struct _GResource_Res *_GResource_Res;
46 
rcompar(const void * _r1,const void * _r2)47 static int rcompar(const void *_r1,const void *_r2) {
48     const struct _GResource_Res *r1 = _r1, *r2 = _r2;
49 return( strcmp(r1->res,r2->res));
50 }
51 
_GResource_FindResName(const char * name)52 int _GResource_FindResName(const char *name) {
53     int top=rsummit, bottom = rbase;
54     int test, cmp;
55 
56     if ( rcur==0 )
57 return( -1 );
58 
59     for (;;) {
60 	if ( top==bottom )
61 return( -1 );
62 	test = (top+bottom)/2;
63 	cmp = strcmp(name,_GResource_Res[test].res+rskiplen);
64 	if ( cmp==0 )
65 return( test );
66 	if ( test==bottom )
67 return( -1 );
68 	if ( cmp>0 )
69 	    bottom=test+1;
70 	else
71 	    top = test;
72     }
73 }
74 
GResourceRestrict(char * prefix)75 static int GResourceRestrict(char *prefix) {
76     int top=rcur, bottom = 0;
77     int test, cmp;
78     int plen;
79     int oldtest, oldtop;
80 
81     if ( prefix==NULL || *prefix=='\0' ) {
82 	rbase = rskiplen = 0; rsummit = rcur;
83 return( rcur==0?-1:0 );
84     }
85     if ( rcur==0 )
86 return( -1 );
87 
88     plen = strlen(prefix);
89 
90     for (;;) {
91 	test = (top+bottom)/2;
92 	cmp = strncmp(prefix,_GResource_Res[test].res,plen);
93 	if ( cmp==0 )
94     break;
95 	if ( test==bottom )
96 return( -1 );
97 	if ( cmp>0 ) {
98 	    bottom=test+1;
99 	    if ( bottom==top )
100 return( -1 );
101 	} else
102 	    top = test;
103     }
104     /* at this point the resource at test begins with the prefix */
105     /* we want to find the first and last resources that do */
106     oldtop = top; oldtest = top = test;		/* find the first resource */
107     for (;;) {
108 	test = (top+bottom)/2;
109 	cmp = strncmp(prefix,_GResource_Res[test].res,plen);
110 	if ( cmp<0 ) {
111 	    GDrawIError("Resource list out of order");
112 return( -1 );
113 	}
114 	if ( test==bottom ) {
115 	    if ( cmp!=0 ) ++test;
116     break;
117 	}
118 	if ( cmp>0 ) {
119 	    bottom=++test;
120 	    if ( bottom==top )
121     break;
122 	} else
123 	    top = test;
124     }
125     rbase = test;
126 
127     top = oldtop; bottom = oldtest+1;		/* find the last resource */
128     if ( bottom == top )
129 	test = top;
130     else for (;;) {
131 	test = (top+bottom)/2;
132 	cmp = strncmp(prefix,_GResource_Res[test].res,plen);
133 	if ( cmp>0 ) {
134 	    GDrawIError("Resource list out of order");
135 return( -1 );
136 	}
137 	if ( test==bottom ) {
138 	    if ( cmp==0 ) ++test;
139     break;
140 	}
141 	if ( cmp==0 ) {
142 	    bottom=++test;
143 	    if ( bottom==top )
144     break;
145 	} else
146 	    top = test;
147     }
148     rsummit = test;
149     rskiplen = plen;
150 return( 0 );
151 }
152 
GResourceSetProg(char * prog)153 void GResourceSetProg(char *prog) {
154     char filename[1025], *pt;
155     extern char *_GFile_find_program_dir(char *prog);
156 
157     if ( prog!=NULL ) {
158 	if ( GResourceProgramName!=NULL && strcmp(prog,GResourceProgramName)==0 )
159 return;
160 	free(GResourceProgramName);
161 	if (( pt=strrchr(prog,'/'))!=NULL )
162 	    ++pt;
163 	else
164 	    pt = prog;
165 	GResourceProgramName = copy(pt);
166     } else if ( GResourceProgramName==NULL )
167 	GResourceProgramName = copy("gdraw");
168     else
169 return;
170 }
171 
GResourceAddResourceString(char * string,char * prog)172 void GResourceAddResourceString(char *string,char *prog) {
173     char *pt, *ept, *next;
174     int cnt, plen;
175     struct _GResource_Res temp;
176     int i,j,k, off;
177 
178     GResourceSetProg(prog);
179     plen = strlen(GResourceProgramName);
180 
181     if ( string==NULL )
182 return;
183 
184     cnt = 0;
185     pt = string;
186     while ( *pt!='\0' ) {
187 	next = strchr(pt,'\n');
188 	if ( next==NULL ) next = pt+strlen(pt);
189 	else ++next;
190 	if ( strncmp(pt,"Gdraw.",6)==0 ) ++cnt;
191 	else if ( strncmp(pt,GResourceProgramName,plen)==0 && pt[plen]=='.' ) ++cnt;
192 	else if ( strncmp(pt,"*",1)==0 ) ++cnt;
193 	pt = next;
194     }
195     if ( cnt==0 )
196 return;
197 
198     if ( rcur+cnt>=rmax ) {
199 	if ( cnt<10 ) cnt = 10;
200 	if ( rmax==0 )
201 	    _GResource_Res = malloc(cnt*sizeof(struct _GResource_Res));
202 	else
203 	    _GResource_Res = realloc(_GResource_Res,(rcur+cnt)*sizeof(struct _GResource_Res));
204 	rmax += cnt;
205     }
206 
207     pt = string;
208     while ( *pt!='\0' ) {
209 	next = strchr(pt,'\n');
210 	if ( next==NULL ) next = pt+strlen(pt);
211 	if ( strncmp(pt,"Gdraw.",6)==0 || strncmp(pt,"*",1)==0 ||
212 		(strncmp(pt,GResourceProgramName,plen)==0 && pt[plen]=='.' )) {
213 	    temp.generic = false;
214 	    if ( strncmp(pt,"Gdraw.",6)==0 ) {
215 		temp.generic = true;
216 		off = 6;
217 	    } else if ( strncmp(pt,"*",1)==0 ) {
218 		temp.generic = true;
219 		off = 1;
220 	    } else
221 		off = plen+1;
222 	    ept = strchr(pt+off,':');
223 	    if ( ept==NULL )
224 	goto bad;
225 	    temp.res = copyn(pt+off,ept-(pt+off));
226 	    pt = ept+1;
227 	    while ( isspace( *pt ) && pt<next ) ++pt;
228 	    temp.val = copyn(pt,next-pt);
229 	    temp.new = true;
230 	    _GResource_Res[rcur++] = temp;
231 	}
232 	bad:
233 	if ( *next ) ++next;
234 	pt = next;
235     }
236 
237     if ( rcur!=0 )
238 	qsort(_GResource_Res,rcur,sizeof(struct _GResource_Res),rcompar);
239 
240     for ( i=j=0; i<rcur; ) {
241 	if ( i!=j )
242 	    _GResource_Res[j] = _GResource_Res[i];
243 	for ( k=i+1; k<rcur && strcmp(_GResource_Res[j].res,_GResource_Res[k].res)==0; ++k ) {
244 	    if (( !_GResource_Res[k].generic && (_GResource_Res[i].generic || _GResource_Res[i+1].new)) ||
245 		    (_GResource_Res[k].generic && _GResource_Res[i].generic && _GResource_Res[i+1].new)) {
246 		free(_GResource_Res[j].res); free(_GResource_Res[j].val);
247 		_GResource_Res[i].res=NULL;
248 		_GResource_Res[j] = _GResource_Res[k];
249 	    } else {
250 		free(_GResource_Res[k].res); free(_GResource_Res[k].val);
251 		_GResource_Res[k].res=NULL;
252 	    }
253 	}
254 	i = k; ++j;
255     }
256     rcur = rsummit = j;
257     for ( i=0; i<j; ++i )
258 	_GResource_Res[i].new = false;
259 
260     if ( (i=_GResource_FindResName("LocalCharSet"))!=-1 ) {
261 	local_encoding = _GDraw_ParseMapping(c_to_u(_GResource_Res[i].val));
262 	if ( local_encoding==em_none )
263 	    local_encoding = em_iso8859_1;
264 	local_encoding += e_iso8859_1-em_iso8859_1;
265     }
266 }
267 
GResourceAddResourceFile(char * filename,char * prog,int warn)268 void GResourceAddResourceFile(char *filename,char *prog,int warn) {
269     FILE *file;
270     char buffer[1000];
271 
272     file = fopen(filename,"r");
273     if ( file==NULL ) {
274 	if ( warn )
275 	    fprintf( stderr, "Failed to open resource file: %s\n", filename );
276 return;
277     }
278     while ( fgets(buffer,sizeof(buffer),file)!=NULL )
279 	GResourceAddResourceString(buffer,prog);
280     fclose(file);
281 }
282 
GResourceFind(GResStruct * info,char * prefix)283 void GResourceFind( GResStruct *info,char *prefix) {
284     int pos;
285 
286     if ( GResourceRestrict(prefix)== -1 ) {
287 	rbase = rskiplen = 0; rsummit = rcur;
288 return;
289     }
290     while ( info->resname!=NULL ) {
291 	pos = _GResource_FindResName(info->resname);
292 	info->found = (pos!=-1);
293 	if ( pos==-1 )
294 	    /* Do Nothing */;
295 	else if ( info->type == rt_string ) {
296 	    if ( info->cvt!=NULL )
297 		*(void **) (info->val) = (info->cvt)( _GResource_Res[pos].val, *(void **) (info->val) );
298 	    else
299 		*(char **) (info->val) = copy( _GResource_Res[pos].val );
300 	} else if ( info->type == rt_color ) {
301 	    Color temp = _GImage_ColourFName(_GResource_Res[pos].val );
302 	    if ( temp==-1 ) {
303 		fprintf( stderr, "Can't convert %s to a Color for resource: %s\n",
304 			_GResource_Res[pos].val, info->resname );
305 		info->found = false;
306 	    } else
307 		*(Color *) (info->val) = temp;
308 	} else if ( info->type == rt_int ) {
309 	    char *end;
310 	    int val = strtol(_GResource_Res[pos].val,&end,0);
311 	    if ( *end!='\0' ) {
312 		fprintf( stderr, "Can't convert %s to an int for resource: %s\n",
313 			_GResource_Res[pos].val, info->resname );
314 		info->found = false;
315 	    } else
316 		*(int *) (info->val) = val;
317 	} else if ( info->type == rt_bool ) {
318 	    int val = -1;
319 	    if ( strmatch(_GResource_Res[pos].val,"true")==0 ||
320 		    strmatch(_GResource_Res[pos].val,"on")==0 || strcmp(_GResource_Res[pos].val,"1")==0 )
321 		val = 1;
322 	    else if ( strmatch(_GResource_Res[pos].val,"false")==0 ||
323 		    strmatch(_GResource_Res[pos].val,"off")==0 || strcmp(_GResource_Res[pos].val,"0")==0 )
324 		val = 0;
325 	    if ( val==-1 ) {
326 		fprintf( stderr, "Can't convert %s to a boolean for resource: %s\n",
327 			_GResource_Res[pos].val, info->resname );
328 		info->found = false;
329 	    } else
330 		*(int *) (info->val) = val;
331 	} else if ( info->type == rt_double ) {
332 	    char *end;
333 	    double val = strtod(_GResource_Res[pos].val,&end);
334 	    if ( *end=='.' || *end==',' ) {
335 		*end = (*end==',')?'.':',';
336 		val = strtod(_GResource_Res[pos].val,&end);
337 	    }
338 	    if ( *end!='\0' ) {
339 		fprintf( stderr, "Can't convert %s to a double for resource: %s\n",
340 			_GResource_Res[pos].val, info->resname );
341 		info->found = false;
342 	    } else
343 		*(double *) (info->val) = val;
344 	} else {
345 	    fprintf( stderr, "Invalid resource type for: %s\n", info->resname );
346 	    info->found = false;
347 	}
348 	++info;
349     }
350     rbase = rskiplen = 0; rsummit = rcur;
351 }
352 
GResourceFindString(char * name)353 char *GResourceFindString(char *name) {
354     int pos;
355 
356     pos = _GResource_FindResName(name);
357     if ( pos==-1 )
358 return( NULL );
359     else
360 return( copy(_GResource_Res[pos].val));
361 }
362 
GResourceFindBool(char * name,int def)363 int GResourceFindBool(char *name, int def) {
364     int pos;
365     int val = -1;
366 
367     pos = _GResource_FindResName(name);
368     if ( pos==-1 )
369 return( def );
370 
371     if ( strmatch(_GResource_Res[pos].val,"true")==0 ||
372 	    strmatch(_GResource_Res[pos].val,"on")==0 || strcmp(_GResource_Res[pos].val,"1")==0 )
373 	val = 1;
374     else if ( strmatch(_GResource_Res[pos].val,"false")==0 ||
375 	    strmatch(_GResource_Res[pos].val,"off")==0 || strcmp(_GResource_Res[pos].val,"0")==0 )
376 	val = 0;
377 
378     if ( val==-1 )
379 return( def );
380 
381 return( val );
382 }
383 
GResourceFindInt(char * name,long def)384 long GResourceFindInt(char *name, long def) {
385     int pos;
386     char *end;
387     long ret;
388 
389     pos = _GResource_FindResName(name);
390     if ( pos==-1 )
391 return( def );
392 
393     ret = strtol(_GResource_Res[pos].val,&end,10);
394     if ( *end!='\0' )
395 return( def );
396 
397 return( ret );
398 }
399 
GResourceFindColor(char * name,Color def)400 Color GResourceFindColor(char *name, Color def) {
401     int pos;
402     Color ret;
403 
404     pos = _GResource_FindResName(name);
405     if ( pos==-1 )
406 return( def );
407 
408     ret = _GImage_ColourFName(_GResource_Res[pos].val );
409     if ( ret==-1 )
410 return( def );
411 
412 return( ret );
413 }
414