1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "encoding.h"
31 
32 #include "bitmapchar.h"
33 #include "bvedit.h"
34 #include "dumppfa.h"
35 #include "encoding.h"
36 #include "ffglib.h"
37 #include "fontforgevw.h"
38 #include "fvfonts.h"
39 #include "gfile.h"
40 #include "namelist.h"
41 #include "psfont.h"
42 #include "psread.h"
43 #include "pua.h"
44 #include "splinefill.h"
45 #include "splinefont.h"
46 #include "splinesaveafm.h"
47 #include "splineutil.h"
48 #include "splineutil2.h"
49 #include "ustring.h"
50 #include "utype.h"
51 
52 #include <dirent.h>
53 #include <math.h>
54 #include <sys/types.h>
55 #include <unistd.h>
56 
57 Encoding *default_encoding = NULL;
58 
59 static int32 tex_base_encoding[] = {
60     0x0000, 0x02d9, 0xfb01, 0xfb02, 0x2044, 0x02dd, 0x0141, 0x0142,
61     0x02db, 0x02da, 0x000a, 0x02d8, 0x2212, 0x000d, 0x017d, 0x017e,
62     0x02c7, 0x0131, 0xf6be, 0xfb00, 0xfb03, 0xfb04, 0x2260, 0x221e,
63     0x2264, 0x2265, 0x2202, 0x2211, 0x220f, 0x03c0, 0x0060, 0x0027,
64     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019,
65     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
66     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
67     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
68     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
69     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
70     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
71     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
72     0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
73     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
74     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
75     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
76     0x20ac, 0x222b, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
77     0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x2126, 0x221a, 0x2248,
78     0x0090, 0x0091, 0x0092, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
79     0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x2206, 0x25ca, 0x0178,
80     0x0000, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
81     0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x002d, 0x00ae, 0x00af,
82     0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
83     0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
84     0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
85     0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
86     0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
87     0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
88     0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
89     0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
90     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
91     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
92 };
93 
94 static int32 unicode_from_MacSymbol[] = {
95   0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
96   0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
97   0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
98   0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
99   0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220d,
100   0x0028, 0x0029, 0x2217, 0x002b, 0x002c, 0x2212, 0x002e, 0x002f,
101   0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
102   0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
103   0x2245, 0x0391, 0x0392, 0x03a7, 0x0394, 0x0395, 0x03a6, 0x0393,
104   0x0397, 0x0399, 0x03d1, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f,
105   0x03a0, 0x0398, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03c2, 0x03a9,
106   0x039e, 0x03a8, 0x0396, 0x005b, 0x2234, 0x005d, 0x22a5, 0x005f,
107   0xf8e5, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3,
108   0x03b7, 0x03b9, 0x03d5, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03bf,
109   0x03c0, 0x03b8, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d6, 0x03c9,
110   0x03be, 0x03c8, 0x03b6, 0x007b, 0x007c, 0x007d, 0x223c, 0x007f,
111   0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
112   0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
113   0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
114   0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
115   0x0000, 0x03d2, 0x2032, 0x2264, 0x2044, 0x221e, 0x0192, 0x2663,
116   0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
117   0x00b0, 0x00b1, 0x2033, 0x2265, 0x00d7, 0x221d, 0x2202, 0x2022,
118   0x00f7, 0x2260, 0x2261, 0x2248, 0x2026, 0xf8e6, 0xf8e7, 0x21b5,
119   0x2135, 0x2111, 0x211c, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
120   0x222a, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
121   0x2220, 0x2207, 0x00ae, 0x00a9, 0x2122, 0x220f, 0x221a, 0x22c5,
122   0x00ac, 0x2227, 0x2228, 0x21d4, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
123   0x22c4, 0x2329, 0xf8e8, 0xf8e9, 0xf8ea, 0x2211, 0xf8eb, 0xf8ec,
124   0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0, 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4,
125   0xf8ff, 0x232a, 0x222b, 0x2320, 0xf8f5, 0x2321, 0xf8f6, 0xf8f7,
126   0xf8f8, 0xf8f9, 0xf8fa, 0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0x02c7
127 };
128 
129 /* I don't think iconv provides encodings for zapfdingbats nor jis201 */
130 /*  Perhaps I should list them here for compatability, but I think I'll just */
131 /*  leave them out. I doubt they get used. */
132 static Encoding texbase = { "TeX-Base-Encoding", 256, tex_base_encoding, NULL, NULL, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
133        Encoding custom = { "Custom", 0, NULL, NULL, &texbase,                        1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
134 static Encoding original = { "Original", 0, NULL, NULL, &custom,                     1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
135 static Encoding unicodebmp = { "UnicodeBmp", 65536, NULL, NULL, &original,           1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
136 static Encoding unicodefull = { "UnicodeFull", 17*65536, NULL, NULL, &unicodebmp,    1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
137 static Encoding adobestd = { "AdobeStandard", 256, unicode_from_adobestd, (char**)AdobeStandardEncoding, &unicodefull,
138                                                                                      1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
139 static Encoding symbol = { "Symbol", 256, unicode_from_MacSymbol, NULL, &adobestd,   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
140 
141 Encoding *enclist = &symbol;
142 
FindUnicharName(void)143 const char *FindUnicharName(void) {
144     /* Iconv and libiconv use different names for UCS2. Just great. Perhaps */
145     /*  different versions of each use still different names? */
146     /* Even worse, both accept UCS-2, but under iconv it means native byte */
147     /*  ordering and under libiconv it means big-endian */
148     iconv_t test;
149     static const char *goodname = NULL;
150     static const char *names[] = { "UCS-4-INTERNAL", "UCS-4", "UCS4", "ISO-10646-UCS-4", "UTF-32", NULL };
151     static const char *namesle[] = { "UCS-4LE", "UTF-32LE", NULL };
152     static const char *namesbe[] = { "UCS-4BE", "UTF-32BE", NULL };
153     const char **testnames;
154     int i;
155     union {
156 	short s;
157 	char c[2];
158     } u;
159 
160     if ( goodname!=NULL )
161 return( goodname );
162 
163     u.c[0] = 0x1; u.c[1] = 0x2;
164     if ( u.s==0x201 ) {		/* Little endian */
165 	testnames = namesle;
166     } else {
167 	testnames = namesbe;
168     }
169     for ( i=0; testnames[i]!=NULL; ++i ) {
170 	test = iconv_open(testnames[i],"ISO-8859-1");
171 	if ( test!=(iconv_t) -1 && test!=NULL ) {
172 	    iconv_close(test);
173 	    goodname = testnames[i];
174     break;
175 	}
176     }
177 
178     if ( goodname==NULL ) {
179 	for ( i=0; names[i]!=NULL; ++i ) {
180 	    test = iconv_open(names[i],"ISO-8859-1");
181 	    if ( test!=(iconv_t) -1 && test!=NULL ) {
182 		iconv_close(test);
183 		goodname = names[i];
184 	break;
185 	    }
186 	}
187     }
188 
189     if ( goodname==NULL ) {
190 	IError( "I can't figure out your version of iconv(). I need a name for the UCS-4 encoding and I can't find one. Reconfigure --without-iconv. Bye.");
191 	exit( 1 );
192     }
193 
194     test = iconv_open(goodname,"Mac");
195     if ( test==(iconv_t) -1 || test==NULL ) {
196 	IError( "Your version of iconv does not support the \"Mac Roman\" encoding.\nIf this causes problems, reconfigure --without-iconv." );
197     } else
198 	iconv_close(test);
199 
200     /* I really should check for ISO-2022-JP, KR, CN, and all the other encodings */
201     /*  I might find in a ttf 'name' table. But those tables take too long to build */
202 return( goodname );
203 }
204 
TryEscape(Encoding * enc,const char * escape_sequence)205 static int TryEscape( Encoding *enc, const char *escape_sequence ) {
206     char from[20], ucs[20];
207     size_t fromlen, tolen;
208     ICONV_CONST char *fpt;
209     char *upt;
210     int i, j, low;
211     int esc_len = strlen(escape_sequence);
212 
213     strcpy(from,escape_sequence);
214 
215     enc->has_2byte = false;
216     low = -1;
217     for ( i=0; i<256; ++i ) if ( i!=escape_sequence[0] ) {
218 	for ( j=0; j<256; ++j ) {
219 	    from[esc_len] = i; from[esc_len+1] = j; from[esc_len+2] = 0;
220 	    fromlen = esc_len+2;
221 	    fpt = from;
222 	    upt = ucs;
223 	    tolen = sizeof(ucs);
224 	    if ( iconv( enc->tounicode , &fpt, &fromlen, &upt, &tolen )!= (size_t) (-1) &&
225 		    upt-ucs==sizeof(unichar_t) /* Exactly one character */ ) {
226 		if ( low==-1 ) {
227 		    enc->low_page = low = i;
228 		    enc->has_2byte = true;
229 		}
230 		enc->high_page = i;
231 	break;
232 	    }
233 	}
234     }
235     if ( enc->low_page==enc->high_page )
236 	enc->has_2byte = false;
237     if ( enc->has_2byte ) {
238 	strcpy(enc->iso_2022_escape, escape_sequence);
239 	enc->iso_2022_escape_len = esc_len;
240     }
241 return( enc->has_2byte );
242 }
243 
_FindOrMakeEncoding(const char * name,int make_it)244 Encoding *_FindOrMakeEncoding(const char *name,int make_it) {
245     Encoding *enc;
246     char buffer[20];
247     const char *iconv_name;
248     Encoding temp;
249     uint8 good[256];
250     int i, j, any, all;
251     char from[8], ucs[20];
252     size_t fromlen, tolen;
253     ICONV_CONST char *fpt;
254     char *upt;
255     /* iconv is not case sensitive */
256 
257     if ( strncasecmp(name,"iso8859_",8)==0 || strncasecmp(name,"koi8_",5)==0 ) {
258 	    /* Fixup for old naming conventions */
259 	    strncpy(buffer,name,sizeof(buffer));
260         buffer[sizeof(buffer)-1] = '\0';
261 	    *strchr(buffer,'_') = '-';
262 	    name = buffer;
263     } else if ( strcasecmp(name,"iso-8859")==0 ) {
264 	    /* Fixup for old naming conventions */
265 	    strncpy(buffer,name,3);
266 	    strncpy(buffer+3,name+4,sizeof(buffer)-3);
267         buffer[sizeof(buffer)-1] = '\0';
268 	    name = buffer;
269     } else if ( strcasecmp(name,"isolatin10")==0 || strcasecmp(name,"latin10")==0 ) {
270         name = "iso8859-16";	/* try 10 before trying 1 */
271     } else if ( strcasecmp(name,"isolatin1")==0 ) {
272         name = "iso8859-1";
273     } else if ( strcasecmp(name,"isocyrillic")==0 ) {
274         name = "iso8859-5";
275     } else if ( strcasecmp(name,"isoarabic")==0 ) {
276         name = "iso8859-6";
277     } else if ( strcasecmp(name,"isogreek")==0 ) {
278         name = "iso8859-7";
279     } else if ( strcasecmp(name,"isohebrew")==0 ) {
280         name = "iso8859-8";
281     } else if ( strcasecmp(name,"isothai")==0 ) {
282 	name = "tis-620";	/* TIS doesn't define non-breaking space in 0xA0 */
283     } else if ( strcasecmp(name,"latin0")==0 || strcasecmp(name,"latin9")==0 ) {
284 	name = "iso8859-15";	/* "latin-9" is supported (libiconv bug?) */
285     } else if ( strcasecmp(name,"koi8r")==0 ) {
286         name = "koi8-r";
287     } else if ( strncasecmp(name,"jis201",6)==0 || strncasecmp(name,"jisx0201",8)==0 ) {
288         name = "jis_x0201";
289     } else if ( strcasecmp(name,"AdobeStandardEncoding")==0 || strcasecmp(name,"Adobe")==0 )
290 	name = "AdobeStandard";
291     for ( enc=enclist; enc!=NULL; enc=enc->next )
292 	if ( strmatch(name,enc->enc_name)==0 ||
293 		(enc->iconv_name!=NULL && strmatch(name,enc->iconv_name)==0))
294 return( enc );
295     if ( strmatch(name,"unicode")==0 || strmatch(name,"iso10646")==0 || strmatch(name,"iso10646-1")==0 )
296 return( &unicodebmp );
297     if ( strmatch(name,"unicode4")==0 || strmatch(name,"ucs4")==0 )
298 return( &unicodefull );
299 
300     iconv_name = name;
301     /* Mac seems to work ok */
302     if ( strcasecmp(name,"win")==0 || strcasecmp(name,"ansi")==0 )
303 	iconv_name = "MS-ANSI";		/* "WINDOWS-1252";*/
304     else if ( strncasecmp(name,"jis208",6)==0 || strncasecmp(name,"jisx0208",8)==0 )
305 	iconv_name = "ISO-2022-JP";
306     else if ( strncasecmp(name,"jis212",6)==0 || strncasecmp(name,"jisx0212",8)==0 )
307 	iconv_name = "ISO-2022-JP-2";
308     else if ( strncasecmp(name,"ksc5601",7)==0 )
309 	iconv_name = "ISO-2022-KR";
310     else if ( strcasecmp(name,"gb2312pk")==0 || strcasecmp(name,"gb2312packed")==0 )
311 	iconv_name = "EUC-CN";
312     else if ( strncasecmp(name,"gb2312",6)==0 )
313 	iconv_name = "ISO-2022-CN";
314     else if ( strcasecmp(name,"wansung")==0 )
315 	iconv_name = "EUC-KR";
316     else if ( strcasecmp(name,"EUC-CN")==0 ) {
317 	iconv_name = name;
318 	name = "gb2312pk";
319     } else if ( strcasecmp(name,"EUC-KR")==0 ) {
320 	iconv_name = name;
321 	name = "wansung";
322     }
323 
324 /* Escape sequences:					*/
325 /*	ISO-2022-CN:     \e $ ) A ^N			*/
326 /*	ISO-2022-KR:     \e $ ) C ^N			*/
327 /*	ISO-2022-JP:     \e $ B				*/
328 /*	ISO-2022-JP-2:   \e $ ( D			*/
329 /*	ISO-2022-JP-3:   \e $ ( O			*/ /* Capital "O", not zero */
330 /*	ISO-2022-CN-EXT: \e $ ) E ^N			*/ /* Not sure about this, also uses CN escape */
331 
332     memset(&temp,0,sizeof(temp));
333     temp.builtin = true;
334     temp.tounicode = iconv_open(FindUnicharName(),iconv_name);
335     if ( temp.tounicode==(iconv_t) -1 || temp.tounicode==NULL )
336 return( NULL );			/* Iconv doesn't recognize this name */
337     temp.fromunicode = iconv_open(iconv_name,FindUnicharName());
338     if ( temp.fromunicode==(iconv_t) -1 || temp.fromunicode==NULL ) {
339 	/* This should never happen, but if it does... */
340 	iconv_close(temp.tounicode);
341 return( NULL );
342     }
343 
344     memset(good,0,sizeof(good));
345     any = false; all = true;
346     for ( i=1; i<256; ++i ) {
347 	from[0] = i; from[1] = 0;
348 	fromlen = 1;
349 	fpt = from;
350 	upt = ucs;
351 	tolen = sizeof(ucs);
352 	if ( iconv( temp.tounicode , &fpt, &fromlen, &upt, &tolen )!= (size_t) (-1)) {
353 	    good[i] = true;
354 	    any = true;
355 	} else
356 	    all = false;
357     }
358     if ( any )
359 	temp.has_1byte = true;
360     if ( all )
361 	temp.only_1byte = true;
362 
363     if ( !all ) {
364 	if ( strstr(iconv_name,"2022")==NULL ) {
365 	    for ( i=temp.has_1byte; i<256; ++i ) if ( !good[i] ) {
366 		for ( j=0; j<256; ++j ) {
367 		    from[0] = i; from[1] = j; from[2] = 0;
368 		    fromlen = 2;
369 		    fpt = from;
370 		    upt = ucs;
371 		    tolen = sizeof(ucs);
372 		    if ( iconv( temp.tounicode , &fpt, &fromlen, &upt, &tolen )!= (size_t) (-1) &&
373 			    upt-ucs==sizeof(unichar_t) /* Exactly one character */ ) {
374 			if ( temp.low_page==-1 )
375 			    temp.low_page = i;
376 			temp.high_page = i;
377 			temp.has_2byte = true;
378 		break;
379 		    }
380 		}
381 	    }
382 	    if ( temp.low_page==temp.high_page ) {
383 		temp.has_2byte = false;
384 		temp.low_page = temp.high_page = -1;
385 	    }
386 	}
387 	if ( !temp.has_2byte && !good[033]/* escape */ ) {
388 	    if ( strstr(iconv_name,"2022")!=NULL &&
389 		    strstr(iconv_name,"JP3")!=NULL &&
390 		    TryEscape( &temp,"\33$(O" )) {
391 		;
392 	    } else if ( strstr(iconv_name,"2022")!=NULL &&
393 		    strstr(iconv_name,"JP2")!=NULL &&
394 		    TryEscape( &temp,"\33$(D" )) {
395 		;
396 	    } else if ( strstr(iconv_name,"2022")!=NULL &&
397 		    strstr(iconv_name,"JP")!=NULL &&
398 		    TryEscape( &temp,"\33$B" )) {
399 		;
400 	    } else if ( strstr(iconv_name,"2022")!=NULL &&
401 		    strstr(iconv_name,"KR")!=NULL &&
402 		    TryEscape( &temp,"\33$)C\16" )) {
403 		;
404 	    } else if ( strstr(iconv_name,"2022")!=NULL &&
405 		    strstr(iconv_name,"CN")!=NULL &&
406 		    TryEscape( &temp,"\33$)A\16" )) {
407 		;
408 	    }
409 	}
410     }
411     if ( !temp.has_1byte && !temp.has_2byte )
412 return( NULL );
413     if ( !make_it )
414 return( NULL );
415 
416     enc = chunkalloc(sizeof(Encoding));
417     *enc = temp;
418     enc->enc_name = copy(name);
419     if ( iconv_name!=name )
420 	enc->iconv_name = copy(iconv_name);
421     enc->next = enclist;
422     enc->builtin = true;
423     enclist = enc;
424     if ( enc->has_2byte )
425 	enc->char_cnt = (enc->high_page<<8) + 256;
426     else {
427 	enc->char_cnt = 256;
428 	enc->only_1byte = true;
429     }
430     if ( strstrmatch(iconv_name,"JP")!=NULL ||
431 	    strstrmatch(iconv_name,"sjis")!=NULL ||
432 	    strstrmatch(iconv_name,"cp932")!=NULL )
433 	enc->is_japanese = true;
434     else if ( strstrmatch(iconv_name,"KR")!=NULL )
435 	enc->is_korean = true;
436     else if ( strstrmatch(iconv_name,"CN")!=NULL )
437 	enc->is_simplechinese = true;
438     else if ( strstrmatch(iconv_name,"BIG")!=NULL && strstrmatch(iconv_name,"5")!=NULL )
439 	enc->is_tradchinese = true;
440 
441     if ( strstrmatch(name,"ISO8859")!=NULL &&
442 	    strtol(name+strlen(name)-2,NULL,10)>=16 )
443 	/* Not in our menu, don't hide */;
444     else if ( iconv_name!=name || strmatch(name,"mac")==0 || strstrmatch(name,"ISO8859")!=NULL ||
445 	    strmatch(name,"koi8-r")==0 || strmatch(name,"sjis")==0 ||
446 	    strmatch(name,"big5")==0 || strmatch(name,"big5hkscs")==0 )
447 	enc->hidden = true;
448 
449 return( enc );
450 }
451 
FindOrMakeEncoding(const char * name)452 Encoding *FindOrMakeEncoding(const char *name) {
453 return( _FindOrMakeEncoding(name,true));
454 }
455 
456 /* Plugin API */
AddEncoding(char * name,EncFunc enc_to_uni,EncFunc uni_to_enc,int max)457 int AddEncoding(char *name,EncFunc enc_to_uni,EncFunc uni_to_enc,int max) {
458     Encoding *enc;
459     int i;
460 
461     for ( enc=enclist; enc!=NULL; enc=enc->next ) {
462 	if ( strmatch(name,enc->enc_name)==0 ||
463 		(enc->iconv_name!=NULL && strmatch(name,enc->iconv_name)==0)) {
464 	    if ( enc->tounicode_func==NULL )
465 return( 0 );			/* Failure */
466 	    else {
467 		enc->tounicode_func   = enc_to_uni;
468 		enc->fromunicode_func = uni_to_enc;
469 		enc->char_cnt	      = max;
470 return( 2 );
471 	    }
472 	}
473     }
474 
475     if ( strmatch(name,"unicode")==0 || strmatch(name,"iso10646")==0 || strmatch(name,"iso10646-1")==0 )
476 return( 0 );			/* Failure */
477     if ( strmatch(name,"unicode4")==0 || strmatch(name,"ucs4")==0 )
478 return( 0 );			/* Failure */
479 
480     enc = chunkalloc(sizeof(Encoding));
481     enc->enc_name = copy(name);
482     enc->next = enclist;
483     enclist = enc;
484     enc->tounicode_func   = enc_to_uni;
485     enc->fromunicode_func = uni_to_enc;
486     enc->char_cnt	      = max;
487     for ( i=0; i<256 && i<max; ++i )
488 	if ( enc_to_uni(i)!=-1 )
489     break;
490 
491     if ( i<256 && i<max )
492 	enc->has_1byte = true;
493     if ( max<256 )
494 	enc->only_1byte = true;
495     else
496 	enc->has_2byte = true;
497 return( 1 );
498 }
499 
getPfaEditEncodings(void)500 static char *getPfaEditEncodings(void) {
501     static char *encfile=NULL;
502     char buffer[1025];
503     char *ffdir;
504 
505     if ( encfile!=NULL )
506         return encfile;
507     ffdir = getFontForgeUserDir(Config);
508     if ( ffdir==NULL )
509         return NULL;
510     sprintf(buffer,"%s/Encodings.ps", ffdir);
511     free(ffdir);
512     encfile = copy(buffer);
513     return encfile;
514 }
515 
EncodingFree(Encoding * item)516 void EncodingFree(Encoding *item) {
517     int i;
518 
519     if ( item==NULL )
520 	return;
521 
522     free(item->enc_name);
523     if ( item->psnames!=NULL ) {
524 	for ( i=0; i<item->char_cnt; ++i )
525 	    free(item->psnames[i]);
526 	free(item->psnames);
527     }
528     free(item->unicode);
529     free(item);
530 }
531 
DeleteEncoding(Encoding * me)532 void DeleteEncoding(Encoding *me) {
533     FontViewBase *fv;
534     Encoding *prev;
535 
536     if ( me->builtin )
537 return;
538 
539     for ( fv = FontViewFirst(); fv!=NULL; fv = fv->next ) {
540 	if ( fv->map->enc==me )
541 	    fv->map->enc = &custom;
542     }
543     if ( me==enclist )
544 	enclist = me->next;
545     else {
546 	for ( prev = enclist; prev!=NULL && prev->next!=me; prev=prev->next );
547 	if ( prev!=NULL ) prev->next = me->next;
548     }
549     EncodingFree(me);
550     if ( default_encoding == me )
551 	default_encoding = FindOrMakeEncoding("ISO8859-1");
552     if ( default_encoding == NULL )
553 	default_encoding = &custom;
554     DumpPfaEditEncodings();
555 }
556 
557 /* Parse a TXT file from the unicode consortium */
558     /* Unicode Consortium Format A */
559     /* List of lines with several fields, */
560 	/* first is the encoding value (in hex), second the Unicode value (in hex) */
561     /* # is a comment character (to eol) */
ParseConsortiumEncodingFile(FILE * file)562 static Encoding *ParseConsortiumEncodingFile(FILE *file) {
563     char buffer[200];
564     int32 encs[0x10000];
565     int enc, unienc, max;
566     Encoding *item;
567 
568     memset(encs, 0, sizeof(encs));
569     max = -1;
570 
571     while ( fgets(buffer,sizeof(buffer),file)!=NULL ) {
572 	if ( ishexdigit(buffer[0]) ) {
573 	    if ( sscanf(buffer, "%x %x", (unsigned *) &enc, (unsigned *) &unienc)==2 &&
574 		    enc<0x10000 && enc>=0 ) {
575 		encs[enc] = unienc;
576 		if ( enc>max ) max = enc;
577 	    }
578 	}
579     }
580 
581     if ( max==-1 )
582 return( NULL );
583 
584     ++max;
585     if ( max<256 ) max = 256;
586     item = calloc(1,sizeof(Encoding));
587     item->only_1byte = item->has_1byte = true;
588     item->char_cnt = max;
589     item->unicode = malloc(max*sizeof(int32));
590     memcpy(item->unicode,encs,max*sizeof(int32));
591 return( item );
592 }
593 
594 /**
595  *  \brief Parses a GlyphOrderAndAliasDB encoding file
596  *
597  *  \param [in] file The file handle to the encoding file
598  *  \return The encoding, or NULL if none could be made
599  *
600  *  \details Each line in the file contains one glyph name (equating to one slot).
601  *           It is assumed that values are tab separated. There
602  *           are at least two columns, with a third column being optional.
603  *           The first column is the glyph name to be used on output. This
604  *           is what will normally be used to determine the unicode value for
605  *           this slot.
606  *           The second column is the 'friendly' name - this is what will
607  *           be used for the slot's name.
608  *           The third, optional column specifies the unicode value that the
609  *           slot should map to. When available, this will be used in preference
610  *           to the first column.
611  */
ParseGlyphOrderAndAliasDB(FILE * file)612 static Encoding *ParseGlyphOrderAndAliasDB(FILE *file) {
613     GArray *enc_arr = g_array_sized_new(FALSE, TRUE, sizeof(int32), 256);
614     GArray *names_arr = g_array_sized_new(FALSE, TRUE, sizeof(char *), 256);
615     Encoding *item = NULL;
616     char buffer[BUFSIZ];
617     int enc, any = FALSE, has_1byte = FALSE;
618 
619     while (fgets(buffer, sizeof(buffer), file)) {
620         char *split = strchr(buffer, '\t'), *split2, *enc_name = NULL;
621         if (split == NULL) {
622             // Skip entries that do not contain at least two (tab separated) values
623             LogError(_("ParseGlyphOrderAndAliasDB: Invalid (non-tab separated entry) at index %d: %s\n"), enc_arr->len, g_strstrip(buffer));
624             //enc = -1;
625             //g_array_append_val(enc_arr, enc);
626             //g_array_append_val(names_arr, enc_name);
627             continue;
628         }
629         *split++ = '\0';
630         // Buffer now contains the first column
631         g_strstrip(buffer);
632         // split contains the second, and possibly the third column
633         g_strstrip(split);
634 
635         // Optional third column
636         split2 = strchr(split, '\t');
637         if (split2 != NULL) {
638             *split2++ = '\0';
639             g_strstrip(split2);
640         }
641 
642         // Use the third column in preference to the first
643         enc = UniFromName((split2 != NULL) ? split2 : buffer, ui_none, &custom);
644         if (split[0] != '\0') {
645             /* Used not to do this, but there are several legal names */
646             /*  for some slots and people get unhappy (rightly) if we */
647             /*  use the wrong one */
648             enc_name = copy(split);
649             any = TRUE;
650         }
651 
652         if (enc != -1 && enc_arr->len < 256) {
653             // We have a valid encoding within the first 256 entries
654             has_1byte = TRUE;
655         }
656 
657         // Append entry to our arrays
658         g_array_append_val(enc_arr, enc);
659         g_array_append_val(names_arr, enc_name);
660     }
661 
662     if (enc_arr->len > 0) {
663         // If we have mappings, we make an encoding.
664         char *tmp_name = ff_ask_string(_("Encoding name"), "GlyphOrderAndAliasDB", _("Please name this encoding"));
665         if (tmp_name != NULL) {
666             if (tmp_name[0] == '\0') {
667                 // Encodings must be named.
668                 free(tmp_name);
669                 tmp_name = NULL;
670             } else {
671                 item = calloc(1, sizeof(Encoding));
672                 item->enc_name = tmp_name;
673                 // We pad the map in accordance with existing code in FindOrMakeEncoding and elsewhere.
674                 // Nobody knows why.
675                 item->char_cnt = (enc_arr->len < 256) ? 256 : enc_arr->len;
676                 item->unicode = malloc(item->char_cnt * sizeof(int32));
677                 memcpy(item->unicode, enc_arr->data, enc_arr->len * sizeof(int32));
678                 if (item->char_cnt > enc_arr->len) {
679                     // Pad the unfilled entries with -1
680                     memset(item->unicode + enc_arr->len, -1, sizeof(int32) * (enc_arr->len - item->char_cnt));
681                 }
682                 if (any) {
683                     item->psnames = calloc(item->char_cnt, sizeof(char *));
684                     memcpy(item->psnames, names_arr->data, names_arr->len * sizeof(char *));
685                 }
686 
687                 item->is_custom = TRUE;
688                 item->has_1byte = has_1byte;
689                 if (enc_arr->len < 256) {
690                     item->only_1byte = TRUE;
691                 } else {
692                     item->has_2byte = TRUE;
693                 }
694             }
695         }
696     }
697 
698     g_array_free(enc_arr, TRUE);
699     g_array_free(names_arr, TRUE);
700     return item;
701 }
702 
RemoveMultiples(Encoding * item)703 void RemoveMultiples(Encoding *item) {
704     Encoding *test;
705 
706     for ( test=enclist; test!=NULL; test = test->next ) {
707 	if ( strcmp(test->enc_name,item->enc_name)==0 )
708     break;
709     }
710     if ( test!=NULL )
711 	DeleteEncoding(test);
712 }
713 
ParseEncodingFile(char * filename,char * encodingname)714 char *ParseEncodingFile(char *filename, char *encodingname) {
715     FILE *file;
716     char *orig = filename;
717     Encoding *head, *item, *prev, *next;
718     char *buf, *name;
719     int i,ch;
720 
721     if ( filename==NULL ) filename = getPfaEditEncodings();
722     file = fopen(filename,"r");
723     if ( file==NULL ) {
724 	if ( orig!=NULL )
725 	    ff_post_error(_("Couldn't open file"), _("Couldn't open file %.200s"), orig);
726 return( NULL );
727     }
728     ch = getc(file);
729     if ( ch==EOF ) {
730 	fclose(file);
731 return( NULL );
732     }
733 
734     /* Here we detect file format and decide which format
735        parsing routine to actually use.
736     */
737     ungetc(ch, file);
738 
739 
740     if(strlen(filename) >= 20
741        && !strcmp(filename + strlen(filename) - 20, "GlyphOrderAndAliasDB")){
742         head = ParseGlyphOrderAndAliasDB(file);
743     } else if (ch=='#' || ch=='0') {
744         head = ParseConsortiumEncodingFile(file);
745         if(encodingname)
746             head->enc_name = copy(encodingname);
747     } else {
748         head = PSSlurpEncodings(file);
749     }
750     fclose(file);
751     if ( head==NULL ) {
752 	ff_post_error(_("Bad encoding file format"),_("Bad encoding file format") );
753 	return( NULL );
754     }
755 
756     for ( i=0, prev=NULL, item=head; item!=NULL; prev = item, item=next, ++i ) {
757 	next = item->next;
758 	if ( item->enc_name==NULL ) {
759 	    if ( no_windowing_ui ) {
760 		ff_post_error(_("Bad encoding file format"),_("This file contains an unnamed encoding, which cannot be named in a script"));
761                 EncodingFree(head);
762 		return( NULL );
763 	    }
764 	    if ( item==head && item->next==NULL )
765 		buf = strdup(_( "Please name this encoding" ));
766 	    else
767 		buf = smprintf(_( "Please name encoding %d in this file" ), i );
768 
769 	    name = ff_ask_string( buf, NULL, buf );
770 
771 	    if ( name!=NULL ) {
772 		item->enc_name = copy(name);
773 		free(name);
774 	    } else {
775 		if ( prev==NULL )
776 		    head = item->next;
777 		else
778 		    prev->next = item->next;
779 		EncodingFree(item);
780 	    }
781 	}
782     }
783     for ( item=head; item!=NULL; item=item->next )
784 	RemoveMultiples(item);
785 
786     if ( enclist == NULL )
787 	enclist = head;
788     else {
789 	for ( item=enclist; item->next!=NULL; item=item->next );
790 	item->next = head;
791     }
792 return( copy( head->enc_name ) );
793 }
794 
LoadPfaEditEncodings(void)795 void LoadPfaEditEncodings(void) {
796     free(ParseEncodingFile(NULL, NULL));
797 }
798 
DumpPfaEditEncodings(void)799 void DumpPfaEditEncodings(void) {
800     FILE *file;
801     Encoding *item;
802     int i;
803     char buffer[80];
804 
805     for ( item=enclist; item!=NULL && item->builtin; item=item->next );
806     if ( item==NULL ) {
807 	unlink(getPfaEditEncodings());
808 return;
809     }
810 
811     file = fopen( getPfaEditEncodings(), "w");
812     if ( file==NULL ) {
813 	LogError( _("couldn't write encodings file\n") );
814 return;
815     }
816 
817     for ( item=enclist; item!=NULL; item = item->next ) if ( !item->builtin && item->tounicode_func==NULL ) {
818 	fprintf( file, "/%s [\n", item->enc_name );
819 	if ( item->psnames==NULL )
820 	    fprintf( file, "%% Use codepoints.\n" );
821 	for ( i=0; i<item->char_cnt; ++i ) {
822 	    if ( item->psnames!=NULL && item->psnames[i]!=NULL )
823 		fprintf( file, " /%s", item->psnames[i]);
824 	    else if ( item->unicode[i]<' ' || (item->unicode[i]>=0x7f && item->unicode[i]<0xa0))
825 		fprintf( file, " /.notdef" );
826 	    else
827 		fprintf( file, " /%s", StdGlyphName(buffer,item->unicode[i],ui_none,(NameList *) -1));
828 	    if ( (i&0xf)==0 )
829 		fprintf( file, "\t\t%% 0x%02x\n", i );
830 	    else
831 		putc('\n',file);
832 	}
833 	fprintf( file, "] def\n\n" );
834     }
835     fclose(file);
836 }
837 
838 /* ************************************************************************** */
839 /* ****************************** CID Encodings ***************************** */
840 /* ************************************************************************** */
841 struct cidmap *cidmaps = NULL;
842 
CIDFromName(char * name,SplineFont * cidmaster)843 int CIDFromName(char *name,SplineFont *cidmaster) {
844     /* We've had various conventions for encoding a cid inside a name */
845     /* I'm primarily interested in this when the name is something like */
846     /*  Japan1.504.vert */
847     /* which tells me that the current glyph is the rotated version of */
848     /*  cid 504 */
849     /* Other convention "cid-504.vert" */
850     int len = strlen( cidmaster->ordering );
851     int cid;
852     char *end;
853 
854     if ( strncmp(name,cidmaster->ordering,len)==0 ) {
855 	if ( name[len]=='.' ) ++len;
856     } else if ( strncmp(name,"cid-",4)==0 ) {
857 	len = 4;
858     } else
859 	len = 0;
860     cid = strtol(name+len,&end,10);
861     if ( end==name+len )
862 return( -1 );
863     if ( *end!='.' && *end!='\0' )
864 return( -1 );
865 
866 return ( cid );
867 }
868 
CID2Uni(struct cidmap * map,int cid)869 int CID2Uni(struct cidmap *map,int cid) {
870     unsigned int uni;
871 
872     if ( map==NULL )
873 return( -1 );
874     else if ( cid==0 )
875 return( 0 );
876     else if ( cid<map->namemax && map->unicode[cid]!=0 )
877 return( map->unicode[cid] );
878     else if ( cid<map->namemax && map->name[cid]!=NULL ) {
879 	if ( sscanf(map->name[cid],"uni%x", &uni )==1 )
880 return( uni );
881     }
882 
883 return( -1 );
884 }
885 
CID2NameUni(struct cidmap * map,int cid,char * buffer,int len)886 int CID2NameUni(struct cidmap *map,int cid, char *buffer, int len) {
887     int enc = -1;
888     const char *temp;
889 
890     if ( map==NULL )
891 	snprintf(buffer,len,"cid-%d", cid);
892     else if ( cid<map->namemax && map->name[cid]!=NULL ) {
893 	strncpy(buffer,map->name[cid],len);
894 	buffer[len-1] = '\0';
895     } else if ( cid==0 )
896 	strcpy(buffer,".notdef");
897     else if ( cid<map->namemax && map->unicode[cid]!=0 ) {
898 	if ( map->unicode==NULL || map->namemax==0 )
899 	    enc = 0;
900 	else
901 	    enc = map->unicode[cid];
902 	temp = StdGlyphName(buffer,enc,ui_none,(NameList *) -1);
903 	if ( temp!=buffer )
904 	    strcpy(buffer,temp);
905     } else
906 	snprintf(buffer,len,"%s.%d", map->ordering, cid);
907 return( enc );
908 }
909 
NameUni2CID(struct cidmap * map,int uni,const char * name)910 int NameUni2CID(struct cidmap *map, int uni, const char *name) {
911     int i;
912     struct cidaltuni *alts;
913 
914     if ( map==NULL )
915 		return( -1 );
916     if ( uni!=-1 ) {
917 		// Search for a matching code.
918 		for ( i=0; i<map->namemax; ++i )
919 		    if ( map->unicode[i]==(uint32)uni )
920 				return( i );
921 		for ( alts=map->alts; alts!=NULL; alts=alts->next )
922 		    if ( alts->uni==uni )
923 				return( alts->cid );
924     } else {
925 	// Search for a matching name.
926 	if ( name!=NULL )
927 	    for ( i=0; i<map->namemax; ++i )
928 		if ( map->name[i]!=NULL && strcmp(map->name[i],name)==0 )
929 		    return( i );
930     }
931 	return( -1 );
932 }
933 
CIDSetAltUnis(struct cidmap * map,int cid)934 struct altuni *CIDSetAltUnis(struct cidmap *map,int cid) {
935     /* Some CIDs are mapped to several unicode code points, damn it */
936     struct altuni *sofar = NULL, *alt;
937     struct cidaltuni *alts;
938 
939     for ( alts=map->alts; alts!=NULL; alts=alts->next ) {
940 	if ( alts->cid==cid ) {
941 	    alt = chunkalloc(sizeof(struct altuni));
942 	    alt->next = sofar;
943 	    sofar = alt;
944 	    alt->unienc = alts->uni;
945 	    alt->vs = -1;
946 	}
947     }
948 return( sofar );
949 }
950 
MaxCID(struct cidmap * map)951 int MaxCID(struct cidmap *map) {
952 return( map->cidmax );
953 }
954 
SearchDirForCidMap(const char * dir,char * registry,char * ordering,int supplement,char ** maybefile)955 static char *SearchDirForCidMap(const char *dir,char *registry,char *ordering,
956 	int supplement,char **maybefile) {
957     char maybe[FILENAME_MAX+1];
958     struct dirent *ent;
959     DIR *d;
960     int len, rlen = strlen(registry), olen=strlen(ordering);
961     char *pt, *end, *ret;
962     int test, best = -1;
963 
964     if ( dir==NULL )
965 return( NULL );
966 
967     if ( *maybefile!=NULL ) {
968 	char *pt = strrchr(*maybefile,'.');
969 	while ( pt>*maybefile && isdigit(pt[-1]))
970 	    --pt;
971 	best = strtol(pt,NULL,10);
972     }
973 
974     d = opendir(dir);
975     if ( d==NULL )
976 return( NULL );
977     while ( (ent = readdir(d))!=NULL ) {
978 	if ( (len = strlen(ent->d_name))<8 )
979     continue;
980 	if ( strcmp(ent->d_name+len-7,".cidmap")!=0 )
981     continue;
982 	if ( strncmp(ent->d_name,registry,rlen)!=0 || ent->d_name[rlen]!='-' )
983     continue;
984 	pt = ent->d_name+rlen+1;
985 	if ( strncmp(pt,ordering,olen)!=0 || pt[olen]!='-' )
986     continue;
987 	pt += olen+1;
988 	if ( !isdigit(*pt))
989     continue;
990 	test = strtol(pt,&end,10);
991 	if ( *end!='.' )
992     continue;
993 	if ( test>=supplement ) {
994 	    ret = malloc(strlen(dir)+1+len+1);
995 	    strcpy(ret,dir);
996 	    strcat(ret,"/");
997 	    strcat(ret,ent->d_name);
998 	    closedir(d);
999 return( ret );
1000 	} else if ( test>best ) {
1001 	    best = test;
1002 	    strcpy(maybe,ent->d_name);
1003 	}
1004     }
1005     closedir(d);
1006     if ( best>-1 ) {
1007 	ret = malloc(strlen(dir)+1+strlen(maybe)+1);
1008 	strcpy(ret,dir);
1009 	strcat(ret,"/");
1010 	strcat(ret,maybe);
1011 	*maybefile = ret;
1012     }
1013 return( NULL );
1014 }
1015 
MakeDummyMap(char * registry,char * ordering,int supplement)1016 static struct cidmap *MakeDummyMap(char *registry,char *ordering,int supplement) {
1017     struct cidmap *ret = malloc(sizeof(struct cidmap));
1018 
1019     ret->registry = copy(registry);
1020     ret->ordering = copy(ordering);
1021     ret->supplement = ret->maxsupple = supplement;
1022     ret->cidmax = ret->namemax = 0;
1023     ret->unicode = NULL; ret->name = NULL;
1024     ret->alts = NULL;
1025     ret->next = cidmaps;
1026     cidmaps = ret;
1027 return( ret );
1028 }
1029 
LoadMapFromFile(char * file,char * registry,char * ordering,int supplement)1030 struct cidmap *LoadMapFromFile(char *file,char *registry,char *ordering,
1031 	int supplement) {
1032     struct cidmap *ret = malloc(sizeof(struct cidmap));
1033     char *pt = strrchr(file,'.');
1034     FILE *f;
1035     int cid1, cid2, uni, cnt, i, ch;
1036     char name[100];
1037 
1038     while ( pt>file && isdigit(pt[-1]))
1039 	--pt;
1040     ret->supplement = ret->maxsupple = strtol(pt,NULL,10);
1041     if ( supplement>ret->maxsupple )
1042 	ret->maxsupple = supplement;
1043     ret->registry = copy(registry);
1044     ret->ordering = copy(ordering);
1045     ret->alts = NULL;
1046     ret->cidmax = ret->namemax = 0;
1047     ret->unicode = NULL; ret->name = NULL;
1048     ret->next = cidmaps;
1049     cidmaps = ret;
1050 
1051     f = fopen( file,"r" );
1052     if ( f==NULL ) {
1053 	ff_post_error(_("Missing cidmap file"),_("Couldn't open cidmap file: %s"), file );
1054     } else if ( fscanf( f, "%d %d", &ret->cidmax, &ret->namemax )!=2 ) {
1055 	ff_post_error(_("Bad cidmap file"),_("%s is not a cidmap file, please download\nhttp://fontforge.sourceforge.net/cidmaps.tgz"), file );
1056 	fprintf( stderr, _("%s is not a cidmap file, please download\nhttp://fontforge.sourceforge.net/cidmaps.tgz"), file );
1057 	fclose(f);
1058     } else {
1059 	ret->unicode = calloc(ret->namemax+1,sizeof(uint32));
1060 	ret->name = calloc(ret->namemax+1,sizeof(char *));
1061 	while ( 1 ) {
1062 	    cnt=fscanf( f, "%d..%d %x", &cid1, &cid2, (unsigned *) &uni );
1063 	    if ( cnt<=0 )
1064 	break;
1065 	    if ( cid1>ret->namemax )
1066 	continue;
1067 	    if ( cnt==3 ) {
1068 		if ( cid2>ret->namemax ) cid2 = ret->namemax;
1069 		for ( i=cid1; i<=cid2; ++i )
1070 		    ret->unicode[i] = uni++;
1071 	    } else if ( cnt==1 ) {
1072 		if ( fscanf(f,"%x", (unsigned *) &uni )==1 ) {
1073 		    ret->unicode[cid1] = uni;
1074 		    ch = getc(f);
1075 		    while ( ch==',' ) {
1076 			if ( fscanf(f,"%x", (unsigned *) &uni )==1 ) {
1077 			    struct cidaltuni *alt = chunkalloc(sizeof(struct cidaltuni));
1078 			    alt->next = ret->alts;
1079 			    ret->alts = alt;
1080 			    alt->uni = uni;
1081 			    alt->cid = cid1;
1082 			}
1083 			ch = getc(f);
1084 		    }
1085 		    ungetc(ch,f);
1086 		} else if ( fscanf(f," /%s", name )==1 )
1087 		    ret->name[cid1] = copy(name);
1088 	    }
1089 	}
1090 	fclose(f);
1091     }
1092 return( ret );
1093 }
1094 
FindCidMap(char * registry,char * ordering,int supplement,SplineFont * sf)1095 struct cidmap *FindCidMap(char *registry,char *ordering,int supplement,SplineFont *sf) {
1096     struct cidmap *map, *maybe=NULL;
1097     char *file;
1098     char *maybefile=NULL;
1099     int maybe_sup = -1;
1100     const char *buts[3], *buts2[3], *buts3[3];
1101     char *buf = NULL;
1102     int ret;
1103 
1104     if ( sf!=NULL && sf->cidmaster ) sf = sf->cidmaster;
1105     if ( sf!=NULL && sf->loading_cid_map )
1106 return( NULL );
1107 
1108     for ( map = cidmaps; map!=NULL; map = map->next ) {
1109 	if ( strcmp(map->registry,registry)==0 && strcmp(map->ordering,ordering)==0 ) {
1110 	    if ( supplement<=map->supplement )
1111 return( map );
1112 	    else if ( maybe==NULL || maybe->supplement<map->supplement )
1113 		maybe = map;
1114 	}
1115     }
1116     if ( maybe!=NULL && supplement<=maybe->maxsupple )
1117 return( maybe );	/* User has said it's ok to use maybe at this supplement level */
1118 
1119     file = SearchDirForCidMap(".",registry,ordering,supplement,&maybefile);
1120     if ( file==NULL )
1121 	file = SearchDirForCidMap(getFontForgeShareDir(),registry,ordering,supplement,&maybefile);
1122 
1123     if ( file==NULL && (maybe!=NULL || maybefile!=NULL)) {
1124 	if ( maybefile!=NULL ) {
1125 	    char *pt = strrchr(maybefile,'.');
1126 	    while ( pt>maybefile && isdigit(pt[-1]))
1127 		--pt;
1128 	    maybe_sup = strtol(pt,NULL,10);
1129 	    if ( maybe!=NULL && maybe->supplement >= maybe_sup ) {
1130 		free(maybefile); maybefile = NULL;
1131 		maybe_sup = maybe->supplement;
1132 	    } else
1133 		maybe = NULL;
1134 	}
1135 	if ( maybe!=NULL )
1136 	    maybe_sup = maybe->supplement;
1137 	if ( sf!=NULL ) sf->loading_cid_map = true;
1138 	buts[0] = _("_Use It"); buts[1] = _("_Search"); buts[2] = NULL;
1139 	ret = ff_ask(_("Use CID Map"),(const char **) buts,0,1,_("This font is based on the charset %1$.20s-%2$.20s-%3$d, but the best I've been able to find is %1$.20s-%2$.20s-%4$d.\nShall I use that or let you search?"),
1140 		registry,ordering,supplement,maybe_sup);
1141 	if ( sf!=NULL ) sf->loading_cid_map = false;
1142 	if ( ret==0 ) {
1143 	    if ( maybe!=NULL ) {
1144 		maybe->maxsupple = supplement;
1145 return( maybe );
1146 	    } else {
1147 		file = maybefile;
1148 		maybefile = NULL;
1149 	    }
1150 	}
1151     }
1152 
1153     if ( file==NULL ) {
1154 	char *uret;
1155 	buf = smprintf( "%s-%s-*.cidmap", registry, ordering );
1156 	if ( maybe==NULL && maybefile==NULL ) {
1157 	    buts3[0] = _("_Browse"); buts3[1] = _("_Give Up"); buts3[2] = NULL;
1158 	    ret = ff_ask(_("No cidmap file..."),(const char **)buts3,0,1,_("FontForge was unable to find a cidmap file for this font. It is not essential to have one, but some things will work better if you do. If you have not done so you might want to download the cidmaps from:\n   http://FontForge.sourceforge.net/cidmaps.tgz\nand then gunzip and untar them and move them to:\n  %.80s\n\nWould you like to search your local disk for an appropriate file?"),
1159 		    getFontForgeShareDir()==NULL?"/usr/share/fontforge":getFontForgeShareDir()
1160 		    );
1161 	    if ( ret==1 || no_windowing_ui )
1162 		buf = NULL;
1163 	}
1164 	uret = NULL;
1165 	if ( ( buf != NULL ) && !no_windowing_ui ) {
1166 	    if ( sf!=NULL ) sf->loading_cid_map = true;
1167 	    uret = ff_open_filename(_("Find a cidmap file..."), NULL, (char *) buf );
1168 	    if ( sf!=NULL ) sf->loading_cid_map = false;
1169 	}
1170 	if ( uret==NULL ) {
1171 	    buts2[0] = "_Use It"; buts2[1] = "_Search"; buts2[2] = NULL;
1172 	    if ( maybe==NULL && maybefile==NULL )
1173 		/* No luck */;
1174 	    else if ( no_windowing_ui && maybe!=NULL ) {
1175 		maybe->maxsupple = supplement;
1176 return( maybe );
1177 	    } else if ( no_windowing_ui ) {
1178 		file = maybefile;
1179 		maybefile = NULL;
1180 	    } else if ( ff_ask(_("Use CID Map"),(const char **)buts2,0,1,_("Are you sure you don't want to use the cidmap I found?"))==0 ) {
1181 		if ( maybe!=NULL ) {
1182 		    maybe->maxsupple = supplement;
1183 return( maybe );
1184 		} else {
1185 		    file = maybefile;
1186 		    maybefile = NULL;
1187 		}
1188 	    }
1189 	} else {
1190 	    file = utf82def_copy(uret);
1191 	    free(uret);
1192 	}
1193     }
1194 
1195     free(maybefile);
1196     if ( file!=NULL ) {
1197 	map = LoadMapFromFile(file,registry,ordering,supplement);
1198 	free(file);
1199 return( map );
1200     }
1201 
1202 return( MakeDummyMap(registry,ordering,supplement));
1203 }
1204 
SFApplyOrdering(SplineFont * sf,int glyphcnt)1205 static void SFApplyOrdering(SplineFont *sf, int glyphcnt) {
1206     SplineChar **glyphs, *sc;
1207     int i;
1208     RefChar *refs, *rnext, *rprev;
1209     SplineSet *new, *spl;
1210 
1211     /* Remove references to characters which aren't in the new map (if any) */
1212     /* Don't need to fix up dependencies, because we throw the char away */
1213     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1214 	for ( rprev = NULL, refs=sc->layers[ly_fore].refs; refs!=NULL; refs=rnext ) {
1215 	    rnext = refs->next;
1216 	    if ( refs->sc->orig_pos==-1 ) {
1217 		new = refs->layers[0].splines;
1218 		if ( new!=NULL ) {
1219 		    for ( spl = new; spl->next!=NULL; spl = spl->next );
1220 		    spl->next = sc->layers[ly_fore].splines;
1221 		    sc->layers[ly_fore].splines = new;
1222 		}
1223 		refs->layers[0].splines=NULL;
1224 		RefCharFree(refs);
1225 		if ( rprev==NULL )
1226 		    sc->layers[ly_fore].refs = rnext;
1227 		else
1228 		    rprev->next = rnext;
1229 	    } else
1230 		rprev = refs;
1231 	}
1232     }
1233 
1234     glyphs = calloc(glyphcnt+1,sizeof(SplineChar *));
1235     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1236 	if ( sc->orig_pos==-1 )
1237 	    SplineCharFree(sc);
1238 	else
1239 	    glyphs[sc->orig_pos] = sc;
1240     }
1241 
1242     free(sf->glyphs);
1243     sf->glyphcnt = sf->glyphmax = glyphcnt;
1244     sf->glyphs = glyphs;
1245 }
1246 
1247 /* Convert a normal font to a cid font, rearranging glyphs into cid order */
SFEncodeToMap(SplineFont * sf,struct cidmap * map)1248 void SFEncodeToMap(SplineFont *sf,struct cidmap *map) {
1249     SplineChar *sc;
1250     int i,max=0, anyextras=0;
1251 
1252     for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sc = sf->glyphs[i]) ) {
1253 	sc->orig_pos = NameUni2CID(map,sc->unicodeenc,sc->name);
1254 	if ( sc->orig_pos>max ) max = sc->orig_pos;
1255 	else if ( sc->orig_pos==-1 ) ++anyextras;
1256     } else if ( sc!=NULL )
1257 	sc->orig_pos = -1;
1258 
1259     if ( anyextras ) {
1260 	char *buttons[3];
1261 	buttons[0] = _("_Delete"); buttons[1] = _("_Add"); buttons[2] = NULL;
1262 	if ( ff_ask(_("Extraneous glyphs"),(const char **) buttons,0,1,_("The current encoding contains glyphs which I cannot map to CIDs.\nShould I delete them or add them to the end (where they may conflict with future ros definitions)?"))==1 ) {
1263 	    if ( map!=NULL && max<map->cidmax ) max = map->cidmax;
1264 	    anyextras = 0;
1265 	    for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sc = sf->glyphs[i]) ) {
1266 		if ( sc->orig_pos == -1 ) sc->orig_pos = max + anyextras++;
1267 	    }
1268 	    max += anyextras;
1269 	}
1270     }
1271     SFApplyOrdering(sf, max+1);
1272 }
1273 
1274 enum cmaptype { cmt_out=-1, cmt_coderange, cmt_notdefs, cmt_cid, cmt_max };
1275 struct coderange { uint32 first, last, cid; };
1276 struct cmap {
1277     struct {
1278 	int n;
1279 	struct coderange *ranges;
1280     } groups[cmt_max];
1281     char *registry;
1282     char *ordering;
1283     int supplement;
1284     struct remap *remap;
1285     int total;
1286 };
1287 
cmapfree(struct cmap * cmap)1288 static void cmapfree(struct cmap *cmap) {
1289     free(cmap->registry);
1290     free(cmap->ordering);
1291     free(cmap->groups[cmt_coderange].ranges);
1292     free(cmap->groups[cmt_notdefs].ranges);
1293     free(cmap->groups[cmt_cid].ranges);
1294     free(cmap->remap);
1295     free(cmap);
1296 }
1297 
ExtendArray(struct coderange * ranges,int * n,int val)1298 static struct coderange *ExtendArray(struct coderange *ranges,int *n, int val) {
1299     if ( *n == 0 )
1300 	ranges = calloc(val,sizeof(struct coderange));
1301     else {
1302 	ranges = realloc(ranges,(*n+val)*sizeof(struct coderange));
1303 	memset(ranges+*n,0,val*sizeof(struct coderange));
1304     }
1305     *n += val;
1306 return( ranges );
1307 }
1308 
readpsstr(char * str)1309 static char *readpsstr(char *str) {
1310     char *eos;
1311 
1312     while ( isspace(*str)) ++str;
1313     if ( *str=='(' ) ++str;
1314     /* PostScript strings can be more complicated than this (hex, nested parens, Enc85...) */
1315     /*  but none of those should show up here */
1316     for ( eos = str; *eos!=')' && *eos!='\0'; ++eos );
1317 return( copyn(str,eos-str));
1318 }
1319 
ParseCMap(char * filename)1320 static struct cmap *ParseCMap(char *filename) {
1321     char buf2[200];
1322     FILE *file;
1323     struct cmap *cmap;
1324     char *end, *pt;
1325     int val, pos;
1326     enum cmaptype in;
1327     int in_is_single; // We set this if we are to parse cidchars into cidranges.
1328     static const char *bcsr = "begincodespacerange", *bndr = "beginnotdefrange", *bcr = "begincidrange", *bcc = "begincidchar";
1329     static const char *reg = "/Registry", *ord = "/Ordering", *sup="/Supplement";
1330 
1331     file = fopen(filename,"r");
1332     if ( file==NULL )
1333 return( NULL );
1334 
1335     cmap = calloc(1,sizeof(struct cmap));
1336     in = cmt_out;
1337     while ( fgets(buf2,sizeof(buf2),file)!=NULL ) {
1338 	for ( pt=buf2; isspace(*pt); ++pt);
1339 	if ( in==cmt_out ) {
1340 	    if ( *pt=='/' ) {
1341 		if ( strncmp(pt,reg,strlen(reg))==0 )
1342 		    cmap->registry = readpsstr(pt+strlen(reg));
1343 		else if ( strncmp(pt,ord,strlen(ord))==0 )
1344 		    cmap->ordering = readpsstr(pt+strlen(ord));
1345 		else if ( strncmp(pt,sup,strlen(sup))==0 ) {
1346 		    for ( pt += strlen(sup); isspace(*pt); ++pt );
1347 		    cmap->supplement = strtol(pt,NULL,10);
1348 		}
1349     continue;
1350 	    } else if ( !isdigit(*pt) )
1351     continue;
1352 	    val = strtol(pt,&end,10);
1353 	    while ( isspace(*end)) ++end;
1354 	    in_is_single = 0;
1355 	    if ( strncmp(end,bcsr,strlen(bcsr))==0 ) {
1356 		in = cmt_coderange;
1357 	    } else if ( strncmp(end,bndr,strlen(bndr))==0 ) {
1358 		in = cmt_notdefs;
1359 	    } else if ( strncmp(end,bcr,strlen(bcr))==0 ) {
1360 		in = cmt_cid;
1361 	    } else if ( strncmp(end,bcc,strlen(bcc))==0 ) {
1362 		in = cmt_cid;
1363 		in_is_single = 1;
1364 	    }
1365 	    if ( in!=cmt_out ) {
1366 		pos = cmap->groups[in].n;
1367 		cmap->groups[in].ranges = ExtendArray(cmap->groups[in].ranges,&cmap->groups[in].n,val);
1368 	    }
1369 	} else if ( strncmp(pt,"end",3)== 0 )
1370 	    in = cmt_out;
1371     else if (pos >= cmap->groups[in].n) {
1372         LogError(_("cidmap entry out of bounds: %s"), buf2);
1373     }
1374 	else {
1375 	    // Read the first bracketed code.
1376 	    if ( *pt!='<' )
1377 	continue;
1378 	    cmap->groups[in].ranges[pos].first = strtoul(pt+1,&end,16);
1379 	    if ( *end=='>' ) ++end;
1380 	    while ( isspace(*end)) ++end;
1381 	    if (in_is_single) {
1382 	      cmap->groups[in].ranges[pos].last = cmap->groups[in].ranges[pos].first;
1383 	    } else {
1384 	      // Read the second bracketed code.
1385 	      if ( *end=='<' ) ++end;
1386 	      cmap->groups[in].ranges[pos].last = strtoul(end,&end,16);
1387 	      if ( *end=='>' ) ++end;
1388 	    }
1389 	    if ( in!=cmt_coderange ) {
1390 		while ( isspace(*end)) ++end;
1391 	        // Read the unbracketed argument.
1392 		cmap->groups[in].ranges[pos].cid = strtol(end,&end,10);
1393 	    }
1394 	    ++pos;
1395 	}
1396     }
1397     fclose(file);
1398 return( cmap );
1399 }
1400 
CompressCMap(struct cmap * cmap)1401 static void CompressCMap(struct cmap *cmap) {
1402     int32 i,j,k, pos, base;
1403     uint32 min, oldmax;
1404     /* we can't really deal with three and four byte encodings */
1405     /*  so if we get one arrange for the sf itself to do a remap */
1406 
1407     cmap->total = 0x10000;
1408     for ( i=0; i<cmap->groups[cmt_coderange].n; ++i )
1409 	if ( cmap->groups[cmt_coderange].ranges[i].last>0xfffff )
1410     break;
1411     if ( i==cmap->groups[cmt_coderange].n )	/* No need to remap */
1412 return;
1413 
1414     cmap->remap = calloc(cmap->groups[cmt_coderange].n+1,sizeof(struct remap));
1415     base = 0;
1416     for ( i=0; i<cmap->groups[cmt_coderange].n; ++i )
1417 	if ( cmap->groups[cmt_coderange].ranges[i].last<0xffff ) {
1418 	    base = 0x10000;
1419     break;
1420 	}
1421 
1422     pos=0;
1423     oldmax = base==0?0:0xffff;
1424     for ( i=0; i<cmap->groups[cmt_coderange].n; ++i ) {
1425 	min = 0xffffffff; k=-1;
1426 	for ( j=0; j<cmap->groups[cmt_coderange].n; ++j )
1427 	    if ( cmap->groups[cmt_coderange].ranges[j].first>oldmax &&
1428 		    cmap->groups[cmt_coderange].ranges[j].first<min ) {
1429 		min = cmap->groups[cmt_coderange].ranges[j].first;
1430 		k = j;
1431 	    }
1432 	if ( k==-1 )
1433     break;
1434 	cmap->remap[pos].firstenc = cmap->groups[cmt_coderange].ranges[k].first&~0xff;
1435 	cmap->remap[pos].lastenc = cmap->groups[cmt_coderange].ranges[k].last|0xff;
1436 	cmap->remap[pos].infont = base;
1437 	base += cmap->remap[pos].lastenc-cmap->remap[pos].firstenc+1;
1438 	oldmax = cmap->remap[pos].lastenc;
1439 	++pos;
1440     }
1441     cmap->remap[pos].infont = -1;	/* Marks end */
1442     cmap->total = base;
1443     /* so cmap->remap will map sf indeces into the encoding in the cmap */
1444 
1445     /* And now we want to change the groups[cmt_cid].ranges so that they will */
1446     /*  map into sf indeces rather than into the encoding of the cmap */
1447     for ( i=0; i<cmap->groups[cmt_cid].n; ++i ) {
1448 	for ( k=0; cmap->remap[k].infont!=-1; ++k )
1449 	    if ( cmap->groups[cmt_cid].ranges[i].first>=cmap->remap[k].firstenc &&
1450 		    cmap->groups[cmt_cid].ranges[i].first<=cmap->remap[k].lastenc )
1451 	break;
1452 	if ( cmap->remap[k].infont==-1 )
1453     continue;
1454 	cmap->groups[cmt_cid].ranges[i].first += cmap->remap[k].infont-cmap->remap[k].firstenc;
1455 	cmap->groups[cmt_cid].ranges[i].last += cmap->remap[k].infont-cmap->remap[k].firstenc;
1456     }
1457 }
1458 
CIDFlatten(SplineFont * cidmaster,SplineChar ** glyphs,int charcnt)1459 SplineFont *CIDFlatten(SplineFont *cidmaster,SplineChar **glyphs,int charcnt) {
1460     FontViewBase *fvs;
1461     SplineFont *new;
1462     char buffer[20];
1463     BDFFont *bdf;
1464     int j;
1465 
1466     if ( cidmaster==NULL )
1467 return(NULL);
1468     new = SplineFontEmpty();
1469     new->fontname = copy(cidmaster->fontname);
1470     new->fullname = copy(cidmaster->fullname);
1471     new->familyname = copy(cidmaster->familyname);
1472     new->weight = copy(cidmaster->weight);
1473     new->copyright = copy(cidmaster->copyright);
1474     sprintf(buffer,"%g", (double)cidmaster->cidversion);
1475     new->version = copy(buffer);
1476     new->italicangle = cidmaster->italicangle;
1477     new->upos = cidmaster->upos;
1478     new->uwidth = cidmaster->uwidth;
1479     new->ascent = cidmaster->ascent;
1480     new->descent = cidmaster->descent;
1481     new->changed = new->changed_since_autosave = true;
1482     new->display_antialias = cidmaster->display_antialias;
1483     new->hasvmetrics = cidmaster->hasvmetrics;
1484     new->fv = cidmaster->fv;
1485     /* Don't copy the grid splines, there won't be anything meaningfull at top level */
1486     /*  and won't know which font to copy from below */
1487     new->bitmaps = cidmaster->bitmaps;		/* should already be flattened */
1488     cidmaster->bitmaps = NULL;			/* don't free 'em */
1489     for ( bdf=new->bitmaps; bdf!=NULL; bdf=bdf->next )
1490 	bdf->sf = new;
1491     new->gpos_lookups = cidmaster->gpos_lookups;
1492     cidmaster->gpos_lookups = NULL;
1493     new->gsub_lookups = cidmaster->gsub_lookups;
1494     cidmaster->gsub_lookups = NULL;
1495     new->kerns = cidmaster->kerns; new->vkerns = cidmaster->vkerns;
1496     cidmaster->kerns = cidmaster->vkerns = NULL;
1497     new->names = cidmaster->names; cidmaster->names = NULL;
1498     new->horiz_base = cidmaster->horiz_base; cidmaster->horiz_base = NULL;
1499     new->vert_base = cidmaster->vert_base; cidmaster->vert_base = NULL;
1500     new->pfminfo = cidmaster->pfminfo;
1501     new->texdata = cidmaster->texdata;
1502     new->possub = cidmaster->possub; cidmaster->possub = NULL;
1503     new->sm = cidmaster->sm; cidmaster->sm = NULL;
1504     new->features = cidmaster->features; cidmaster->features = NULL;
1505     new->macstyle = cidmaster->macstyle;
1506     new->origname = copy( cidmaster->origname );
1507     new->display_size = cidmaster->display_size;
1508     /* Don't copy private */
1509     new->xuid = copy(cidmaster->xuid);
1510     new->glyphs = glyphs;
1511     new->glyphcnt = new->glyphmax = charcnt;
1512     for ( j=0; j<charcnt; ++j ) if ( glyphs[j]!=NULL ) {
1513 	glyphs[j]->parent = new;
1514 	glyphs[j]->orig_pos = j;
1515     }
1516     for ( fvs=new->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1517 	fvs->cidmaster = NULL;
1518 	if ( fvs->sf->glyphcnt!=new->glyphcnt ) {
1519 	    free(fvs->selected);
1520 	    fvs->selected = calloc(new->glyphcnt,sizeof(uint8));
1521 	    if ( fvs->map->encmax < new->glyphcnt )
1522 		fvs->map->map = realloc(fvs->map->map,(fvs->map->encmax = new->glyphcnt)*sizeof(int32));
1523 	    fvs->map->enccount = new->glyphcnt;
1524 	    if ( fvs->map->backmax < new->glyphcnt )
1525 		fvs->map->backmap = realloc(fvs->map->backmap,(fvs->map->backmax = new->glyphcnt)*sizeof(int32));
1526 	    for ( j=0; j<new->glyphcnt; ++j )
1527 		fvs->map->map[j] = fvs->map->backmap[j] = j;
1528 	}
1529 	fvs->sf = new;
1530 	FVSetTitle(fvs);
1531     }
1532     FontViewReformatAll(new);
1533     SplineFontFree(cidmaster);
1534 return( new );
1535 }
1536 
SFFlatten(SplineFont ** cidmasterpp)1537 void SFFlatten(SplineFont **cidmasterpp) {
1538     SplineChar **glyphs;
1539     SplineFont *cidmaster = *cidmasterpp;
1540     int i,j,max;
1541 
1542     if ( cidmaster==NULL )
1543 	return;
1544 
1545     if ( cidmaster->cidmaster!=NULL ) {
1546 	cidmaster = cidmaster->cidmaster;
1547 	cidmasterpp = &cidmaster;
1548     }
1549     /* This doesn't change the ordering, so no need for special tricks to */
1550     /*  preserve scrolling location. */
1551     for ( i=max=0; i<cidmaster->subfontcnt; ++i ) {
1552 	if ( max<cidmaster->subfonts[i]->glyphcnt )
1553 	    max = cidmaster->subfonts[i]->glyphcnt;
1554     }
1555     glyphs = calloc(max,sizeof(SplineChar *));
1556     for ( j=0; j<max; ++j ) {
1557 	for ( i=0; i<cidmaster->subfontcnt; ++i ) {
1558 	    if ( j<cidmaster->subfonts[i]->glyphcnt && cidmaster->subfonts[i]->glyphs[j]!=NULL ) {
1559 		glyphs[j] = cidmaster->subfonts[i]->glyphs[j];
1560 		cidmaster->subfonts[i]->glyphs[j] = NULL;
1561 	break;
1562 	    }
1563 	}
1564     }
1565     *cidmasterpp = CIDFlatten(cidmaster,glyphs,max);
1566 }
1567 
SFFlattenByCMap(SplineFont ** sfpp,char * cmapname)1568 int SFFlattenByCMap(SplineFont **sfpp,char *cmapname) {
1569     struct cmap *cmap;
1570     int i,j,k,l,m, extras, max, curmax, warned;
1571     int found[4];
1572     SplineChar **glyphs = NULL, *sc;
1573     SplineFont *sf = *sfpp;
1574     FontViewBase *fvs;
1575 
1576     if ( sf->cidmaster!=NULL ) {
1577 	sf = sf->cidmaster;
1578 	sfpp = &sf;
1579     }
1580     if ( sf->subfontcnt==0 ) {
1581 	ff_post_error(_("Not a CID-keyed font"),_("Not a CID-keyed font"));
1582 return( false );
1583     }
1584     if ( cmapname==NULL )
1585 return( false );
1586     cmap = ParseCMap(cmapname);
1587     if ( cmap==NULL )
1588 return( false );
1589     CompressCMap(cmap);
1590     max = 0;
1591     for ( i=0; i<cmap->groups[cmt_cid].n; ++i ) {
1592 	if ( max<cmap->groups[cmt_cid].ranges[i].last )
1593 	    max = cmap->groups[cmt_cid].ranges[i].last;
1594 	if ( cmap->groups[cmt_cid].ranges[i].last>0x100000 ) {
1595 	    ff_post_error(_("Encoding Too Large"),_("Encoding Too Large"));
1596 	    cmapfree(cmap);
1597 return( false );
1598 	}
1599     }
1600 
1601     curmax = 0;
1602     for ( k=0; k<sf->subfontcnt; ++k ) {
1603 	if ( curmax < sf->subfonts[k]->glyphcnt )
1604 	    curmax = sf->subfonts[k]->glyphcnt;
1605     }
1606 
1607     glyphs = calloc(curmax,sizeof(SplineChar *));
1608     for ( i=0; i<curmax; ++i ) {
1609 	for ( k=0; k<sf->subfontcnt; ++k )
1610 	    if ( i<sf->subfonts[k]->glyphcnt && sf->subfonts[k]->glyphs[i]!=NULL ) {
1611 		glyphs[i] = sf->subfonts[k]->glyphs[i];
1612 		sf->subfonts[k]->glyphs[i] = NULL;
1613 	break;
1614 	    }
1615     }
1616     *sfpp = sf = CIDFlatten(sf,glyphs,curmax);
1617 
1618     warned = false;
1619     for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1620 	EncMap *map = fvs->map;
1621 	for ( j=0; j<2; ++j ) {
1622 	    extras = 0;
1623 	    for ( i=0; i<curmax; ++i ) {
1624 		sc = glyphs[i];
1625 		if ( sc!=NULL ) {
1626 		    m = 0;
1627 		    for ( l=0; l<cmap->groups[cmt_cid].n; ++l ) {
1628 			if ( i>=cmap->groups[cmt_cid].ranges[l].cid &&
1629 				i<=cmap->groups[cmt_cid].ranges[l].cid +
1630 				   cmap->groups[cmt_cid].ranges[l].last -
1631 				    cmap->groups[cmt_cid].ranges[l].first ) {
1632 			    if ( m<sizeof(found)/sizeof(found[0]) )
1633 				found[m++] = l;
1634 			    else if ( !warned ) {
1635 				ff_post_notice(_("MultipleEncodingIgnored"),
1636 					_("The glyph at CID %d is mapped to more than %d encodings. Only the first %d are handled."), i,
1637 					sizeof(found)/sizeof(found[0]),
1638 					sizeof(found)/sizeof(found[0]));
1639 				warned = true;
1640 			    }
1641 			}
1642 		    }
1643 		    if ( m==0 ) {
1644 			if ( j ) {
1645 			    map->map[max+extras] = sc->orig_pos;
1646 			    map->backmap[sc->orig_pos] = max+extras;
1647 			}
1648 			++extras;
1649 		    } else {
1650 			if ( j ) {
1651 			    int p = cmap->groups[cmt_cid].ranges[found[0]].first +
1652 				    i-cmap->groups[cmt_cid].ranges[found[0]].cid;
1653 			    map->map[p] = sc->orig_pos;
1654 			    map->backmap[sc->orig_pos] = p;
1655 			    for ( l=1; l<m; ++l ) {
1656 				int pos = cmap->groups[cmt_cid].ranges[found[l]].first +
1657 					i-cmap->groups[cmt_cid].ranges[found[l]].cid;
1658 				map->map[pos] = sc->orig_pos;
1659 			    }
1660 			}
1661 		    }
1662 		}
1663 	    }
1664 	    if ( !j ) {
1665 		map->map = realloc(map->map,(map->encmax = map->enccount = max+extras)*sizeof(int32));
1666 		memset(map->map,-1,map->enccount*sizeof(int32));
1667 		memset(map->backmap,-1,sf->glyphcnt*sizeof(int32));
1668 		fvs->selected = realloc(fvs->selected, map->enccount*sizeof(uint8));
1669 		if (map->enccount > sf->glyphcnt) {
1670 		    memset(fvs->selected+sf->glyphcnt, 0, map->enccount-sf->glyphcnt);
1671 		}
1672 		map->remap = cmap->remap; cmap->remap = NULL;
1673 	    }
1674 	    warned = true;
1675 	}
1676     }
1677     cmapfree(cmap);
1678     FontViewReformatAll(sf);
1679 return( true );
1680 }
1681 
Enc2CMap(struct cmap * cmap,int enc)1682 static int Enc2CMap(struct cmap *cmap,int enc) {
1683     int i;
1684 
1685     for ( i=0; i<cmap->groups[cmt_cid].n; ++i )
1686 	if ( enc>=cmap->groups[cmt_cid].ranges[i].first &&
1687 		enc<=cmap->groups[cmt_cid].ranges[i].last )
1688 return( enc-cmap->groups[cmt_cid].ranges[i].first+
1689 	    cmap->groups[cmt_cid].ranges[i].cid );
1690 
1691 return( -1 );
1692 }
1693 
SFEncodeToCMap(SplineFont * cidmaster,SplineFont * sf,EncMap * oldmap,struct cmap * cmap)1694 static void SFEncodeToCMap(SplineFont *cidmaster,SplineFont *sf,EncMap *oldmap, struct cmap *cmap) {
1695     SplineChar *sc, *GID0=NULL;
1696     int i,max=0, anyextras=0;
1697 
1698     cidmaster->cidregistry = cmap->registry; cmap->registry = NULL;
1699     cidmaster->ordering = cmap->ordering; cmap->ordering = NULL;
1700     cidmaster->supplement = cmap->supplement;
1701 
1702     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1703 	if ( strcmp(sc->name,".notdef")==0 )
1704 	    sc->orig_pos = 0;
1705 	else if ( oldmap->backmap[i]==-1 )
1706 	    sc->orig_pos = -1;
1707 	else {
1708 	    sc->orig_pos = Enc2CMap(cmap,oldmap->backmap[i]);
1709 	    if ( sc->orig_pos==0 ) {
1710 		if ( GID0==NULL )
1711 		    GID0 = sc;
1712 		else
1713 		    sc->orig_pos = -1;
1714 	    }
1715 	}
1716 	if ( sc->orig_pos>max ) max = sc->orig_pos;
1717 	else if ( sc->orig_pos==-1 ) ++anyextras;
1718     }
1719     if ( GID0!=NULL )
1720 	GID0->orig_pos = ++max;
1721 
1722     if ( anyextras ) {
1723 	char *buttons[3];
1724 	buttons[0] = _("_Delete");
1725 	buttons[1] = _("_Add");
1726 	buttons[2] = NULL;
1727 	if ( ff_ask(_("Extraneous glyphs"),(const char **) buttons,0,1,_("The current encoding contains glyphs which I cannot map to CIDs.\nShould I delete them or add them to the end (where they may conflict with future ros definitions)?"))==1 ) {
1728 	    if ( cmap!=NULL && max<cmap->total ) max = cmap->total;
1729 	    anyextras = 0;
1730 	    for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1731 		if ( sc->orig_pos == -1 ) sc->orig_pos = max + anyextras++;
1732 	    }
1733 	    max += anyextras;
1734 	}
1735     }
1736     SFApplyOrdering(sf, max+1);
1737 }
1738 
1739 /* If we change the ascent/descent of a sub font then consider changing the */
1740 /*  as/ds of the master font. I used to think this irrelevant, but as the */
1741 /*  typoAscent/Descent is based on the master's ascent/descent it actually */
1742 /*  is meaningful. Set the master to the subfont with the most glyphs */
CIDMasterAsDes(SplineFont * sf)1743 void CIDMasterAsDes(SplineFont *sf) {
1744     SplineFont *cidmaster = sf->cidmaster;
1745     SplineFont *best;
1746     int i, cid, cnt, bcnt;
1747 
1748     if ( cidmaster==NULL )
1749 return;
1750     best = NULL; bcnt = 0;
1751     for ( i=0; i<cidmaster->subfontcnt; ++i ) {
1752 	sf = cidmaster->subfonts[i];
1753 	for ( cid=cnt=0; cid<sf->glyphcnt; ++cid )
1754 	    if ( sf->glyphs[cid]!=NULL )
1755 		++cnt;
1756 	if ( cnt>bcnt ) {
1757 	    best = sf;
1758 	    bcnt = cnt;
1759 	}
1760     }
1761     if ( best==NULL && cidmaster->subfontcnt>0 )
1762 	best = cidmaster->subfonts[0];
1763     if ( best!=NULL ) {
1764 	double ratio = 1000.0/(best->ascent+best->descent);
1765 	int ascent = rint(best->ascent*ratio);
1766 	if ( cidmaster->ascent!=ascent || cidmaster->descent!=1000-ascent ) {
1767 	    cidmaster->ascent = ascent;
1768 	    cidmaster->descent = 1000-ascent;
1769 	}
1770     }
1771 }
1772 
MakeCIDMaster(SplineFont * sf,EncMap * oldmap,int bycmap,char * cmapfilename,struct cidmap * cidmap)1773 SplineFont *MakeCIDMaster(SplineFont *sf,EncMap *oldmap,int bycmap,char *cmapfilename, struct cidmap *cidmap) {
1774     SplineFont *cidmaster;
1775     struct cidmap *map;
1776     struct cmap *cmap;
1777     FontViewBase *fvs;
1778 
1779     cidmaster = SplineFontEmpty();
1780     if ( bycmap ) {
1781 	if ( cmapfilename==NULL ) {
1782 	    SplineFontFree(cidmaster);
1783 return(NULL);
1784 	}
1785 	cmap = ParseCMap(cmapfilename);
1786 	if ( cmap==NULL ) {
1787 	    SplineFontFree(cidmaster);
1788 return(NULL);
1789 	}
1790 	CompressCMap(cmap);
1791 	SFEncodeToCMap(cidmaster,sf,oldmap,cmap);
1792 	cmapfree(cmap);
1793     } else {
1794 	map = cidmap;
1795 	if ( map==NULL ) {
1796 	    SplineFontFree(cidmaster);
1797 return(NULL);
1798 	}
1799 	cidmaster->cidregistry = copy(map->registry);
1800 	cidmaster->ordering = copy(map->ordering);
1801 	cidmaster->supplement = map->supplement;
1802 	SFEncodeToMap(sf,map);
1803     }
1804     if ( sf->uni_interp!=ui_none && sf->uni_interp!=ui_unset )
1805 	cidmaster->uni_interp = sf->uni_interp;
1806     else if ( strstrmatch(cidmaster->ordering,"japan")!=NULL )
1807 	cidmaster->uni_interp = ui_japanese;
1808     else if ( strstrmatch(cidmaster->ordering,"CNS")!=NULL )
1809 	cidmaster->uni_interp = ui_trad_chinese;
1810     else if ( strstrmatch(cidmaster->ordering,"GB")!=NULL )
1811 	cidmaster->uni_interp = ui_simp_chinese;
1812     else if ( strstrmatch(cidmaster->ordering,"Korea")!=NULL )
1813 	cidmaster->uni_interp = ui_korean;
1814     sf->uni_interp = cidmaster->uni_interp;
1815     cidmaster->fontname = copy(sf->fontname);
1816     cidmaster->fullname = copy(sf->fullname);
1817     cidmaster->familyname = copy(sf->familyname);
1818     cidmaster->weight = copy(sf->weight);
1819     cidmaster->copyright = copy(sf->copyright);
1820     cidmaster->cidversion = 1.0;
1821     cidmaster->display_antialias = sf->display_antialias;
1822     cidmaster->display_size = sf->display_size;
1823     cidmaster->ascent = sf->ascent /*880*/;
1824     cidmaster->descent = sf->descent /*120*/;
1825     cidmaster->changed = cidmaster->changed_since_autosave = true;
1826     for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1827 	fvs->cidmaster = cidmaster;
1828     cidmaster->fv = sf->fv;
1829     sf->cidmaster = cidmaster;
1830     cidmaster->subfontcnt = 1;
1831     cidmaster->subfonts = calloc(2,sizeof(SplineFont *));
1832     cidmaster->subfonts[0] = sf;
1833     cidmaster->gpos_lookups = sf->gpos_lookups; sf->gpos_lookups = NULL;
1834     cidmaster->gsub_lookups = sf->gsub_lookups; sf->gsub_lookups = NULL;
1835     cidmaster->horiz_base = sf->horiz_base; sf->horiz_base = NULL;
1836     cidmaster->vert_base = sf->vert_base; sf->vert_base = NULL;
1837     cidmaster->possub = sf->possub; sf->possub = NULL;
1838     cidmaster->kerns = sf->kerns; sf->kerns = NULL;
1839     cidmaster->vkerns = sf->vkerns; sf->vkerns = NULL;
1840     if ( sf->private==NULL )
1841 	sf->private = calloc(1,sizeof(struct psdict));
1842     if ( !PSDictHasEntry(sf->private,"lenIV"))
1843 	PSDictChangeEntry(sf->private,"lenIV","1");		/* It's 4 by default, in CIDs the convention seems to be 1 */
1844     for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1845 	free(fvs->selected);
1846 	fvs->selected = calloc(fvs->sf->glyphcnt,sizeof(uint8));
1847 	EncMapFree(fvs->map);
1848 	fvs->map = EncMap1to1(fvs->sf->glyphcnt);
1849 	FVSetTitle(fvs);
1850     }
1851     CIDMasterAsDes(sf);
1852     FontViewReformatAll(sf);
1853 return( cidmaster );
1854 }
1855 
CountOfEncoding(Encoding * encoding_name)1856 int CountOfEncoding(Encoding *encoding_name) {
1857 return( encoding_name->char_cnt );
1858 }
1859 
SFEncodingName(SplineFont * sf,EncMap * map)1860 char *SFEncodingName(SplineFont *sf,EncMap *map) {
1861     char buffer[130];
1862 
1863     if ( sf->cidmaster!=NULL )
1864 	sf = sf->cidmaster;
1865     if ( sf->subfontcnt!=0 ) {
1866 	sprintf( buffer, "%.50s-%.50s-%d", sf->cidregistry, sf->ordering, sf->supplement );
1867 return( copy( buffer ));
1868     }
1869 return( copy( map->enc->enc_name ));
1870 }
1871 
1872 /* ************************** Reencoding  routines ************************** */
1873 
BDFOrigFixup(BDFFont * bdf,int orig_cnt,SplineFont * sf)1874 void BDFOrigFixup(BDFFont *bdf,int orig_cnt,SplineFont *sf) {
1875     BDFChar **glyphs;
1876     int i;
1877 
1878     if ( bdf->glyphmax>=orig_cnt ) {
1879 	if ( bdf->glyphcnt<orig_cnt ) {
1880 	    for ( i=bdf->glyphcnt; i<orig_cnt; ++i )
1881 		bdf->glyphs[i] = NULL;
1882 	    bdf->glyphcnt = orig_cnt;
1883 	}
1884 return;
1885     }
1886 
1887     glyphs = calloc(orig_cnt,sizeof(BDFChar *));
1888     for ( i=0; i<bdf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1889 	glyphs[sf->glyphs[i]->orig_pos] = bdf->glyphs[i];
1890 	if ( bdf->glyphs[i]!=NULL )	/* Not all glyphs exist in a piecemeal font */
1891 	    bdf->glyphs[i]->orig_pos = sf->glyphs[i]->orig_pos;
1892     }
1893     free(bdf->glyphs);
1894     bdf->glyphs = glyphs;
1895     bdf->glyphcnt = bdf->glyphmax = orig_cnt;
1896     bdf->ticked = true;
1897 }
1898 
_SFForceEncoding(SplineFont * sf,EncMap * old,Encoding * new_enc)1899 static int _SFForceEncoding(SplineFont *sf,EncMap *old, Encoding *new_enc) {
1900     int enc_cnt,i;
1901     BDFFont *bdf;
1902     FontViewBase *fvs;
1903 
1904     /* Normally we base our encoding process on unicode code points. */
1905     /*  but encodings like AdobeStandard are more interested in names than */
1906     /*  code points. It is perfectly possible to have a font properly */
1907     /*  encoded by code point which is not properly encoded by name */
1908     /*  (might have f_i where it should have fi). So even if it's got */
1909     /*  the right encoding, we still may want to force the names */
1910     if ( new_enc->is_custom )
1911 return(false);			/* Custom, it's whatever's there */
1912 
1913     if ( new_enc->is_original ) {
1914 	SplineChar **glyphs;
1915 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1916 	    sf->glyphs[i]->orig_pos = -1;
1917 	for ( i=enc_cnt=0; i<old->enccount; ++i )
1918 	    if ( old->map[i]!=-1 && sf->glyphs[old->map[i]]!=NULL &&
1919 		    sf->glyphs[old->map[i]]->orig_pos == -1 )
1920 		sf->glyphs[old->map[i]]->orig_pos = enc_cnt++;
1921 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1922 	    if ( sf->glyphs[i]->orig_pos==-1 )
1923 		sf->glyphs[i]->orig_pos = enc_cnt++;
1924 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1925 	    struct splinecharlist *scl;
1926 	    int layer;
1927 	    RefChar *ref;
1928 
1929 	    for ( scl=sf->glyphs[i]->dependents; scl!=NULL; scl=scl->next ) {
1930 		for ( layer=0; layer<scl->sc->layer_cnt; ++layer )
1931 		    for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1932 			ref->orig_pos = ref->sc->orig_pos;
1933 	    }
1934 	}
1935 	for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1936 	    fvs->map->ticked = false;
1937 	    /*if ( fvs->filled!=NULL ) fvs->filled->ticked = false;*/
1938 	}
1939 	for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) if ( !fvs->map->ticked ) {
1940 	    EncMap *map = fvs->map;
1941 	    for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 )
1942 		map->map[i] = sf->glyphs[map->map[i]]->orig_pos;
1943 	    if ( enc_cnt>map->backmax ) {
1944 		free(map->backmap);
1945 		map->backmax = enc_cnt;
1946 		map->backmap = malloc(enc_cnt*sizeof(int32));
1947 	    }
1948 	    memset(map->backmap,-1,enc_cnt*sizeof(int32));
1949 	    for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 )
1950 		if ( map->backmap[map->map[i]]==-1 )
1951 		    map->backmap[map->map[i]] = i;
1952 	    map->ticked = true;
1953 	}
1954 	if ( !old->ticked )
1955 	    IError( "Unticked encmap" );
1956 	for ( bdf=sf->bitmaps; bdf!=NULL; bdf=bdf->next )
1957 	    BDFOrigFixup(bdf,enc_cnt,sf);
1958 	for ( fvs=sf->fv; fvs!=NULL ; fvs=fvs->nextsame )
1959 	    FVBiggerGlyphCache(fvs,enc_cnt);
1960 	glyphs = calloc(enc_cnt,sizeof(SplineChar *));
1961 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1962 	    glyphs[sf->glyphs[i]->orig_pos] = sf->glyphs[i];
1963 	free(sf->glyphs);
1964 	sf->glyphs = glyphs;
1965 	sf->glyphcnt = sf->glyphmax = enc_cnt;
1966 return( true );
1967     }
1968 
1969     enc_cnt = new_enc->char_cnt;
1970 
1971     if ( old->enccount<enc_cnt ) {
1972 	if ( old->encmax<enc_cnt ) {
1973 	    old->map = realloc(old->map,enc_cnt*sizeof(int32));
1974 	    old->encmax = enc_cnt;
1975 	}
1976 	memset(old->map+old->enccount,-1,(enc_cnt-old->enccount)*sizeof(int32));
1977 	old->enccount = enc_cnt;
1978     }
1979     old->enc = new_enc;
1980     for ( i=0; i<old->enccount && i<enc_cnt; ++i ) if ( old->map[i]!=-1 && sf->glyphs[old->map[i]]!=NULL ) {
1981 	SplineChar dummy;
1982 	int j = old->map[i];
1983 	SCBuildDummy(&dummy,sf,old,i);
1984 	sf->glyphs[j]->unicodeenc = dummy.unicodeenc;
1985 	free(sf->glyphs[j]->name);
1986 	sf->glyphs[j]->name = copy(dummy.name);
1987     }
1988     /* We just changed the unicode values for most glyphs */
1989     /* but any references to them will have the old values, and that's bad, so fix 'em up */
1990     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1991 	struct splinecharlist *scl;
1992 	int layer;
1993 	RefChar *ref;
1994 
1995 	for ( scl=sf->glyphs[i]->dependents; scl!=NULL; scl=scl->next ) {
1996 	    for ( layer=0; layer<scl->sc->layer_cnt; ++layer )
1997 		for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1998 		    ref->unicode_enc = ref->sc->unicodeenc;
1999 	}
2000     }
2001 return( true );
2002 }
2003 
SFForceEncoding(SplineFont * sf,EncMap * old,Encoding * new_enc)2004 int SFForceEncoding(SplineFont *sf,EncMap *old, Encoding *new_enc) {
2005     if ( sf->mm!=NULL ) {
2006 	MMSet *mm = sf->mm;
2007 	int i;
2008 	for ( i=0; i<mm->instance_count; ++i )
2009 	    _SFForceEncoding(mm->instances[i],old,new_enc);
2010 	_SFForceEncoding(mm->normal,old,new_enc);
2011     } else
2012 return( _SFForceEncoding(sf,old,new_enc));
2013 
2014 return( true );
2015 }
2016 
EncMapFromEncoding(SplineFont * sf,Encoding * enc)2017 EncMap *EncMapFromEncoding(SplineFont *sf,Encoding *enc) {
2018     int i,j, extras, found, base, unmax;
2019     int32 *encoded=NULL, *unencoded=NULL;
2020     EncMap *map;
2021     struct altuni *altuni;
2022     SplineChar *sc;
2023 
2024     if ( enc==NULL )
2025 return( NULL );
2026 
2027     base = enc->char_cnt;
2028     if ( enc->is_original )
2029 	base = 0;
2030     else if ( enc->char_cnt<=256 )
2031 	base = 256;
2032     else if ( enc->char_cnt<=0x10000 )
2033 	base = 0x10000;
2034     if ( base>0 ) {
2035 	encoded = malloc(base*sizeof(int32));
2036 	memset(encoded,-1,base*sizeof(int32));
2037     }
2038     if ( sf->glyphcnt>0 ) {
2039 	unencoded = malloc(sf->glyphcnt*sizeof(int32));
2040 	unmax = sf->glyphcnt;
2041     }
2042 
2043     for ( i=extras=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2044 	found = false;
2045 	if ( enc->psnames!=NULL ) {
2046 	    for ( j=enc->char_cnt-1; j>=0; --j ) {
2047 		if ( enc->psnames[j]!=NULL &&
2048 			strcmp(enc->psnames[j],sc->name)==0 ) {
2049 		    found = true;
2050 		    encoded[j] = i;
2051 		}
2052 	    }
2053 	}
2054 	if ( !found ) {
2055 	    if ( sc->unicodeenc!=-1 &&
2056                  sc->unicodeenc < (int)unicode4_size &&
2057 		     (j = EncFromUni(sc->unicodeenc,enc))!= -1 )
2058 		encoded[j] = i;
2059 	    else {
2060 		/* I don't think extras can surpass unmax now, but it doesn't */
2061 		/*  hurt to leave the code (it's from when we encoded duplicates see below) */
2062 		if ( extras>=unmax ) unencoded = realloc(unencoded,(unmax+=300)*sizeof(int32));
2063 		unencoded[extras++] = i;
2064 	    }
2065 	    for ( altuni=sc->altuni; altuni!=NULL; altuni=altuni->next ) {
2066 		if ( altuni->unienc!=-1 &&
2067                      (uint32)altuni->unienc<unicode4_size &&
2068 			 altuni->vs==-1 &&
2069 			 altuni->fid==0 &&
2070 			 (j = EncFromUni(altuni->unienc,enc))!= -1 )
2071 		    encoded[j] = i;
2072 		/* I used to have code here to add these unencoded duplicates */
2073 		/*  but I don't really see any reason to do so. The main unicode */
2074 		/*  will occur, and any encoded duplicates so the glyph won't */
2075 		/*  vanish */
2076 	    }
2077 	}
2078     }
2079 
2080     /* Some glyphs have both a pua encoding and an encoding in a non-bmp */
2081     /*  plane. Big5HK does and the AMS glyphs do */
2082     if ( enc->is_unicodefull && (sf->uni_interp == ui_trad_chinese ||
2083 				 sf->uni_interp == ui_ams )) {
2084 	const int *pua = sf->uni_interp == ui_ams? amspua : cns14pua;
2085 	for ( i=0xe000; i<0xf8ff; ++i ) {
2086 	    if ( pua[i-0xe000]!=0 )
2087 		encoded[pua[i-0xe000]] = encoded[i];
2088 	}
2089     }
2090 
2091     if ( enc->psnames != NULL ) {
2092 	/* Names are more important than unicode code points for some encodings */
2093 	/*  AdobeStandard for instance which won't work if you have a glyph  */
2094 	/*  named "f_i" (must be "fi") even though the code point is correct */
2095 	/* The code above would match f_i where AS requires fi, so force the */
2096 	/*  names to be correct. */
2097 	for ( j=0; j<enc->char_cnt; ++j ) {
2098 	    if ( encoded[j]!=-1 && enc->psnames[j]!=NULL &&
2099 		    strcmp(sf->glyphs[encoded[j]]->name,enc->psnames[j])!=0 ) {
2100 		free(sf->glyphs[encoded[j]]->name);
2101 		sf->glyphs[encoded[j]]->name = copy(enc->psnames[j]);
2102 	    }
2103 	}
2104     }
2105 
2106     map = chunkalloc(sizeof(EncMap));
2107     map->enccount = map->encmax = base + extras;
2108     if ( map->enccount>0 ) {
2109 	map->map = malloc(map->enccount*sizeof(int32));
2110 	if ( base>0 )
2111 	    memcpy(map->map,encoded,base*sizeof(int32));
2112 	if ( extras>0 )
2113 	    memcpy(map->map+base,unencoded,extras*sizeof(int32));
2114     }
2115     map->backmax = sf->glyphcnt;
2116     if ( sf->glyphcnt>0 ) {
2117 	map->backmap = malloc(sf->glyphcnt*sizeof(int32));
2118 	memset(map->backmap,-1,sf->glyphcnt*sizeof(int32));	/* Just in case there are some unencoded glyphs (duplicates perhaps) */
2119 	for ( i = map->enccount-1; i>=0; --i ) if ( map->map[i]!=-1 )
2120 	    map->backmap[map->map[i]] = i;
2121     }
2122     map->enc = enc;
2123 
2124     free(encoded);
2125     free(unencoded);
2126 
2127 return( map );
2128 }
2129 
CompactEncMap(EncMap * map,SplineFont * sf)2130 EncMap *CompactEncMap(EncMap *map, SplineFont *sf) {
2131     int i, inuse, gid;
2132     int32 *newmap;
2133 
2134     for ( i=inuse=0; i<map->enccount ; ++i )
2135 	if ( (gid = map->map[i])!=-1 && SCWorthOutputting(sf->glyphs[gid]))
2136 	    ++inuse;
2137     newmap = malloc(inuse*sizeof(int32));
2138     for ( i=inuse=0; i<map->enccount ; ++i )
2139 	if ( (gid = map->map[i])!=-1 && SCWorthOutputting(sf->glyphs[gid]))
2140 	    newmap[inuse++] = gid;
2141     free(map->map);
2142     map->map = newmap;
2143     map->enccount = inuse;
2144     map->encmax = inuse;
2145     map->enc = &custom;
2146     memset(map->backmap,-1,sf->glyphcnt*sizeof(int32));
2147     for ( i=inuse-1; i>=0; --i )
2148 	if ( (gid=map->map[i])!=-1 )
2149 	    map->backmap[gid] = i;
2150 return( map );
2151 }
2152 
BCProtectUndoes(Undoes * undo,BDFChar * bc)2153 static void BCProtectUndoes( Undoes *undo,BDFChar *bc ) {
2154     BDFRefChar *brhead, *brprev=NULL, *brnext;
2155 
2156     for ( ; undo!=NULL; undo=undo->next ) {
2157 	switch ( undo->undotype ) {
2158 	  case ut_bitmap:
2159 	    for ( brhead=undo->u.bmpstate.refs; brhead != NULL; brhead=brnext ) {
2160 		brnext = brhead->next;
2161 		if ( brhead->bdfc == bc ) {
2162 		    BCPasteInto( &undo->u.bmpstate,bc,brhead->xoff,brhead->yoff,false,false );
2163 		    if ( brprev == NULL )
2164 			undo->u.bmpstate.refs = brnext;
2165 		    else
2166 			brprev->next = brnext;
2167 		    free( brhead );
2168 		} else
2169 		    brprev = brhead;
2170 	    }
2171 	  break;
2172 	  case ut_multiple:
2173 	    BCProtectUndoes( undo->u.multiple.mult,bc );
2174 	  break;
2175 	  case ut_composit:
2176 	    BCProtectUndoes( undo->u.composit.bitmaps,bc );
2177 	  break;
2178 	}
2179     }
2180 }
2181 
SFReencode(SplineFont * sf,const char * encname,int force)2182 int SFReencode(SplineFont *sf, const char *encname, int force) {
2183     Encoding *new_enc;
2184     FontViewBase *fv = sf->fv;
2185 
2186     if ( strmatch(encname,"compacted")==0 ) {
2187 	fv->normal = EncMapCopy(fv->map);
2188 	CompactEncMap(fv->map,sf);
2189     } else {
2190 	new_enc = FindOrMakeEncoding(encname);
2191 	if ( new_enc==NULL )
2192 return -1;
2193 	if ( force )
2194 	    SFForceEncoding(sf,fv->map,new_enc);
2195 	else if ( new_enc==&custom )
2196 	    fv->map->enc = &custom;
2197 	else {
2198 	    EncMap *map = EncMapFromEncoding(sf,new_enc);
2199 	    EncMapFree(fv->map);
2200 	    if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = map; }
2201 	    fv->map = map;
2202 	    if ( !no_windowing_ui )
2203 		FVSetTitle(fv);
2204 	}
2205 	if ( fv->normal!=NULL ) {
2206 	    EncMapFree(fv->normal);
2207 	    if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = NULL; }
2208 	    fv->normal = NULL;
2209 	}
2210 	SFReplaceEncodingBDFProps(sf,fv->map);
2211     }
2212     free(fv->selected);
2213     fv->selected = calloc(fv->map->enccount,sizeof(uint8));
2214     if ( !no_windowing_ui )
2215 	FontViewReformatAll(sf);
2216 
2217 return 0;
2218 }
2219 
SFRemoveGlyph(SplineFont * sf,SplineChar * sc)2220 void SFRemoveGlyph( SplineFont *sf,SplineChar *sc ) {
2221     struct splinecharlist *dep, *dnext;
2222     struct bdfcharlist *bdep, *bdnext;
2223     RefChar *rf, *refs, *rnext;
2224     BDFRefChar *bref, *brnext, *brprev;
2225     KernPair *kp, *kprev;
2226     int i;
2227     BDFFont *bdf;
2228     BDFChar *bfc, *dbc;
2229     int layer;
2230 
2231     if ( sc==NULL )
2232 return;
2233 
2234     /* Close any open windows */
2235     SCCloseAllViews(sc);
2236 
2237     /* Turn any references to this glyph into inline copies of it */
2238     for ( dep=sc->dependents; dep!=NULL; dep=dnext ) {
2239 	SplineChar *dsc = dep->sc;
2240 	dnext = dep->next;
2241 	/* May be more than one reference to us, colon has two refs to period */
2242 	/*  but only one dlist entry */
2243 	for ( layer=0; layer<dsc->layer_cnt; ++layer ) {
2244 	    for ( rf = dsc->layers[layer].refs; rf!=NULL; rf=rnext ) {
2245 		rnext = rf->next;
2246 		if ( rf->sc==sc )
2247 		    SCRefToSplines(dsc,rf,layer);
2248 	    }
2249 	}
2250     }
2251 
2252     for ( layer=0; layer<sc->layer_cnt; ++layer ) {
2253 	for ( refs=sc->layers[layer].refs; refs!=NULL; refs = rnext ) {
2254 	    rnext = refs->next;
2255 	    SCRemoveDependent(sc,refs,layer);
2256 	}
2257     }
2258 
2259     /* Remove any kerning pairs that look at this character */
2260     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2261 	for ( kprev=NULL, kp=sf->glyphs[i]->kerns; kp!=NULL; kprev = kp, kp=kp->next ) {
2262 	    if ( kp->sc==sc ) {
2263 		if ( kprev==NULL )
2264 		    sf->glyphs[i]->kerns = kp->next;
2265 		else
2266 		    kprev->next = kp->next;
2267 		kp->next = NULL;
2268 		KernPairsFree(kp);
2269 	break;
2270 	    }
2271 	}
2272     }
2273 
2274     sf->glyphs[sc->orig_pos] = NULL;
2275 
2276     for ( bdf=sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
2277 	if ( sc->orig_pos<bdf->glyphcnt && (bfc = bdf->glyphs[sc->orig_pos])!= NULL ) {
2278 	    /* Turn any references to this glyph into inline copies of it */
2279 	    for ( bdep=bfc->dependents; bdep!=NULL; bdep=bdnext ) {
2280 		dbc = bdep->bc;
2281 		bdnext = bdep->next;
2282 		brprev = NULL;
2283 		/* May be more than one reference to us, colon has two refs to period */
2284 		/*  but only one dlist entry */
2285 		for ( bref = dbc->refs; bref!=NULL; bref=brnext ) {
2286 		    brnext = bref->next;
2287 		    if ( bref->bdfc==bfc ) {
2288 			BCPasteInto( dbc,bref->bdfc,bref->xoff,bref->yoff,false,false );
2289 			if ( brprev == NULL ) dbc->refs = brnext;
2290 			else brprev->next = brnext;
2291 			free( bref );
2292 		    } else
2293 			brprev = bref;
2294 		}
2295 	    }
2296 	    /* Suppose we have deleted a reference from a composite glyph and than
2297 	     * going to remove the previously referenced glyph from the font. The
2298 	     * void reference still remains in the undoes stack, so that executing Undo/Redo
2299 	     * on the first glyph may lead to unpredictable effects. It is also
2300 	     * impossible to detect such problematic undoes checking just our
2301 	     * going-to-be-deleted glyph's dependents, because the composite character
2302 	     * no longer contains the problematic reference and so is not listed
2303 	     * in the dependents. Thus the only solution seems to be checking
2304 	     * every single glyph in the font.
2305 	     */
2306 	    for ( i=0; i<bdf->glyphcnt; i++ ) if (( dbc = bdf->glyphs[i] ) != NULL ) {
2307 		BCProtectUndoes( dbc->undoes,bfc );
2308 		BCProtectUndoes( dbc->redoes,bfc );
2309 	    }
2310 	    for ( bref=bfc->refs; refs!=NULL; bref = brnext ) {
2311 		brnext = bref->next;
2312 		BCRemoveDependent( bfc,bref );
2313 	    }
2314 	    bdf->glyphs[sc->orig_pos] = NULL;
2315 	    BDFCharFree(bfc);
2316 	}
2317     }
2318 
2319     SplineCharFree(sc);
2320     GlyphHashFree(sf);
2321 }
2322 
MapAddEncodingSlot(EncMap * map,int gid)2323 static int MapAddEncodingSlot(EncMap *map,int gid) {
2324     int enc;
2325 
2326     if ( map->enccount>=map->encmax )
2327 	map->map = realloc(map->map,(map->encmax+=10)*sizeof(int32));
2328     enc = map->enccount++;
2329     map->map[enc] = gid;
2330     map->backmap[gid] = enc;
2331 return( enc );
2332 }
2333 
FVAddEncodingSlot(FontViewBase * fv,int gid)2334 void FVAddEncodingSlot(FontViewBase *fv,int gid) {
2335     EncMap *map = fv->map;
2336     int enc;
2337 
2338     enc = MapAddEncodingSlot(map,gid);
2339 
2340     fv->selected = realloc(fv->selected,map->enccount);
2341     fv->selected[enc] = 0;
2342     FVAdjustScrollBarRows(fv,enc);
2343 }
2344 
SFAddEncodingSlot(SplineFont * sf,int gid)2345 void SFAddEncodingSlot(SplineFont *sf,int gid) {
2346     FontViewBase *fv;
2347     for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame )
2348 	FVAddEncodingSlot(fv,gid);
2349 }
2350 
MapAddEnc(SplineFont * sf,SplineChar * sc,EncMap * basemap,EncMap * map,int baseenc,int gid,FontViewBase * fv)2351 static int MapAddEnc(SplineFont *sf,SplineChar *sc,EncMap *basemap, EncMap *map,int baseenc, int gid, FontViewBase *fv) {
2352     int any = false, enc;
2353 
2354     if ( gid>=map->backmax ) {
2355 	map->backmap = realloc(map->backmap,(map->backmax+=10)*sizeof(int32));
2356 	memset(map->backmap+map->backmax-10,-1,10*sizeof(int32));
2357     }
2358     if ( map->enc->psnames!=NULL ) {
2359 	/* Check for multiple encodings */
2360 	for ( enc = map->enc->char_cnt-1; enc>=0; --enc ) {
2361 	    if ( map->enc->psnames[enc]!=NULL && strcmp(sc->name,map->enc->psnames[enc])==0 ) {
2362 		if ( !any ) {
2363 		    map->backmap[gid] = enc;
2364 		    any = true;
2365 		}
2366 		map->map[enc] = gid;
2367 	    }
2368 	}
2369     } else {
2370 	enc = SFFindSlot(sf,map,sc->unicodeenc,sc->name);
2371 	if ( enc!=-1 ) {
2372 	    map->map[enc] = gid;
2373 	    map->backmap[gid] = enc;
2374 	    any = true;
2375 	}
2376     }
2377     if ( basemap!=NULL && map->enc==basemap->enc && baseenc!=-1 ) {
2378 	if ( baseenc>=map->enccount ) {
2379 	    if ( fv && map==fv->map )
2380 		FVAddEncodingSlot(fv,gid);
2381 	    else
2382 		MapAddEncodingSlot(map,gid);
2383 	} else {
2384 	    map->map[baseenc] = gid;
2385 	    if ( map->backmap[gid]==-1 )
2386 		map->backmap[gid] = baseenc;
2387 	}
2388 	any = true;
2389     }
2390 return( any );
2391 }
2392 
SFAddGlyphAndEncode(SplineFont * sf,SplineChar * sc,EncMap * basemap,int baseenc)2393 void SFAddGlyphAndEncode(SplineFont *sf,SplineChar *sc,EncMap *basemap, int baseenc) {
2394     int gid, mapfound = false;
2395     FontViewBase *fv;
2396     BDFFont *bdf;
2397 
2398     if ( sf->cidmaster==NULL ) {
2399 	if ( sf->glyphcnt+1>=sf->glyphmax )
2400 	    sf->glyphs = realloc(sf->glyphs,(sf->glyphmax+=10)*sizeof(SplineChar *));
2401 	gid = sf->glyphcnt++;
2402 	for ( bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2403 	    if ( sf->glyphcnt+1>=bdf->glyphmax )
2404 		bdf->glyphs = realloc(bdf->glyphs,(bdf->glyphmax=sf->glyphmax)*sizeof(BDFChar *));
2405 	    if ( sf->glyphcnt>bdf->glyphcnt ) {
2406 		memset(bdf->glyphs+bdf->glyphcnt,0,(sf->glyphcnt-bdf->glyphcnt)*sizeof(BDFChar *));
2407 		bdf->glyphcnt = sf->glyphcnt;
2408 	    }
2409 	}
2410 	for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame ) {
2411 	    EncMap *map = fv->map;
2412 	    if ( gid>=map->backmax )
2413 		map->backmap = realloc(map->backmap,(map->backmax=gid+10)*sizeof(int32));
2414 	    map->backmap[gid] = -1;
2415 	}
2416     } else {
2417 	gid = baseenc < 0 ? sf->glyphcnt : baseenc;
2418 	if ( gid+1>=sf->glyphmax )
2419 	    sf->glyphs = realloc(sf->glyphs,(sf->glyphmax = gid+10)*sizeof(SplineChar *));
2420 	if ( gid>=sf->glyphcnt ) {
2421 	    memset(sf->glyphs+sf->glyphcnt,0,(gid+1-sf->glyphcnt)*sizeof(SplineChar *));
2422 	    sf->glyphcnt = gid+1;
2423 	    for ( bdf = sf->cidmaster->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2424 		if ( gid+1>=bdf->glyphmax )
2425 		    bdf->glyphs = realloc(bdf->glyphs,(bdf->glyphmax=gid+10)*sizeof(BDFChar *));
2426 		if ( gid+1>bdf->glyphcnt ) {
2427 		    memset(bdf->glyphs+bdf->glyphcnt,0,(gid+1-bdf->glyphcnt)*sizeof(BDFChar *));
2428 		    bdf->glyphcnt = gid+1;
2429 		}
2430 	    }
2431 	    for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame ) if ( fv->sf==sf ) {
2432 		EncMap *map = fv->map;
2433 		if ( gid>=map->backmax )
2434 		    map->backmap = realloc(map->backmap,(map->backmax=gid+10)*sizeof(int32));
2435 		map->backmap[gid] = -1;
2436 	    }
2437 	}
2438     }
2439     sf->glyphs[gid] = NULL;
2440     for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame ) {
2441 	EncMap *map = fv->map;
2442 
2443 	FVBiggerGlyphCache(fv,gid);
2444 
2445 	if ( !MapAddEnc(sf,sc,basemap,map,baseenc,gid,fv) )
2446 	    FVAddEncodingSlot(fv,gid);
2447 	if ( map==basemap ) mapfound = true;
2448 	if ( fv->normal!=NULL ) {
2449 	    if ( !MapAddEnc(sf,sc,basemap,fv->normal,baseenc,gid,fv))
2450 		MapAddEncodingSlot(fv->normal,gid);
2451 	}
2452     }
2453     if ( !mapfound && basemap!=NULL )
2454 	MapAddEnc(sf,sc,basemap,basemap,baseenc,gid,fv);
2455     sf->glyphs[gid] = sc;
2456     sc->orig_pos = gid;
2457     sc->parent = sf;
2458     SFHashGlyph(sf,sc);
2459 }
2460 
SplineCharMatch(SplineFont * parent,SplineChar * sc)2461 static SplineChar *SplineCharMatch(SplineFont *parent,SplineChar *sc) {
2462     SplineChar *scnew = SFSplineCharCreate(parent);
2463 
2464     scnew->parent = parent;
2465     scnew->orig_pos = sc->orig_pos;
2466     scnew->name = copy(sc->name);
2467     scnew->unicodeenc = sc->unicodeenc;
2468     scnew->width = sc->width;
2469     scnew->vwidth = sc->vwidth;
2470     scnew->widthset = true;
2471 return( scnew );
2472 }
2473 
SFMatchGlyphs(SplineFont * sf,SplineFont * target,int addempties)2474 void SFMatchGlyphs(SplineFont *sf,SplineFont *target,int addempties) {
2475     /* reorder sf so that its glyphs array is the same as that in target */
2476     int i, j, cnt, cnt2;
2477     SplineChar **glyphs;
2478     BDFFont *bdf;
2479 
2480     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2481 	sf->glyphs[i]->ticked = false;
2482     if (( cnt = target->glyphcnt )<sf->glyphcnt ) cnt = sf->glyphcnt;
2483     glyphs = calloc(cnt,sizeof(SplineChar *));
2484     for ( i=0; i<target->glyphcnt; ++i ) if ( target->glyphs[i]!=NULL ) {
2485 	SplineChar *sc = SFGetChar(sf,target->glyphs[i]->unicodeenc,target->glyphs[i]->name );
2486 	if ( sc==NULL && addempties )
2487 	    sc = SplineCharMatch(sf,target->glyphs[i]);
2488 	if ( sc!=NULL ) {
2489 	    glyphs[i] = sc;
2490 	    sc->ticked = true;
2491 	}
2492     }
2493     for ( i=cnt2=0; i<sf->glyphcnt; ++i )
2494 	if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked )
2495 	    ++cnt2;
2496     if ( target->glyphcnt+cnt2>cnt ) {
2497 	glyphs = realloc(glyphs,(target->glyphcnt+cnt2)*sizeof(SplineChar *));
2498 	memset(glyphs+cnt,0,(target->glyphcnt+cnt2-cnt)*sizeof(SplineChar *));
2499 	cnt = target->glyphcnt+cnt2;
2500     }
2501     j = target->glyphcnt;
2502     for ( i=0; i<sf->glyphcnt; ++i )
2503 	if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked )
2504 	    glyphs[j++] = sf->glyphs[i];
2505     free(sf->glyphs);
2506     sf->glyphs = glyphs;
2507     sf->glyphcnt = sf->glyphmax = cnt;
2508     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2509 	sf->glyphs[i]->orig_pos = i;
2510     for ( bdf = sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
2511 	BDFChar **glyphs;
2512 	glyphs = calloc(sf->glyphcnt,sizeof(BDFChar *));
2513 	for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL )
2514 	    glyphs[bdf->glyphs[i]->sc->orig_pos] = bdf->glyphs[i];
2515 	free(bdf->glyphs);
2516 	bdf->glyphs = glyphs;
2517 	bdf->glyphcnt = bdf->glyphmax = sf->glyphcnt;
2518     }
2519 }
2520 
MMMatchGlyphs(MMSet * mm)2521 void MMMatchGlyphs(MMSet *mm) {
2522     /* reorder all instances so that they have the same orig_pos */
2523     int i, j, index, lasthole;
2524     SplineFont *sf, *base = NULL;
2525     SplineChar *sc, *scnew, *sc2;
2526 
2527     for ( i = 0; i<mm->instance_count; ++i ) if ( mm->instances[i]!=NULL ) {
2528 	base = mm->instances[i];
2529     break;
2530     }
2531     if ( base==NULL )
2532 return;
2533 
2534     /* First build up an ordering that uses all glyphs found in any of the */
2535     /*  sub-fonts, "base" will be the start of it. We will add glyphs to */
2536     /*  "base" as needed */
2537     lasthole = -1;
2538     for ( i = 0; i<mm->instance_count; ++i ) if ( (sf=mm->instances[i])!=NULL && sf!=NULL ) {
2539 	for ( j=0; j<sf->glyphcnt; ++j ) if ( (sc=sf->glyphs[j])!=NULL ) {
2540 	    if ( j<base->glyphcnt && base->glyphs[j]!=NULL &&
2541 		    base->glyphs[j]->unicodeenc==sc->unicodeenc &&
2542 		    strcmp(base->glyphs[j]->name,sc->name)==0 )
2543 	continue;	/* It's good, and in the same place */
2544 	    else if ( (sc2=SFGetChar(base,sc->unicodeenc,sc->name))!=NULL &&
2545 		    sc2->unicodeenc==sc->unicodeenc &&
2546 		    strcmp(sc2->name,sc->name)==0 )
2547 	continue;	/* Well, it's in there somewhere */
2548 	    else {
2549 		/* We need to add it */
2550 		if ( j<base->glyphcnt && base->glyphs[j]==NULL )
2551 		    index = j;
2552 		else {
2553 		    for ( ++lasthole ; lasthole<base->glyphcnt && base->glyphs[lasthole]!=NULL; ++lasthole );
2554 		    index = lasthole;
2555 		    if ( lasthole>=base->glyphmax )
2556 			base->glyphs = realloc(base->glyphs,(base->glyphmax+=20)*sizeof(SplineChar *));
2557 		    if ( lasthole>=base->glyphcnt )
2558 			base->glyphcnt = lasthole+1;
2559 		}
2560 		base->glyphs[index] = scnew = SplineCharMatch(base,sc);
2561 		scnew->orig_pos = index;
2562 	    }
2563 	}
2564     }
2565 
2566     /* Now force all other instances to match */
2567     for ( i = 0; i<mm->instance_count; ++i ) if ( (sf=mm->instances[i])!=NULL && sf!=base )
2568 	SFMatchGlyphs(sf,base,true);
2569     if ( mm->normal!=NULL )
2570 	SFMatchGlyphs(mm->normal,base,true);
2571 }
2572 
UniFromEnc(int enc,Encoding * encname)2573 int32 UniFromEnc(int enc, Encoding *encname) {
2574     char from[20];
2575     unichar_t to[20];
2576     ICONV_CONST char *fpt;
2577     char *tpt;
2578     size_t fromlen, tolen;
2579 
2580     if ( encname->is_custom || encname->is_original )
2581 return( -1 );
2582     if ( enc>=encname->char_cnt )
2583 return( -1 );
2584     if ( encname->is_unicodebmp || encname->is_unicodefull )
2585 return( enc );
2586     if ( encname->unicode!=NULL )
2587 return( encname->unicode[enc] );
2588     else if ( encname->tounicode ) {
2589 	/* To my surprise, on RH9, doing a reset on conversion of CP1258->UCS2 */
2590 	/* causes subsequent calls to return garbage */
2591 	if ( encname->iso_2022_escape_len ) {
2592 	    tolen = sizeof(to); fromlen = 0;
2593 	    iconv(encname->tounicode,NULL,&fromlen,NULL,&tolen);	/* Reset state */
2594 	}
2595 	fpt = from; tpt = (char *) to; tolen = sizeof(to);
2596 	if ( encname->has_1byte && enc<256 ) {
2597 	    *(char *) fpt = enc;
2598 	    fromlen = 1;
2599 	} else if ( encname->has_2byte ) {
2600 	    if ( encname->iso_2022_escape_len )
2601 		strncpy(from,encname->iso_2022_escape,encname->iso_2022_escape_len );
2602 	    fromlen = encname->iso_2022_escape_len;
2603 	    from[fromlen++] = enc>>8;
2604 	    from[fromlen++] = enc&0xff;
2605 	}
2606 	if ( iconv(encname->tounicode,&fpt,&fromlen,&tpt,&tolen)==(size_t) -1 )
2607 return( -1 );
2608 	if ( tpt-(char *) to == 0 ) {
2609 	    /* This strange call appears to be what we need to make CP1258->UCS2 */
2610 	    /*  work.  It's supposed to reset the state and give us the shift */
2611 	    /*  out. As there is no state, and no shift out I have no idea why*/
2612 	    /*  this works, but it does. */
2613 	    if ( iconv(encname->tounicode,NULL,&fromlen,&tpt,&tolen)==(size_t) -1 )
2614 return( -1 );
2615 	}
2616 	if ( tpt-(char *) to == sizeof(unichar_t) )
2617 	{
2618 	    return( to[0] );
2619 	}
2620     } else if ( encname->tounicode_func!=NULL ) {
2621 return( (encname->tounicode_func)(enc) );
2622     }
2623 return( -1 );
2624 }
2625 
EncFromUni(int32 uni,Encoding * enc)2626 int32 EncFromUni(int32 uni, Encoding *enc) {
2627     unichar_t from[20];
2628     unsigned char to[20];
2629     ICONV_CONST char *fpt;
2630     char *tpt;
2631     size_t fromlen, tolen;
2632     int i;
2633 
2634     if ( enc->is_custom || enc->is_original || enc->is_compact || uni==-1 )
2635 return( -1 );
2636     if ( enc->is_unicodebmp || enc->is_unicodefull )
2637 return( uni<enc->char_cnt ? uni : -1 );
2638 
2639     if ( enc->unicode!=NULL ) {
2640 	for ( i=0; i<enc->char_cnt; ++i ) {
2641 	    if ( enc->unicode[i]==uni )
2642 return( i );
2643 	}
2644 return( -1 );
2645     } else if ( enc->fromunicode!=NULL ) {
2646 	/* I don't see how there can be any state to reset in this direction */
2647 	/*  So I don't reset it */
2648 	from[0] = uni;
2649 	fromlen = sizeof(unichar_t);
2650 	fpt = (char *) from; tpt = (char *) to; tolen = sizeof(to);
2651 	iconv(enc->fromunicode,NULL,NULL,NULL,NULL);	/* reset shift in/out, etc. */
2652 	if ( iconv(enc->fromunicode,&fpt,&fromlen,&tpt,&tolen)==(size_t) -1 )
2653 return( -1 );
2654 	if ( tpt-(char *) to == 1 )
2655 return( to[0] );
2656 	if ( enc->iso_2022_escape_len!=0 ) {
2657 	    if ( tpt-(char *) to == enc->iso_2022_escape_len+2 &&
2658 		    strncmp((char *) to,enc->iso_2022_escape,enc->iso_2022_escape_len)==0 )
2659 return( (to[enc->iso_2022_escape_len]<<8) | to[enc->iso_2022_escape_len+1] );
2660 	} else {
2661 	    if ( tpt-(char *) to == sizeof(unichar_t) )
2662 return( (to[0]<<8) | to[1] );
2663 	}
2664     } else if ( enc->fromunicode_func!=NULL ) {
2665 return( (enc->fromunicode_func)(uni) );
2666     }
2667 return( -1 );
2668 }
2669 
EncFromName(const char * name,enum uni_interp interp,Encoding * encname)2670 int32 EncFromName(const char *name,enum uni_interp interp,Encoding *encname) {
2671     int i;
2672     if ( encname->psnames!=NULL ) {
2673 	for ( i=0; i<encname->char_cnt; ++i )
2674 	    if ( encname->psnames[i]!=NULL && strcmp(name,encname->psnames[i])==0 )
2675 return( i );
2676     }
2677     i = UniFromName(name,interp,encname);
2678     if ( i==-1 && strlen(name)==4 ) {
2679 	/* MS says use this kind of name, Adobe says use the one above */
2680 	char *end;
2681 	i = strtol(name,&end,16);
2682 	if ( i<0 || i>0xffff || *end!='\0' )
2683 return( -1 );
2684     }
2685 return( EncFromUni(i,encname));
2686 }
2687 
SFExpandGlyphCount(SplineFont * sf,int newcnt)2688 void SFExpandGlyphCount(SplineFont *sf, int newcnt) {
2689     int old = sf->glyphcnt;
2690     FontViewBase *fv;
2691 
2692     if ( old>=newcnt )
2693 return;
2694     if ( sf->glyphmax<newcnt ) {
2695 	sf->glyphs = realloc(sf->glyphs,newcnt*sizeof(SplineChar *));
2696 	sf->glyphmax = newcnt;
2697     }
2698     memset(sf->glyphs+sf->glyphcnt,0,(newcnt-sf->glyphcnt)*sizeof(SplineChar *));
2699     sf->glyphcnt = newcnt;
2700 
2701     for ( fv=sf->fv; fv!=NULL; fv=fv->nextsame ) {
2702 	if ( fv->sf==sf ) {	/* Beware of cid keyed fonts which might look at a different subfont */
2703 	    if ( fv->normal!=NULL )
2704     continue;			/* If compacted then we haven't added any glyphs so haven't changed anything */
2705 	    /* Don't display any of these guys, so not mapped. */
2706 	    /*  No change to selection, or to map->map, but change to backmap */
2707 	    if ( newcnt>fv->map->backmax )
2708 		fv->map->backmap = realloc(fv->map->backmap,(fv->map->backmax = newcnt+5)*sizeof(int32));
2709 	    memset(fv->map->backmap+old,-1,(newcnt-old)*sizeof(int32));
2710 	}
2711     }
2712 }
2713