upload tizen1.0 source
[framework/uifw/xorg/lib/libxfont.git] / src / FreeType / xttcap.c
1 /* ===EmacsMode: -*- Mode: C; tab-width:4; c-basic-offset: 4; -*- === */
2 /* ===FileName: ===
3    Copyright (c) 1998 Takuya SHIOZAKI, All Rights reserved.
4    Copyright (c) 1998 X-TrueType Server Project, All rights reserved. 
5    Copyright (c) 2003 After X-TT Project, All rights reserved.
6
7 ===Notice
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions
10    are met:
11    1. Redistributions of source code must retain the above copyright
12       notice, this list of conditions and the following disclaimer.
13    2. Redistributions in binary form must reproduce the above copyright
14       notice, this list of conditions and the following disclaimer in the
15       documentation and/or other materials provided with the distribution.
16
17    THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27    SUCH DAMAGE.
28
29    Major Release ID: X-TrueType Server Version 1.4 [Charles's Wain Release 0]
30
31 Notice===
32  */
33
34 /*
35 #include "xttversion.h"
36
37 static char const * const releaseID =
38     _XTT_RELEASE_NAME;
39 */
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 #include <X11/fonts/fontmisc.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <math.h>
48
49 #ifndef True
50 #define True (-1)
51 #endif /* True */
52 #ifndef False
53 #define False (0)
54 #endif /* False */
55
56 #include "xttcap.h"
57
58
59 /**************************************************************************
60   Private Data Types
61  */
62
63 /* Property Record List */
64 /* List Node */
65 typedef struct TagSPropRecValListNodeP
66 {
67     SPropRecValContainerEntityP containerE;
68     struct TagSPropRecValListNodeP *nextNode;
69 } SPropRecValListNodeP;
70
71
72 /**************************************************************************
73   Tables
74  */
75
76 /* valid record field */
77 static SPropertyRecord const validRecords[] =
78 {
79     { "FontFile",               eRecTypeString  },
80     { "FaceNumber",             eRecTypeString },
81     { "AutoItalic",             eRecTypeDouble  },
82     { "DoubleStrike",           eRecTypeString  },
83     { "FontProperties",         eRecTypeBool    },
84     { "ForceSpacing",           eRecTypeString  },
85     { "ScaleBBoxWidth",         eRecTypeString  },
86     { "ScaleWidth",             eRecTypeDouble  },
87     { "EncodingOptions",        eRecTypeString  },
88     { "Hinting",                eRecTypeBool    },
89     { "VeryLazyMetrics",        eRecTypeBool    },
90     { "CodeRange",              eRecTypeString  },
91     { "EmbeddedBitmap",         eRecTypeString  },
92     { "VeryLazyBitmapWidthScale", eRecTypeDouble  },
93     { "ForceConstantSpacingCodeRange", eRecTypeString },
94     { "ForceConstantSpacingMetrics", eRecTypeString },
95     { "Dummy",                  eRecTypeVoid    }
96 };
97 static int const
98 numOfValidRecords = sizeof(validRecords)/sizeof(validRecords[0]);
99
100 /* correspondence between record name and cap variable name */
101 static struct {
102     char const * capVariable;
103     char const * recordName;
104 } const correspondRelations[] = {
105     { "fn", "FaceNumber" },
106     { "ai", "AutoItalic" },
107     { "ds", "DoubleStrike" },
108     { "fp", "FontProperties" },
109     { "fs", "ForceSpacing" },
110     { "bw", "ScaleBBoxWidth" },
111     { "sw", "ScaleWidth" },
112     { "eo", "EncodingOptions" },
113     { "vl", "VeryLazyMetrics" },
114     { "bs", "VeryLazyBitmapWidthScale" },
115     { "cr", "CodeRange" },
116     { "eb", "EmbeddedBitmap" },
117     { "hi", "Hinting" },
118     { "fc", "ForceConstantSpacingCodeRange" },
119     { "fm", "ForceConstantSpacingMetrics" }
120 };
121 static int const
122 numOfCorrespondRelations
123 = sizeof(correspondRelations)/sizeof(correspondRelations[0]);
124
125 /**************************************************************************
126   Functions
127  */
128
129 /* get property record type by record name */
130 static Bool /* True == Found, False == Not Found */
131 get_record_type_by_name(SPropertyRecord const ** const refRefRecord, /*result*/
132                         char const *strName)
133 {
134     Bool result = False;
135     int i;
136     
137     *refRefRecord = NULL;
138     for (i=0; i<numOfValidRecords; i++) {
139         if (!strcasecmp(validRecords[i].strRecordName, strName)) {
140             result = True;
141             *refRefRecord = &validRecords[i];
142             break;
143         }
144     }
145     
146     return result;
147 }
148
149 /* Add Property Record Value */
150 static Bool /* True == Error, False == Success */
151 SPropRecValList_add_record(SDynPropRecValList *pThisList,
152                            char const * const recordName,
153                            char const * const strValue)
154 {
155     Bool result = False;
156     SPropRecValContainerEntityP tmpContainerE;
157
158     if (get_record_type_by_name(&tmpContainerE.refRecordType, recordName)) {
159         switch (tmpContainerE.refRecordType->recordType) {
160         case eRecTypeInteger:
161             {
162                 int val;
163                 char *endPtr;
164                     
165                 val = strtol(strValue, &endPtr, 0);
166                 if ('\0' != *endPtr) {
167                     fprintf(stderr,
168                             "truetype font property : "
169                             "%s record needs integer value.\n",
170                             recordName);
171                     result = True;
172                     goto quit;
173                 }
174                 SPropContainer_value_int(&tmpContainerE) = val;
175             }
176             break;
177         case eRecTypeDouble:
178             {
179                 double val;
180                 char *endPtr;
181                     
182                 val = strtod(strValue, &endPtr);
183                 if ('\0' != *endPtr) {
184                     fprintf(stderr,
185                             "truetype font property : "
186                             "%s record needs floating point value.\n",
187                             recordName);
188                     result = True;
189                     goto quit;
190                 }
191                 SPropContainer_value_dbl(&tmpContainerE) = val;
192             }
193             break;
194         case eRecTypeBool:
195             {
196                 Bool val;
197                 
198                 if (!strcasecmp(strValue, "yes"))
199                     val = True;
200                 else if (!strcasecmp(strValue, "y"))
201                     val = True;
202                 else if (!strcasecmp(strValue, "on"))
203                     val = True;
204                 else if (!strcasecmp(strValue, "true"))
205                     val = True;
206                 else if (!strcasecmp(strValue, "t"))
207                     val = True;
208                 else if (!strcasecmp(strValue, "ok"))
209                     val = True;
210                 else if (!strcasecmp(strValue, "no"))
211                     val = False;
212                 else if (!strcasecmp(strValue, "n"))
213                     val = False;
214                 else if (!strcasecmp(strValue, "off"))
215                     val = False;
216                 else if (!strcasecmp(strValue, "false"))
217                     val = False;
218                 else if (!strcasecmp(strValue, "f"))
219                     val = False;
220                 else if (!strcasecmp(strValue, "bad"))
221                     val = False;
222                 else {
223                     fprintf(stderr,
224                             "truetype font property : "
225                             "%s record needs boolean value.\n",
226                             recordName);
227                     result = True;
228                     goto quit;
229                 }
230                 SPropContainer_value_bool(&tmpContainerE) = val;
231             }
232             break;
233         case eRecTypeString:
234             {
235                 char *p;
236                     
237                 if (NULL == (p = malloc(strlen(strValue)+1))) {
238                     fprintf(stderr,
239                             "truetype font property : "
240                             "cannot allocate memory.\n");
241                     result = True;
242                     goto quit;
243                 }
244                 strcpy(p, strValue);
245                 SPropContainer_value_str(&tmpContainerE) = p;
246             }
247             break;
248         case eRecTypeVoid:
249             if ('\0' != *strValue) {
250                 fprintf(stderr,
251                         "truetype font property : "
252                         "%s record needs void.\n", recordName);
253                 result = True;
254             }
255             break;
256         }
257         {
258             /* add to list */
259             SPropRecValListNodeP *newNode;
260             
261             if (NULL == (newNode = malloc(sizeof(*newNode)))) {
262                 fprintf(stderr,
263                         "truetype font property : "
264                         "cannot allocate memory.\n");
265                 result = True;
266                 goto quit;
267             }
268             newNode->nextNode = pThisList->headNode;
269             newNode->containerE = tmpContainerE;
270             tmpContainerE.refRecordType = NULL; /* invalidate --
271                                                    disown value handle. */
272             pThisList->headNode = newNode;
273         }
274     } else {
275         /* invalid record name */
276         fprintf(stderr,
277                 "truetype font : "
278                 "invalid record name \"%s.\"\n", recordName);
279         result = True;
280     }
281
282  quit:
283     return result;
284 }
285
286 #ifdef USE_TTP_FILE
287
288 #ifndef LEN_LINEBUF
289 #define LEN_LINEBUF 2048
290 #endif /* !def LEN_LINEBUF */
291
292 /* get one line */
293 static Bool /* True == Error, False == Success */
294 get_one_line(FILE *is, char *buf)
295 {
296     Bool result = False;
297     int count = 0;
298     Bool flHead = True;
299     Bool flSpace = False;
300     Bool flInSingleQuote = False;
301     Bool flInDoubleQuote = False;
302     Bool flBackSlash = False;
303     Bool flFirstElement = True;
304     
305     *buf = '\0';
306     for (;;) {
307         int c = fgetc(is);
308         
309         if (ferror(is)) {
310             fprintf(stderr, "truetype font property file : read error.\n");
311             result = True;
312             break;
313         }
314
315         if (EOF == c) {
316             if (flInSingleQuote || flInDoubleQuote) {
317                 fprintf(stderr,
318                         "truetype font property file : unmatched quote.\n");
319                 result = True;
320             }
321             break;
322         }
323         if (flInSingleQuote) {
324             if ('\'' == c) {
325                 /* end of single quoted string */
326                 flInSingleQuote = False;
327                 c = -1; /* NOT extract to buffer. */
328             } else
329                 /* others, extract all character to buffer unconditionally. */
330                 ;
331             goto trans;
332         }
333         if (flBackSlash) {
334             /* escape --- when just before character is backslash,
335                next character is escaped. */
336             flBackSlash = False;
337             if ('n' == c)
338                 /* newline */
339                 c = '\n';
340             if ('\n' == c)
341                 /* ignore newline */
342                 c = -1;
343             else
344                 /* others, extract all character to buffer unconditionally. */
345                 ;
346             goto trans;
347         }
348         if ('\\' == c) {
349             /* set flag to escape next character. */
350             flBackSlash = True;
351             c = -1; /* NOT extract to buffer. */
352             goto trans;
353         }
354         if (flInDoubleQuote) {
355             if ('"' == c) {
356                 /* end of double quoted string */
357                 flInDoubleQuote = False;
358                 c = -1; /* NOT extract to buffer. */
359             } else
360                 /* others, extract all character to buffer unconditionally. */
361                 ;
362             goto trans;
363         }
364         if ('#' == c) {
365             /* skip comment till end of line. */
366             while ('\n' != c) {
367                 c = fgetc(is);
368                 if (ferror(is)) {
369                     fprintf(stderr,
370                             "truetype font property file : read error.\n");
371                     result = True;
372                     break;
373                 }
374                 if (EOF == c) {
375                     break;
376                 }
377             }
378             break;
379         }
380         if ('\'' == c) {
381             /* into single quoted string */
382             flInSingleQuote = True;
383             c = -1; /* NOT extract to buffer. */
384             goto trans;
385         }
386         if ('"' == c) {
387             /* into double quoted string */
388             flInDoubleQuote = True;
389             c = -1; /* NOT extract to buffer. */
390             goto trans;
391         }
392         if ('\n' == c)
393             /* End of Line */
394             break;
395         if (isspace(c)) {
396             /* convine multiple spaces */
397             if (!flHead)
398                 /* except space at the head of line */
399                 flSpace = True;
400             continue;
401         }
402       trans:
403         /* set flHead to False, since current character is not white space
404            when reaches here. */
405         flHead = False;
406         do {
407           if (count>=LEN_LINEBUF-1) {
408               /* overflow */
409               fprintf(stderr,
410                       "truetype font property file : too long line.\n");
411               result = True;
412               goto quit;
413           }
414           if (flSpace) {
415               /* just before characters is white space, but
416                  current character is not WS. */
417               if (flFirstElement) {
418                   /* this spaces is the first cell(?) of white spaces. */
419                   flFirstElement = False;
420                   /* separate record name and record value */
421                   *buf = (char)0xff;
422               } else
423                   *buf = ' ';
424               flSpace = False;
425           } else
426               if (-1 != c) {
427                   *buf = c;
428                   c = -1; /* invalidate */
429               } else
430                   /* skip */
431                   buf--;
432           buf++;
433         } while (-1 != c); /* when 'c' is not -1, it means
434                               that 'c' contains an untreated character. */
435     }
436     *buf = '\0';
437
438   quit:
439     return result;
440 }
441
442 /* parse one line */
443 static Bool /* True == Error, False == Success */
444 parse_one_line(SDynPropRecValList *pThisList, FILE *is)
445 {
446     Bool result = False;
447     char *buf = NULL;
448     char *recordHead, *valueHead = NULL;
449     
450     if (NULL == (buf = malloc(LEN_LINEBUF))) {
451         fprintf(stderr,
452                 "truetype font property file : cannot allocate memory.\n");
453         result = True;
454         goto abort;
455     }
456     {
457         recordHead = buf;
458 /*        refRecordValue->refRecordType = NULL;*/
459         do {
460             if (get_one_line(is, buf)) {
461                 result = True;
462                 goto quit;
463             }
464             if (feof(is)) {
465                 if ('\0' == *buf)
466                     goto quit;
467                 break;
468             }
469         } while ('\0' == *buf);
470
471         if (NULL != (valueHead = strchr(buf, 0xff))) {
472             *valueHead = '\0';
473             valueHead++;
474         } else
475             valueHead = buf+strlen(buf);
476 #if 0
477         fprintf(stderr,
478                 "truetype font property file : \n"
479                 "recName:\"%s\"\nvalue:\"%s\"\n",
480                 recordHead, valueHead);
481 #endif
482         result = SPropRecValList_add_record(pThisList, recordHead, valueHead);
483     }
484   quit:
485     free(buf);
486   abort:    
487     return result;
488 }
489
490 /* Read Property File */
491 Bool /* True == Error, False == Success */
492 SPropRecValList_read_prop_file(SDynPropRecValList *pThisList,
493                                char const * const strFileName)
494 {
495     Bool result = False;
496     FILE *is;
497     
498 #if 1
499     if (!strcmp(strFileName, "-"))
500         is = stdin;
501     else
502 #endif
503         is = fopen(strFileName, "r");
504     if (NULL == is) {
505         fprintf(stderr, "truetype font property : cannot open file %s.\n",
506                 strFileName);
507         result = True;
508         goto abort;
509     }
510     {
511         for (;;) {
512             if (False != (result = parse_one_line(pThisList, is)))
513                 goto quit;
514             if (feof(is))
515                 break;
516         }
517     }
518   quit:
519 #if 1
520     if (strcmp(strFileName, "-"))
521 #endif
522         fclose(is);
523   abort:
524     return result;
525 }
526 #endif /* USE_TTP_FILE */
527
528 /* Constructor for Container Node */
529 Bool /* True == Error, False == Success */
530 SPropRecValList_new(SDynPropRecValList *pThisList)
531 {
532     Bool result = False;
533     
534     pThisList->headNode = NULL;
535
536     return result;
537 }
538
539 #ifdef DUMP
540 void
541 SPropRecValList_dump(SRefPropRecValList *pThisList)
542 {
543     SPropRecValListNodeP *p;
544     for (p=pThisList->headNode; NULL!=p; p=p->nextNode) {
545         switch (p->containerE.refRecordType->recordType) {
546         case eRecTypeInteger:
547             fprintf(stderr, "%s = %d\n",
548                     p->containerE.refRecordType->strRecordName,
549                     p->containerE.uValue.integerValue);
550             break;
551         case eRecTypeDouble:
552             fprintf(stderr, "%s = %f\n",
553                     p->containerE.refRecordType->strRecordName,
554                     p->containerE.uValue.doubleValue);
555             break;
556         case eRecTypeBool:
557             fprintf(stderr, "%s = %s\n",
558                     p->containerE.refRecordType->strRecordName,
559                     p->containerE.uValue.boolValue
560                     ? "True":"False");
561             break;
562         case eRecTypeString:
563             fprintf(stderr, "%s = \"%s\"\n",
564                     p->containerE.refRecordType->strRecordName,
565                     p->containerE.uValue.dynStringValue);
566             break;
567         case eRecTypeVoid:
568             fprintf(stderr, "%s = void\n",
569                     p->containerE.refRecordType->strRecordName);
570             break;
571         }
572     }
573 }
574 #endif
575
576
577 /* Search Property Record */
578 Bool /* True == Hit, False == Miss */
579 SPropRecValList_search_record(SRefPropRecValList *pThisList,
580                               SPropRecValContainer *refRecValue,
581                               char const * const recordName)
582 {
583     Bool result = False;
584     SPropRecValListNodeP *p;
585     
586     *refRecValue = NULL;
587     for (p=pThisList->headNode; NULL!=p; p=p->nextNode) {
588         if (!strcasecmp(p->containerE.refRecordType->strRecordName,
589                           recordName)) {
590             *refRecValue = &p->containerE;
591             result = True;
592             break;
593         }
594     }
595
596     return result;
597 }
598
599
600 /* Parse TTCap */
601 Bool /* True == Error, False == Success */
602 SPropRecValList_add_by_font_cap(SDynPropRecValList *pThisList,
603                                 char const *strCapHead)
604 {
605     Bool result = False;
606     /*    SPropertyRecord const *refRecordType; */
607     char const *term;
608     
609     if (NULL == (term = strrchr(strCapHead, ':')))
610         goto abort;
611
612     {
613         /* for xfsft compatible */
614         char const *p;
615         for (p=term-1; p>=strCapHead; p--) {
616             if ( ':'==*p ) {
617                 /*
618                  * :num:filename
619                  * ^p  ^term
620                  */
621                 if ( p!=term ) {
622                     int len = term-p-1;
623                     char *value;
624
625                     len = term-p-1;
626                     value=malloc(len+1);
627                     memcpy(value, p+1, len);
628                     value[len]='\0';
629                     SPropRecValList_add_record(pThisList,
630                                                "FaceNumber",
631                                                value);
632                     free(value);
633                     term=p;
634                 }
635                 break;
636             }
637             if ( !isdigit(*p) )
638                 break;
639         }
640     }
641
642     while (strCapHead<term) {
643         int i;
644         char const *nextColon = strchr(strCapHead, ':');
645         if (0<nextColon-strCapHead) {
646             char *duplicated = malloc((nextColon-strCapHead)+1);
647             {
648                 char *value;
649             
650                 memcpy(duplicated, strCapHead, nextColon-strCapHead);
651                 duplicated[nextColon-strCapHead] = '\0';
652                 if (NULL != (value=strchr(duplicated, '='))) {
653                     *value = '\0';
654                     value++;
655                 } else
656                     value = &duplicated[nextColon-strCapHead];
657             
658                 for (i=0; i<numOfCorrespondRelations; i++) {
659                     if (!strcasecmp(correspondRelations[i].capVariable,
660                                       duplicated)) {
661                         if (SPropRecValList_add_record(pThisList,
662                                                         correspondRelations[i]
663                                                        .recordName,
664                                                        value))
665                             break;
666                         goto next;
667                     }
668                 }
669                 fprintf(stderr, "truetype font : Illegal Font Cap.\n");
670                 result = True;
671                 break;
672               next:
673                 ;
674             }
675             free(duplicated);
676         }
677         strCapHead = nextColon+1;
678     }
679     
680     /*  quit: */
681   abort:
682     return result;
683 }
684
685
686 /**************************************************************************
687   Functions (xttmisc)
688  */
689
690 /* strdup clone with using the allocator of X server */
691 char *
692 XttXstrdup(char const *str)
693 {
694     char *result;
695     
696     result = malloc(strlen(str)+1);
697
698     if (result)
699         strcpy(result, str);
700
701     return result;
702 }
703
704
705 /* end of file */