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