1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2013 by Jose Da Silva */
3 /*
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6 
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9 
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13 
14  * The name of the author may not be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <fontforge-config.h>
30 
31 #include "ffglib.h"
32 #include "unicodelibinfo.h"
33 #include "ustring.h"
34 
35 #ifndef _NO_LIBUNINAMESLIST
36 #include <uninameslist.h>
37 #else
38 struct unicode_block {
39 	int start, end;
40 	const char *name;
41 };
42 #endif
43 const struct unicode_nameannot * const *const *_UnicodeNameAnnot = NULL; /* deprecated */
44 const struct unicode_block *_UnicodeBlock = NULL;
45 #ifndef _NO_LIBUNICODENAMES
46 #include <libunicodenames.h>
47 uninm_names_db names_db; /* Unicode character names and annotations database */
48 uninm_blocks_db blocks_db;
49 #endif
50 
51 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
52 #else
53 static const char *chosung[] = { "G", "GG", "N", "D", "DD", "L", "M", "B",	\
54 	"BB", "S", "SS", "", "J", "JJ", "C", "K", "T", "P", "H", NULL };
55 static const char *jungsung[] = { "A", "AE", "YA", "YAE", "EO", "E", "YEO",	\
56 	"YE", "O", "WA", "WAE", "OE", "YO", "U", "WEO", "WE", "WI", "YU",	\
57 	"EU", "YI", "I", NULL };
58 static const char *jongsung[] = { "", "G", "GG", "GS", "N", "NJ", "NH", "D",	\
59 	"L", "LG", "LM", "LB", "LS", "LT", "LP", "LH", "M", "B", "BS", "S",	\
60 	"SS", "NG", "J", "C", "K", "T", "P", "H", NULL };
61 #endif
62 
inituninameannot(void)63 void inituninameannot(void) {
64 /* Initialize unicode name-annotation library access for FontForge */
65 
66 #if _NO_LIBUNINAMESLIST
67     _UnicodeNameAnnot = NULL; /* libuninameslist not available */
68     _UnicodeBlock = NULL;
69 #else
70     /* backward compatibility for other programs using libuninames */
71     _UnicodeNameAnnot = UnicodeNameAnnot;
72     _UnicodeBlock = UnicodeBlock;
73 #endif
74 
75 #ifndef _NO_LIBUNICODENAMES
76     /* Open database file, read data for this 'local', then close. */
77     char *names_db_file;
78     char *blocks_db_file;
79 
80     /* Load character names and annotations that come from the Unicode NamesList.txt */
81     /* This should not be done until after the locale has been set */
82     names_db_file = uninm_find_names_db(NULL);
83     names_db = (names_db_file == NULL) ? ((uninm_names_db) 0) : uninm_names_db_open(names_db_file);
84     free(names_db_file);
85     /* NOTE: you need to do uninm_names_db_close(names_db); when you exit program */
86 
87     blocks_db_file = uninm_find_blocks_db(NULL);
88     blocks_db = (blocks_db_file == NULL) ? ((uninm_blocks_db) 0) : uninm_blocks_db_open(blocks_db_file);
89     free(blocks_db_file);
90     /* NOTE: you need to do uninm_blocks_db_close(blocks_db); when you exit program */
91 #endif
92 }
93 
unicode_name(int32 unienc)94 char *unicode_name(int32 unienc) {
95 /* Return the unicode name for the value given from a data library.	  */
96 /* If there's no data available for this code, or no library, return NULL */
97 /* User should free the return string when finished with this information */
98 
99 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
100     /* no nameslist library code available to use */
101     //fprintf(stderr,"no library\n");
102     return( NULL );
103 #else
104     /* have nameslist library code available to use */
105     if ( unienc<0 || unienc>=0x110000 )
106 	return( NULL );
107 
108     char *name_data=NULL;
109 #ifndef _NO_LIBUNINAMESLIST
110 #if (_LIBUNINAMESLIST_FUN <= 3)
111     /* old libuninameslist library code */
112     if ( _UnicodeNameAnnot!=NULL &&
113 	    _UnicodeNameAnnot[unienc>>16][(unienc>>8)&0xff][unienc&0xff].name!=NULL ) {
114 	name_data=copy(_UnicodeNameAnnot[unienc>>16][(unienc>>8)&0xff][unienc&0xff].name);
115     }
116     //fprintf(stderr,"use old code library ->%s<-\n",name_data);
117 #else
118     /* new libuninameslist library code */
119     name_data=copy(uniNamesList_name(unienc));
120     //fprintf(stderr,"new library ->%s<-\n",name_data\n");
121 #endif
122 #else
123     /* libunicodesnames library code */
124     name_data=copy(uninm_name(names_db,(unsigned int)(unienc)));
125     //fprintf(stderr,"libunicodes library ->%s<-\n",name_data);
126 #endif
127 
128     /* Unicode name derivation rule NR1
129      * Code moved here from fontforgeexe/fontview.c
130      * FIXME: maybe this belongs to lower library stack instead,
131      * revisit later.
132      */
133     if( ( unienc >= 0xAC00 && unienc <= 0xD7A3 ) && ( name_data == NULL ) ) {
134 	name_data = smprintf( "HANGUL SYLLABLE %s%s%s",
135 		chosung [ (unienc - 0xAC00) / (21*28) ],
136 		jungsung[ ((unienc - 0xAC00) / 28 ) % 21 ],
137 		jongsung[ (unienc - 0xAC00) % 28 ] );
138     }
139 
140     return( name_data );
141 #endif
142 }
143 
144 #ifndef _NO_LIBUNINAMESLIST
unicode_nicer(const char * from)145 static char *unicode_nicer(const char *from) {
146 /* Return nicer looking unicode annotations by changing the '*' to bullet */
147 /* and other markers to fancier utf8 style symbols. if empty, return NULL */
148 /* User should free the return string when finished with this information */
149     const char *pf;
150     char ch,*to,*pt;
151     long c;
152     int l;
153 
154     if ( from==NULL )
155 	return( NULL );
156 
157     /* check if we need to convert some chars to bullets and symbols */
158     c=l=0;
159     for ( pf=from; (ch=*pf++)!='\0'; ++l ) if ( ch=='\t' ) {
160 	/* require extra space for these larger utf8 type chars */
161 	if ( *pf=='*' || *pf=='%' || *pf=='x' || *pf=='~' || *pf==':' || *pf=='#' ) ++c;
162     }
163 
164     if ( (pt=to=malloc(l+c+c+1))!=NULL ) {
165 	if ( c ) {
166 	    while ( (ch=*pt++=*from++)!='\0' ) if (ch=='\t' ) {
167 		if ( *from=='*' ) {
168 		    c=0x2022; goto unicode_expand_c; /* 0x2022, bullet */
169 		} else if ( *from=='%' ) {
170 		    c=0x203b; goto unicode_expand_c; /* 0x203b, reference mark */
171 		} else if ( *from=='x' ) {
172 		    c=0x2192; goto unicode_expand_c; /* 0x2192, rightwards arrow */
173 		} else if ( *from=='~' ) {
174 		    c=0x2053; goto unicode_expand_c; /* 0x2053, swung dash */
175 		} else if ( *from==':' ) {
176 		    c=0x2261; goto unicode_expand_c; /* 0x2261, identical to */
177 		} else if ( *from=='#' ) {
178 		    c=0x2248; goto unicode_expand_c; /* 0x2248, almost equal to */
179 unicode_expand_c:
180 		    ++from;
181 		    *pt++ =0xe0+((c>>12)&0x0f);
182 		    *pt++ =0x80+((c>>6)&0x3f);
183 		    *pt++ =0x80+(c&0x3f);
184 		}
185 	    }
186 	} else
187 	    /* simply copy information verbatim, without the need to edit */
188 	    while ( (*pt++=*from++)!='\0' );
189     }
190 
191     return( to );
192 }
193 
unicode_block_check(int block_i)194 static int unicode_block_check(int block_i) {
195 #if (_LIBUNINAMESLIST_FUN <= 3)
196 /* Older uninameslist database needs to be checked from start since we do */
197 /* not know which is the last block. Currently this should be around 234. */
198     if ( _UnicodeBlock!=NULL ) {
199 	int i;
200 
201 	for ( i=0; i<block_i; ++i )
202 	    if ( _UnicodeBlock[i].end>=0x10ffff )
203 		break;
204 	if ( i==block_i )
205 	    return( i );
206     }
207     return( -1 );
208 #else
209     /* libuninameslist-0.4.2014____ has a function to return block count. */
210     if ( _UnicodeBlock!=NULL && block_i < uniNamesList_blockCount() )
211 	return( block_i );
212     return( -1 );
213 #endif
214 }
215 #endif
216 
unicode_annot(int32 unienc)217 char *unicode_annot(int32 unienc) {
218 /* Return the unicode annotation for the value given from a data library. */
219 /* If there's no data available for this code, or no library, return NULL */
220 /* User should free the return string when finished with this information */
221 
222 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
223     /* no nameslist library code available to use */
224     //fprintf(stderr,"no library - annotation\n");
225     return( NULL );
226 #else
227     /* have nameslist library code available to use */
228     if ( unienc<0 || unienc>=0x110000 )
229 	return( NULL );
230 
231     char *annot_data=NULL;
232 
233 #ifndef _NO_LIBUNINAMESLIST
234 #if (_LIBUNINAMESLIST_FUN <= 3)
235     /* old libuninameslist library code */
236     if ( _UnicodeNameAnnot!=NULL &&
237 	    _UnicodeNameAnnot[unienc>>16][(unienc>>8)&0xff][unienc&0xff].annot!=NULL ) {
238 	annot_data=unicode_nicer(_UnicodeNameAnnot[unienc>>16][(unienc>>8)&0xff][unienc&0xff].annot);
239     }
240     //fprintf(stderr,"use old code unicode_annot() - annotation ->%s<-\n",annot_data);
241 #else
242     /* new libuninameslist library code */
243     annot_data=unicode_nicer(uniNamesList_annot(unienc));
244     //fprintf(stderr,"new unicode_annot() - annotation ->%s<-\n",annot_data);
245 #endif
246 #else
247     /* libunicodesnames library code */
248     annot_data=copy(uninm_annotation(names_db,(unsigned int)(unienc)));
249     //fprintf(stderr,"libunicodes unicode_annot() - annotation ->%s<-\n",annot_data);
250 #endif
251 
252     return( annot_data );
253 #endif
254 }
255 
unicode_block_count(void)256 int32 unicode_block_count(void) {
257 /* Return the number of unicode blocks contained in this NameList library */
258 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
259     /* no nameslist library available to use */
260     return( -1 );
261 #else
262     int32 unicount;
263 
264     unicount=-1;
265 #ifndef _NO_LIBUNINAMESLIST
266 #if (_LIBUNINAMESLIST_FUN >= 4)
267     /* version 0.4+ have function to do this */
268     unicount=uniNamesList_blockCount();
269     //fprintf(stderr,"ver 0.4+ unicode_block_count(), have %d\n",unicount);
270 #else
271     /* old libuninameslist<=0.3 library code */
272     if ( _UnicodeBlock!=NULL ) {
273 	int i;
274 
275 	for ( i=0; i<100000; ++i )
276 	    if ( _UnicodeBlock[i].end>=0x10ffff )
277 		break;
278 	if ( i>0 )
279 	    unicount = i;
280 	//fprintf(stderr,"old code unicode_block_count(), have %d, %d\n",i,unicount);
281     }
282 #endif
283 #else
284     /* libunicodesnames library code */
285     unicount=uninm_num_blocks(blocks_db);
286     //fprintf(stderr,"libunicodes unicode_block_count() have %d\n",unicount);
287 #endif
288 
289     return( unicount );
290 #endif
291 }
292 
unicode_block_start(int32 block_i)293 int32 unicode_block_start(int32 block_i) {
294 /* Return the unicode value for the start of next unicode block. If no	  */
295 /* library or data available, then return -1.				  */
296 
297 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
298     /* no nameslist library available to use */
299     //fprintf(stderr,"no block library\n");
300     return( -1 );
301 #else
302     int32 unistart;
303 
304     unistart=-1;
305 #ifndef _NO_LIBUNINAMESLIST
306 #if (_LIBUNINAMESLIST_FUN >= 4)
307     /* version 0.4+ have function to do this */
308     unistart=uniNamesList_blockStart(block_i);
309     //fprintf(stderr,"ver 0.4+ code unicode_block_start(), have %d %d\n",block_i,unistart);
310 #else
311     /* old libuninameslist<=0.3 library code */
312     if ( (unistart=unicode_block_check(block_i))>=0 )
313 	unistart=_UnicodeBlock[unistart].start;
314     //fprintf(stderr,"use old code unicode_block_start(), have %d %d\n",block_i,unistart);
315 #endif
316 #else
317     /* libunicodesnames library code */
318     unistart=uninm_block_start(blocks_db,(unsigned int)(block_i));
319     //fprintf(stderr,"libunicodes unicode_block_start()have %d %d\n",block_i,unistart);
320 #endif
321 
322     return( unistart );
323 #endif
324 }
325 
unicode_block_end(int32 block_i)326 int32 unicode_block_end(int32 block_i) {
327 /* Return the unicode value for the end of this unicode block. If there	  */
328 /* is no library or data available, then return -1			  */
329 
330 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
331     /* no nameslist library available to use */
332     //fprintf(stderr,"no block library\n");
333     return( -1 );
334 #else
335     int32 uniend;
336 
337     uniend=-1;
338 #ifndef _NO_LIBUNINAMESLIST
339 #if (_LIBUNINAMESLIST_FUN >= 4)
340     /* version 0.4+ have function to do this */
341     uniend=uniNamesList_blockEnd(block_i);
342     //fprintf(stderr,"ver 0.4+ code unicode_block_end(), have %d %d\n",block_i,uniend);
343 #else
344     /* old libuninameslist<=0.3 library code */
345     if ( (uniend=unicode_block_check(block_i))>=0 )
346 	uniend=_UnicodeBlock[uniend].end;
347     //fprintf(stderr,"use old code unicode_block_end(), have %d %d\n",block_i,uniend);
348 #endif
349 #else
350     /* libunicodesnames library code */
351     uniend=uninm_block_end(blocks_db,(unsigned int)(block_i));
352     //fprintf(stderr,"libunicodes unicode_block_end(), have %d %d\n",block_i,uniend);
353 #endif
354 
355     return( uniend );
356 #endif
357 }
358 
unicode_block_name(int32 block_i)359 char *unicode_block_name(int32 block_i) {
360 /* Return the unicode name for this unicode block. If there is no library */
361 /* then return NULL							  */
362 
363 #if _NO_LIBUNINAMESLIST && _NO_LIBUNICODENAMES
364     /* no nameslist library code available to use */
365     //fprintf(stderr,"no library\n");
366     return( NULL );
367 #else
368     char *name_data=NULL;
369 #ifndef _NO_LIBUNINAMESLIST
370 #if (_LIBUNINAMESLIST_FUN >= 4)
371     /* version 0.4+ have function to do this */
372     name_data=copy(uniNamesList_blockName(block_i));
373     //fprintf(stderr,"ver 0.4+ code unicode_block_name(), have %d ->%s<-\n",block_i,name_data);
374 #else
375     int i;
376     /* old libuninameslist<=0.3 library code */
377     if ( (i=unicode_block_check(block_i))>=0 )
378 	name_data=copy(_UnicodeBlock[i].name);
379     //fprintf(stderr,"use old code unicode_block_name(), have %d %d ->%s<-\n",i,block_i,name_data);
380 #endif
381 #else
382     /* libunicodesnames library code */
383     name_data=copy(uninm_block_name(blocks_db,(unsigned int)(block_i)));
384     //fprintf(stderr,"libunicodes unicode_block_name() %d ->%s<-\n",block_i,name_data);
385 #endif
386 
387     return( name_data );
388 #endif
389 }
390 
391 /* libuninameslist 0.5 and higher functions, otherwise return NULL or -1. */
392 #if !(_NO_LIBUNINAMESLIST) && (_LIBUNINAMESLIST_FUN >= 5)
393 /* Get count for libuninameslist names2 table list-size available to read */
unicode_names2cnt(void)394 int32 unicode_names2cnt(void) {
395     return( (int32)(uniNamesList_names2cnt()) );
396 }
397 
398 /* Return unicode value for "Nth" internal table location or -1 if error. */
unicode_names2valFrmTab(int32 n)399 int32 unicode_names2valFrmTab(int32 n) {
400     return( (int32)(uniNamesList_names2val(n)) );
401 }
402 
403 /* Return "Nth" internal_table_location for this unicode value. None==-1. */
unicode_names2getUtabLoc(int32 unienc)404 int32 unicode_names2getUtabLoc(int32 unienc) {
405     return( (int32)(uniNamesList_names2getU((unsigned long)(unienc))) );
406 }
407 
408 /* Return unicode name2 for "Nth" internal table location. NULL if error. */
409 /* NOTE: free() the string before exiting fontforge to avoid memory leak. */
unicode_name2FrmTab(int32 n)410 char *unicode_name2FrmTab(int32 n) {
411     int l;
412     char *p;
413     if ( n<0 || n>=uniNamesList_names2cnt() )
414 	return( NULL );
415     l=uniNamesList_names2lnC((int)(n))*sizeof(char);
416     if ( (p=(char *)(calloc(1,l+sizeof(char))))==NULL )
417 	return( NULL );
418     memcpy(p,uniNamesList_names2anC((int)(n)),l);
419     return( p );
420 }
421 
422 /* Return unicode name2 for unicode "unienc" if exists, else return NULL. */
423 /* NOTE: free() the string before exiting fontforge to avoid memory leak. */
unicode_name2(int32 unienc)424 char *unicode_name2(int32 unienc) {
425     return( unicode_name2FrmTab(unicode_names2getUtabLoc(unienc)) );
426 }
427 #else
428 /* libuninameslist ver0.4 or older, or libunicodenames return NULL or -1. */
429 /* for these older libraries, we would need to search entire list to find */
430 /* about 28 or less possible names2 codes. This isn't an effective use of */
431 /* computer use and it's better for user to use a more recent names list. */
unicode_names2cnt(void)432 int32 unicode_names2cnt(void) {
433     return( -1 );
434 }
unicode_names2valFrmTab(int32 n)435 int32 unicode_names2valFrmTab(int32 n) {
436     return( -1 );
437 }
unicode_names2getUtabLoc(int32 unienc)438 int32 unicode_names2getUtabLoc(int32 unienc) {
439     return( -1 );
440 }
unicode_name2FrmTab(int32 n)441 char *unicode_name2FrmTab(int32 n) {
442     return( NULL );
443 }
unicode_name2(int32 unienc)444 char *unicode_name2(int32 unienc) {
445     return( NULL );
446 }
447 #endif
448 
unicode_library_version(void)449 char *unicode_library_version(void) {
450 /* Return the unicode version for this library. Sometimes users still use */
451 /* older libuninameslist or libunincodenames libraries because they don't */
452 /* realize that these need to be updated to keep current too but not made */
453 /* at same time that FontForge is released (release dates not in sync).   */
454 
455 #if !(_NO_LIBUNINAMESLIST) && (_LIBUNINAMESLIST_FUN >= 3)
456     /* libuninameslist-0.3.20130501-1 and later have a "version" function */
457     char *version_str;
458 
459     version_str=copy(uniNamesList_NamesListVersion());
460 
461     return( version_str );
462 #else
463     /* Libunicodenames and older versions of libuninames don't have a ver */
464     /* function so we need to either test various annotations to find out */
465     /* what version we have, or we keep it simple and just return nothing */
466     return( NULL );
467 #endif
468 }
469