]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/ubidi_props.c
ICU-8.11.tar.gz
[apple/icu.git] / icuSources / common / ubidi_props.c
CommitLineData
73c04bcf
A
1/*
2*******************************************************************************
3*
4* Copyright (C) 2004-2006, International Business Machines
5* Corporation and others. All Rights Reserved.
6*
7*******************************************************************************
8* file name: ubidi_props.c
9* encoding: US-ASCII
10* tab size: 8 (not used)
11* indentation:4
12*
13* created on: 2004dec30
14* created by: Markus W. Scherer
15*
16* Low-level Unicode bidi/shaping properties access.
17*/
18
19#include "unicode/utypes.h"
20#include "unicode/uset.h"
21#include "unicode/udata.h" /* UDataInfo */
22#include "ucmndata.h" /* DataHeader */
23#include "udatamem.h"
24#include "umutex.h"
25#include "uassert.h"
26#include "cmemory.h"
27#include "utrie.h"
28#include "ubidi_props.h"
29#include "ucln_cmn.h"
30
31struct UBiDiProps {
32 UDataMemory *mem;
33 const int32_t *indexes;
34 const uint32_t *mirrors;
35 const uint8_t *jgArray;
36
37 UTrie trie;
38 uint8_t formatVersion[4];
39};
40
41/* data loading etc. -------------------------------------------------------- */
42
43#define UBIDI_HARDCODE_DATA 1
44
45#if UBIDI_HARDCODE_DATA
46
47/* ubidi_props_data.c is machine-generated by genbidi --csource */
48#include "ubidi_props_data.c"
49
50#else
51
52static UBool U_CALLCONV
53isAcceptable(void *context,
54 const char *type, const char *name,
55 const UDataInfo *pInfo) {
56 if(
57 pInfo->size>=20 &&
58 pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
59 pInfo->charsetFamily==U_CHARSET_FAMILY &&
60 pInfo->dataFormat[0]==UBIDI_FMT_0 && /* dataFormat="BiDi" */
61 pInfo->dataFormat[1]==UBIDI_FMT_1 &&
62 pInfo->dataFormat[2]==UBIDI_FMT_2 &&
63 pInfo->dataFormat[3]==UBIDI_FMT_3 &&
64 pInfo->formatVersion[0]==1 &&
65 pInfo->formatVersion[2]==UTRIE_SHIFT &&
66 pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
67 ) {
68 UBiDiProps *bdp=(UBiDiProps *)context;
69 uprv_memcpy(bdp->formatVersion, pInfo->formatVersion, 4);
70 return TRUE;
71 } else {
72 return FALSE;
73 }
74}
75
76static UBiDiProps *
77ubidi_openData(UBiDiProps *bdpProto,
78 const uint8_t *bin, int32_t length, UErrorCode *pErrorCode) {
79 UBiDiProps *bdp;
80 int32_t size;
81
82 bdpProto->indexes=(const int32_t *)bin;
83 if( (length>=0 && length<16*4) ||
84 bdpProto->indexes[UBIDI_IX_INDEX_TOP]<16
85 ) {
86 /* length or indexes[] too short for minimum indexes[] length of 16 */
87 *pErrorCode=U_INVALID_FORMAT_ERROR;
88 return NULL;
89 }
90 size=bdpProto->indexes[UBIDI_IX_INDEX_TOP]*4;
91 if(length>=0) {
92 if(length>=size && length>=bdpProto->indexes[UBIDI_IX_LENGTH]) {
93 length-=size;
94 } else {
95 /* length too short for indexes[] or for the whole data length */
96 *pErrorCode=U_INVALID_FORMAT_ERROR;
97 return NULL;
98 }
99 }
100 bin+=size;
101 /* from here on, assume that the sizes of the items fit into the total length */
102
103 /* unserialize the trie, after indexes[] */
104 size=bdpProto->indexes[UBIDI_IX_TRIE_SIZE];
105 utrie_unserialize(&bdpProto->trie, bin, size, pErrorCode);
106 if(U_FAILURE(*pErrorCode)) {
107 return NULL;
108 }
109 bin+=size;
110
111 /* get mirrors[] */
112 size=4*bdpProto->indexes[UBIDI_IX_MIRROR_LENGTH];
113 bdpProto->mirrors=(const uint32_t *)bin;
114 bin+=size;
115
116 /* get jgArray[] */
117 size=bdpProto->indexes[UBIDI_IX_JG_LIMIT]-bdpProto->indexes[UBIDI_IX_JG_START];
118 bdpProto->jgArray=bin;
119 bin+=size;
120
121 /* allocate, copy, and return the new UBiDiProps */
122 bdp=(UBiDiProps *)uprv_malloc(sizeof(UBiDiProps));
123 if(bdp==NULL) {
124 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
125 return NULL;
126 } else {
127 uprv_memcpy(bdp, bdpProto, sizeof(UBiDiProps));
128 return bdp;
129 }
130}
131
132U_CAPI UBiDiProps * U_EXPORT2
133ubidi_openProps(UErrorCode *pErrorCode) {
134 UBiDiProps bdpProto={ NULL }, *bdp;
135
136 bdpProto.mem=udata_openChoice(NULL, UBIDI_DATA_TYPE, UBIDI_DATA_NAME, isAcceptable, &bdpProto, pErrorCode);
137 if(U_FAILURE(*pErrorCode)) {
138 return NULL;
139 }
140
141 bdp=ubidi_openData(
142 &bdpProto,
143 udata_getMemory(bdpProto.mem),
144 udata_getLength(bdpProto.mem),
145 pErrorCode);
146 if(U_FAILURE(*pErrorCode)) {
147 udata_close(bdpProto.mem);
148 return NULL;
149 } else {
150 return bdp;
151 }
152}
153
154U_CAPI UBiDiProps * U_EXPORT2
155ubidi_openBinary(const uint8_t *bin, int32_t length, UErrorCode *pErrorCode) {
156 UBiDiProps bdpProto={ NULL };
157 const DataHeader *hdr;
158
159 if(U_FAILURE(*pErrorCode)) {
160 return NULL;
161 }
162 if(bin==NULL) {
163 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
164 return NULL;
165 }
166
167 /* check the header */
168 if(length>=0 && length<20) {
169 *pErrorCode=U_INVALID_FORMAT_ERROR;
170 return NULL;
171 }
172 hdr=(const DataHeader *)bin;
173 if(
174 !(hdr->dataHeader.magic1==0xda && hdr->dataHeader.magic2==0x27 &&
175 hdr->info.isBigEndian==U_IS_BIG_ENDIAN &&
176 isAcceptable(&bdpProto, UBIDI_DATA_TYPE, UBIDI_DATA_NAME, &hdr->info))
177 ) {
178 *pErrorCode=U_INVALID_FORMAT_ERROR;
179 return NULL;
180 }
181
182 bin+=hdr->dataHeader.headerSize;
183 if(length>=0) {
184 length-=hdr->dataHeader.headerSize;
185 }
186 return ubidi_openData(&bdpProto, bin, length, pErrorCode);
187}
188
189#endif
190
191U_CAPI void U_EXPORT2
192ubidi_closeProps(UBiDiProps *bdp) {
193 if(bdp!=NULL) {
194#if !UBIDI_HARDCODE_DATA
195 udata_close(bdp->mem);
196#endif
197 uprv_free(bdp);
198 }
199}
200
201/* UBiDiProps singleton ----------------------------------------------------- */
202
203static UBiDiProps *gBdp=NULL, *gBdpDummy=NULL;
204#if !UBIDI_HARDCODE_DATA
205static UErrorCode gErrorCode=U_ZERO_ERROR;
206static int8_t gHaveData=0;
207#endif
208
209static UBool U_CALLCONV
210ubidi_cleanup(void) {
211 ubidi_closeProps(gBdp);
212 gBdp=NULL;
213 ubidi_closeProps(gBdpDummy);
214 gBdpDummy=NULL;
215#if !UBIDI_HARDCODE_DATA
216 gErrorCode=U_ZERO_ERROR;
217 gHaveData=0;
218#endif
219 return TRUE;
220}
221
222U_CAPI const UBiDiProps * U_EXPORT2
223ubidi_getSingleton(UErrorCode *pErrorCode) {
224#if UBIDI_HARDCODE_DATA
225 if(U_FAILURE(*pErrorCode)) {
226 return NULL;
227 }
228 return &ubidi_props_singleton;
229#else
230 int8_t haveData;
231
232 if(U_FAILURE(*pErrorCode)) {
233 return NULL;
234 }
235
236 UMTX_CHECK(NULL, gHaveData, haveData);
237
238 if(haveData>0) {
239 /* data was loaded */
240 return gBdp;
241 } else if(haveData<0) {
242 /* data loading failed */
243 *pErrorCode=gErrorCode;
244 return NULL;
245 } else /* haveData==0 */ {
246 /* load the data */
247 UBiDiProps *bdp=ubidi_openProps(pErrorCode);
248 if(U_FAILURE(*pErrorCode)) {
249 gHaveData=-1;
250 gErrorCode=*pErrorCode;
251 return NULL;
252 }
253
254 /* set the static variables */
255 umtx_lock(NULL);
256 if(gBdp==NULL) {
257 gBdp=bdp;
258 bdp=NULL;
259 gHaveData=1;
260 ucln_common_registerCleanup(UCLN_COMMON_UBIDI, ubidi_cleanup);
261 }
262 umtx_unlock(NULL);
263
264 ubidi_closeProps(bdp);
265 return gBdp;
266 }
267#endif
268}
269
270U_CAPI const UBiDiProps * U_EXPORT2
271ubidi_getDummy(UErrorCode *pErrorCode) {
272 UBiDiProps *bdp;
273
274 if(U_FAILURE(*pErrorCode)) {
275 return NULL;
276 }
277
278 UMTX_CHECK(NULL, gBdpDummy, bdp);
279
280 if(bdp!=NULL) {
281 /* the dummy object was already created */
282 return bdp;
283 } else /* bdp==NULL */ {
284 /* create the dummy object */
285 int32_t *indexes;
286
287 bdp=(UBiDiProps *)uprv_malloc(sizeof(UBiDiProps)+UBIDI_IX_TOP*4+UTRIE_DUMMY_SIZE);
288 if(bdp==NULL) {
289 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
290 return NULL;
291 }
292 uprv_memset(bdp, 0, sizeof(UBiDiProps)+UBIDI_IX_TOP*4);
293
294 bdp->indexes=indexes=(int32_t *)(bdp+1);
295 indexes[UBIDI_IX_INDEX_TOP]=UBIDI_IX_TOP;
296
297 indexes[UBIDI_IX_TRIE_SIZE]=
298 utrie_unserializeDummy(&bdp->trie, indexes+UBIDI_IX_TOP, UTRIE_DUMMY_SIZE, 0, 0, TRUE, pErrorCode);
299 if(U_FAILURE(*pErrorCode)) {
300 uprv_free(bdp);
301 return NULL;
302 }
303
304 bdp->formatVersion[0]=1;
305 bdp->formatVersion[2]=UTRIE_SHIFT;
306 bdp->formatVersion[3]=UTRIE_INDEX_SHIFT;
307
308 /* set the static variables */
309 umtx_lock(NULL);
310 if(gBdpDummy==NULL) {
311 gBdpDummy=bdp;
312 bdp=NULL;
313 ucln_common_registerCleanup(UCLN_COMMON_UBIDI, ubidi_cleanup);
314 }
315 umtx_unlock(NULL);
316
317 uprv_free(bdp);
318 return gBdpDummy;
319 }
320}
321
322/* set of property starts for UnicodeSet ------------------------------------ */
323
324static UBool U_CALLCONV
325_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
326 /* add the start code point to the USet */
327 const USetAdder *sa=(const USetAdder *)context;
328 sa->add(sa->set, start);
329 return TRUE;
330}
331
332U_CAPI void U_EXPORT2
333ubidi_addPropertyStarts(const UBiDiProps *bdp, const USetAdder *sa, UErrorCode *pErrorCode) {
334 int32_t i, length;
335 UChar32 c, start, limit;
336
337 const uint8_t *jgArray;
338 uint8_t prev, jg;
339
340 if(U_FAILURE(*pErrorCode)) {
341 return;
342 }
343
344 /* add the start code point of each same-value range of the trie */
345 utrie_enum(&bdp->trie, NULL, _enumPropertyStartsRange, sa);
346
347 /* add the code points from the bidi mirroring table */
348 length=bdp->indexes[UBIDI_IX_MIRROR_LENGTH];
349 for(i=0; i<length; ++i) {
350 c=UBIDI_GET_MIRROR_CODE_POINT(bdp->mirrors[i]);
351 sa->addRange(sa->set, c, c+1);
352 }
353
354 /* add the code points from the Joining_Group array where the value changes */
355 start=bdp->indexes[UBIDI_IX_JG_START];
356 limit=bdp->indexes[UBIDI_IX_JG_LIMIT];
357 jgArray=bdp->jgArray;
358 prev=0;
359 while(start<limit) {
360 jg=*jgArray++;
361 if(jg!=prev) {
362 sa->add(sa->set, start);
363 prev=jg;
364 }
365 ++start;
366 }
367 if(prev!=0) {
368 /* add the limit code point if the last value was not 0 (it is now start==limit) */
369 sa->add(sa->set, limit);
370 }
371
372 /* add code points with hardcoded properties, plus the ones following them */
373
374 /* (none right now) */
375}
376
377/* data access primitives --------------------------------------------------- */
378
379/* UTRIE_GET16() itself validates c */
380#define GET_PROPS(bdp, c, result) \
381 UTRIE_GET16(&(bdp)->trie, c, result);
382
383/* property access functions ------------------------------------------------ */
384
385U_CFUNC int32_t
386ubidi_getMaxValue(const UBiDiProps *bdp, UProperty which) {
387 int32_t max;
388
389 if(bdp==NULL) {
390 return -1;
391 }
392
393 max=bdp->indexes[UBIDI_MAX_VALUES_INDEX];
394 switch(which) {
395 case UCHAR_BIDI_CLASS:
396 return (max&UBIDI_CLASS_MASK);
397 case UCHAR_JOINING_GROUP:
398 return (max&UBIDI_MAX_JG_MASK)>>UBIDI_MAX_JG_SHIFT;
399 case UCHAR_JOINING_TYPE:
400 return (max&UBIDI_JT_MASK)>>UBIDI_JT_SHIFT;
401 default:
402 return -1; /* undefined */
403 }
404}
405
406U_CAPI UCharDirection U_EXPORT2
407ubidi_getClass(const UBiDiProps *bdp, UChar32 c) {
408 uint32_t props;
409 GET_PROPS(bdp, c, props);
410 return (UCharDirection)UBIDI_GET_CLASS(props);
411}
412
413U_CAPI UBool U_EXPORT2
414ubidi_isMirrored(const UBiDiProps *bdp, UChar32 c) {
415 uint32_t props;
416 GET_PROPS(bdp, c, props);
417 return (UBool)UBIDI_GET_FLAG(props, UBIDI_IS_MIRRORED_SHIFT);
418}
419
420U_CAPI UChar32 U_EXPORT2
421ubidi_getMirror(const UBiDiProps *bdp, UChar32 c) {
422 uint32_t props;
423 int32_t delta;
424
425 GET_PROPS(bdp, c, props);
426 delta=((int16_t)props)>>UBIDI_MIRROR_DELTA_SHIFT;
427 if(delta!=UBIDI_ESC_MIRROR_DELTA) {
428 return c+delta;
429 } else {
430 /* look for mirror code point in the mirrors[] table */
431 const uint32_t *mirrors;
432 uint32_t m;
433 int32_t i, length;
434 UChar32 c2;
435
436 mirrors=bdp->mirrors;
437 length=bdp->indexes[UBIDI_IX_MIRROR_LENGTH];
438
439 /* linear search */
440 for(i=0; i<length; ++i) {
441 m=mirrors[i];
442 c2=UBIDI_GET_MIRROR_CODE_POINT(m);
443 if(c==c2) {
444 /* found c, return its mirror code point using the index in m */
445 return UBIDI_GET_MIRROR_CODE_POINT(mirrors[UBIDI_GET_MIRROR_INDEX(m)]);
446 } else if(c<c2) {
447 break;
448 }
449 }
450
451 /* c not found, return it itself */
452 return c;
453 }
454}
455
456U_CAPI UBool U_EXPORT2
457ubidi_isBidiControl(const UBiDiProps *bdp, UChar32 c) {
458 uint32_t props;
459 GET_PROPS(bdp, c, props);
460 return (UBool)UBIDI_GET_FLAG(props, UBIDI_BIDI_CONTROL_SHIFT);
461}
462
463U_CAPI UBool U_EXPORT2
464ubidi_isJoinControl(const UBiDiProps *bdp, UChar32 c) {
465 uint32_t props;
466 GET_PROPS(bdp, c, props);
467 return (UBool)UBIDI_GET_FLAG(props, UBIDI_JOIN_CONTROL_SHIFT);
468}
469
470U_CAPI UJoiningType U_EXPORT2
471ubidi_getJoiningType(const UBiDiProps *bdp, UChar32 c) {
472 uint32_t props;
473 GET_PROPS(bdp, c, props);
474 return (UJoiningType)((props&UBIDI_JT_MASK)>>UBIDI_JT_SHIFT);
475}
476
477U_CAPI UJoiningGroup U_EXPORT2
478ubidi_getJoiningGroup(const UBiDiProps *bdp, UChar32 c) {
479 UChar32 start, limit;
480
481 start=bdp->indexes[UBIDI_IX_JG_START];
482 limit=bdp->indexes[UBIDI_IX_JG_LIMIT];
483 if(start<=c && c<limit) {
484 return (UJoiningGroup)bdp->jgArray[c-start];
485 } else {
486 return U_JG_NO_JOINING_GROUP;
487 }
488}
489
490/* public API (see uchar.h) ------------------------------------------------- */
491
492U_CAPI UCharDirection U_EXPORT2
493u_charDirection(UChar32 c) {
494 UErrorCode errorCode=U_ZERO_ERROR;
495 const UBiDiProps *bdp=ubidi_getSingleton(&errorCode);
496 if(bdp!=NULL) {
497 return ubidi_getClass(bdp, c);
498 } else {
499 return U_LEFT_TO_RIGHT;
500 }
501}
502
503U_CAPI UBool U_EXPORT2
504u_isMirrored(UChar32 c) {
505 UErrorCode errorCode=U_ZERO_ERROR;
506 const UBiDiProps *bdp=ubidi_getSingleton(&errorCode);
507 return (UBool)(bdp!=NULL && ubidi_isMirrored(bdp, c));
508}
509
510U_CAPI UChar32 U_EXPORT2
511u_charMirror(UChar32 c) {
512 UErrorCode errorCode=U_ZERO_ERROR;
513 const UBiDiProps *bdp=ubidi_getSingleton(&errorCode);
514 if(bdp!=NULL) {
515 return ubidi_getMirror(bdp, c);
516 } else {
517 return c;
518 }
519}