- support of [Strings.LanguageID]-sections for inf-files added in setupapi
[reactos.git] / reactos / lib / 3rdparty / icu4ros / icu / source / common / ubidi_props.c
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2004-2007, 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
31 struct 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
52 static UBool U_CALLCONV
53 isAcceptable(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
76 static UBiDiProps *
77 ubidi_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
132 U_CFUNC UBiDiProps *
133 ubidi_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
154 U_CFUNC UBiDiProps *
155 ubidi_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
191 U_CFUNC void
192 ubidi_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
203 static UBiDiProps *gBdpDummy=NULL;
204 #if !UBIDI_HARDCODE_DATA
205 static UBiDiProps *gBdp=NULL;
206 static UErrorCode gErrorCode=U_ZERO_ERROR;
207 static int8_t gHaveData=0;
208 #endif
209
210 static UBool U_CALLCONV
211 ubidi_cleanup(void) {
212 ubidi_closeProps(gBdpDummy);
213 gBdpDummy=NULL;
214 #if !UBIDI_HARDCODE_DATA
215 ubidi_closeProps(gBdp);
216 gBdp=NULL;
217 gErrorCode=U_ZERO_ERROR;
218 gHaveData=0;
219 #endif
220 return TRUE;
221 }
222
223 U_CFUNC const UBiDiProps *
224 ubidi_getSingleton(UErrorCode *pErrorCode) {
225 #if UBIDI_HARDCODE_DATA
226 if(U_FAILURE(*pErrorCode)) {
227 return NULL;
228 }
229 return &ubidi_props_singleton;
230 #else
231 int8_t haveData;
232
233 if(U_FAILURE(*pErrorCode)) {
234 return NULL;
235 }
236
237 UMTX_CHECK(NULL, gHaveData, haveData);
238
239 if(haveData>0) {
240 /* data was loaded */
241 return gBdp;
242 } else if(haveData<0) {
243 /* data loading failed */
244 *pErrorCode=gErrorCode;
245 return NULL;
246 } else /* haveData==0 */ {
247 /* load the data */
248 UBiDiProps *bdp=ubidi_openProps(pErrorCode);
249 if(U_FAILURE(*pErrorCode)) {
250 gHaveData=-1;
251 gErrorCode=*pErrorCode;
252 return NULL;
253 }
254
255 /* set the static variables */
256 umtx_lock(NULL);
257 if(gBdp==NULL) {
258 gBdp=bdp;
259 bdp=NULL;
260 gHaveData=1;
261 ucln_common_registerCleanup(UCLN_COMMON_UBIDI, ubidi_cleanup);
262 }
263 umtx_unlock(NULL);
264
265 ubidi_closeProps(bdp);
266 return gBdp;
267 }
268 #endif
269 }
270
271 U_CAPI const UBiDiProps *
272 ubidi_getDummy(UErrorCode *pErrorCode) {
273 UBiDiProps *bdp;
274
275 if(U_FAILURE(*pErrorCode)) {
276 return NULL;
277 }
278
279 UMTX_CHECK(NULL, gBdpDummy, bdp);
280
281 if(bdp!=NULL) {
282 /* the dummy object was already created */
283 return bdp;
284 } else /* bdp==NULL */ {
285 /* create the dummy object */
286 int32_t *indexes;
287
288 bdp=(UBiDiProps *)uprv_malloc(sizeof(UBiDiProps)+UBIDI_IX_TOP*4+UTRIE_DUMMY_SIZE);
289 if(bdp==NULL) {
290 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
291 return NULL;
292 }
293 uprv_memset(bdp, 0, sizeof(UBiDiProps)+UBIDI_IX_TOP*4);
294
295 bdp->indexes=indexes=(int32_t *)(bdp+1);
296 indexes[UBIDI_IX_INDEX_TOP]=UBIDI_IX_TOP;
297
298 indexes[UBIDI_IX_TRIE_SIZE]=
299 utrie_unserializeDummy(&bdp->trie, indexes+UBIDI_IX_TOP, UTRIE_DUMMY_SIZE, 0, 0, TRUE, pErrorCode);
300 if(U_FAILURE(*pErrorCode)) {
301 uprv_free(bdp);
302 return NULL;
303 }
304
305 bdp->formatVersion[0]=1;
306 bdp->formatVersion[2]=UTRIE_SHIFT;
307 bdp->formatVersion[3]=UTRIE_INDEX_SHIFT;
308
309 /* set the static variables */
310 umtx_lock(NULL);
311 if(gBdpDummy==NULL) {
312 gBdpDummy=bdp;
313 bdp=NULL;
314 ucln_common_registerCleanup(UCLN_COMMON_UBIDI, ubidi_cleanup);
315 }
316 umtx_unlock(NULL);
317
318 uprv_free(bdp);
319 return gBdpDummy;
320 }
321 }
322
323 /* set of property starts for UnicodeSet ------------------------------------ */
324
325 static UBool U_CALLCONV
326 _enumPropertyStartsRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
327 /* add the start code point to the USet */
328 const USetAdder *sa=(const USetAdder *)context;
329 sa->add(sa->set, start);
330 return TRUE;
331 }
332
333 U_CFUNC void
334 ubidi_addPropertyStarts(const UBiDiProps *bdp, const USetAdder *sa, UErrorCode *pErrorCode) {
335 int32_t i, length;
336 UChar32 c, start, limit;
337
338 const uint8_t *jgArray;
339 uint8_t prev, jg;
340
341 if(U_FAILURE(*pErrorCode)) {
342 return;
343 }
344
345 /* add the start code point of each same-value range of the trie */
346 utrie_enum(&bdp->trie, NULL, _enumPropertyStartsRange, sa);
347
348 /* add the code points from the bidi mirroring table */
349 length=bdp->indexes[UBIDI_IX_MIRROR_LENGTH];
350 for(i=0; i<length; ++i) {
351 c=UBIDI_GET_MIRROR_CODE_POINT(bdp->mirrors[i]);
352 sa->addRange(sa->set, c, c+1);
353 }
354
355 /* add the code points from the Joining_Group array where the value changes */
356 start=bdp->indexes[UBIDI_IX_JG_START];
357 limit=bdp->indexes[UBIDI_IX_JG_LIMIT];
358 jgArray=bdp->jgArray;
359 prev=0;
360 while(start<limit) {
361 jg=*jgArray++;
362 if(jg!=prev) {
363 sa->add(sa->set, start);
364 prev=jg;
365 }
366 ++start;
367 }
368 if(prev!=0) {
369 /* add the limit code point if the last value was not 0 (it is now start==limit) */
370 sa->add(sa->set, limit);
371 }
372
373 /* add code points with hardcoded properties, plus the ones following them */
374
375 /* (none right now) */
376 }
377
378 /* data access primitives --------------------------------------------------- */
379
380 /* UTRIE_GET16() itself validates c */
381 #define GET_PROPS(bdp, c, result) \
382 UTRIE_GET16(&(bdp)->trie, c, result);
383
384 /* property access functions ------------------------------------------------ */
385
386 U_CFUNC int32_t
387 ubidi_getMaxValue(const UBiDiProps *bdp, UProperty which) {
388 int32_t max;
389
390 if(bdp==NULL) {
391 return -1;
392 }
393
394 max=bdp->indexes[UBIDI_MAX_VALUES_INDEX];
395 switch(which) {
396 case UCHAR_BIDI_CLASS:
397 return (max&UBIDI_CLASS_MASK);
398 case UCHAR_JOINING_GROUP:
399 return (max&UBIDI_MAX_JG_MASK)>>UBIDI_MAX_JG_SHIFT;
400 case UCHAR_JOINING_TYPE:
401 return (max&UBIDI_JT_MASK)>>UBIDI_JT_SHIFT;
402 default:
403 return -1; /* undefined */
404 }
405 }
406
407 U_CAPI UCharDirection
408 ubidi_getClass(const UBiDiProps *bdp, UChar32 c) {
409 uint32_t props;
410 GET_PROPS(bdp, c, props);
411 return (UCharDirection)UBIDI_GET_CLASS(props);
412 }
413
414 U_CFUNC UBool
415 ubidi_isMirrored(const UBiDiProps *bdp, UChar32 c) {
416 uint32_t props;
417 GET_PROPS(bdp, c, props);
418 return (UBool)UBIDI_GET_FLAG(props, UBIDI_IS_MIRRORED_SHIFT);
419 }
420
421 U_CFUNC UChar32
422 ubidi_getMirror(const UBiDiProps *bdp, UChar32 c) {
423 uint32_t props;
424 int32_t delta;
425
426 GET_PROPS(bdp, c, props);
427 delta=((int16_t)props)>>UBIDI_MIRROR_DELTA_SHIFT;
428 if(delta!=UBIDI_ESC_MIRROR_DELTA) {
429 return c+delta;
430 } else {
431 /* look for mirror code point in the mirrors[] table */
432 const uint32_t *mirrors;
433 uint32_t m;
434 int32_t i, length;
435 UChar32 c2;
436
437 mirrors=bdp->mirrors;
438 length=bdp->indexes[UBIDI_IX_MIRROR_LENGTH];
439
440 /* linear search */
441 for(i=0; i<length; ++i) {
442 m=mirrors[i];
443 c2=UBIDI_GET_MIRROR_CODE_POINT(m);
444 if(c==c2) {
445 /* found c, return its mirror code point using the index in m */
446 return UBIDI_GET_MIRROR_CODE_POINT(mirrors[UBIDI_GET_MIRROR_INDEX(m)]);
447 } else if(c<c2) {
448 break;
449 }
450 }
451
452 /* c not found, return it itself */
453 return c;
454 }
455 }
456
457 U_CFUNC UBool
458 ubidi_isBidiControl(const UBiDiProps *bdp, UChar32 c) {
459 uint32_t props;
460 GET_PROPS(bdp, c, props);
461 return (UBool)UBIDI_GET_FLAG(props, UBIDI_BIDI_CONTROL_SHIFT);
462 }
463
464 U_CFUNC UBool
465 ubidi_isJoinControl(const UBiDiProps *bdp, UChar32 c) {
466 uint32_t props;
467 GET_PROPS(bdp, c, props);
468 return (UBool)UBIDI_GET_FLAG(props, UBIDI_JOIN_CONTROL_SHIFT);
469 }
470
471 U_CFUNC UJoiningType
472 ubidi_getJoiningType(const UBiDiProps *bdp, UChar32 c) {
473 uint32_t props;
474 GET_PROPS(bdp, c, props);
475 return (UJoiningType)((props&UBIDI_JT_MASK)>>UBIDI_JT_SHIFT);
476 }
477
478 U_CFUNC UJoiningGroup
479 ubidi_getJoiningGroup(const UBiDiProps *bdp, UChar32 c) {
480 UChar32 start, limit;
481
482 start=bdp->indexes[UBIDI_IX_JG_START];
483 limit=bdp->indexes[UBIDI_IX_JG_LIMIT];
484 if(start<=c && c<limit) {
485 return (UJoiningGroup)bdp->jgArray[c-start];
486 } else {
487 return U_JG_NO_JOINING_GROUP;
488 }
489 }
490
491 /* public API (see uchar.h) ------------------------------------------------- */
492
493 U_CFUNC UCharDirection
494 u_charDirection(UChar32 c) {
495 UErrorCode errorCode=U_ZERO_ERROR;
496 const UBiDiProps *bdp=ubidi_getSingleton(&errorCode);
497 if(bdp!=NULL) {
498 return ubidi_getClass(bdp, c);
499 } else {
500 return U_LEFT_TO_RIGHT;
501 }
502 }
503
504 U_CFUNC UBool
505 u_isMirrored(UChar32 c) {
506 UErrorCode errorCode=U_ZERO_ERROR;
507 const UBiDiProps *bdp=ubidi_getSingleton(&errorCode);
508 return (UBool)(bdp!=NULL && ubidi_isMirrored(bdp, c));
509 }
510
511 U_CFUNC UChar32
512 u_charMirror(UChar32 c) {
513 UErrorCode errorCode=U_ZERO_ERROR;
514 const UBiDiProps *bdp=ubidi_getSingleton(&errorCode);
515 if(bdp!=NULL) {
516 return ubidi_getMirror(bdp, c);
517 } else {
518 return c;
519 }
520 }