1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Font API client */
18 
19 #include "stdlib.h"             /* abs() */
20 
21 #include "memory_.h"
22 #include "math_.h"
23 #include "stat_.h"              /* include before definition of esp macro, bug 691123 */
24 #include "string_.h"
25 #include "ghost.h"
26 #include "gp.h"
27 #include "oper.h"
28 #include "gxdevice.h"
29 #include "gxfont.h"
30 #include "gxfont1.h"
31 #include "gxchar.h"
32 #include "gzpath.h"
33 #include "gxpath.h"
34 #include "gxfcache.h"
35 #include "gxchrout.h"
36 #include "gximask.h"
37 #include "gscoord.h"
38 #include "gspaint.h"
39 #include "gsfont.h"
40 #include "gspath.h"
41 #include "bfont.h"
42 #include "dstack.h"
43 #include "estack.h"
44 #include "ichar.h"
45 #include "idict.h"
46 #include "iname.h"
47 #include "ifont.h"
48 #include "icid.h"
49 #include "igstate.h"
50 #include "icharout.h"
51 
52 #include "ifapi.h"
53 #include "iplugin.h"
54 #include "store.h"
55 #include "gzstate.h"
56 /* #include "gdevpsf.h" */
57 #include "stream.h"             /* for files.h */
58 #include "gscrypt1.h"
59 #include "gxfcid.h"
60 #include "gsstype.h"
61 #include "gxchar.h"             /* for st_gs_show_enum */
62 #include "ipacked.h"            /* for packed_next */
63 #include "iddict.h"
64 #include "ifont42.h"            /* for string_array_access_proc */
65 #include "gdebug.h"
66 #include "gsimage.h"
67 #include "gxcldev.h"
68 #include "gxdevmem.h"
69 
70 #include "gxfapi.h"
71 
72 /* -------------------------------------------------------- */
73 
74 typedef struct sfnts_reader_s sfnts_reader;
75 struct sfnts_reader_s
76 {
77     ref *sfnts;
78     const gs_memory_t *memory;
79     const byte *p;
80     long index;
81     uint offset;
82     uint length;
83     bool error;
84          byte(*rbyte) (sfnts_reader *r);
85          ushort(*rword) (sfnts_reader *r);
86          ulong(*rlong) (sfnts_reader *r);
87     int (*rstring) (sfnts_reader *r, byte *v, int length);
88     void (*seek) (sfnts_reader *r, ulong pos);
89 };
90 
91 static void
sfnts_next_elem(sfnts_reader * r)92 sfnts_next_elem(sfnts_reader *r)
93 {
94     ref s;
95     int code;
96 
97     if (r->error)
98         return;
99     do {
100     	r->index++;
101     	code = array_get(r->memory, r->sfnts, r->index, &s);
102     	if (code == gs_error_rangecheck) {
103     		r->error |= 2;
104     	}
105     	else if (code < 0) {
106     		r->error |= 1;
107     	}
108     	if (r->error)
109     		return;
110     	r->p = s.value.const_bytes;
111     	r->length = r_size(&s) & ~(uint) 1; /* See Adobe Technical Note # 5012, section 4.2. */
112     } while (r->length == 0);
113     r->offset = 0;
114 }
115 
116 static inline byte
sfnts_reader_rbyte_inline(sfnts_reader * r)117 sfnts_reader_rbyte_inline(sfnts_reader *r)
118 {
119     if (r->offset >= r->length)
120         sfnts_next_elem(r);
121     return (r->error ? 0 : r->p[r->offset++]);
122 }
123 
124 static byte
sfnts_reader_rbyte(sfnts_reader * r)125 sfnts_reader_rbyte(sfnts_reader *r)
126 {                               /* old compiler compatibility */
127     return (sfnts_reader_rbyte_inline(r));
128 }
129 
130 #define SFNTS_READER_RBYTE_TO_USHORT(r) ((ulong)sfnts_reader_rbyte_inline(r))
131 
132 static ushort
sfnts_reader_rword(sfnts_reader * r)133 sfnts_reader_rword(sfnts_reader *r)
134 {
135     ushort retval;
136 
137     retval = SFNTS_READER_RBYTE_TO_USHORT(r) << 8;
138     retval += SFNTS_READER_RBYTE_TO_USHORT(r);
139 
140     return retval;
141 }
142 
143 #undef SFNTS_READER_RBYTE_TO_USHORT
144 
145 #define SFNTS_READER_RBYTE_TO_ULONG(r) ((ulong)sfnts_reader_rbyte_inline(r))
146 
147 static ulong
sfnts_reader_rlong(sfnts_reader * r)148 sfnts_reader_rlong(sfnts_reader *r)
149 {
150     ulong retval;
151     retval = SFNTS_READER_RBYTE_TO_ULONG(r) << 24;
152     retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 16;
153     retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 8;
154     retval += SFNTS_READER_RBYTE_TO_ULONG(r);
155     return retval;
156 }
157 
158 #undef SFNTS_READER_RWORD_TO_LONG
159 
160 static int
sfnts_reader_rstring(sfnts_reader * r,byte * v,int length)161 sfnts_reader_rstring(sfnts_reader *r, byte *v, int length)
162 {
163     int rlength = length;
164 
165     if (length <= 0)
166         return (0);
167     while (!r->error) {
168         int l = min(length, r->length - r->offset);
169 
170         memcpy(v, r->p + r->offset, l);
171         length -= l;
172         r->offset += l;
173         if (length <= 0)
174             return (rlength);
175         v += l;
176         sfnts_next_elem(r);
177     }
178     return (rlength - length);
179 }
180 
181 static void
sfnts_reader_seek(sfnts_reader * r,ulong pos)182 sfnts_reader_seek(sfnts_reader *r, ulong pos)
183 {                               /* fixme : optimize */
184     ulong skipped = 0;
185 
186     r->index = -1;
187     sfnts_next_elem(r);
188     while (skipped + r->length < pos && !r->error) {
189         skipped += r->length;
190         sfnts_next_elem(r);
191     }
192     r->offset = pos - skipped;
193 }
194 
195 static void
sfnts_reader_init(sfnts_reader * r,ref * pdr)196 sfnts_reader_init(sfnts_reader *r, ref *pdr)
197 {
198     r->rbyte = sfnts_reader_rbyte;
199     r->rword = sfnts_reader_rword;
200     r->rlong = sfnts_reader_rlong;
201     r->rstring = sfnts_reader_rstring;
202     r->seek = sfnts_reader_seek;
203     r->index = -1;
204     r->error = false;
205     if (r_type(pdr) != t_dictionary ||
206         dict_find_string(pdr, "sfnts", &r->sfnts) <= 0)
207         r->error = true;
208     sfnts_next_elem(r);
209 }
210 
211 /* -------------------------------------------------------- */
212 
213 typedef struct sfnts_writer_s sfnts_writer;
214 struct sfnts_writer_s
215 {
216     byte *buf, *p;
217     int buf_size;
218     void (*wbyte) (sfnts_writer *w, byte v);
219     void (*wword) (sfnts_writer *w, ushort v);
220     void (*wlong) (sfnts_writer *w, ulong v);
221     void (*wstring) (sfnts_writer *w, byte *v, int length);
222 };
223 
224 static void
sfnts_writer_wbyte(sfnts_writer * w,byte v)225 sfnts_writer_wbyte(sfnts_writer *w, byte v)
226 {
227     if (w->buf + w->buf_size < w->p + 1)
228         return;                 /* safety */
229     w->p[0] = v;
230     w->p++;
231 }
232 
233 static void
sfnts_writer_wword(sfnts_writer * w,ushort v)234 sfnts_writer_wword(sfnts_writer *w, ushort v)
235 {
236     if (w->buf + w->buf_size < w->p + 2)
237         return;                 /* safety */
238     w->p[0] = v / 256;
239     w->p[1] = v % 256;
240     w->p += 2;
241 }
242 
243 static void
sfnts_writer_wlong(sfnts_writer * w,ulong v)244 sfnts_writer_wlong(sfnts_writer *w, ulong v)
245 {
246     if (w->buf + w->buf_size < w->p + 4)
247         return;                 /* safety */
248     w->p[0] = v >> 24;
249     w->p[1] = (v >> 16) & 0xFF;
250     w->p[2] = (v >> 8) & 0xFF;
251     w->p[3] = v & 0xFF;
252     w->p += 4;
253 }
254 
255 static void
sfnts_writer_wstring(sfnts_writer * w,byte * v,int length)256 sfnts_writer_wstring(sfnts_writer *w, byte *v, int length)
257 {
258     if (w->buf + w->buf_size < w->p + length)
259         return;                 /* safety */
260     memcpy(w->p, v, length);
261     w->p += length;
262 }
263 
264 static const sfnts_writer sfnts_writer_stub = {
265     0, 0, 0,
266     sfnts_writer_wbyte,
267     sfnts_writer_wword,
268     sfnts_writer_wlong,
269     sfnts_writer_wstring
270 };
271 
272 /* -------------------------------------------------------- */
273 
274 static inline bool
sfnts_need_copy_table(byte * tag)275 sfnts_need_copy_table(byte *tag)
276 {
277     return (memcmp(tag, "glyf", 4) && memcmp(tag, "glyx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
278             memcmp(tag, "loca", 4) && memcmp(tag, "locx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
279             memcmp(tag, "cmap", 4));
280 }
281 
282 static void
sfnt_copy_table(sfnts_reader * r,sfnts_writer * w,int length)283 sfnt_copy_table(sfnts_reader *r, sfnts_writer *w, int length)
284 {
285     byte buf[1024];
286 
287     while (length > 0 && !r->error) {
288         int l = min(length, sizeof(buf));
289 
290         (void)r->rstring(r, buf, l);
291         w->wstring(w, buf, l);
292         length -= l;
293     }
294 }
295 
296 static ulong
sfnts_copy_except_glyf(sfnts_reader * r,sfnts_writer * w)297 sfnts_copy_except_glyf(sfnts_reader *r, sfnts_writer *w)
298 {                               /* Note : TTC is not supported and probably is unuseful for Type 42. */
299     /* This skips glyf, loca and cmap from copying. */
300     struct
301     {
302         byte tag[4];
303         ulong checkSum, offset, offset_new, length;
304     } tables[30];
305     const ushort alignment = 4; /* Not sure, maybe 2 */
306     ulong version = r->rlong(r);
307     ushort num_tables = r->rword(r);
308     ushort i, num_tables_new = 0;
309     ushort searchRange, entrySelector = 0, rangeShift, v;
310     ulong size_new = 12;
311 
312     r->rword(r);                /* searchRange */
313     r->rword(r);                /* entrySelector */
314     r->rword(r);                /* rangeShift */
315     for (i = 0; i < num_tables; i++) {
316         if (r->error)
317             return 0;
318         (void)r->rstring(r, tables[i].tag, 4);
319         tables[i].checkSum = r->rlong(r);
320         tables[i].offset = r->rlong(r);
321         tables[i].length = r->rlong(r);
322         tables[i].offset_new = size_new;
323         if (sfnts_need_copy_table(tables[i].tag)) {
324             num_tables_new++;
325             size_new +=
326                 (tables[i].length + alignment - 1) / alignment * alignment;
327         }
328     }
329     size_new += num_tables_new * 16;
330     if (w == 0)
331         return size_new;
332 
333     searchRange = v = num_tables_new * 16;
334     for (i = 0; v; i++) {
335         v >>= 1;
336         searchRange |= v;
337         entrySelector++;
338     }
339     searchRange -= searchRange >> 1;
340     rangeShift = num_tables_new * 16 - searchRange;
341 
342     w->wlong(w, version);
343     w->wword(w, num_tables_new);
344     w->wword(w, searchRange);
345     w->wword(w, entrySelector);
346     w->wword(w, rangeShift);
347     for (i = 0; i < num_tables; i++) {
348         if (sfnts_need_copy_table(tables[i].tag)) {
349             w->wstring(w, tables[i].tag, 4);
350             w->wlong(w, tables[i].checkSum);
351             w->wlong(w, tables[i].offset_new + num_tables_new * 16);
352             w->wlong(w, tables[i].length);
353         }
354     }
355     for (i = 0; i < num_tables; i++) {
356         if (sfnts_need_copy_table(tables[i].tag)) {
357             int k = tables[i].length;
358 
359             r->seek(r, tables[i].offset);
360             if (r->error)
361                 return 0;
362             if (w->p - w->buf != tables[i].offset_new + num_tables_new * 16)
363                 return 0;       /* the algorithm consistency check */
364             sfnt_copy_table(r, w, tables[i].length);
365             for (; k & (alignment - 1); k++)
366                 w->wbyte(w, 0);
367         }
368     }
369     return (size_new);
370 }
371 
372 static ulong
true_type_size(ref * pdr)373 true_type_size(ref *pdr)
374 {
375     sfnts_reader r;
376 
377     sfnts_reader_init(&r, pdr);
378     return (sfnts_copy_except_glyf(&r, 0));
379 }
380 
381 static ushort
FAPI_FF_serialize_tt_font(gs_fapi_font * ff,void * buf,int buf_size)382 FAPI_FF_serialize_tt_font(gs_fapi_font *ff, void *buf, int buf_size)
383 {
384     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
385     sfnts_reader r;
386     sfnts_writer w = sfnts_writer_stub;
387 
388     w.buf_size = buf_size;
389     w.buf = w.p = buf;
390     sfnts_reader_init(&r, pdr);
391     if (!sfnts_copy_except_glyf(&r, &w))
392         return (1);
393     return (r.error);
394 }
395 
396 static inline ushort
float_to_ushort(float v)397 float_to_ushort(float v)
398 {
399     return ((ushort) (v * 16)); /* fixme : the scale may depend on renderer */
400 }
401 
402 /* In general, we assumed that the entries we use below have been validated (at least for type)
403  * at definefont time. This means validating each entry only once, rather than on every read
404  * here. Better, for example, for BlendDesignMap which is an array, of arrays, of arrays of
405  * numbers.
406  */
407 static ushort
FAPI_FF_get_word(gs_fapi_font * ff,gs_fapi_font_feature var_id,int index)408 FAPI_FF_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index)
409 {
410     gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
411     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
412 
413     switch ((int)var_id) {
414         case gs_fapi_font_feature_Weight:
415             return 0;           /* wrong */
416         case gs_fapi_font_feature_ItalicAngle:
417             return 0;           /* wrong */
418         case gs_fapi_font_feature_IsFixedPitch:
419             return 0;           /* wrong */
420         case gs_fapi_font_feature_UnderLinePosition:
421             return 0;           /* wrong */
422         case gs_fapi_font_feature_UnderlineThickness:
423             return 0;           /* wrong */
424         case gs_fapi_font_feature_FontType:
425             return (pfont->FontType == 2 ? 2 : 1);
426         case gs_fapi_font_feature_FontBBox:
427             switch (index) {
428                 case 0:
429                     return ((ushort) pfont->FontBBox.p.x);
430                 case 1:
431                     return ((ushort) pfont->FontBBox.p.y);
432                 case 2:
433                     return ((ushort) pfont->FontBBox.q.x);
434                 case 3:
435                     return ((ushort) pfont->FontBBox.q.y);
436             }
437             return 0;
438         case gs_fapi_font_feature_BlueValues_count:
439             return (pfont->data.BlueValues.count);
440         case gs_fapi_font_feature_BlueValues:
441             return (float_to_ushort(pfont->data.BlueValues.values[index]));
442         case gs_fapi_font_feature_OtherBlues_count:
443             return (pfont->data.OtherBlues.count);
444         case gs_fapi_font_feature_OtherBlues:
445             return (float_to_ushort(pfont->data.OtherBlues.values[index]));
446         case gs_fapi_font_feature_FamilyBlues_count:
447             return (pfont->data.FamilyBlues.count);
448         case gs_fapi_font_feature_FamilyBlues:
449             return (float_to_ushort(pfont->data.FamilyBlues.values[index]));
450         case gs_fapi_font_feature_FamilyOtherBlues_count:
451             return (pfont->data.FamilyOtherBlues.count);
452         case gs_fapi_font_feature_FamilyOtherBlues:
453             return (float_to_ushort
454                     (pfont->data.FamilyOtherBlues.values[index]));
455         case gs_fapi_font_feature_BlueShift:
456             return (float_to_ushort(pfont->data.BlueShift));
457         case gs_fapi_font_feature_BlueFuzz:
458             return (float_to_ushort(pfont->data.BlueShift));
459         case gs_fapi_font_feature_StdHW:
460             return (pfont->data.StdHW.count == 0 ? 0 : float_to_ushort(pfont->data.StdHW.values[0]));   /* UFST bug ? */
461         case gs_fapi_font_feature_StdVW:
462             return (pfont->data.StdVW.count == 0 ? 0 : float_to_ushort(pfont->data.StdVW.values[0]));   /* UFST bug ? */
463         case gs_fapi_font_feature_StemSnapH_count:
464             return (pfont->data.StemSnapH.count);
465         case gs_fapi_font_feature_StemSnapH:
466             return (float_to_ushort(pfont->data.StemSnapH.values[index]));
467         case gs_fapi_font_feature_StemSnapV_count:
468             return (pfont->data.StemSnapV.count);
469         case gs_fapi_font_feature_StemSnapV:
470             return (float_to_ushort(pfont->data.StemSnapV.values[index]));
471         case gs_fapi_font_feature_ForceBold:
472             return (pfont->data.ForceBold);
473         case gs_fapi_font_feature_LanguageGroup:
474             return (pfont->data.LanguageGroup);
475         case gs_fapi_font_feature_lenIV:
476             return (ff->need_decrypt ? 0 : pfont->data.lenIV);
477         case gs_fapi_font_feature_GlobalSubrs_count:
478             {
479                 ref *Private, *GlobalSubrs;
480 
481                 if (pfont->FontType == ft_encrypted2) {
482                     if (dict_find_string(pdr, "Private", &Private) <= 0)
483                         return 0;
484                     if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs)
485                         <= 0)
486                         return 0;;
487                     return (r_size(GlobalSubrs));
488                 }
489                 /* Since we don't have an error return capability, use as unlikely a value as possible */
490                 return (65535);
491             }
492         case gs_fapi_font_feature_Subrs_count:
493             {
494                 ref *Private, *Subrs;
495 
496                 if (dict_find_string(pdr, "Private", &Private) <= 0)
497                     return 0;
498                 if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
499                     return 0;
500                 return (r_size(Subrs));
501             }
502         case gs_fapi_font_feature_CharStrings_count:
503             {
504                 ref *CharStrings;
505 
506                 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
507                     return 0;
508                 return (dict_maxlength(CharStrings));
509             }
510             /* Multiple Master specific */
511         case gs_fapi_font_feature_DollarBlend:
512             {
513                 ref *DBlend;
514 
515                 if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
516                     return 0;
517                 return 1;
518             }
519         case gs_fapi_font_feature_BlendAxisTypes_count:
520             {
521                 ref *Info, *Axes;
522 
523                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
524                     return 0;
525                 if (dict_find_string(Info, "BlendAxisTypes", &Axes) <= 0)
526                     return 0;
527                 return (r_size(Axes));
528             }
529         case gs_fapi_font_feature_BlendFontInfo_count:
530             {
531                 ref *Info, *FontInfo;
532 
533                 if (dict_find_string(pdr, "Blend", &Info) <= 0)
534                     return 0;
535                 if (dict_find_string(Info, "FontInfo", &FontInfo) <= 0)
536                     return 0;
537                 return (dict_length(FontInfo));
538             }
539         case gs_fapi_font_feature_BlendPrivate_count:
540             {
541                 ref *Info, *Private;
542 
543                 if (dict_find_string(pdr, "Blend", &Info) <= 0)
544                     return 0;
545                 if (dict_find_string(Info, "Private", &Private) <= 0)
546                     return 0;
547                 return (dict_length(Private));
548             }
549         case gs_fapi_font_feature_WeightVector_count:
550             {
551                 return pfont->data.WeightVector.count;
552             }
553         case gs_fapi_font_feature_BlendDesignPositionsArrays_count:
554             {
555                 ref *Info, *Array;
556 
557                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
558                     return 0;
559                 if (dict_find_string(Info, "BlendDesignPositions", &Array) <=
560                     0)
561                     return 0;
562                 return (r_size(Array));
563             }
564         case gs_fapi_font_feature_BlendDesignMapArrays_count:
565             {
566                 ref *Info, *Array;
567 
568                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
569                     return 0;
570                 if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0)
571                     return 0;
572                 return (r_size(Array));
573             }
574         case gs_fapi_font_feature_BlendDesignMapSubArrays_count:
575             {
576                 ref *Info, *Array, SubArray;
577 
578                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
579                     return 0;
580                 if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0)
581                     return 0;
582                 if (array_get(ff->memory, Array, index, &SubArray) < 0)
583                     return 0;
584                 return (r_size(&SubArray));
585             }
586         case gs_fapi_font_feature_DollarBlend_length:
587             {
588                 ref *DBlend, Element, string;
589                 int i, length = 0;
590                 char Buffer[32];
591 
592                 if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
593                     return 0;
594                 for (i = 0; i < r_size(DBlend); i++) {
595                     if (array_get(ff->memory, DBlend, i, &Element) < 0)
596                         return 0;
597                     switch (r_btype(&Element)) {
598                         case t_name:
599                             name_string_ref(ff->memory, &Element, &string);
600                             length += r_size(&string) + 1;
601                             break;
602                         case t_real:
603                             gs_sprintf(Buffer, "%f", Element.value.realval);
604                             length += strlen(Buffer) + 1;
605                             break;
606                         case t_integer:
607                             gs_sprintf(Buffer, "%"PRIpsint, Element.value.intval);
608                             length += strlen(Buffer) + 1;
609                             break;
610                         case t_operator:
611                             {
612                                 op_def const *op;
613 
614                                 op = op_index_def(r_size(&Element));
615                                 length += strlen(op->oname + 1) + 1;
616                             }
617                             break;
618                         default:
619                             break;
620                     }
621                 }
622                 return length;
623             }
624         case gs_fapi_font_feature_BlendFontBBox_length:
625             {
626                 ref *Blend, *bfbbox;
627                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
628                     return 0;
629 
630                 if (dict_find_string(Blend, "FontBBox", &bfbbox) <= 0)
631                     return 0;
632                 return ((ushort)r_size(bfbbox));
633             }
634         case gs_fapi_font_feature_BlendFontBBox:
635             {
636                 ref *Blend, *bfbbox, subbfbbox, val;
637                 int aind, ind;
638                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
639                     return 0;
640                 if (dict_find_string(Blend, "FontBBox", &bfbbox) <= 0)
641                     return 0;
642                 ind = index % 4;
643                 aind = (index - ind) /4;
644                 if (array_get(ff->memory, bfbbox, aind, &subbfbbox) < 0)
645                     return 0;
646                 if (array_get(ff->memory, &subbfbbox, ind, &val) < 0)
647                     return 0;
648 
649                 return (ushort)val.value.intval;
650             }
651         case gs_fapi_font_feature_BlendBlueValues_length:
652             {
653                 ref *Priv, *Blend, *bbv;
654                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
655                     return 0;
656                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
657                     return 0;
658                 if (dict_find_string(Priv, "BlueValues", &bbv) <= 0)
659                     return 0;
660                 return ((ushort)r_size(bbv));
661             }
662         case gs_fapi_font_feature_BlendBlueValues_count:
663             {
664                 ref *Priv, *Blend, *bbv, sub;
665 
666                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
667                     return 0;
668                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
669                     return 0;
670                 if (dict_find_string(Priv, "BlueValues", &bbv) <= 0)
671                     return 0;
672                 if (array_get(ff->memory, bbv, index, &sub) < 0)
673                     return 0;
674                 return ((ushort)r_size(&sub));
675             }
676         case gs_fapi_font_feature_BlendBlueValues:
677             {
678                 ref *Priv, *Blend, *bbv, sub, r;
679                 int aind = 0;
680                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
681                     return 0;
682                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
683                     return 0;
684                 if (dict_find_string(Priv, "BlueValues", &bbv) <= 0)
685                     return 0;
686 
687                 while (1) {
688                     if (array_get(ff->memory, bbv, aind++, &sub) < 0)
689                         return 0;
690                     if (index - (int)r_size(&sub) < 0) {
691                         break;
692                     }
693                     index -= r_size(&sub);
694                 }
695                 if (array_get(ff->memory, &sub, index, &r) < 0)
696                     return 0;
697 
698                 return ((ushort)r.value.intval);
699             }
700         case gs_fapi_font_feature_BlendOtherBlues_length:
701             {
702                 ref *Priv, *Blend, *bob;
703                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
704                     return 0;
705                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
706                     return 0;
707                 if (dict_find_string(Priv, "OtherBlues", &bob) <= 0)
708                     return 0;
709                 return ((ushort)r_size(bob));
710             }
711         case gs_fapi_font_feature_BlendOtherBlues_count:
712             {
713                 ref *Priv, *Blend, *bob, sub;
714                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
715                     return 0;
716                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
717                     return 0;
718                 if (dict_find_string(Priv, "OtherBlues", &bob) <= 0)
719                     return 0;
720 
721                  if (array_get(ff->memory, bob, index, &sub) < 0)
722                     return 0;
723                return ((ushort)r_size(&sub));
724             }
725         case gs_fapi_font_feature_BlendOtherBlues:
726             {
727                 ref *Priv, *Blend, *bob, sub, r;
728                 int aind = 0;
729                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
730                     return 0;
731                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
732                     return 0;
733                 if (dict_find_string(Priv, "OtherBlues", &bob) <= 0)
734                     return 0;
735 
736                 while (1) {
737                     if (array_get(ff->memory, bob, aind++, &sub) < 0)
738                         return 0;
739                     if (index - (int)r_size(&sub) < 0) {
740                         break;
741                     }
742                     index -= r_size(&sub);
743                 }
744                 if (array_get(ff->memory, &sub, index, &r) < 0)
745                     return 0;
746 
747                 return ((ushort)r.value.intval);
748             }
749         case gs_fapi_font_feature_BlendBlueScale_count:
750             {
751                 ref *Priv, *Blend, *bbs;
752                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
753                     return 0;
754                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
755                     return 0;
756                 if (dict_find_string(Priv, "BlueScale", &bbs) <= 0)
757                     return 0;
758                return ((ushort)r_size(bbs));
759             }
760         case gs_fapi_font_feature_BlendBlueShift_count:
761             {
762                 ref *Priv, *Blend, *bbs;
763                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
764                     return 0;
765                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
766                     return 0;
767                 if (dict_find_string(Priv, "BlueShift", &bbs) <= 0)
768                     return 0;
769                return ((ushort)r_size(bbs));
770             }
771         case gs_fapi_font_feature_BlendBlueShift:
772             {
773                 ref *Priv, *Blend, *bbs, r;
774                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
775                     return 0;
776                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
777                     return 0;
778                 if (dict_find_string(Priv, "BlueShift", &bbs) <= 0)
779                     return 0;
780                 if (array_get(ff->memory, bbs, index, &r) < 0)
781                     return 0;
782 
783                return ((ushort)r.value.intval);
784             }
785         case gs_fapi_font_feature_BlendBlueFuzz_count:
786             {
787                 ref *Priv, *Blend, *bbf;
788                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
789                     return 0;
790                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
791                     return 0;
792                 if (dict_find_string(Priv, "BlueFuzz", &bbf) <= 0)
793                     return 0;
794                return ((ushort)r_size(bbf));
795             }
796         case gs_fapi_font_feature_BlendBlueFuzz:
797             {
798                 ref *Priv, *Blend, *bbf, r;
799                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
800                     return 0;
801                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
802                     return 0;
803                 if (dict_find_string(Priv, "BlueFuzz", &bbf) <= 0)
804                     return 0;
805                 if (array_get(ff->memory, bbf, index, &r) < 0)
806                     return 0;
807 
808                return ((ushort)r.value.intval);
809             }
810         case gs_fapi_font_feature_BlendForceBold_count:
811             {
812                 ref *Priv, *Blend, *bfb;
813                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
814                     return 0;
815                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
816                     return 0;
817                 if (dict_find_string(Priv, "ForceBold", &bfb) <= 0)
818                     return 0;
819                return ((ushort)r_size(bfb));
820             }
821         case gs_fapi_font_feature_BlendForceBold:
822             {
823                 ref *Priv, *Blend, *bfb, r;
824                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
825                     return 0;
826                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
827                     return 0;
828                 if (dict_find_string(Priv, "BlueFuzz", &bfb) <= 0)
829                     return 0;
830                 if (array_get(ff->memory, bfb, index, &r) < 0)
831                     return 0;
832 
833                return ((ushort)r.value.boolval);
834             }
835         case gs_fapi_font_feature_BlendStdHW_length:
836             {
837                 ref *Priv, *Blend, *stdhw;
838                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
839                     return 0;
840                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
841                     return 0;
842                 if (dict_find_string(Priv, "StdHW", &stdhw) <= 0)
843                     return 0;
844                 return ((ushort)r_size(stdhw));
845             }
846         case gs_fapi_font_feature_BlendStdHW_count:
847             {
848                 ref *Priv, *Blend, *stdhw, sub;
849                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
850                     return 0;
851                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
852                     return 0;
853                 if (dict_find_string(Priv, "StdHW", &stdhw) <= 0)
854                     return 0;
855 
856                 if (array_get(ff->memory, stdhw, index, &sub) < 0)
857                     return 0;
858                 return ((ushort)r_size(&sub));
859             }
860         case gs_fapi_font_feature_BlendStdHW:
861             {
862                 ref *Priv, *Blend, *stdhw, sub, r;
863                 int aind = 0;
864                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
865                     return 0;
866                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
867                     return 0;
868                 if (dict_find_string(Priv, "StdHW", &stdhw) <= 0)
869                     return 0;
870 
871                 while (1) {
872                     if (array_get(ff->memory, stdhw, aind++, &sub) < 0)
873                         return 0;
874                     if (index - (int)r_size(&sub) < 0) {
875                         break;
876                     }
877                     index -= r_size(&sub);
878                 }
879                 if (array_get(ff->memory, &sub, index, &r) < 0)
880                     return 0;
881 
882                 return ((ushort)r.value.intval);
883             }
884         case gs_fapi_font_feature_BlendStdVW_length:
885             {
886                 ref *Priv, *Blend, *stdvw;
887                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
888                     return 0;
889                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
890                     return 0;
891                 if (dict_find_string(Priv, "StdVW", &stdvw) <= 0)
892                     return 0;
893                 return ((ushort)r_size(stdvw));
894             }
895         case gs_fapi_font_feature_BlendStdVW_count:
896             {
897                 ref *Priv, *Blend, *stdvw, sub;
898                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
899                     return 0;
900                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
901                     return 0;
902                 if (dict_find_string(Priv, "StdVW", &stdvw) <= 0)
903                     return 0;
904 
905                 if (array_get(ff->memory, stdvw, index, &sub) < 0)
906                     return 0;
907                 return ((ushort)r_size(&sub));
908             }
909         case gs_fapi_font_feature_BlendStdVW:
910             {
911                 ref *Priv, *Blend, *stdvw, sub, r;
912                 int aind = 0;
913                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
914                     return 0;
915                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
916                     return 0;
917                 if (dict_find_string(Priv, "StdVW", &stdvw) <= 0)
918                     return 0;
919 
920                 while (1) {
921                     if (array_get(ff->memory, stdvw, aind++, &sub) < 0)
922                         return 0;
923                     if (index - (int)r_size(&sub) < 0) {
924                         break;
925                     }
926                     index -= r_size(&sub);
927                 }
928                 if (array_get(ff->memory, &sub, index, &r) < 0)
929                     return 0;
930 
931                 return ((ushort)r.value.intval);
932             }
933         case gs_fapi_font_feature_BlendStemSnapH_length:
934             {
935                 ref *Priv, *Blend, *ssh;
936                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
937                     return 0;
938                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
939                     return 0;
940                 if (dict_find_string(Priv, "StemSnapH", &ssh) <= 0)
941                     return 0;
942                 return ((ushort)r_size(ssh));
943             }
944         case gs_fapi_font_feature_BlendStemSnapH_count:
945             {
946                 ref *Priv, *Blend, *bssh, sub;
947                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
948                     return 0;
949                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
950                     return 0;
951                 if (dict_find_string(Priv, "StemSnapH", &bssh) <= 0)
952                     return 0;
953 
954                 if (array_get(ff->memory, bssh, index, &sub) < 0)
955                     return 0;
956                 return ((ushort)r_size(&sub));
957             }
958         case gs_fapi_font_feature_BlendStemSnapH:
959             {
960                 ref *Priv, *Blend, *bssh, sub, r;
961                 int aind = 0;
962                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
963                     return 0;
964                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
965                     return 0;
966                 if (dict_find_string(Priv, "StemSnapH", &bssh) <= 0)
967                     return 0;
968 
969                 while (1) {
970                     if (array_get(ff->memory, bssh, aind++, &sub) < 0)
971                         return 0;
972                     if (index - (int)r_size(&sub) < 0) {
973                         break;
974                     }
975                     index -= r_size(&sub);
976                 }
977                 if (array_get(ff->memory, &sub, index, &r) < 0)
978                     return 0;
979 
980                 return ((ushort)r.value.intval);
981             }
982         case gs_fapi_font_feature_BlendStemSnapV_length:
983             {
984                 ref *Priv, *Blend, *ssv;
985                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
986                     return 0;
987                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
988                     return 0;
989                 if (dict_find_string(Priv, "StdHW", &ssv) <= 0)
990                     return 0;
991                 return ((ushort)r_size(ssv));
992             }
993         case gs_fapi_font_feature_BlendStemSnapV_count:
994             {
995                 ref *Priv, *Blend, *bssv, sub;
996                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
997                     return 0;
998                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
999                     return 0;
1000                 if (dict_find_string(Priv, "StemSnapV", &bssv) <= 0)
1001                     return 0;
1002 
1003                 if (array_get(ff->memory, bssv, index, &sub) < 0)
1004                     return 0;
1005                 return ((ushort)r_size(&sub));
1006             }
1007         case gs_fapi_font_feature_BlendStemSnapV:
1008             {
1009                 ref *Priv, *Blend, *bssv, sub, r;
1010                 int aind = 0;
1011                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
1012                     return 0;
1013                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
1014                     return 0;
1015                 if (dict_find_string(Priv, "StemSnapV", &bssv) <= 0)
1016                     return 0;
1017 
1018                 while (1) {
1019                     if (array_get(ff->memory, bssv, aind++, &sub) < 0)
1020                         return 0;
1021                     if (index - (int)r_size(&sub) < 0) {
1022                         break;
1023                     }
1024                     index -= r_size(&sub);
1025                 }
1026                 if (array_get(ff->memory, &sub, index, &r) < 0)
1027                     return 0;
1028 
1029                 return ((ushort)r.value.intval);
1030             }
1031 
1032             /* End MM specifics */
1033     }
1034     return 0;
1035 }
1036 
1037 static ulong
FAPI_FF_get_long(gs_fapi_font * ff,gs_fapi_font_feature var_id,int index)1038 FAPI_FF_get_long(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index)
1039 {
1040     gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
1041 
1042     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1043 
1044     switch ((int)var_id) {
1045         case gs_fapi_font_feature_UniqueID:
1046             return (pfont->UID.id);
1047         case gs_fapi_font_feature_BlueScale:
1048             return ((ulong) (pfont->data.BlueScale * 65536));
1049         case gs_fapi_font_feature_Subrs_total_size:
1050             {
1051                 ref *Private, *Subrs, v;
1052                 int lenIV = max(pfont->data.lenIV, 0), k;
1053                 ulong size = 0;
1054                 long i;
1055                 const char *name[2] = { "Subrs", "GlobalSubrs" };
1056                 if (dict_find_string(pdr, "Private", &Private) <= 0)
1057                     return 0;
1058                 for (k = 0; k < 2; k++) {
1059                     if (dict_find_string(Private, name[k], &Subrs) > 0)
1060                         for (i = r_size(Subrs) - 1; i >= 0; i--) {
1061                             array_get(pfont->memory, Subrs, i, &v);
1062                             if (r_type(&v) == t_string) {
1063                                 size += r_size(&v) - (ff->need_decrypt ? 0 : lenIV);
1064                             }
1065                         }
1066                 }
1067                 return size;
1068             }
1069         case gs_fapi_font_feature_TT_size:
1070             return (true_type_size(pdr));
1071     }
1072     return 0;
1073 }
1074 
1075 static float
FAPI_FF_get_float(gs_fapi_font * ff,gs_fapi_font_feature var_id,int index)1076 FAPI_FF_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index)
1077 {
1078     gs_font_type1 *pfont1 = (gs_font_type1 *) ff->client_font_data;
1079     gs_font_base *pbfont = (gs_font_base *) ff->client_font_data2;
1080     ref *pdr = pfont_dict(pbfont);
1081 
1082     gs_fapi_server *I = pbfont->FAPI;
1083 
1084     switch ((int)var_id) {
1085         case gs_fapi_font_feature_FontMatrix:
1086             {
1087                 double FontMatrix_div;
1088                 gs_matrix m, *mptr;
1089 
1090                 if (I && I->get_fontmatrix) {
1091                     FontMatrix_div = 1;
1092                     mptr = &m;
1093                     I->get_fontmatrix(I, mptr);
1094                 }
1095                 else {
1096                     FontMatrix_div =
1097                         ((ff->is_cid
1098                           && (!FAPI_ISCIDFONT(pbfont))) ? 1000 : 1);
1099                     mptr = &(pbfont->base->FontMatrix);
1100                 }
1101                 switch (index) {
1102                     case 0:
1103                     default:
1104                         return (mptr->xx / FontMatrix_div);
1105                     case 1:
1106                         return (mptr->xy / FontMatrix_div);
1107                     case 2:
1108                         return (mptr->yx / FontMatrix_div);
1109                     case 3:
1110                         return (mptr->yy / FontMatrix_div);
1111                     case 4:
1112                         return (mptr->tx / FontMatrix_div);
1113                     case 5:
1114                         return (mptr->ty / FontMatrix_div);
1115                 }
1116             }
1117 
1118         case gs_fapi_font_feature_WeightVector:
1119             {
1120                 if (index < pfont1->data.WeightVector.count) {
1121                     return pfont1->data.WeightVector.values[index];
1122                 }
1123                 else {
1124                     return 0;
1125                 }
1126             }
1127         case gs_fapi_font_feature_BlendDesignPositionsArrayValue:
1128             {
1129                 ref *Info, *Array, SubArray, value;
1130                 int array_index = index / 8;
1131 
1132                 index %= 8;
1133                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
1134                     return 0;
1135                 if (dict_find_string(Info, "BlendDesignPositions", &Array) <=
1136                     0)
1137                     return 0;
1138                 if (array_get(ff->memory, Array, array_index, &SubArray) < 0)
1139                     return 0;
1140                 if (array_get(ff->memory, &SubArray, index, &value) < 0)
1141                     return 0;
1142                 if (!r_has_type(&value, t_integer)) {
1143                     if (r_has_type(&value, t_real)) {
1144                         return (value.value.realval);
1145                     }
1146                     else
1147                         return 0;
1148                 }
1149                 else
1150                     return ((float)value.value.intval);
1151             }
1152         case gs_fapi_font_feature_BlendDesignMapArrayValue:
1153             {
1154                 ref *Info, *Array, SubArray, SubSubArray, value;
1155                 int array_index = index / 64;
1156 
1157                 index %= 8;
1158                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
1159                     return 0;
1160                 if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0)
1161                     return 0;
1162                 if (array_get(ff->memory, Array, array_index, &SubArray) < 0)
1163                     return 0;
1164                 if (array_get(ff->memory, &SubArray, index, &SubSubArray) < 0)
1165                     return 0;
1166                 if (array_get(ff->memory, &SubSubArray, index, &value) < 0)
1167                     return 0;
1168                 if (!r_has_type(&value, t_integer)) {
1169                     if (r_has_type(&value, t_real)) {
1170                         return (value.value.realval);
1171                     }
1172                     else
1173                         return 0;
1174                 }
1175                 else
1176                     return ((float)value.value.intval);
1177             }
1178         case gs_fapi_font_feature_BlendBlueScale:
1179             {
1180                 ref *Priv, *Blend, *bbs, r;
1181                 float val = 0;
1182 
1183                 if (dict_find_string(pdr, "Blend", &Blend) <= 0)
1184                     return 0;
1185                 if (dict_find_string(Blend, "Private", &Priv) <= 0)
1186                     return 0;
1187                 if (dict_find_string(Priv, "BlueScale", &bbs) <= 0)
1188                     return 0;
1189                 if (array_get(ff->memory, bbs, index, &r) < 0)
1190                     return 0;
1191                if (r_has_type(&r, t_real))
1192                    val = r.value.realval;
1193                else if (r_has_type(&r, t_integer))
1194                    val = (float)r.value.intval;
1195                return (val);
1196             }
1197     }
1198     return 0;
1199 }
1200 
1201 static int
FAPI_FF_get_name(gs_fapi_font * ff,gs_fapi_font_feature var_id,int index,char * Buffer,int len)1202 FAPI_FF_get_name(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index,
1203                  char *Buffer, int len)
1204 {
1205     ref name, string;
1206     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1207 
1208     switch ((int)var_id) {
1209         case gs_fapi_font_feature_BlendAxisTypes:
1210             {
1211                 ref *Info, *Axes;
1212 
1213                 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
1214                     return 0;
1215                 if (dict_find_string(Info, "BlendAxisTypes", &Axes) <= 0)
1216                     return 0;
1217                 if (!r_has_type(Axes, t_array))
1218                     return 0;
1219                 if (array_get(ff->memory, Axes, index, &name) < 0)
1220                     return 0;
1221             }
1222     }
1223     name_string_ref(ff->memory, &name, &string);
1224     if (r_size(&string) >= len)
1225         return 0;
1226     memcpy(Buffer, string.value.const_bytes, r_size(&string));
1227     Buffer[r_size(&string)] = 0x00;
1228     return 1;
1229 }
1230 
1231 /* NOTE: we checked the type of $Blend at definefont time, so we know it is a
1232  * procedure and don't need to check it again here
1233  */
1234 static int
FAPI_FF_get_proc(gs_fapi_font * ff,gs_fapi_font_feature var_id,int index,char * Buffer)1235 FAPI_FF_get_proc(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index,
1236                  char *Buffer)
1237 {
1238     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1239     char *ptr = Buffer;
1240 
1241     if (!Buffer)
1242         return 0;
1243 
1244     switch ((int)var_id) {
1245         case gs_fapi_font_feature_DollarBlend:
1246             {
1247                 ref *DBlend, Element, string;
1248                 int i;
1249                 char Buf[32];
1250 
1251                 if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
1252                     return 0;
1253                 for (i = 0; i < r_size(DBlend); i++) {
1254                     *ptr++ = 0x20;
1255                     if (array_get(ff->memory, DBlend, i, &Element) < 0)
1256                         return 0;
1257                     switch (r_btype(&Element)) {
1258                         case t_name:
1259                             name_string_ref(ff->memory, &Element, &string);
1260 
1261                             strncpy(ptr, (char *)string.value.const_bytes,
1262                                     r_size(&string));
1263                             ptr += r_size(&string);
1264                             break;
1265                         case t_real:
1266                             gs_sprintf(Buf, "%f", Element.value.realval);
1267                             strcpy(ptr, Buf);
1268                             ptr += strlen(Buf);
1269                             break;
1270                         case t_integer:
1271                             gs_sprintf(Buf, "%"PRIpsint, Element.value.intval);
1272                             strcpy(ptr, Buf);
1273                             ptr += strlen(Buf);
1274                             break;
1275                         case t_operator:
1276                             {
1277                                 op_def const *op;
1278 
1279                                 op = op_index_def(r_size(&Element));
1280                                 strcpy(ptr, op->oname + 1);
1281                                 ptr += strlen(op->oname + 1);
1282                             }
1283                             break;
1284                         default:
1285                             break;
1286                     }
1287                 }
1288             }
1289     }
1290     return (ptr - Buffer);
1291 }
1292 
1293 static inline void
decode_bytes(byte * p,const byte * s,int l,int lenIV)1294 decode_bytes(byte *p, const byte *s, int l, int lenIV)
1295 {
1296     ushort state = 4330;
1297 
1298     for (; l; s++, l--) {
1299         uchar c = (*s ^ (state >> 8));
1300 
1301         state = (*s + state) * crypt_c1 + crypt_c2;
1302         if (lenIV > 0)
1303             lenIV--;
1304         else {
1305             *p = c;
1306             p++;
1307         }
1308     }
1309 }
1310 
1311 static ushort
get_type1_data(gs_fapi_font * ff,const ref * type1string,byte * buf,ushort buf_length)1312 get_type1_data(gs_fapi_font *ff, const ref *type1string,
1313                byte *buf, ushort buf_length)
1314 {
1315     gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
1316     int lenIV = max(pfont->data.lenIV, 0);
1317     int length = r_size(type1string) - (ff->need_decrypt ? lenIV : 0);
1318 
1319     if (buf != 0) {
1320         int l = min(length, buf_length);        /*safety */
1321 
1322         if (ff->need_decrypt && pfont->data.lenIV >= 0)
1323             decode_bytes(buf, type1string->value.const_bytes, l + lenIV,
1324                          lenIV);
1325         else
1326             memcpy(buf, type1string->value.const_bytes, l);
1327     }
1328     return length;
1329 }
1330 
1331 static ushort
FAPI_FF_get_gsubr(gs_fapi_font * ff,int index,byte * buf,ushort buf_length)1332 FAPI_FF_get_gsubr(gs_fapi_font *ff, int index, byte *buf, ushort buf_length)
1333 {
1334     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1335     ref *Private, *GlobalSubrs, subr;
1336 
1337     if (dict_find_string(pdr, "Private", &Private) <= 0)
1338         return 0;
1339     if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0)
1340         return 0;
1341     if (array_get(ff->memory,
1342                   GlobalSubrs, index, &subr) < 0 || r_type(&subr) != t_string)
1343         return 0;
1344     return (get_type1_data(ff, &subr, buf, buf_length));
1345 }
1346 
1347 static ushort
FAPI_FF_get_subr(gs_fapi_font * ff,int index,byte * buf,ushort buf_length)1348 FAPI_FF_get_subr(gs_fapi_font *ff, int index, byte *buf, ushort buf_length)
1349 {
1350     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1351     ref *Private, *Subrs, subr;
1352 
1353     if (dict_find_string(pdr, "Private", &Private) <= 0)
1354         return 0;
1355     if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
1356         return 0;
1357     if (array_get(ff->memory, Subrs, index, &subr) < 0
1358         || r_type(&subr) != t_string)
1359         return 0;
1360     return (get_type1_data(ff, &subr, buf, buf_length));
1361 }
1362 
1363 static ushort
FAPI_FF_get_raw_subr(gs_fapi_font * ff,int index,byte * buf,ushort buf_length)1364 FAPI_FF_get_raw_subr(gs_fapi_font *ff, int index, byte *buf,
1365                      ushort buf_length)
1366 {
1367     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1368     ref *Private, *Subrs, subr;
1369 
1370     if (dict_find_string(pdr, "Private", &Private) <= 0)
1371         return 0;
1372     if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
1373         return 0;
1374     if (array_get(ff->memory, Subrs, index, &subr) < 0
1375         || r_type(&subr) != t_string)
1376         return 0;
1377     if (buf && buf_length && buf_length >= r_size(&subr)) {
1378         memcpy(buf, subr.value.const_bytes, r_size(&subr));
1379     }
1380     return (r_size(&subr));
1381 }
1382 
1383 /* FAPI_FF_get_charstring_name() and FAPI_FF_get_charstring()
1384  *
1385  * Generally we'd want to use the dictionary content
1386  * enumeration API rather than dict_index_entry(), but
1387  * the FAPI interface doesn't enforce sequential accessing
1388  * of the indices.
1389  * Setting up enumeration and enumerating through the entries
1390  * until we reach the requested valid index is a performance
1391  * hit we don't want to pay.
1392  *
1393  * Luckily, the checks we need for invalid CharString contents
1394  * also handle empty "slots" in the dictionary.
1395  */
1396 
1397 static ushort
FAPI_FF_get_charstring_name(gs_fapi_font * ff,int index,byte * buf,ushort buf_length)1398 FAPI_FF_get_charstring_name(gs_fapi_font *ff, int index, byte *buf,
1399                             ushort buf_length)
1400 {
1401     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1402     ref *CharStrings, eltp[2], string;
1403 
1404     if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
1405         return 0;
1406     if (dict_index_entry(CharStrings, index, eltp) < 0)
1407         return 0;
1408     if (r_type(&eltp[0]) != t_name)
1409         return 0;
1410     name_string_ref(ff->memory, &eltp[0], &string);
1411     if (r_size(&string) > buf_length)
1412         return (r_size(&string));
1413     memcpy(buf, string.value.const_bytes, r_size(&string));
1414     buf[r_size(&string)] = 0x00;
1415     return (r_size(&string));
1416 }
1417 
1418 static ushort
FAPI_FF_get_charstring(gs_fapi_font * ff,int index,byte * buf,ushort buf_length)1419 FAPI_FF_get_charstring(gs_fapi_font *ff, int index, byte *buf,
1420                        ushort buf_length)
1421 {
1422     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1423     ref *CharStrings, eltp[2];
1424 
1425     if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
1426         return 0;
1427     if (dict_index_entry(CharStrings, index, eltp) < 0)
1428         return 0;
1429     if (r_type(&eltp[1]) != t_string)
1430         return 0;
1431     if (buf && buf_length && buf_length >= r_size(&eltp[1])) {
1432         memcpy(buf, eltp[1].value.const_bytes, r_size(&eltp[1]));
1433     }
1434     return (r_size(&eltp[1]));
1435 }
1436 
1437 static int
sfnt_get_sfnt_length(ref * pdr,ulong * len)1438 sfnt_get_sfnt_length(ref *pdr, ulong *len)
1439 {
1440     int code = 0;
1441     ref *sfnts, sfnt_elem;
1442     const gs_memory_t *mem = dict_mem(pdr->value.pdict);
1443 
1444     *len = 0;
1445     if (r_type(pdr) != t_dictionary ||
1446         dict_find_string(pdr, "sfnts", &sfnts) <= 0) {
1447         code = gs_error_invalidfont;
1448     }
1449     else {
1450         if (r_type(sfnts) != t_array && r_type(sfnts) != t_string) {
1451             code = gs_error_invalidfont;
1452         }
1453         else {
1454             if (r_type(sfnts) == t_string) {
1455                 *len = r_size(sfnts);
1456             }
1457             else {
1458                 int i;
1459                 for (i = 0; i < r_size(sfnts); i++) {
1460                     code = array_get(mem, sfnts, i, &sfnt_elem);
1461                     if (code < 0) break;
1462                     *len += r_size(&sfnt_elem);
1463                 }
1464             }
1465         }
1466     }
1467     return code;
1468 }
1469 
1470 static bool
sfnt_get_glyph_offset(ref * pdr,gs_font_type42 * pfont42,int index,ulong * offset0)1471 sfnt_get_glyph_offset(ref *pdr, gs_font_type42 *pfont42, int index,
1472                       ulong *offset0)
1473 {                               /* Note : TTC is not supported and probably is unuseful for Type 42. */
1474     sfnts_reader r;
1475     int glyf_elem_size = (pfont42->data.indexToLocFormat) ? 4 : 2;
1476 
1477     if (index < pfont42->data.trueNumGlyphs) {
1478         sfnts_reader_init(&r, pdr);
1479         r.seek(&r, pfont42->data.loca + index * glyf_elem_size);
1480         *offset0 =
1481             pfont42->data.glyf + (glyf_elem_size ==
1482                               2 ? r.rword(&r) * 2 : r.rlong(&r));
1483     }
1484     else {
1485         r.error = true;
1486     }
1487     return (r.error);
1488 }
1489 
1490 static int
ps_get_GlyphDirectory_data_ptr(gs_fapi_font * ff,int char_code,const byte ** ptr)1491 ps_get_GlyphDirectory_data_ptr(gs_fapi_font *ff, int char_code,
1492                                const byte **ptr)
1493 {
1494     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1495     ref *GlyphDirectory, glyph0, *glyph = &glyph0, glyph_index;
1496 
1497     if (dict_find_string(pdr, "GlyphDirectory", &GlyphDirectory) > 0) {
1498         if (((r_type(GlyphDirectory) == t_dictionary &&
1499               (make_int(&glyph_index, char_code),
1500                dict_find(GlyphDirectory, &glyph_index, &glyph) > 0)) ||
1501              (r_type(GlyphDirectory) == t_array &&
1502               array_get(ff->memory, GlyphDirectory, char_code, &glyph0) >= 0)
1503             )
1504             && r_type(glyph) == t_string) {
1505             *ptr = glyph->value.const_bytes;
1506             return (r_size(glyph));
1507         }
1508         else
1509             /* We have a GlyphDirectory, but couldn't find the glyph. If we
1510              * return -1 then we will attempt to use glyf and loca which
1511              * will fail. Instead return 0, so we execute an 'empty' glyph.
1512              */
1513             return 0;
1514     }
1515     return -1;
1516 }
1517 
1518 static int
get_charstring(gs_fapi_font * ff,int char_code,ref ** proc,ref * char_name)1519 get_charstring(gs_fapi_font *ff, int char_code, ref **proc, ref *char_name)
1520 {
1521     ref *CharStrings;
1522     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1523 
1524     if (ff->is_type1) {
1525         if (ff->is_cid)
1526             return -1;
1527         if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
1528             return -1;
1529 
1530         if (ff->char_data != NULL) {
1531             /*
1532              * Can't use char_code in this case because hooked Type 1 fonts
1533              * with 'glyphshow' may render a character which has no
1534              * Encoding entry.
1535              */
1536             if (name_ref
1537                 (ff->memory, ff->char_data, ff->char_data_len, char_name,
1538                  -1) < 0)
1539                 return -1;
1540         }
1541         else {                  /* seac */
1542             i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p;
1543             ref *StandardEncoding;
1544 
1545             if (dict_find_string
1546                 (systemdict, "StandardEncoding", &StandardEncoding) <= 0
1547                 || array_get(ff->memory, StandardEncoding, char_code,
1548                              char_name) < 0) {
1549                 if (name_ref
1550                     (ff->memory, (const byte *)".notdef", 7, char_name,
1551                      -1) < 0)
1552                     return -1;
1553             }
1554         }
1555         if (dict_find(CharStrings, char_name, (ref **) proc) <= 0)
1556             return -1;
1557     }
1558     return 0;
1559 }
1560 
1561 static int
FAPI_FF_get_glyph(gs_fapi_font * ff,int char_code,byte * buf,ushort buf_length)1562 FAPI_FF_get_glyph(gs_fapi_font *ff, int char_code, byte *buf,
1563                   ushort buf_length)
1564 {
1565     /*
1566      * We assume that renderer requests glyph data with multiple
1567      * consecutive calls to this function.
1568      *
1569      * For a simple glyph it calls this function exactly twice: first
1570      * with buf == NULL for requesting the necessary buffer length, and
1571      * second with buf != NULL for requesting the data (the second call
1572      * may be skipped if the renderer discontinues the rendering).
1573      *
1574      * For a composite glyph it calls this function 2 * (N + 1)
1575      * times: 2 calls for the main glyph (same as above) followed with
1576      * 2 * N calls for subglyphs, where N is less or equal to the number
1577      * of subglyphs (N may be less if the renderer caches glyph data,
1578      * or discontinues rendering on an exception).
1579      */
1580     ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1581 
1582     int glyph_length;
1583     i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p;
1584 
1585     if (ff->is_type1) {
1586         if (ff->is_cid) {
1587             const gs_string *char_str = (const gs_string *)ff->char_data;
1588             ref glyph;
1589 
1590             make_string(&glyph, avm_foreign | a_readonly, char_str->size,
1591                         char_str->data);
1592 
1593             glyph_length = get_type1_data(ff, &glyph, buf, buf_length);
1594         }
1595         else {
1596             ref *CharStrings, char_name, *glyph;
1597 
1598             if (ff->char_data != NULL) {
1599                 /*
1600                  * Can't use char_code in this case because hooked Type 1 fonts
1601                  * with 'glyphshow' may render a character which has no
1602                  * Encoding entry.
1603                  */
1604                 if (name_ref(ff->memory, ff->char_data,
1605                              ff->char_data_len, &char_name, -1) < 0)
1606                     return gs_fapi_glyph_invalid_format;
1607                 if (buf != NULL) {
1608                     /*
1609                      * Trigger the next call to the 'seac' case below.
1610                      * Here we use the assumption about call sequence
1611                      * being documented above.
1612                      */
1613                     ff->char_data = NULL;
1614                 }
1615             }
1616             else {              /* seac */
1617                 ref *StandardEncoding;
1618 
1619                 if (dict_find_string
1620                     (systemdict, "StandardEncoding", &StandardEncoding) <= 0
1621                     || array_get(ff->memory, StandardEncoding, char_code,
1622                                  &char_name) < 0)
1623                     if (name_ref
1624                         (ff->memory, (const byte *)".notdef", 7, &char_name,
1625                          -1) < 0)
1626                         return gs_fapi_glyph_invalid_format;
1627             }
1628             if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
1629                 return gs_fapi_glyph_invalid_format;
1630 
1631             if (dict_find(CharStrings, &char_name, &glyph) <= 0) {
1632                 if (name_ref
1633                     (ff->memory, (const byte *)".notdef", 7, &char_name,
1634                      -1) < 0) {
1635                     return gs_fapi_glyph_invalid_format;
1636                 }
1637                 if (dict_find(CharStrings, &char_name, &glyph) <= 0) {
1638                     return gs_fapi_glyph_invalid_format;
1639                 }
1640             }
1641             if (r_has_type(glyph, t_array) || r_has_type(glyph, t_mixedarray))
1642                 return gs_fapi_glyph_invalid_format;
1643             if (!r_has_type(glyph, t_string))
1644                 return 0;
1645             glyph_length = get_type1_data(ff, glyph, buf, buf_length);
1646         }
1647     }
1648     else {                      /* type 42 */
1649         const byte *data_ptr;
1650         int l = ff->get_glyphdirectory_data(ff, char_code, &data_ptr);
1651         ref *render_notdef_ref;
1652         bool render_notdef = true;
1653 
1654         if (dict_find_string(pdr, ".render_notdef", &render_notdef_ref) > 0
1655             && r_has_type(render_notdef_ref, t_boolean)) {
1656             render_notdef = render_notdef_ref->value.boolval;
1657         }
1658         else {
1659             render_notdef = i_ctx_p->RenderTTNotdef;
1660         }
1661 
1662         /* We should only render the TT notdef if we've been told to - logic lifted from zchar42.c */
1663         if (!render_notdef
1664             &&
1665             ((ff->char_data_len == 7
1666               && strncmp((const char *)ff->char_data, ".notdef", 7) == 0)
1667              || (ff->char_data_len > 9
1668                  && strncmp((const char *)ff->char_data, ".notdef~GS",
1669                             10) == 0))) {
1670             glyph_length = 0;
1671         }
1672         else {
1673             if (l >= 0) {
1674                 int MetricsCount = gs_fapi_get_metrics_count(ff), mc =
1675                     MetricsCount << 1;
1676 
1677                 glyph_length = max((ushort) (l - mc), 0);       /* safety */
1678                 if (buf != 0 && glyph_length > 0)
1679                     memcpy(buf, data_ptr + mc,
1680                            min(glyph_length, buf_length) /* safety */ );
1681             }
1682             else {
1683                 gs_font_type42 *pfont42 = (gs_font_type42 *) ff->client_font_data;
1684                 ulong offset0, length_read;
1685                 bool error = sfnt_get_glyph_offset(pdr, pfont42, char_code, &offset0);
1686 
1687                 if (error != 0) {
1688                     glyph_length = gs_fapi_glyph_invalid_index;
1689                 }
1690                 else if (pfont42->data.len_glyphs) {
1691                     if (char_code <= pfont42->data.numGlyphs)
1692                         glyph_length = pfont42->data.len_glyphs[char_code];
1693                     else
1694                         glyph_length = gs_fapi_glyph_invalid_index;
1695                 }
1696                 else {
1697                     ulong noffs;
1698                     /* If we haven't got a len_glyphs array, try using the offset of the next glyph offset
1699                      * to work out the length
1700                      */
1701                     error = sfnt_get_glyph_offset(pdr, pfont42, char_code + 1, &noffs);
1702                     if (error == 0) {
1703                         glyph_length = noffs - offset0;
1704                     }
1705                     else {
1706                         /* And if we can't get the next glyph offset, use the end of the sfnt data
1707                          * to work out the length.
1708                          */
1709                         int code = sfnt_get_sfnt_length(pdr, &noffs);
1710                         if (code < 0) {
1711                             glyph_length = gs_fapi_glyph_invalid_index;
1712                         }
1713                         else {
1714                             glyph_length = noffs - offset0;
1715                         }
1716                     }
1717                 }
1718 
1719                 if (buf != 0 && !error) {
1720                     sfnts_reader r;
1721 
1722                     sfnts_reader_init(&r, pdr);
1723 
1724                     r.seek(&r, offset0);
1725                     length_read =
1726                         r.rstring(&r, buf,
1727                                   min(glyph_length,
1728                                       buf_length) /* safety */ );
1729                     if (r.error == 1) {
1730                         glyph_length = gs_fapi_glyph_invalid_index;
1731                     }
1732                     /* r.error == 2 means a rangecheck, and probably means that the
1733                      * font is broken, and the final glyph length is longer than the data available for it.
1734                      * In which case we need to return the number of bytes read.
1735                      */
1736                     if (r.error == 2) {
1737                         glyph_length = length_read;
1738                     }
1739                 }
1740             }
1741         }
1742     }
1743     return glyph_length;
1744 }
1745 
1746 static int
ps_fapi_get_metrics(gs_fapi_font * ff,gs_string * char_name,int cid,double * m,bool vertical)1747 ps_fapi_get_metrics(gs_fapi_font *ff, gs_string *char_name, int cid,
1748                     double *m, bool vertical)
1749 {
1750     ref glyph;
1751     int code;
1752     gs_font_base *pbfont = ((gs_font_base *) ff->client_font_data2);
1753 
1754     if (char_name->data != NULL) {
1755         make_string(&glyph, avm_foreign | a_readonly, char_name->size,
1756                     char_name->data);
1757     }
1758     else {
1759         make_int(&glyph, cid);
1760     }
1761 
1762     if (vertical) {
1763         code = zchar_get_metrics2(pbfont, &glyph, m);
1764     }
1765     else {
1766         code = zchar_get_metrics(pbfont, &glyph, m);
1767     }
1768 
1769     make_null(&glyph);
1770 
1771     return (code);
1772 }
1773 
1774 
1775 /* forward declaration for the ps_ff_stub assignment */
1776 static int ps_get_glyphname_or_cid(gs_text_enum_t *penum,
1777                                    gs_font_base *pbfont,
1778                                    gs_string *charstring, gs_string *name,
1779                                    int ccode, gs_string *enc_char_name,
1780                                    char *font_file_path,
1781                                    gs_fapi_char_ref *cr, bool bCID);
1782 
1783 static int ps_fapi_set_cache(gs_text_enum_t *penum,
1784                              const gs_font_base *pbfont,
1785                              const gs_string *char_name, int cid,
1786                              const double pwidth[2], const gs_rect *pbbox,
1787                              const double Metrics2_sbw_default[4],
1788                              bool *imagenow);
1789 
1790 static const gs_fapi_font ps_ff_stub = {
1791     0,                          /* server_font_data */
1792     0,                          /* need_decrypt */
1793     NULL,                       /* const gs_memory_t */
1794     0,                          /* font_file_path */
1795     0,                          /* full_font_buf */
1796     0,                          /* full_font_buf_len */
1797     0,                          /* subfont */
1798     false,                      /* is_type1 */
1799     false,                      /* is_cid */
1800     false,                      /* is_outline_font */
1801     false,                      /* is_mtx_skipped */
1802     false,                      /* is_vertical */
1803     false,                      /* metrics_only */
1804     {{-1, -1}},                 /* ttf_cmap_req */
1805     {-1, -1},                   /* ttf_cmap_selected */
1806     0,                          /* client_ctx_p */
1807     0,                          /* client_font_data */
1808     0,                          /* client_font_data2 */
1809     0,                          /* char_data */
1810     0,                          /* char_data_len */
1811     0,                          /* embolden */
1812     FAPI_FF_get_word,
1813     FAPI_FF_get_long,
1814     FAPI_FF_get_float,
1815     FAPI_FF_get_name,
1816     FAPI_FF_get_proc,
1817     FAPI_FF_get_gsubr,
1818     FAPI_FF_get_subr,
1819     FAPI_FF_get_raw_subr,
1820     FAPI_FF_get_glyph,
1821     FAPI_FF_serialize_tt_font,
1822     FAPI_FF_get_charstring,
1823     FAPI_FF_get_charstring_name,
1824     ps_get_GlyphDirectory_data_ptr,
1825     ps_get_glyphname_or_cid,
1826     ps_fapi_get_metrics,
1827     ps_fapi_set_cache
1828 };
1829 
1830 static int
FAPI_get_xlatmap(i_ctx_t * i_ctx_p,char ** xlatmap)1831 FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap)
1832 {
1833     ref *pref;
1834     int code;
1835 
1836     if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0)
1837         return code;
1838     if (code == 0)
1839         return_error(gs_error_undefined);
1840 
1841     if (r_type(pref) != t_string)
1842         return_error(gs_error_typecheck);
1843     *xlatmap = (char *)pref->value.bytes;
1844     /*  Note : this supposes that xlatmap doesn't move in virtual memory.
1845        Garbager must not be called while plugin executes get_scaled_font, get_decodingID.
1846        Fix some day with making copy of xlatmap in system memory.
1847      */
1848     return 0;
1849 }
1850 
1851 static int
renderer_retcode(gs_memory_t * mem,gs_fapi_server * I,gs_fapi_retcode rc)1852 renderer_retcode(gs_memory_t *mem, gs_fapi_server *I, gs_fapi_retcode rc)
1853 {
1854     if (rc == 0)
1855         return 0;
1856     emprintf2(mem,
1857               "Error: Font Renderer Plugin ( %s ) return code = %d\n",
1858               I->ig.d->subtype, rc);
1859     return rc < 0 ? rc : gs_error_invalidfont;
1860 }
1861 
1862 /* <server name>/<null> object .FAPIavailable bool */
1863 static int
zFAPIavailable(i_ctx_t * i_ctx_p)1864 zFAPIavailable(i_ctx_t *i_ctx_p)
1865 {
1866     os_ptr op = osp;
1867     char *serv_name = NULL;
1868     ref name_ref;
1869 
1870     check_op(1);
1871     if (r_has_type(op, t_name)) {
1872         name_string_ref(imemory, op, &name_ref);
1873 
1874         serv_name =
1875             (char *) ref_to_string(&name_ref, imemory, "zFAPIavailable");
1876         if (!serv_name) {
1877             return_error(gs_error_VMerror);
1878         }
1879     }
1880 
1881     make_bool(op, gs_fapi_available(imemory, serv_name));
1882 
1883     if (serv_name) {
1884         gs_free_string(imemory, (byte *) serv_name,
1885                        strlen((char *)serv_name) + 1, "zFAPIavailable");
1886     }
1887     return (0);
1888 }
1889 
1890 static void
ps_get_server_param(gs_fapi_server * I,const byte * subtype,byte ** server_param,int * server_param_size)1891 ps_get_server_param(gs_fapi_server *I, const byte *subtype,
1892                     byte **server_param, int *server_param_size)
1893 {
1894     ref *FAPIconfig, *options, *server_options;
1895     i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p;
1896 
1897     if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) > 0
1898         && r_has_type(FAPIconfig, t_dictionary)) {
1899         if (dict_find_string(FAPIconfig, "ServerOptions", &options) > 0
1900             && r_has_type(options, t_dictionary)) {
1901             if (dict_find_string(options, (char *)subtype, &server_options) >
1902                 0 && r_has_type(server_options, t_string)) {
1903                 *server_param = (byte *) server_options->value.const_bytes;
1904                 *server_param_size = r_size(server_options);
1905             }
1906         }
1907     }
1908 }
1909 
1910 static int
FAPI_refine_font(i_ctx_t * i_ctx_p,os_ptr op,gs_font * pfont,int subfont,const char * font_file_path)1911 FAPI_refine_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font *pfont,
1912                  int subfont, const char *font_file_path)
1913 {
1914     ref *pdr = op;              /* font dict */
1915     const char *decodingID = NULL;
1916     char *xlatmap = NULL;
1917     gs_font_base *pbfont = (gs_font_base *)pfont;
1918     gs_fapi_server *I = pbfont->FAPI;
1919     ref *Decoding_old;
1920     int code;
1921 
1922     if (font_file_path != NULL && pbfont->FAPI_font_data == NULL)
1923         if ((code = FAPI_get_xlatmap(i_ctx_p, &xlatmap)) < 0)
1924             return code;
1925 
1926     gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p);
1927 
1928     code =
1929         gs_fapi_prepare_font(pfont, I, subfont, font_file_path,
1930                              NULL, xlatmap, &decodingID);
1931     if (code < 0)
1932         return code;
1933 
1934     if (code > 0) {
1935         /* save refined FontBBox back to PS world */
1936         ref *v, mat[4], arr;
1937         int attrs;
1938 
1939         if (dict_find_string(op, "FontBBox", &v) > 0) {
1940             if (!r_has_type(v, t_array) && !r_has_type(v, t_shortarray)
1941                 && !r_has_type(v, t_mixedarray))
1942                 return_error(gs_error_invalidfont);
1943             make_real(&mat[0], pbfont->FontBBox.p.x);
1944             make_real(&mat[1], pbfont->FontBBox.p.y);
1945             make_real(&mat[2], pbfont->FontBBox.q.x);
1946             make_real(&mat[3], pbfont->FontBBox.q.y);
1947             if (r_has_type(v, t_shortarray) || r_has_type(v, t_mixedarray)
1948                 || r_size(v) < 4) {
1949                 /* Create a new full blown array in case the values are reals */
1950                 code = ialloc_ref_array(&arr, a_all, 4, "array");
1951                 if (code < 0)
1952                     return code;
1953                 v = &arr;
1954                 code = idict_put_string(op, "FontBBox", &arr);
1955                 if (code < 0)
1956                     return code;
1957                 ref_assign_new(v->value.refs + 0, &mat[0]);
1958                 ref_assign_new(v->value.refs + 1, &mat[1]);
1959                 ref_assign_new(v->value.refs + 2, &mat[2]);
1960                 ref_assign_new(v->value.refs + 3, &mat[3]);
1961             }
1962             else {
1963                 ref_assign_old(v, v->value.refs + 0, &mat[0],
1964                                "FAPI_refine_font_BBox");
1965                 ref_assign_old(v, v->value.refs + 1, &mat[1],
1966                                "FAPI_refine_font_BBox");
1967                 ref_assign_old(v, v->value.refs + 2, &mat[2],
1968                                "FAPI_refine_font_BBox");
1969                 ref_assign_old(v, v->value.refs + 3, &mat[3],
1970                                "FAPI_refine_font_BBox");
1971             }
1972             attrs = v->tas.type_attrs;
1973             r_clear_attrs(v, a_all);
1974             r_set_attrs(v, attrs | a_execute);
1975         }
1976     }
1977 
1978     /* Assign a Decoding : */
1979     if (decodingID != 0 && *decodingID
1980         && dict_find_string(pdr, "Decoding", &Decoding_old) <= 0) {
1981         ref Decoding;
1982 
1983         if (FAPI_ISCIDFONT(pbfont)) {
1984             ref *CIDSystemInfo, *Ordering, SubstNWP;
1985             byte buf[30];
1986             int ordering_length, decodingID_length =
1987                 min(strlen(decodingID), sizeof(buf) - 2);
1988 
1989             if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) <= 0
1990                 || !r_has_type(CIDSystemInfo, t_dictionary))
1991                 return_error(gs_error_invalidfont);
1992 
1993             if (dict_find_string(CIDSystemInfo, "Ordering", &Ordering) <= 0
1994                 || !r_has_type(Ordering, t_string)) {
1995                 return_error(gs_error_invalidfont);
1996             }
1997 
1998             ordering_length =
1999                 min(r_size(Ordering), sizeof(buf) - 2 - decodingID_length);
2000             memcpy(buf, Ordering->value.const_bytes, ordering_length);
2001             if ((code =
2002                  name_ref(imemory, buf, ordering_length, &SubstNWP, 0)) < 0)
2003                 return code;
2004             if ((code =
2005                  dict_put_string(pdr, "SubstNWP", &SubstNWP, NULL)) < 0)
2006                 return code;
2007             buf[ordering_length] = '.';
2008             memcpy(buf + ordering_length + 1, decodingID, decodingID_length);
2009             buf[decodingID_length + 1 + ordering_length] = 0;   /* Debug purpose only */
2010             if ((code = name_ref(imemory, buf,
2011                                  decodingID_length + 1 + ordering_length,
2012                                  &Decoding, 0)) < 0)
2013                 return code;
2014         }
2015         else if ((code = name_ref(imemory, (const byte *)decodingID,
2016                                   strlen(decodingID), &Decoding, 0)) < 0)
2017             return code;
2018         if ((code = dict_put_string(pdr, "Decoding", &Decoding, NULL)) < 0)
2019             return code;
2020     }
2021     return 0;
2022 }
2023 
2024 /*  <string|name> <font> <is_disk_font> .rebuildfontFAPI <string|name> <font> */
2025 /*  Rebuild a font for handling it with an external renderer.
2026 
2027     The font was built as a native GS font to allow easy access
2028     to font features. Then zFAPIrebuildfont sets FAPI entry
2029     into gx_font_base and replaces BuildGlyph and BuildChar
2030     to enforce the FAPI handling.
2031 
2032     This operator must not be called with devices which embed fonts.
2033 
2034 */
2035 static int
zFAPIrebuildfont(i_ctx_t * i_ctx_p)2036 zFAPIrebuildfont(i_ctx_t *i_ctx_p)
2037 {
2038     os_ptr op = osp;
2039     build_proc_refs build;
2040     gs_font *pfont;
2041     int code = font_param(op - 1, &pfont);
2042     gs_font_base *pbfont = (gs_font_base *) pfont;
2043     ref *v;
2044     char *font_file_path = NULL;
2045     char FAPI_ID[20];
2046     const byte *pchars;
2047     uint len;
2048     font_data *pdata;
2049     gs_fapi_server *I;
2050     bool has_buildglyph;
2051     bool has_buildchar;
2052     int subfont;
2053 
2054     if (code < 0)
2055         return code;
2056 
2057     check_type(*op, t_boolean);
2058     /* If someone has copied the font dictionary, we may still
2059      * have the FAPI entry in the dict, but not have the FAPI
2060      * server assigned in the font object.
2061      */
2062     if (pbfont->FAPI == NULL) {
2063         if (dict_find_string(op - 1, "FAPI", &v) <= 0
2064             || !r_has_type(v, t_name))
2065             return_error(gs_error_invalidfont);
2066         obj_string_data(imemory, v, &pchars, &len);
2067         len = min(len, sizeof(FAPI_ID) - 1);
2068         strncpy((char *)FAPI_ID, (const char *)pchars, len);
2069         FAPI_ID[len] = 0;
2070 
2071         gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p);
2072 
2073         code =
2074             gs_fapi_find_server(imemory, FAPI_ID,
2075                                 (gs_fapi_server **) & (pbfont->FAPI),
2076                                 (gs_fapi_get_server_param_callback)
2077                                 ps_get_server_param);
2078         if (!pbfont->FAPI || code < 0) {
2079             return_error(gs_error_invalidfont);
2080         }
2081     }
2082 
2083     pdata = (font_data *) pfont->client_data;
2084     I = pbfont->FAPI;
2085 
2086     if (dict_find_string((op - 1), "SubfontId", &v) > 0
2087         && r_has_type(v, t_integer))
2088         subfont = v->value.intval;
2089     else
2090         subfont = 0;
2091 
2092 
2093     if (r_type(&(pdata->BuildGlyph)) != t_null) {
2094         has_buildglyph = true;
2095     }
2096     else {
2097         has_buildglyph = false;
2098     }
2099 
2100     if (r_type(&(pdata->BuildChar)) != t_null) {
2101         has_buildchar = true;
2102     }
2103     else {
2104         has_buildchar = false;
2105     }
2106 
2107     /* This shouldn't happen, but just in case */
2108     if (has_buildglyph == false && has_buildchar == false) {
2109         has_buildglyph = true;
2110     }
2111 
2112     if (dict_find_string(op - 1, "Path", &v) <= 0 || !r_has_type(v, t_string)) {
2113         v = NULL;
2114     }
2115 
2116     if (pfont->FontType == ft_CID_encrypted && v == NULL) {
2117         if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildGlyph9",
2118                                          ".FAPIBuildGlyph9")) < 0) {
2119             return code;
2120         }
2121     }
2122     else {
2123         if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildChar",
2124                                          ".FAPIBuildGlyph")) < 0) {
2125             return code;
2126         }
2127     }
2128 
2129     if (!
2130         ((r_type(&(pdata->BuildChar)) != t_null
2131           && pdata->BuildChar.value.pname && build.BuildChar.value.pname
2132           && name_index(imemory, &pdata->BuildChar) == name_index(imemory,
2133                                                                   &build.
2134                                                                   BuildChar))
2135          || (r_type(&(pdata->BuildGlyph)) != t_null
2136              && pdata->BuildGlyph.value.pname && build.BuildGlyph.value.pname
2137              && name_index(imemory, &pdata->BuildGlyph) == name_index(imemory,
2138                                                                       &build.
2139                                                                       BuildGlyph))))
2140     {
2141 
2142         if (has_buildchar == true) {
2143             ref_assign_new(&pdata->BuildChar, &build.BuildChar);
2144         }
2145         else {
2146             make_null(&pdata->BuildChar);
2147         }
2148 
2149         if (has_buildglyph == true) {
2150             ref_assign_new(&pdata->BuildGlyph, &build.BuildGlyph);
2151         }
2152         else {
2153             make_null(&pdata->BuildGlyph);
2154         }
2155         if (v != NULL) {
2156             font_file_path =
2157                 ref_to_string(v, imemory_global, "font file path");
2158         }
2159 
2160         code =
2161             FAPI_refine_font(i_ctx_p, op - 1, pfont, subfont,
2162                              font_file_path);
2163 
2164         memcpy(&I->initial_FontMatrix, &pbfont->FontMatrix,
2165                sizeof(gs_matrix));
2166 
2167         if (font_file_path != NULL) {
2168             gs_free_string(imemory_global, (byte *) font_file_path,
2169                            r_size(v) + 1, "font file path");
2170         }
2171     }
2172     pop(1);
2173     return code;
2174 }
2175 
2176 static ulong
array_find(const gs_memory_t * mem,ref * Encoding,ref * char_name)2177 array_find(const gs_memory_t *mem, ref *Encoding, ref *char_name)
2178 {
2179     ulong n = r_size(Encoding), i;
2180     ref v;
2181 
2182     for (i = 0; i < n; i++)
2183         if (array_get(mem, Encoding, i, &v) < 0)
2184             break;
2185         else if (r_type(char_name) == r_type(&v)
2186                  && char_name->value.const_pname == v.value.const_pname)
2187             return i;
2188     return 0;
2189 }
2190 
2191 static int
zfapi_finish_render(i_ctx_t * i_ctx_p)2192 zfapi_finish_render(i_ctx_t *i_ctx_p)
2193 {
2194     os_ptr op = osp;
2195     gs_font *pfont;
2196     int code = font_param(op - 1, &pfont);
2197 
2198     if (code == 0) {
2199         gs_font_base *pbfont = (gs_font_base *) pfont;
2200         gs_fapi_server *I = pbfont->FAPI;
2201         gs_text_enum_t *penum = op_show_find(i_ctx_p);
2202 
2203         gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p);
2204 
2205         code = gs_fapi_finish_render(pfont, igs, penum, I);
2206         pop(2);
2207         I->release_char_data(I);
2208     }
2209     return code;
2210 }
2211 
2212 static int
ps_fapi_set_cache(gs_text_enum_t * penum,const gs_font_base * pbfont,const gs_string * char_name,int cid,const double pwidth[2],const gs_rect * pbbox,const double Metrics2_sbw_default[4],bool * imagenow)2213 ps_fapi_set_cache(gs_text_enum_t *penum, const gs_font_base *pbfont,
2214                   const gs_string *char_name, int cid,
2215                   const double pwidth[2], const gs_rect *pbbox,
2216                   const double Metrics2_sbw_default[4], bool *imagenow)
2217 {
2218     i_ctx_t *i_ctx_p = (i_ctx_t *) pbfont->FAPI->client_ctx_p;
2219     op_proc_t exec_cont = 0;    /* dummy - see below */
2220     int code = 0;
2221 
2222     if (cid < 0) {
2223         ref cname;
2224 
2225         make_string(&cname, avm_foreign | a_readonly, char_name->size,
2226                     char_name->data);
2227         code =
2228             zchar_set_cache(i_ctx_p, pbfont, &cname, NULL, pwidth, pbbox,
2229                             zfapi_finish_render, &exec_cont,
2230                             Metrics2_sbw_default);
2231     }
2232     else {
2233         ref cidref;
2234 
2235         make_int(&cidref, cid);
2236         code = zchar_set_cache(i_ctx_p, pbfont, &cidref, NULL, pwidth, pbbox,
2237                                zfapi_finish_render, &exec_cont,
2238                                Metrics2_sbw_default);
2239     }
2240 
2241     if (code >= 0 && exec_cont != NULL) {
2242         *imagenow = true;
2243     }
2244     else {
2245         *imagenow = false;
2246     }
2247     /* We ignore the value of exec_cont here, and leave it up to
2248      * gs_fapi_do_char() to do the "right" thing based on the
2249      * return value
2250      */
2251     return (code);
2252 }
2253 
2254 
2255 static const byte *
find_substring(const byte * where,int length,const char * what)2256 find_substring(const byte *where, int length, const char *what)
2257 {
2258     int l = strlen(what);
2259     int n = length - l;
2260     const byte *p = where;
2261 
2262     for (; n >= 0; n--, p++)
2263         if (!memcmp(p, what, l))
2264             return p;
2265     return NULL;
2266 }
2267 
2268 static int
ps_get_glyphname_or_cid(gs_text_enum_t * penum,gs_font_base * pbfont,gs_string * charstring,gs_string * name,int ccode,gs_string * enc_char_name,char * font_file_path,gs_fapi_char_ref * cr,bool bCID)2269 ps_get_glyphname_or_cid(gs_text_enum_t *penum,
2270                         gs_font_base *pbfont, gs_string *charstring,
2271                         gs_string *name, int ccode,
2272                         gs_string *enc_char_name, char *font_file_path,
2273                         gs_fapi_char_ref *cr, bool bCID)
2274 {
2275     ref *pdr = pfont_dict(pbfont);
2276     int client_char_code = ccode;
2277     ref char_name, cname_str;
2278     int code = 0;
2279     gs_fapi_server *I = pbfont->FAPI;
2280     bool is_TT_from_type42 = (pbfont->FontType == ft_TrueType && font_file_path == NULL);
2281     bool is_glyph_index = false;
2282     bool is_embedded_type1 =
2283         ((pbfont->FontType == ft_encrypted
2284           || pbfont->FontType == ft_encrypted2) && font_file_path == NULL);
2285     i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p;
2286     bool unicode_cp = false;
2287 
2288     /* Obtain the character name : */
2289     if (bCID) {
2290         if (pbfont->FontType == ft_CID_TrueType && font_file_path) {
2291             ref *pdr2, *fidr, *dummy;
2292             pdr2 = pfont_dict(gs_rootfont(igs));
2293             if (dict_find_string(pdr2, "FontInfo", &fidr) > 0 &&
2294                 dict_find_string(fidr, "GlyphNames2Unicode", &dummy) > 0)
2295             {
2296                 unsigned char uc[4] = {0};
2297                 unsigned int cc = 0;
2298                 int i, l;
2299                 if (penum->text.operation & TEXT_FROM_SINGLE_CHAR) {
2300                     cc = penum->text.data.d_char;
2301                 } else if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) {
2302                     cc = penum->text.data.d_glyph - GS_MIN_CID_GLYPH;
2303                 }
2304                 else {
2305                     byte *c = (byte *)&penum->text.data.bytes[penum->index - penum->bytes_decoded];
2306                     for (i = 0; i < penum->bytes_decoded ; i++) {
2307                       cc |= c[i] << ((penum->bytes_decoded - 1) - i) * 8;
2308                     }
2309                 }
2310                 l = ((gs_font_base *)gs_rootfont(igs))->procs.decode_glyph(gs_rootfont(igs), cc + GS_MIN_CID_GLYPH, ccode, (unsigned short *)uc, sizeof(uc));
2311                 if (l > 0 && l < sizeof(uc)) {
2312                     cc = 0;
2313                     for (i = 0; i < l; i++) {
2314                         cc |= uc[l - 1 - i] << (i * 8);
2315                     }
2316                     ccode = cc;
2317                     unicode_cp = true;
2318                 }
2319             }
2320         }
2321         client_char_code = ccode;
2322         make_null(&char_name);
2323         enc_char_name->data = NULL;
2324         enc_char_name->size = 0;
2325     }
2326     else {
2327         if (ccode >= 0) {
2328             /* Translate from PS encoding to char name : */
2329             ref *Encoding;
2330 
2331             client_char_code = ccode;
2332             if (dict_find_string(pdr, "Encoding", &Encoding) > 0 &&
2333                 (r_has_type(Encoding, t_array) ||
2334                  r_has_type(Encoding, t_shortarray)
2335                  || r_has_type(Encoding, t_mixedarray))) {
2336                 if (array_get(imemory, Encoding, client_char_code, &char_name)
2337                     < 0)
2338                     if ((code =
2339                          name_ref(imemory, (const byte *)".notdef", 7,
2340                                   &char_name, -1)) < 0)
2341                         return code;
2342             }
2343             else {
2344                 return_error(gs_error_invalidfont);
2345             }
2346         }
2347         else {
2348             code =
2349                 names_ref(imemory->gs_lib_ctx->gs_name_table,
2350                           (const byte *)name->data, name->size, &char_name,
2351                           0);
2352 
2353         }
2354         /* We need to store the name as we get it (from the Encoding array), in case it's
2355          * had the name extended (with "~GS~xx"), we'll remove the extension before passing
2356          * it to the renderer for a disk based font. But the metrics dictionary may have
2357          * been constructed using the extended name....
2358          */
2359         if (!r_has_type(&char_name, t_name))
2360             return_error(gs_error_invalidfont);
2361         name_string_ref(imemory, &char_name, &cname_str);
2362         enc_char_name->data = cname_str.value.bytes;
2363         enc_char_name->size = r_size(&cname_str);
2364     }
2365 
2366     /* Obtain the character code or glyph index : */
2367     cr->char_codes_count = 1;
2368     if (bCID) {
2369         if (font_file_path != NULL) {
2370             ref *Decoding, *TT_cmap = NULL, *SubstNWP;
2371             ref src_type, dst_type;
2372             uint c = 0;
2373 
2374             is_glyph_index = true;
2375 
2376             if (dict_find_string(pdr, "Decoding", &Decoding) <= 0
2377                 || !r_has_type(Decoding, t_dictionary))
2378                 return_error(gs_error_invalidfont);
2379             if (dict_find_string(pdr, "SubstNWP", &SubstNWP) <= 0
2380                 || !r_has_type(SubstNWP, t_array))
2381                 return_error(gs_error_invalidfont);
2382             if (dict_find_string(pdr, "TT_cmap", &TT_cmap) <= 0
2383                 || !r_has_type(TT_cmap, t_dictionary)) {
2384                 ref *DecodingArray, char_code, char_code1, ih;
2385                 int i = client_char_code % 256, n;
2386 
2387                 make_int(&ih, client_char_code / 256);
2388                 /* Check the Decoding array for this block of CIDs */
2389                 if (dict_find(Decoding, &ih, &DecodingArray) <= 0
2390                     || !r_has_type(DecodingArray, t_array)
2391                     || array_get(imemory, DecodingArray, i, &char_code) < 0) {
2392                     return_error(gs_error_invalidfont);
2393                 }
2394 
2395                 /* Check the Decoding entry */
2396                 if (r_has_type(&char_code, t_integer)) {
2397                     n = 1;
2398                 }
2399                 else if (r_has_type(&char_code, t_array)) {
2400                     DecodingArray = &char_code;
2401                     i = 0;
2402                     n = r_size(DecodingArray);
2403                 }
2404                 else {
2405                     return_error(gs_error_invalidfont);
2406                 }
2407 
2408                 for (; n--; i++) {
2409                     if (array_get(imemory, DecodingArray, i, &char_code1) < 0
2410                         || !r_has_type(&char_code1, t_integer)) {
2411                         return_error(gs_error_invalidfont);
2412                     }
2413 
2414                     c = char_code1.value.intval;
2415                     I->check_cmap_for_GID(I, &c);
2416                     if (c != 0)
2417                         break;
2418                 }
2419             }
2420             else {
2421                 ref *CIDSystemInfo;
2422                 ref *Ordering;
2423                 ref *fdict, *CMapDict, *CMapName, *WMode, CMapNameStr;
2424                 char *cmapnm = NULL;
2425                 int cmapnmlen = 0;
2426                 int wmode = 0;
2427                 /* leave off the -H or -V */
2428                 const char * const utfcmap = "Identity-UTF16";
2429                 int utfcmaplen = strlen(utfcmap);
2430 
2431                 fdict = pfont_dict(gs_rootfont(igs));
2432                 code = dict_find_string(fdict, "CMap", &CMapDict);
2433                 if (code > 0 && r_has_type(CMapDict, t_dictionary)) {
2434                     code = dict_find_string(CMapDict, "WMode", &WMode);
2435                     if (code > 0 && r_has_type(WMode, t_integer)) {
2436                         wmode = WMode->value.intval;
2437                     }
2438                     code = dict_find_string(CMapDict, "CMapName", &CMapName);
2439                     if (code > 0 && r_has_type(CMapName, t_name)) {
2440                         name_string_ref(imemory, CMapName, &CMapNameStr);
2441                         cmapnm = (char *)CMapNameStr.value.bytes;
2442                         cmapnmlen = r_size(&CMapNameStr);
2443                     }
2444                 }
2445                 /* We only have to lookup the char code if we're *not* using an identity ordering
2446                    with the exception of Identity-UTF16 which is a different beast altogether */
2447                 if (unicode_cp || (cmapnmlen > 0 && !strncmp(cmapnm, utfcmap, cmapnmlen > utfcmaplen ? utfcmaplen : cmapnmlen))
2448                     || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) > 0
2449                     && r_has_type(CIDSystemInfo, t_dictionary)
2450                     && dict_find_string(CIDSystemInfo, "Ordering",
2451                                         &Ordering) > 0
2452                     && r_has_type(Ordering, t_string)
2453                     && strncmp((const char *)Ordering->value.bytes,
2454                                "Identity", 8) != 0)) {
2455 
2456                     if ((code =
2457                          cid_to_TT_charcode(imemory, Decoding, TT_cmap,
2458                                             SubstNWP, client_char_code, &c,
2459                                             &src_type, &dst_type)) < 0) {
2460                         return code;
2461                     }
2462                 }
2463                 else {
2464                     if (pbfont->FontType == ft_CID_TrueType) {
2465                         c = ((gs_font_cid2 *)pbfont)->cidata.CIDMap_proc(((gs_font_cid2 *)pbfont),
2466                                                   client_char_code + GS_MIN_CID_GLYPH);
2467                     }
2468                     else {
2469                         c = client_char_code;
2470                     }
2471                 }
2472                 if (pbfont->FontType == ft_CID_TrueType)
2473                     c = ((gs_font_cid2 *)pbfont)->data.substitute_glyph_index_vertical((gs_font_type42 *)pbfont, c, wmode, ccode);
2474             }
2475             if (pbfont->FontType == ft_CID_TrueType && c == 0 && TT_cmap) {
2476                 ref cc32;
2477                 ref *gid;
2478                 make_int(&cc32, 32);
2479                 if (dict_find(TT_cmap, &cc32, &gid) > 0)
2480                     c = gid->value.intval;
2481             }
2482             cr->char_codes[0] = c;
2483             /* fixme : process the narrow/wide/proportional mapping type,
2484                using src_type, dst_type. Should adjust the 'matrix' above.
2485                Call get_font_proportional_feature for proper choice.
2486              */
2487         }
2488         else {
2489             ref *CIDMap;
2490             byte *Map;
2491             int c_code = client_char_code;
2492             int gdb = 2;
2493             int i;
2494             ref *GDBytes = NULL;
2495 
2496             if ((dict_find_string(pdr, "GDBytes", &GDBytes) > 0)
2497                 && r_has_type(GDBytes, t_integer)) {
2498                 gdb = GDBytes->value.intval;
2499             }
2500 
2501             /* The PDF Reference says that we should use a CIDToGIDMap, but the PDF
2502              * interpreter converts this into a CIDMap (see pdf_font.ps, processCIDToGIDMap)
2503              */
2504             if (dict_find_string(pdr, "CIDMap", &CIDMap) > 0
2505                 && !r_has_type(CIDMap, t_name) && (r_has_type(CIDMap, t_array)
2506                                                    || r_has_type(CIDMap,
2507                                                                  t_string))) {
2508 
2509                 if (r_has_type(CIDMap, t_array)) {
2510 
2511                     /* Too big for single string, so its an array of 2 strings */
2512                     code = string_array_access_proc(pbfont->memory, CIDMap, 1,
2513                                                  client_char_code * gdb, gdb,
2514                                                  NULL, NULL,
2515                                                  (const byte **)&Map);
2516                 }
2517                 else {
2518                     if (CIDMap->tas.rsize <= c_code * gdb) {
2519                         c_code = 0;
2520                     }
2521                     Map = &CIDMap->value.bytes[c_code * gdb];
2522                 }
2523                 cr->char_codes[0] = 0;
2524                 is_glyph_index = true;
2525                 if (code >= 0) {
2526                     for (i = 0; i < gdb; i++) {
2527                         cr->char_codes[0] = (cr->char_codes[0] << 8) + Map[i];
2528                     }
2529                 }
2530                 else {
2531                     ref *cstr, *refcode;
2532                     code = dict_find_string(pdr, "CharStrings", &cstr);
2533                     if (code > 0) {
2534                         code = dict_find_string(cstr, ".notdef", &refcode);
2535                         if (code > 0) {
2536                             cr->char_codes[0] = refcode->value.intval;
2537                         }
2538                     }
2539                 }
2540             }
2541             else
2542                 cr->char_codes[0] = client_char_code;
2543         }
2544     }
2545     else if (is_TT_from_type42) {
2546         /* This font must not use 'cmap', so compute glyph index from CharStrings : */
2547         ref *CharStrings, *glyph_index;
2548 
2549         if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0
2550             || !r_has_type(CharStrings, t_dictionary))
2551             return_error(gs_error_invalidfont);
2552         if ((dict_find(CharStrings, &char_name, &glyph_index) <= 0)
2553             || r_has_type(glyph_index, t_null)) {
2554 #ifdef DEBUG
2555             ref *pvalue;
2556 
2557             if (gs_debug_c('1')
2558                 && (dict_find_string(systemdict, "QUIET", &pvalue)) > 0
2559                 && (r_has_type(pvalue, t_boolean)
2560                     && pvalue->value.boolval == false)) {
2561                 char *glyphn;
2562 
2563                 name_string_ref(imemory, &char_name, &char_name);
2564 
2565                 glyphn =
2566                     ref_to_string(&char_name, imemory,
2567                                   "ps_get_glyphname_or_cid");
2568                 if (glyphn) {
2569                     dmprintf2(imemory, " Substituting .notdef for %s in the font %s \n",
2570                              glyphn, pbfont->font_name.chars);
2571                     gs_free_string(imemory, (byte *) glyphn,
2572                                    strlen(glyphn) + 1,
2573                                    "ps_get_glyphname_or_cid");
2574                 }
2575             }
2576 #endif
2577 
2578             cr->char_codes[0] = 0;      /* .notdef */
2579             if ((code =
2580                  name_ref(imemory, (const byte *)".notdef", 7, &char_name,
2581                           -1)) < 0)
2582                 return code;
2583         }
2584         else if (r_has_type(glyph_index, t_integer)) {
2585             cr->char_codes[0] = glyph_index->value.intval;
2586         }
2587         else {
2588 #if 1                           /* I can't find this ever being used, no idea what it's for..... */
2589             os_ptr op = osp;
2590 
2591             /* Check execution stack has space for BuldChar proc and finish_render */
2592             check_estack(2);
2593             /* check space and duplicate the glyph index for BuildChar */
2594             check_op(1);
2595             push(1);
2596             ref_assign_inline(op, op - 1);
2597             /* Come back to fapi_finish_render after running the BuildChar */
2598             push_op_estack(zfapi_finish_render);
2599             ++esp;
2600             ref_assign(esp, glyph_index);
2601             return o_push_estack;
2602 #else
2603             return (gs_error_invalidfont);
2604 #endif
2605         }
2606         is_glyph_index = true;
2607     }
2608     else if (is_embedded_type1) {
2609         /*  Since the client passes charstring by callback using I->ff.char_data,
2610            the client doesn't need to provide a good cr here.
2611            Perhaps since UFST uses char codes as glyph cache keys (UFST 4.2 cannot use names),
2612            we provide font char codes equal to document's char codes.
2613            This trick assumes that Encoding can't point different glyphs
2614            for same char code. The last should be true due to
2615            PLRM3, "5.9.4 Subsetting and Incremental Definition of Glyphs".
2616          */
2617         if (ccode >= 0) {
2618             cr->char_codes[0] = client_char_code;
2619         }
2620         else {
2621             /*
2622              * Reverse Encoding here, because it can be an incremental one.
2623              * Note that this can cause problems with UFST (see the comment above),
2624              * if the encoding doesn't contain the glyph name rendered with glyphshow.
2625              */
2626             ref *Encoding;
2627             ref glyph;
2628 
2629             if ((code = name_ref(pbfont->memory, name->data, name->size, &glyph, false)) < 0)
2630                 return code;
2631 
2632             if (dict_find_string(osp - 1, "Encoding", &Encoding) > 0) {
2633                 cr->char_codes[0] =
2634                     (uint) array_find(imemory, Encoding, &glyph);
2635             }
2636             else
2637                 return_error(gs_error_invalidfont);
2638         }
2639     }
2640     else {                      /* a non-embedded font, i.e. a disk font */
2641         bool can_retrieve_char_by_name = false;
2642         const byte *p;
2643 
2644         obj_string_data(imemory, &char_name, &cr->char_name,
2645                         &cr->char_name_length);
2646         p = find_substring(cr->char_name, cr->char_name_length,
2647                            gx_extendeg_glyph_name_separator);
2648         if (p != NULL) {
2649             cr->char_name_length = p - cr->char_name;
2650             if ((code = name_ref(pbfont->memory, cr->char_name,
2651                              cr->char_name_length, &char_name, true)) < 0)
2652                 return code;
2653         }
2654         if ((code =
2655              renderer_retcode(imemory, I,
2656                               I->can_retrieve_char_by_name(I, &I->ff, cr,
2657                                                            &can_retrieve_char_by_name)))
2658             < 0)
2659             return code;
2660 
2661         if (!can_retrieve_char_by_name) {
2662             /* Translate from char name to encoding used with 3d party font technology : */
2663             ref *Decoding, *char_code;
2664 
2665             if (dict_find_string(osp - 1, "Decoding", &Decoding) > 0
2666                 && r_has_type(Decoding, t_dictionary)) {
2667                 if (dict_find(Decoding, &char_name, &char_code) > 0) {
2668                     code = 0;
2669                     if (r_has_type(char_code, t_integer)) {
2670                         int c_code;
2671                         int_param(char_code, 0xFFFF, &c_code);
2672                         cr->char_codes[0] = (gs_glyph)c_code;
2673                     }
2674                     else if (r_has_type(char_code, t_array)
2675                              || r_has_type(char_code, t_shortarray)) {
2676                         int i;
2677                         ref v;
2678 
2679                         cr->char_codes_count = r_size(char_code);
2680                         if (cr->char_codes_count > count_of(cr->char_codes))
2681                             code = gs_note_error(gs_error_rangecheck);
2682                         if (code >= 0) {
2683                             for (i = 0; i < cr->char_codes_count; i++) {
2684                                 code = array_get(imemory, char_code, i, &v);
2685                                 if (code < 0)
2686                                     break;
2687                                 if (!r_has_type(char_code, t_integer)) {
2688                                     code = gs_note_error(gs_error_rangecheck);
2689                                     break;
2690                                 }
2691                                 cr->char_codes[i] = v.value.intval;
2692                             }
2693                         }
2694                     }
2695                     else {
2696                         code = gs_note_error(gs_error_rangecheck);
2697                     }
2698                     if (code < 0) {
2699                         char buf[16];
2700                         int l = cr->char_name_length;
2701 
2702                         if (l > sizeof(buf) - 1) {
2703                             l = sizeof(buf) - 1;
2704                         }
2705                         memcpy(buf, cr->char_name, l);
2706                         buf[l] = 0;
2707                         emprintf1(imemory,
2708                                   "Wrong decoding entry for the character '%s'.\n",
2709                                   buf);
2710                         return_error(gs_error_rangecheck);
2711                     }
2712                 }
2713             }
2714         }
2715     }
2716 
2717     /* Provide glyph data for renderer : */
2718     /* Occasionally, char_name is already a glyph index to pass to the rendering engine
2719      * so don't treat it as a name object.
2720      * I believe this will only happen with a TTF/Type42, but checking the object type
2721      * is cheap, and covers all font type eventualities.
2722      */
2723     if (!I->ff.is_cid && r_has_type(&char_name, t_name)) {
2724         ref sname;
2725 
2726         name_string_ref(imemory, &char_name, &sname);
2727         I->ff.char_data = sname.value.const_bytes;
2728         I->ff.char_data_len = r_size(&sname);
2729     }
2730     else if (I->ff.is_type1) {
2731         I->ff.char_data = charstring;
2732     }
2733 
2734     cr->is_glyph_index = is_glyph_index;
2735     cr->client_char_code = client_char_code;
2736 
2737     return (code);
2738 }
2739 
2740 
2741 static int
FAPI_char(i_ctx_t * i_ctx_p,bool bBuildGlyph,ref * charstring)2742 FAPI_char(i_ctx_t *i_ctx_p, bool bBuildGlyph, ref *charstring)
2743 {                               /* Stack : <font> <code|name> --> - */
2744     os_ptr op = osp;
2745     ref *pdr = op - 1;
2746     ref *v;
2747     char *font_file_path = NULL;
2748     gs_font *pfont;
2749     int code = font_param(osp - 1, &pfont);
2750 
2751     if (code == 0) {
2752         gs_font_base *pbfont = (gs_font_base *) pfont;
2753         bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL);
2754         int subfont;
2755         gs_fapi_server *I = pbfont->FAPI;
2756         gs_text_enum_t *penum = op_show_find(i_ctx_p);
2757         gs_string char_string, *c_string_p = NULL;
2758         gs_string char_name, *c_name_p = NULL;
2759         int cindex = -1;
2760         ref gname;
2761 
2762         if (I == NULL)
2763             return_error(gs_error_invalidfont);
2764 
2765         /* initialise the FAPI font, this includes language specific stuff */
2766         I->ff = ps_ff_stub;
2767 
2768         I->client_ctx_p = i_ctx_p;
2769 
2770         if (bBuildGlyph && !bCID) {
2771             if (r_type(op) != t_name) {
2772                 name_enter_string(imemory, ".notdef", op);
2773             }
2774             check_type(*op, t_name);
2775 
2776             name_string_ref(imemory, op, &gname);
2777             c_name_p = &char_name;
2778             c_name_p->data = gname.value.bytes;
2779             c_name_p->size = r_size(&gname);
2780 
2781         }
2782         else {
2783             if (bBuildGlyph && pbfont->FontType == ft_CID_TrueType
2784                 && r_has_type(op, t_name)) {
2785                 ref *chstrs, *chs;
2786 
2787                 /* This logic is lifted from %Type11BuildGlyph in gs_cidfn.ps
2788                  * Note we only have to deal with mistakenly being given a name object
2789                  * here, the out of range CID is handled later
2790                  */
2791                 if ((dict_find_string(op - 1, "CharStrings", &chstrs)) <= 0) {
2792                     return_error(gs_error_undefined);
2793                 }
2794 
2795                 if ((dict_find_string(chstrs, ".notdef", &chs)) <= 0) {
2796                     return_error(gs_error_undefined);
2797                 }
2798                 ref_assign_inline(op, chs);
2799             }
2800 
2801             make_null(&gname);
2802             check_type(*op, t_integer);
2803             int_param(op, 0xFFFF, &cindex);
2804         }
2805 
2806         if (dict_find_string(pdr, "SubfontId", &v) > 0
2807             && r_has_type(v, t_integer))
2808             subfont = v->value.intval;
2809         else
2810             subfont = 0;
2811 
2812         if (dict_find_string(osp - 1, "Path", &v) > 0
2813             && r_has_type(v, t_string)) {
2814             font_file_path = ref_to_string(v, imemory, "font file path");
2815         }
2816 
2817         if (charstring) {
2818             c_string_p = &char_string;
2819             c_string_p->data = charstring->value.bytes;
2820             c_string_p->size = r_size(charstring);
2821         }
2822 
2823         code =
2824             gs_fapi_do_char(pfont, igs, penum, font_file_path,
2825                             bBuildGlyph, c_string_p, c_name_p, (gs_char)cindex, (gs_glyph)cindex,
2826                             subfont);
2827         if (font_file_path != NULL) {
2828             gs_free_string(imemory, (byte *) font_file_path, r_size(v) + 1,
2829                            "font file path");
2830         }
2831         /* This handles the situation where a charstring has been replaced with a PS procedure.
2832          * against the rules, but not *that* rare.
2833          * It's also something that GS does internally to simulate font styles.
2834          */
2835         if (code == gs_error_unregistered) {
2836             os_ptr op = osp;
2837             ref *proc = NULL, gname;
2838 
2839             if (I->ff.is_type1
2840                 && (get_charstring(&I->ff, cindex, &proc, &gname) >= 0)
2841                 && proc != NULL && (r_has_type(proc, t_array)
2842                     || r_has_type(proc, t_mixedarray))) {
2843                 push(2);
2844                 ref_assign(op - 1, &gname);
2845                 ref_assign(op, proc);
2846                 return (zchar_exec_char_proc(i_ctx_p));
2847             }
2848             else {
2849                 return_error(gs_error_invalidfont);
2850             }
2851         }
2852     }
2853     /* We've already imaged teh glyph, pop the operands */
2854     if (code == 0)
2855         pop(2);
2856     return code;
2857 }
2858 
2859 static int
zFAPIBuildGlyph9(i_ctx_t * i_ctx_p)2860 zFAPIBuildGlyph9(i_ctx_t *i_ctx_p)
2861 {
2862     /*  The alghorithm is taken from %Type9BuildGlyph - see gs_cidfn.ps .  */
2863     os_ptr lop, op = osp;
2864     int cid, code;
2865     avm_space s = ialloc_space(idmemory);
2866     ref font9 = *pfont_dict(gs_currentfont(igs));
2867     ref *rFDArray, f;
2868     int font_index;
2869 
2870     check_type(op[0], t_integer);
2871     check_type(op[-1], t_dictionary);
2872     cid = op[0].value.intval;
2873     push(2);
2874     op[-1] = *pfont_dict(gs_currentfont(igs));
2875     op[0] = op[-2];             /* <font0> <cid> <font9> <cid> */
2876     ialloc_set_space(idmemory, (r_is_local(op - 3) ? avm_global : avm_local));  /* for ztype9mapcid */
2877 
2878     /* stack: <font0> <cid> <font9> <cid> */
2879     if ((code = ztype9mapcid(i_ctx_p)) < 0)
2880         return code;            /* <font0> <cid> <charstring> <font_index> */
2881     /* fixme: what happens if the charstring is absent ?
2882        Can FDArray contain 'null' (see %Type9BuildGlyph in gs_cidfn.ps)? */
2883     font_index = op[0].value.intval;
2884     if (dict_find_string(&font9, "FDArray", &rFDArray) <= 0
2885         || r_type(rFDArray) != t_array)
2886         return_error(gs_error_invalidfont);
2887     if (array_get(imemory, rFDArray, font_index, &f) < 0
2888         || r_type(&f) != t_dictionary)
2889         return_error(gs_error_invalidfont);
2890 
2891     op[0] = op[-2];
2892     op[-2] = op[-1];            /* Keep the charstring on ostack for the garbager. */
2893     op[-1] = f;                 /* <font0> <charstring> <subfont> <cid> */
2894     if ((code = FAPI_char(i_ctx_p, true, op - 2)) < 0)
2895         return code;
2896     /* stack: <font0> <charstring> */
2897 
2898     lop = osp;
2899     if (code == 5) {
2900         int i, ind = (lop - op);
2901 
2902         op = osp;
2903 
2904         for (i = ind; i >= 0; i--) {
2905             op[-i - 2] = op[-i];
2906         }
2907         pop(2);
2908     }
2909     else if (code < 0) {        /* <font0> <dirty> <dirty> <dirty> */
2910         /* Adjust ostack for the correct error handling : */
2911         make_int(op - 2, cid);
2912         pop(2);                 /* <font0> <cid> */
2913     }
2914     else if (code != 5) {       /* <font0> <dirty> */
2915 
2916 
2917         pop(2);                 /* */
2918         /*  Note that this releases the charstring, and it may be garbage-collected
2919            before the interpreter calls fapi_finish_render. This requires the server
2920            to keep glyph raster internally between calls to get_char_raster_metrics
2921            and get_char_raster. Perhaps UFST cannot provide metrics without
2922            building a raster, so this constraint actually goes from UFST.
2923          */
2924     }
2925     ialloc_set_space(idmemory, s);
2926     return code;
2927 }
2928 
2929 /* <font> <code> .FAPIBuildChar - */
2930 static int
zFAPIBuildChar(i_ctx_t * i_ctx_p)2931 zFAPIBuildChar(i_ctx_t *i_ctx_p)
2932 {
2933     return FAPI_char(i_ctx_p, false, NULL);
2934 }
2935 
2936 /* non-CID : <font> <code> .FAPIBuildGlyph - */
2937 /*     CID : <font> <name> .FAPIBuildGlyph - */
2938 static int
zFAPIBuildGlyph(i_ctx_t * i_ctx_p)2939 zFAPIBuildGlyph(i_ctx_t *i_ctx_p)
2940 {
2941     return FAPI_char(i_ctx_p, true, NULL);
2942 }
2943 
2944 
2945 /* <font_dict> .FAPIpassfont bool <font_dict> */
2946 /* must insert /FAPI to font dictionary */
2947 static int
zFAPIpassfont(i_ctx_t * i_ctx_p)2948 zFAPIpassfont(i_ctx_t *i_ctx_p)
2949 {
2950     os_ptr op = osp;
2951     gs_font *pfont;
2952     int code;
2953     char *font_file_path = NULL;
2954     ref *v;
2955     char *xlatmap = NULL;
2956     char *fapi_request = NULL;
2957     char *fapi_id = NULL;
2958     ref reqstr;
2959     int subfont;
2960 
2961     /* Normally embedded fonts have no Path, but if a CID font is
2962      * emulated with a TT font, and it is hooked with FAPI,
2963      * the path presents and is neccessary to access the full font data.
2964      */
2965     check_type(*op, t_dictionary);
2966 
2967     code = font_param(osp, &pfont);
2968     if (code < 0)
2969         return code;
2970 
2971     if (dict_find_string(op, "SubfontId", &v) > 0
2972         && r_has_type(v, t_integer))
2973         subfont = v->value.intval;
2974     else
2975         subfont = 0;
2976 
2977     code = FAPI_get_xlatmap(i_ctx_p, &xlatmap); /* Useful for emulated fonts hooked with FAPI. */
2978     if (code < 0)
2979         return code;
2980 
2981     /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us
2982      * to try to use a specific FAPI plugin, so find it, and try it....
2983      */
2984     if (dict_find_string(op, "FAPIPlugInReq", &v) > 0 && r_type(v) == t_name) {
2985 
2986         name_string_ref(imemory, v, &reqstr);
2987 
2988         fapi_request = ref_to_string(&reqstr, imemory, "zFAPIpassfont");
2989     }
2990 
2991     if (dict_find_string(op, "Path", &v) > 0 && r_has_type(v, t_string))
2992         font_file_path = ref_to_string(v, imemory_global, "font file path");
2993 
2994     gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p);
2995 
2996     code =
2997         gs_fapi_passfont(pfont, subfont, font_file_path, NULL, fapi_request, xlatmap,
2998                          &fapi_id, (gs_fapi_get_server_param_callback)ps_get_server_param);
2999 
3000     if (font_file_path != NULL)
3001         gs_free_string(imemory_global, (byte *) font_file_path, r_size(v) + 1,
3002                        "font file path");
3003 
3004     if (fapi_request != NULL)
3005         gs_free_string(imemory, (byte *) fapi_request,
3006                        strlen(fapi_request) + 1, "do_FAPIpassfont");
3007     if (code < 0 && code != gs_error_invalidaccess)
3008         return code;
3009 
3010     if (code >= 0 && fapi_id != NULL) {
3011         ref FAPI_ID;
3012 
3013         if ((code =
3014              name_ref(imemory, (const byte *)fapi_id,
3015                       strlen(fapi_id), &FAPI_ID, false)) < 0)
3016             return code;
3017         if ((code = dict_put_string(op, "FAPI", &FAPI_ID, NULL)) < 0)
3018             return code;        /* Insert FAPI entry to font dictionary. */
3019     }
3020     push(1);
3021     make_bool(op, (fapi_id != NULL));
3022     return 0;
3023 }
3024 
3025 const op_def zfapi_op_defs[] = {
3026     {"1.FAPIavailable", zFAPIavailable},
3027     {"2.FAPIpassfont", zFAPIpassfont},
3028     {"2.FAPIrebuildfont", zFAPIrebuildfont},
3029     {"2.FAPIBuildChar", zFAPIBuildChar},
3030     {"2.FAPIBuildGlyph", zFAPIBuildGlyph},
3031     {"2.FAPIBuildGlyph9", zFAPIBuildGlyph9},
3032     op_def_end(0)
3033 };
3034