1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | #ifdef HAVE_CONFIG_H1 |
42 | #include <config.h> |
43 | #endif |
44 | #include "libxfontint.h" |
45 | #include <X11/fonts/fontmisc.h> |
46 | #include <string.h> |
47 | #include <ctype.h> |
48 | #include <math.h> |
49 | |
50 | #ifndef True(-1) |
51 | #define True(-1) (-1) |
52 | #endif /* True */ |
53 | #ifndef False(0) |
54 | #define False(0) (0) |
55 | #endif /* False */ |
56 | |
57 | #include "xttcap.h" |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | typedef struct TagSPropRecValListNodeP |
67 | { |
68 | SPropRecValContainerEntityP containerE; |
69 | struct TagSPropRecValListNodeP *nextNode; |
70 | } SPropRecValListNodeP; |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | static SPropertyRecord const validRecords[] = |
79 | { |
80 | { "FontFile", eRecTypeString }, |
81 | { "FaceNumber", eRecTypeString }, |
82 | { "AutoItalic", eRecTypeDouble }, |
83 | { "DoubleStrike", eRecTypeString }, |
84 | { "FontProperties", eRecTypeBool }, |
85 | { "ForceSpacing", eRecTypeString }, |
86 | { "ScaleBBoxWidth", eRecTypeString }, |
87 | { "ScaleWidth", eRecTypeDouble }, |
88 | { "EncodingOptions", eRecTypeString }, |
89 | { "Hinting", eRecTypeBool }, |
90 | { "VeryLazyMetrics", eRecTypeBool }, |
91 | { "CodeRange", eRecTypeString }, |
92 | { "EmbeddedBitmap", eRecTypeString }, |
93 | { "VeryLazyBitmapWidthScale", eRecTypeDouble }, |
94 | { "ForceConstantSpacingCodeRange", eRecTypeString }, |
95 | { "ForceConstantSpacingMetrics", eRecTypeString }, |
96 | { "Dummy", eRecTypeVoid } |
97 | }; |
98 | static int const |
99 | numOfValidRecords = sizeof(validRecords)/sizeof(validRecords[0]); |
100 | |
101 | |
102 | static struct { |
103 | char const * capVariable; |
104 | char const * recordName; |
105 | } const correspondRelations[] = { |
106 | { "fn", "FaceNumber" }, |
107 | { "ai", "AutoItalic" }, |
108 | { "ds", "DoubleStrike" }, |
109 | { "fp", "FontProperties" }, |
110 | { "fs", "ForceSpacing" }, |
111 | { "bw", "ScaleBBoxWidth" }, |
112 | { "sw", "ScaleWidth" }, |
113 | { "eo", "EncodingOptions" }, |
114 | { "vl", "VeryLazyMetrics" }, |
115 | { "bs", "VeryLazyBitmapWidthScale" }, |
116 | { "cr", "CodeRange" }, |
117 | { "eb", "EmbeddedBitmap" }, |
118 | { "hi", "Hinting" }, |
119 | { "fc", "ForceConstantSpacingCodeRange" }, |
120 | { "fm", "ForceConstantSpacingMetrics" } |
121 | }; |
122 | static int const |
123 | numOfCorrespondRelations |
124 | = sizeof(correspondRelations)/sizeof(correspondRelations[0]); |
125 | |
126 | |
127 | |
128 | |
129 | |
130 | |
131 | static Bool |
132 | get_record_type_by_name(SPropertyRecord const ** const refRefRecord, |
133 | char const *strName) |
134 | { |
135 | Bool result = False(0); |
136 | int i; |
137 | |
138 | *refRefRecord = NULL((void *)0); |
139 | for (i=0; i<numOfValidRecords; i++) { |
140 | if (!strcasecmp(validRecords[i].strRecordName, strName)) { |
141 | result = True(-1); |
142 | *refRefRecord = &validRecords[i]; |
143 | break; |
144 | } |
145 | } |
146 | |
147 | return result; |
148 | } |
149 | |
150 | |
151 | static Bool |
152 | SPropRecValList_add_record(SDynPropRecValList *pThisList, |
153 | char const * const recordName, |
154 | char const * const strValue) |
155 | { |
156 | Bool result = False(0); |
157 | SPropRecValContainerEntityP tmpContainerE; |
158 | |
159 | if (get_record_type_by_name(&tmpContainerE.refRecordType, recordName)) { |
160 | switch (tmpContainerE.refRecordType->recordType) { |
161 | case eRecTypeInteger: |
162 | { |
163 | int val; |
164 | char *endPtr; |
165 | |
166 | val = strtol(strValue, &endPtr, 0); |
167 | if ('\0' != *endPtr) { |
168 | fprintf(stderr__stderrp, |
169 | "truetype font property : " |
170 | "%s record needs integer value.\n", |
171 | recordName); |
172 | result = True(-1); |
173 | goto quit; |
174 | } |
175 | SPropContainer_value_int(&tmpContainerE)((&tmpContainerE)->uValue.integerValue) = val; |
176 | } |
177 | break; |
178 | case eRecTypeDouble: |
179 | { |
180 | double val; |
181 | char *endPtr; |
182 | |
183 | val = strtod(strValue, &endPtr); |
184 | if ('\0' != *endPtr) { |
185 | fprintf(stderr__stderrp, |
186 | "truetype font property : " |
187 | "%s record needs floating point value.\n", |
188 | recordName); |
189 | result = True(-1); |
190 | goto quit; |
191 | } |
192 | SPropContainer_value_dbl(&tmpContainerE)((&tmpContainerE)->uValue.doubleValue) = val; |
193 | } |
194 | break; |
195 | case eRecTypeBool: |
196 | { |
197 | Bool val; |
198 | |
199 | if (!strcasecmp(strValue, "yes")) |
200 | val = True(-1); |
201 | else if (!strcasecmp(strValue, "y")) |
202 | val = True(-1); |
203 | else if (!strcasecmp(strValue, "on")) |
204 | val = True(-1); |
205 | else if (!strcasecmp(strValue, "true")) |
206 | val = True(-1); |
207 | else if (!strcasecmp(strValue, "t")) |
208 | val = True(-1); |
209 | else if (!strcasecmp(strValue, "ok")) |
210 | val = True(-1); |
211 | else if (!strcasecmp(strValue, "no")) |
212 | val = False(0); |
213 | else if (!strcasecmp(strValue, "n")) |
214 | val = False(0); |
215 | else if (!strcasecmp(strValue, "off")) |
216 | val = False(0); |
217 | else if (!strcasecmp(strValue, "false")) |
218 | val = False(0); |
219 | else if (!strcasecmp(strValue, "f")) |
220 | val = False(0); |
221 | else if (!strcasecmp(strValue, "bad")) |
222 | val = False(0); |
223 | else { |
224 | fprintf(stderr__stderrp, |
225 | "truetype font property : " |
226 | "%s record needs boolean value.\n", |
227 | recordName); |
228 | result = True(-1); |
229 | goto quit; |
230 | } |
231 | SPropContainer_value_bool(&tmpContainerE)((&tmpContainerE)->uValue.boolValue) = val; |
232 | } |
233 | break; |
234 | case eRecTypeString: |
235 | { |
236 | char *p; |
237 | |
238 | if (NULL((void *)0) == (p = strdup(strValue))) { |
239 | fprintf(stderr__stderrp, |
240 | "truetype font property : " |
241 | "cannot allocate memory.\n"); |
242 | result = True(-1); |
243 | goto quit; |
244 | } |
245 | SPropContainer_value_str(&tmpContainerE)((&tmpContainerE)->uValue.dynStringValue) = p; |
246 | } |
247 | break; |
248 | case eRecTypeVoid: |
249 | if ('\0' != *strValue) { |
250 | fprintf(stderr__stderrp, |
251 | "truetype font property : " |
252 | "%s record needs void.\n", recordName); |
253 | result = True(-1); |
254 | } |
255 | break; |
256 | } |
257 | { |
258 | |
259 | SPropRecValListNodeP *newNode; |
260 | |
261 | if (NULL((void *)0) == (newNode = malloc(sizeof(*newNode)))) { |
262 | fprintf(stderr__stderrp, |
263 | "truetype font property : " |
264 | "cannot allocate memory.\n"); |
265 | result = True(-1); |
266 | goto quit; |
267 | } |
268 | newNode->nextNode = pThisList->headNode; |
269 | newNode->containerE = tmpContainerE; |
270 | tmpContainerE.refRecordType = NULL((void *)0); |
271 | |
272 | pThisList->headNode = newNode; |
273 | } |
274 | } else { |
275 | |
276 | fprintf(stderr__stderrp, |
277 | "truetype font : " |
278 | "invalid record name \"%s.\"\n", recordName); |
279 | result = True(-1); |
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 | |
293 | static Bool |
294 | get_one_line(FILE *is, char *buf) |
295 | { |
296 | Bool result = False(0); |
297 | int count = 0; |
298 | Bool flHead = True(-1); |
299 | Bool flSpace = False(0); |
300 | Bool flInSingleQuote = False(0); |
301 | Bool flInDoubleQuote = False(0); |
302 | Bool flBackSlash = False(0); |
303 | Bool flFirstElement = True(-1); |
304 | |
305 | *buf = '\0'; |
306 | for (;;) { |
307 | int c = fgetc(is); |
308 | |
309 | if (ferror(is)) { |
310 | fprintf(stderr__stderrp, "truetype font property file : read error.\n"); |
311 | result = True(-1); |
312 | break; |
313 | } |
314 | |
315 | if (EOF(-1) == c) { |
316 | if (flInSingleQuote || flInDoubleQuote) { |
317 | fprintf(stderr__stderrp, |
318 | "truetype font property file : unmatched quote.\n"); |
319 | result = True(-1); |
320 | } |
321 | break; |
322 | } |
323 | if (flInSingleQuote) { |
324 | if ('\'' == c) { |
325 | |
326 | flInSingleQuote = False(0); |
327 | c = -1; |
328 | } else |
329 | |
330 | ; |
331 | goto trans; |
332 | } |
333 | if (flBackSlash) { |
334 | |
335 | |
336 | flBackSlash = False(0); |
337 | if ('n' == c) |
338 | |
339 | c = '\n'; |
340 | if ('\n' == c) |
341 | |
342 | c = -1; |
343 | else |
344 | |
345 | ; |
346 | goto trans; |
347 | } |
348 | if ('\\' == c) { |
349 | |
350 | flBackSlash = True(-1); |
351 | c = -1; |
352 | goto trans; |
353 | } |
354 | if (flInDoubleQuote) { |
355 | if ('"' == c) { |
356 | |
357 | flInDoubleQuote = False(0); |
358 | c = -1; |
359 | } else |
360 | |
361 | ; |
362 | goto trans; |
363 | } |
364 | if ('#' == c) { |
365 | |
366 | while ('\n' != c) { |
367 | c = fgetc(is); |
368 | if (ferror(is)) { |
369 | fprintf(stderr__stderrp, |
370 | "truetype font property file : read error.\n"); |
371 | result = True(-1); |
372 | break; |
373 | } |
374 | if (EOF(-1) == c) { |
375 | break; |
376 | } |
377 | } |
378 | break; |
379 | } |
380 | if ('\'' == c) { |
381 | |
382 | flInSingleQuote = True(-1); |
383 | c = -1; |
384 | goto trans; |
385 | } |
386 | if ('"' == c) { |
387 | |
388 | flInDoubleQuote = True(-1); |
389 | c = -1; |
390 | goto trans; |
391 | } |
392 | if ('\n' == c) |
393 | |
394 | break; |
395 | if (isspace(c)) { |
396 | |
397 | if (!flHead) |
398 | |
399 | flSpace = True(-1); |
400 | continue; |
401 | } |
402 | trans: |
403 | |
404 | |
405 | flHead = False(0); |
406 | do { |
407 | if (count>=LEN_LINEBUF-1) { |
408 | |
409 | fprintf(stderr__stderrp, |
410 | "truetype font property file : too long line.\n"); |
411 | result = True(-1); |
412 | goto quit; |
413 | } |
414 | if (flSpace) { |
415 | |
416 | |
417 | if (flFirstElement) { |
418 | |
419 | flFirstElement = False(0); |
420 | |
421 | *buf = (char)0xff; |
422 | } else |
423 | *buf = ' '; |
424 | flSpace = False(0); |
425 | } else |
426 | if (-1 != c) { |
427 | *buf = c; |
428 | c = -1; |
429 | } else |
430 | |
431 | buf--; |
432 | buf++; |
433 | } while (-1 != c); |
434 | |
435 | } |
436 | *buf = '\0'; |
437 | |
438 | quit: |
439 | return result; |
440 | } |
441 | |
442 | |
443 | static Bool |
444 | parse_one_line(SDynPropRecValList *pThisList, FILE *is) |
445 | { |
446 | Bool result = False(0); |
447 | char *buf = NULL((void *)0); |
448 | char *recordHead, *valueHead = NULL((void *)0); |
449 | |
450 | if (NULL((void *)0) == (buf = malloc(LEN_LINEBUF))) { |
451 | fprintf(stderr__stderrp, |
452 | "truetype font property file : cannot allocate memory.\n"); |
453 | result = True(-1); |
454 | goto abort; |
455 | } |
456 | { |
457 | recordHead = buf; |
458 | |
459 | do { |
460 | if (get_one_line(is, buf)) { |
461 | result = True(-1); |
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((void *)0) != (valueHead = strchr(buf, 0xff))) { |
472 | *valueHead = '\0'; |
473 | valueHead++; |
474 | } else |
475 | valueHead = buf+strlen(buf); |
476 | #if 0 |
477 | fprintf(stderr__stderrp, |
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 | |
491 | Bool |
492 | SPropRecValList_read_prop_file(SDynPropRecValList *pThisList, |
493 | char const * const strFileName) |
494 | { |
495 | Bool result = False(0); |
496 | FILE *is; |
497 | |
498 | #if 1 |
499 | if (!strcmp(strFileName, "-")) |
500 | is = stdin__stdinp; |
501 | else |
502 | #endif |
503 | is = fopen(strFileName, "r"); |
504 | if (NULL((void *)0) == is) { |
505 | fprintf(stderr__stderrp, "truetype font property : cannot open file %s.\n", |
506 | strFileName); |
507 | result = True(-1); |
508 | goto abort; |
509 | } |
510 | { |
511 | for (;;) { |
512 | if (False(0) != (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 | |
529 | Bool |
530 | SPropRecValList_new(SDynPropRecValList *pThisList) |
531 | { |
532 | Bool result = False(0); |
533 | |
534 | pThisList->headNode = NULL((void *)0); |
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((void *)0)!=p; p=p->nextNode) { |
545 | switch (p->containerE.refRecordType->recordType) { |
546 | case eRecTypeInteger: |
547 | fprintf(stderr__stderrp, "%s = %d\n", |
548 | p->containerE.refRecordType->strRecordName, |
549 | p->containerE.uValue.integerValue); |
550 | break; |
551 | case eRecTypeDouble: |
552 | fprintf(stderr__stderrp, "%s = %f\n", |
553 | p->containerE.refRecordType->strRecordName, |
554 | p->containerE.uValue.doubleValue); |
555 | break; |
556 | case eRecTypeBool: |
557 | fprintf(stderr__stderrp, "%s = %s\n", |
558 | p->containerE.refRecordType->strRecordName, |
559 | p->containerE.uValue.boolValue |
560 | ? "True":"False"); |
561 | break; |
562 | case eRecTypeString: |
563 | fprintf(stderr__stderrp, "%s = \"%s\"\n", |
564 | p->containerE.refRecordType->strRecordName, |
565 | p->containerE.uValue.dynStringValue); |
566 | break; |
567 | case eRecTypeVoid: |
568 | fprintf(stderr__stderrp, "%s = void\n", |
569 | p->containerE.refRecordType->strRecordName); |
570 | break; |
571 | } |
572 | } |
573 | } |
574 | #endif |
575 | |
576 | |
577 | |
578 | Bool |
579 | SPropRecValList_search_record(SRefPropRecValList *pThisList, |
580 | SPropRecValContainer *refRecValue, |
581 | char const * const recordName) |
582 | { |
583 | Bool result = False(0); |
584 | SPropRecValListNodeP *p; |
585 | |
586 | *refRecValue = NULL((void *)0); |
587 | for (p=pThisList->headNode; NULL((void *)0)!=p; p=p->nextNode) { |
588 | if (!strcasecmp(p->containerE.refRecordType->strRecordName, |
589 | recordName)) { |
590 | *refRecValue = &p->containerE; |
591 | result = True(-1); |
592 | break; |
593 | } |
594 | } |
595 | |
596 | return result; |
597 | } |
598 | |
599 | |
600 | |
601 | Bool |
602 | SPropRecValList_add_by_font_cap(SDynPropRecValList *pThisList, |
603 | char const *strCapHead) |
604 | { |
605 | Bool result = False(0); |
606 | |
607 | char const *term; |
608 | |
609 | if (NULL((void *)0) == (term = strrchr(strCapHead, ':'))) |
| |
610 | goto abort; |
611 | |
612 | { |
613 | |
614 | char const *p; |
615 | for (p=term-1; p>=strCapHead; p--) { |
| 2 | | Loop condition is false. Execution continues on line 641 | |
|
616 | if ( ':'==*p ) { |
617 | |
618 | |
619 | |
620 | |
621 | if ( p!=term ) { |
622 | int len = term-p-1; |
623 | char *value; |
624 | |
625 | value=malloc(len+1); |
626 | memcpy(value, p+1, len)__builtin___memcpy_chk (value, p+1, len, __builtin_object_size (value, 0)); |
627 | value[len]='\0'; |
628 | SPropRecValList_add_record(pThisList, |
629 | "FaceNumber", |
630 | value); |
631 | free(value); |
632 | term=p; |
633 | } |
634 | break; |
635 | } |
636 | if ( !isdigit((unsigned char)*p) ) |
637 | break; |
638 | } |
639 | } |
640 | |
641 | while (strCapHead<term) { |
| 3 | | Assuming 'strCapHead' is < 'term' | |
|
| 4 | | Loop condition is true. Entering loop body | |
|
642 | int i; |
643 | char const *nextColon = strchr(strCapHead, ':'); |
644 | if (0<nextColon-strCapHead) { |
| |
645 | char *duplicated = malloc((nextColon-strCapHead)+1); |
| |
646 | { |
647 | char *value; |
648 | |
649 | memcpy(duplicated, strCapHead, nextColon-strCapHead)__builtin___memcpy_chk (duplicated, strCapHead, nextColon-strCapHead , __builtin_object_size (duplicated, 0)); |
650 | duplicated[nextColon-strCapHead] = '\0'; |
651 | if (NULL((void *)0) != (value=strchr(duplicated, '='))) { |
| |
652 | *value = '\0'; |
653 | value++; |
654 | } else |
655 | value = &duplicated[nextColon-strCapHead]; |
656 | |
657 | for (i=0; i<numOfCorrespondRelations; i++) { |
| 8 | | Loop condition is true. Entering loop body | |
|
658 | if (!strcasecmp(correspondRelations[i].capVariable, |
| |
659 | duplicated)) { |
660 | if (SPropRecValList_add_record(pThisList, |
| |
661 | correspondRelations[i] |
662 | .recordName, |
663 | value)) |
664 | break; |
| 11 | | Execution continues on line 668 | |
|
665 | goto next; |
666 | } |
667 | } |
668 | fprintf(stderr__stderrp, "truetype font : Illegal Font Cap.\n"); |
| 12 | | Potential leak of memory pointed to by 'duplicated' |
|
669 | result = True(-1); |
670 | break; |
671 | next: |
672 | ; |
673 | } |
674 | free(duplicated); |
675 | } |
676 | strCapHead = nextColon+1; |
677 | } |
678 | |
679 | |
680 | abort: |
681 | return result; |
682 | } |
683 | |
684 | |