1 /*
2 % Copyright (C) 2003-2019 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 %
5 % This program is covered by multiple licenses, which are described in
6 % Copyright.txt. You should have received a copy of Copyright.txt with this
7 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8 %
9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 % %
11 % %
12 % %
13 % TTTTT Y Y PPPP EEEEE %
14 % T Y Y P P E %
15 % T Y PPPP EEE %
16 % T Y P E %
17 % T Y P EEEEE %
18 % %
19 % %
20 % GraphicsMagick Image Type Methods %
21 % %
22 % %
23 % Software Design %
24 % John Cristy %
25 % May 2001 %
26 % %
27 % %
28 % %
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 %
31 %
32 */
33
34 /*
35 Include declarations.
36 */
37 #include "magick/studio.h"
38 #if defined(MSWINDOWS) || defined(__CYGWIN__)
39 # include "magick/nt_feature.h"
40 #endif
41 #include "magick/blob.h"
42 #include "magick/enum_strings.h"
43 #include "magick/log.h"
44 #include "magick/render.h"
45 #include "magick/semaphore.h"
46 #include "magick/type.h"
47 #include "magick/utility.h"
48
49 /*
50 Define declarations.
51 */
52 #define TypeFilename "type.mgk"
53
54 /*
55 Declare type map.
56 */
57 static const char
58 TypeMap[] =
59 "<?xml version=\"1.0\"?>"
60 "<typemap>"
61 " <type stealth=\"True\" />"
62 "</typemap>";
63
64 /*
65 Static declarations.
66 */
67 static SemaphoreInfo
68 *type_semaphore = (SemaphoreInfo *) NULL;
69
70 static TypeInfo
71 *type_list = (TypeInfo *) NULL;
72
73 /*
74 Forward declarations.
75 */
76 static unsigned int
77 ReadTypeConfigureFile(const char *,const unsigned long,ExceptionInfo *);
78
79 /*
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 % %
82 % %
83 % %
84 + D e s t r o y T y p e I n f o %
85 % %
86 % %
87 % %
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 %
90 % Method DestroyTypeInfo deallocates memory associated with the font list.
91 %
92 % The format of the DestroyTypeInfo method is:
93 %
94 % DestroyTypeInfo(void)
95 %
96 %
97 */
DestroyTypeInfo(void)98 MagickExport void DestroyTypeInfo(void)
99 {
100 register TypeInfo
101 *p;
102
103 TypeInfo
104 *type_info;
105
106 for (p=type_list; p != (TypeInfo *) NULL; )
107 {
108 type_info=p;
109 p=p->next;
110 if (type_info->path != (char *) NULL)
111 MagickFreeMemory(type_info->path);
112 if (type_info->name != (char *) NULL)
113 MagickFreeMemory(type_info->name);
114 if (type_info->description != (char *) NULL)
115 MagickFreeMemory(type_info->description);
116 if (type_info->family != (char *) NULL)
117 MagickFreeMemory(type_info->family);
118 if (type_info->encoding != (char *) NULL)
119 MagickFreeMemory(type_info->encoding);
120 if (type_info->foundry != (char *) NULL)
121 MagickFreeMemory(type_info->foundry);
122 if (type_info->format != (char *) NULL)
123 MagickFreeMemory(type_info->format);
124 if (type_info->metrics != (char *) NULL)
125 MagickFreeMemory(type_info->metrics);
126 if (type_info->glyphs != (char *) NULL)
127 MagickFreeMemory(type_info->glyphs);
128 MagickFreeMemory(type_info);
129 }
130 type_list=(TypeInfo *) NULL;
131 DestroySemaphoreInfo(&type_semaphore);
132 }
133
134 /*
135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 % %
137 % %
138 % %
139 + G e t T y p e I n f o %
140 % %
141 % %
142 % %
143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 %
145 % Method GetTypeInfo searches the type list for the specified name and if
146 % found returns attributes for that type.
147 %
148 % The format of the GetTypeInfo method is:
149 %
150 % const TypeInfo *GetTypeInfo(const char *name,ExceptionInfo *exception)
151 %
152 % A description of each parameter follows:
153 %
154 % o type_info: Method GetTypeInfo searches the type list for the specified
155 % name and if found returns attributes for that type.
156 %
157 % o name: The type name.
158 %
159 % o exception: Return any errors or warnings in this structure.
160 %
161 %
162 */
GetTypeInfo(const char * name,ExceptionInfo * exception)163 MagickExport const TypeInfo *GetTypeInfo(const char *name,
164 ExceptionInfo *exception)
165 {
166 register TypeInfo
167 *p;
168
169 if (type_list == (TypeInfo *) NULL)
170 {
171 LockSemaphoreInfo(type_semaphore);
172 if (type_list == (TypeInfo *) NULL)
173 {
174 (void) ReadTypeConfigureFile(TypeFilename,0,exception);
175 #if defined(MSWINDOWS) || defined(__CYGWIN__)
176 {
177 TypeInfo
178 *type_info;
179
180 type_info=NTGetTypeList();
181 if (type_info != (TypeInfo *) NULL)
182 {
183 if (type_list == (TypeInfo *) NULL)
184 type_list=type_info;
185 else
186 {
187 while (type_list->next != (TypeInfo *) NULL)
188 type_list=type_list->next;
189 type_list->next=type_info;
190 type_info->previous=type_list;
191 while (type_list->previous != (TypeInfo *) NULL)
192 type_list=type_list->previous;
193 }
194 }
195 }
196 #endif
197 }
198 UnlockSemaphoreInfo(type_semaphore);
199 }
200 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
201 return((const TypeInfo *) type_list);
202 /*
203 Search for requested type.
204 */
205 LockSemaphoreInfo(type_semaphore);
206 for (p=type_list; p != (TypeInfo *) NULL; p=p->next)
207 if ((p->name != (char *) NULL) && (LocaleCompare(p->name,name) == 0))
208 break;
209 if (p != (TypeInfo *) NULL)
210 if (p != type_list)
211 {
212 /*
213 Self-adjusting list.
214 */
215 if (p->previous != (TypeInfo *) NULL)
216 p->previous->next=p->next;
217 if (p->next != (TypeInfo *) NULL)
218 p->next->previous=p->previous;
219 p->previous=(TypeInfo *) NULL;
220 p->next=type_list;
221 type_list->previous=p;
222 type_list=p;
223 }
224 UnlockSemaphoreInfo(type_semaphore);
225 return((const TypeInfo *) p);
226 }
227
228 /*
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230 % %
231 % %
232 % %
233 + G e t T y p e I n f o B y F a m i l y %
234 % %
235 % %
236 % %
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 %
239 % Method GetTypeInfoByFamily searches the type list for the specified family
240 % and if found returns attributes for that type.
241 %
242 % Type substitution and scoring algorithm contributed by Bob Friesenhahn.
243 %
244 % The format of the GetTypeInfoByFamily method is:
245 %
246 % const TypeInfo *GetTypeInfoByFamily(const char *family,
247 % const StyleType style,const StretchType stretch,
248 % const unsigned long weight,ExceptionInfo *exception)
249 %
250 % A description of each parameter follows:
251 %
252 % o type_info: Method GetTypeInfo searches the type list for the specified
253 % name and if found returns attributes for that type.
254 %
255 % o family: The type family.
256 %
257 % o style: The type style.
258 %
259 % o stretch: The type stretch.
260 %
261 % o weight: The type weight.
262 %
263 % o exception: Return any errors or warnings in this structure.
264 %
265 %
266 */
GetTypeInfoByFamily(const char * family,const StyleType style,const StretchType stretch,const unsigned long weight,ExceptionInfo * exception)267 MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
268 const StyleType style,const StretchType stretch,const unsigned long weight,
269 ExceptionInfo *exception)
270 {
271 const TypeInfo
272 *type_info;
273
274 int
275 range;
276
277 register const TypeInfo
278 *p;
279
280 register unsigned int
281 i;
282
283 static const struct
284 {
285 char
286 name[17],
287 substitute[10];
288 }
289 fontmap[] =
290 {
291 { "fixed", "courier" },
292 { "modern","courier" },
293 { "monotype corsiva", "courier" },
294 { "news gothic", "helvetica" },
295 { "system", "courier" },
296 { "terminal", "courier" },
297 { "wingdings", "symbol" }
298 };
299
300 unsigned int
301 max_score,
302 score;
303
304 /*
305 Check for an exact type match.
306 */
307 (void) GetTypeInfo("*",exception);
308 if (type_list == (TypeInfo *) NULL)
309 return((TypeInfo *) NULL);
310 for (p=type_list; p != (TypeInfo *) NULL; p=p->next)
311 {
312 if (p->family == (char *) NULL)
313 continue;
314 if (family == (const char *) NULL)
315 {
316 if ((LocaleCompare(p->family,"arial") != 0) &&
317 (LocaleCompare(p->family,"helvetica") != 0))
318 continue;
319 }
320 else
321 if (LocaleCompare(p->family,family) != 0)
322 continue;
323 if ((style != AnyStyle) && (p->style != style))
324 continue;
325 if ((stretch != AnyStretch) && (p->stretch != stretch))
326 continue;
327 if ((weight != 0) && (p->weight != weight))
328 continue;
329 return((TypeInfo *) p);
330 }
331 /*
332 Check for types in the same family.
333 */
334 max_score=0;
335 type_info=(TypeInfo *) NULL;
336 for (p=type_list; p != (TypeInfo *) NULL; p=p->next)
337 {
338 if (p->family == (char *) NULL)
339 continue;
340 if (family == (const char *) NULL)
341 {
342 if ((LocaleCompare(p->family,"arial") != 0) &&
343 (LocaleCompare(p->family,"helvetica") != 0))
344 continue;
345 }
346 else
347 if (LocaleCompare(p->family,family) != 0)
348 continue;
349 score=0;
350 if ((style == AnyStyle) || (p->style == style))
351 score+=32;
352 else
353 if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
354 ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
355 score+=25;
356 if (weight == 0)
357 score+=16;
358 else
359 score+=(16*(800-((int) Max(Min(weight,900),p->weight)-
360 (int) Min(Min(weight,900),p->weight))))/800;
361 if (stretch == AnyStretch)
362 score+=8;
363 else
364 {
365 range=(int) UltraExpandedStretch-(int) NormalStretch;
366 score+=(8*(range-((int) Max(stretch,p->stretch)-
367 (int) Min(stretch,p->stretch))))/range;
368 }
369 if (score > max_score)
370 {
371 max_score=score;
372 type_info=p;
373 }
374 }
375 if (type_info != (TypeInfo *) NULL)
376 return((TypeInfo *) type_info);
377 /*
378 Check for table-based substitution match.
379 */
380 for (i=0; i < ArraySize(fontmap); i++)
381 {
382 if (family == (const char *) NULL)
383 {
384 if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
385 (LocaleCompare(fontmap[i].name,"helvetica") != 0))
386 continue;
387 }
388 else
389 if (LocaleCompare(fontmap[i].name,family) != 0)
390 continue;
391 type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
392 exception);
393 break;
394 }
395 if (type_info != (TypeInfo *) NULL)
396 {
397 ThrowException(exception,TypeError,FontSubstitutionRequired,
398 type_info->family);
399 return((TypeInfo *) type_info);
400 }
401 if (family != (const char *) NULL)
402 type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
403 exception);
404 return((TypeInfo *) type_info);
405 }
406
407 /*
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409 % %
410 % %
411 % %
412 % G e t T y p e l i s t %
413 % %
414 % %
415 % %
416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 %
418 % GetTypeList() returns any types that match the specified pattern.
419 %
420 % The format of the GetTypeList function is:
421 %
422 % char **GetTypeList(const char *pattern,unsigned long *number_types)
423 %
424 % A description of each parameter follows:
425 %
426 % o pattern: Specifies a pointer to a text string containing a pattern.
427 %
428 % o number_types: This integer returns the number of types in the list.
429 %
430 %
431 */
GetTypeList(const char * pattern,unsigned long * number_types)432 MagickExport char **GetTypeList(const char *pattern,unsigned long *number_types)
433 {
434 char
435 **typelist;
436
437 ExceptionInfo
438 exception;
439
440 register const TypeInfo
441 *p;
442
443 register long
444 i;
445
446 /*
447 Allocate type list.
448 */
449 assert(pattern != (char *) NULL);
450 assert(number_types != (unsigned long *) NULL);
451 *number_types=0;
452 GetExceptionInfo(&exception);
453 p=GetTypeInfo("*",&exception);
454 DestroyExceptionInfo(&exception);
455 if (p == (const TypeInfo *) NULL)
456 return((char **) NULL);
457 i=0;
458 for (p=type_list; p != (const TypeInfo *) NULL; p=p->next)
459 i++;
460 typelist=MagickAllocateMemory(char **,i*sizeof(char *));
461 if (typelist == (char **) NULL)
462 return((char **) NULL);
463 i=0;
464 for (p=type_list; p != (const TypeInfo *) NULL; p=p->next)
465 {
466 if (p->stealth)
467 continue;
468 if (GlobExpression(p->name,pattern))
469 typelist[i++]=AllocateString(p->name);
470 }
471 *number_types=i;
472 return(typelist);
473 }
474
475 /*
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 % %
478 % %
479 % %
480 + I n i t i a l i z e T y p e I n f o %
481 % %
482 % %
483 % %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 %
486 % Method InitializeTypeInfo initializes the type facility
487 %
488 % The format of the InitializeTypeInfo method is:
489 %
490 % MagickPassFail InitializeTypeInfo(void)
491 %
492 %
493 */
494 MagickPassFail
InitializeTypeInfo(void)495 InitializeTypeInfo(void)
496 {
497 assert(type_semaphore == (SemaphoreInfo *) NULL);
498 type_semaphore=AllocateSemaphoreInfo();
499 return MagickPass;
500 }
501
502 /*
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 % %
505 % %
506 % %
507 % L i s t T y p e I n f o %
508 % %
509 % %
510 % %
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 %
513 % Method ListTypeInfo lists the fonts to a file.
514 %
515 % The format of the ListTypeInfo method is:
516 %
517 % unsigned int ListTypeInfo(FILE *file,ExceptionInfo *exception)
518 %
519 % A description of each parameter follows.
520 %
521 % o file: An pointer to a FILE.
522 %
523 % o exception: Return any errors or warnings in this structure.
524 %
525 %
526 */
527
ListTypeInfo(FILE * file,ExceptionInfo * exception)528 MagickExport unsigned int ListTypeInfo(FILE *file,ExceptionInfo *exception)
529 {
530 char
531 weight[MaxTextExtent];
532
533 const char
534 *family,
535 *name,
536 *stretch,
537 *style;
538
539 register const TypeInfo
540 *p;
541
542 if (file == (FILE *) NULL)
543 file=stdout;
544 (void) GetTypeInfo("*",exception);
545 LockSemaphoreInfo(type_semaphore);
546 for (p=type_list; p != (const TypeInfo *) NULL; p=p->next)
547 {
548 if ((p->previous == (TypeInfo *) NULL) ||
549 (LocaleCompare(p->path,p->previous->path) != 0))
550 {
551 if (p->previous != (TypeInfo *) NULL)
552 (void) fprintf(file,"\n");
553 if (p->path != (char *) NULL)
554 (void) fprintf(file,"Path: %.1024s\n\n",p->path);
555 (void) fprintf(file,"%-32.32s %-23.23s %-7.7s %-8s %-3s\n",
556 "Name","Family","Style","Stretch","Weight");
557 (void) fprintf(file,"--------------------------------------------------"
558 "------------------------------\n");
559 }
560 if (p->stealth)
561 continue;
562 name="unknown";
563 if (p->name != (char *) NULL)
564 name=p->name;
565 family="unknown";
566 if (p->family != (char *) NULL)
567 family=p->family;
568 style=StyleTypeToString(p->style);
569 stretch=StretchTypeToString(p->stretch);
570 FormatString(weight,"%lu",p->weight);
571 (void) fprintf(file,"%-32.32s %-23.23s %-7.7s %-9s %-3s\n",
572 name,family,style,stretch,weight);
573 }
574 (void) fflush(file);
575 UnlockSemaphoreInfo(type_semaphore);
576 return(True);
577 }
578
579 /*
580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581 % %
582 % %
583 % %
584 + R e a d T y p e C o n f i g u r e F i l e %
585 % %
586 % %
587 % %
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589 %
590 % ReadTypeConfigureFile() reads the type configuration file which provides
591 % a mapping between type attributes and font files.
592 %
593 % The format of the ReadTypeConfigureFile method is:
594 %
595 % unsigned int ReadTypeConfigureFile(const char *basename,
596 % const unsigned long depth,ExceptionInfo *exception)
597 %
598 % A description of each parameter follows:
599 %
600 % o status: ReadTypeConfigureFile() returns True if at least one entry
601 % is read, otherwise False is returned.
602 %
603 % o basename: The type configuration filename.
604 %
605 % o depth: depth of <include /> statements.
606 %
607 % o exception: Return any errors or warnings in this structure.
608 %
609 %
610 */
ReadTypeConfigureFile(const char * basename,const unsigned long depth,ExceptionInfo * exception)611 static unsigned int ReadTypeConfigureFile(const char *basename,
612 const unsigned long depth,ExceptionInfo *exception)
613 {
614 char
615 keyword[MaxTextExtent],
616 path[MaxTextExtent],
617 *q,
618 *token,
619 *xml;
620
621 #if defined(MSWINDOWS)
622 char
623 GhostscriptFontDir[MaxTextExtent];
624 #endif
625
626 size_t
627 length,
628 token_max_length;
629
630 /*
631 Read the type configure file.
632 */
633 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
634 "File path=\"%.1024s\", recursion depth=%lu",basename,depth);
635 (void) strlcpy(path,basename,sizeof(path));
636 #if defined(MSWINDOWS)
637 /*
638 For Windows, cache the location of the Ghostscript fonts.
639 */
640 GhostscriptFontDir[0]='\0';
641 if (NTGhostscriptFonts(GhostscriptFontDir,MaxTextExtent-2))
642 (void) strlcat(GhostscriptFontDir,DirectorySeparator,
643 sizeof(GhostscriptFontDir));
644 #endif
645 if (depth == 0)
646 {
647 /*
648 Load top configuration file based on configure search path.
649 */
650 xml=(char *) GetConfigureBlob(basename,path,&length,exception);
651 if (xml == (char *) NULL)
652 xml=AllocateString(TypeMap);
653 }
654 else
655 {
656 /*
657 Load subordinate configuration file based on path specified
658 by parent configuration file.
659 */
660 if (IsAccessibleAndNotEmpty(basename))
661 xml=(char *) FileToBlob(basename,&length,exception);
662 else
663 {
664 GetPathComponent(basename,TailPath,path);
665 xml=(char *) GetConfigureBlob(path,keyword,&length,exception);
666 }
667 if (xml == (char *) NULL)
668 return (False);
669 }
670
671 token=AllocateString(xml);
672 token_max_length=strlen(token);
673 for (q=xml; *q != '\0'; )
674 {
675 /*
676 Interpret XML.
677 */
678 MagickGetToken(q,&q,token,token_max_length);
679 if (*token == '\0')
680 break;
681 (void) strlcpy(keyword,token,MaxTextExtent);
682 if (LocaleNCompare(keyword,"<!--",4) == 0)
683 {
684 /*
685 Comment element.
686 */
687 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
688 MagickGetToken(q,&q,token,token_max_length);
689 continue;
690 }
691 if (LocaleCompare(keyword,"<include") == 0)
692 {
693 /*
694 Include element.
695 */
696 while ( (*token != '/' && *(token+1) != '>') && (*q != '\0'))
697 {
698 (void) strlcpy(keyword,token,MaxTextExtent);
699 MagickGetToken(q,&q,token,token_max_length);
700 if (*token != '=')
701 continue;
702 MagickGetToken(q,&q,token,token_max_length);
703 if (LocaleCompare(keyword,"file") == 0)
704 {
705 if (depth > 200)
706 ThrowException(exception,ConfigureError,IncludeElementNestedTooDeeply,path);
707 else
708 {
709 char
710 filename[MaxTextExtent];
711
712 GetPathComponent(path,HeadPath,filename);
713 if (filename[0] != '\0')
714 (void) strlcat(filename,DirectorySeparator,sizeof(filename));
715 (void) strlcat(filename,token,sizeof(filename));
716 (void) ReadTypeConfigureFile(filename,depth+1,exception);
717 }
718 if (type_list != (TypeInfo *) NULL)
719 while (type_list->next != (TypeInfo *) NULL)
720 type_list=type_list->next;
721 }
722 }
723 continue;
724 }
725 if (LocaleCompare(keyword,"<type") == 0)
726 {
727 TypeInfo
728 *type_info;
729
730 /*
731 Allocate memory for the type list.
732 */
733 type_info=MagickAllocateMemory(TypeInfo *,sizeof(TypeInfo));
734 if (type_info == (TypeInfo *) NULL)
735 MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
736 UnableToAllocateTypeInfo);
737 (void) memset(type_info,0,sizeof(TypeInfo));
738 type_info->path=AcquireString(path);
739 type_info->signature=MagickSignature;
740 if (type_list == (TypeInfo *) NULL)
741 {
742 type_list=type_info;
743 continue;
744 }
745 /*
746 Append entry to end of type list
747 */
748 while (type_list->next != (TypeInfo *) NULL)
749 type_list=type_list->next;
750 type_list->next=type_info;
751 type_info->previous=type_list;
752 type_list=type_list->next;
753 continue;
754 }
755 if (type_list == (TypeInfo *) NULL)
756 continue;
757 MagickGetToken(q,(char **) NULL,token,token_max_length);
758 if (*token != '=')
759 continue;
760 MagickGetToken(q,&q,token,token_max_length);
761 MagickGetToken(q,&q,token,token_max_length);
762 switch (*keyword)
763 {
764 case 'E':
765 case 'e':
766 {
767 if (LocaleCompare((char *) keyword,"encoding") == 0)
768 {
769 type_list->encoding=AcquireString(token);
770 break;
771 }
772 break;
773 }
774 case 'F':
775 case 'f':
776 {
777 if (LocaleCompare((char *) keyword,"family") == 0)
778 {
779 type_list->family=AcquireString(token);
780 break;
781 }
782 if (LocaleCompare((char *) keyword,"format") == 0)
783 {
784 type_list->format=AcquireString(token);
785 break;
786 }
787 if (LocaleCompare((char *) keyword,"foundry") == 0)
788 {
789 type_list->foundry=AcquireString(token);
790 break;
791 }
792 if (LocaleCompare((char *) keyword,"fullname") == 0)
793 {
794 type_list->description=AcquireString(token);
795 break;
796 }
797 break;
798 }
799 case 'G':
800 case 'g':
801 {
802 if (LocaleCompare((char *) keyword,"glyphs") == 0)
803 {
804 char
805 *glyphs;
806
807 glyphs=(char *) NULL;
808 (void) CloneString(&glyphs,token);
809 #if defined(MSWINDOWS)
810 if (strchr(glyphs,'@') != (char *) NULL)
811 SubstituteString(&glyphs,"@ghostscript_font_dir@",GhostscriptFontDir);
812 #endif
813 type_list->glyphs=glyphs;
814 break;
815 }
816 break;
817 }
818 case 'M':
819 case 'm':
820 {
821 if (LocaleCompare((char *) keyword,"metrics") == 0)
822 {
823 char
824 *metrics;
825
826 metrics=AcquireString(token);
827 #if defined(MSWINDOWS)
828 if (strchr(metrics,'@') != (char *) NULL)
829 SubstituteString(&metrics,"@ghostscript_font_dir@",GhostscriptFontDir);
830 #endif
831 type_list->metrics=metrics;
832 break;
833 }
834 break;
835 }
836 case 'N':
837 case 'n':
838 {
839 if (LocaleCompare((char *) keyword,"name") == 0)
840 {
841 type_list->name=AcquireString(token);
842 break;
843 }
844 break;
845 }
846 case 'S':
847 case 's':
848 {
849 if (LocaleCompare((char *) keyword,"stealth") == 0)
850 {
851 type_list->stealth=LocaleCompare(token,"True") == 0;
852 break;
853 }
854 if (LocaleCompare((char *) keyword,"stretch") == 0)
855 {
856 if (LocaleCompare(token,"condensed") == 0)
857 type_list->stretch=CondensedStretch;
858 if (LocaleCompare(token,"expanded") == 0)
859 type_list->stretch=ExpandedStretch;
860 if (LocaleCompare(token,"extra-condensed") == 0)
861 type_list->stretch=ExtraCondensedStretch;
862 if (LocaleCompare(token,"extra-expanded") == 0)
863 type_list->stretch=ExtraExpandedStretch;
864 if (LocaleCompare(token,"normal") == 0)
865 type_list->stretch=NormalStretch;
866 if (LocaleCompare(token,"semi-condensed") == 0)
867 type_list->stretch=SemiCondensedStretch;
868 if (LocaleCompare(token,"semi-expanded") == 0)
869 type_list->stretch=SemiExpandedStretch;
870 if (LocaleCompare(token,"ultra-condensed") == 0)
871 type_list->stretch=UltraCondensedStretch;
872 if (LocaleCompare(token,"ultra-expanded") == 0)
873 type_list->stretch=UltraExpandedStretch;
874 break;
875 }
876 if (LocaleCompare((char *) keyword,"style") == 0)
877 {
878 if (LocaleCompare(token,"italic") == 0)
879 type_list->style=ItalicStyle;
880 if (LocaleCompare(token,"normal") == 0)
881 type_list->style=NormalStyle;
882 if (LocaleCompare(token,"oblique") == 0)
883 type_list->style=ObliqueStyle;
884 break;
885 }
886 break;
887 }
888 case 'W':
889 case 'w':
890 {
891 if (LocaleCompare((char *) keyword,"weight") == 0)
892 {
893 type_list->weight=MagickAtoL(token);
894 if (LocaleCompare(token,"bold") == 0)
895 type_list->weight=700;
896 if (LocaleCompare(token,"normal") == 0)
897 type_list->weight=400;
898 break;
899 }
900 break;
901 }
902 default:
903 break;
904 }
905 }
906 MagickFreeMemory(token);
907 MagickFreeMemory(xml);
908 if (type_list == (TypeInfo *) NULL)
909 return(False);
910 while (type_list->previous != (TypeInfo *) NULL)
911 type_list=type_list->previous;
912 return(True);
913 }
914