2 *******************************************************************************
4 * Copyright (C) 2004-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: ubidi_props.c
10 * tab size: 8 (not used)
13 * created on: 2004dec30
14 * created by: Markus W. Scherer
16 * Low-level Unicode bidi/shaping properties access.
19 #include "unicode/utypes.h"
20 #include "unicode/uset.h"
21 #include "unicode/udata.h" /* UDataInfo */
22 #include "ucmndata.h" /* DataHeader */
28 #include "ubidi_props.h"
33 const int32_t *indexes
;
34 const uint32_t *mirrors
;
35 const uint8_t *jgArray
;
38 uint8_t formatVersion
[4];
41 /* data loading etc. -------------------------------------------------------- */
43 #define UBIDI_HARDCODE_DATA 1
45 #if UBIDI_HARDCODE_DATA
47 /* ubidi_props_data.c is machine-generated by genbidi --csource */
48 #include "ubidi_props_data.c"
52 static UBool U_CALLCONV
53 isAcceptable(void *context
,
54 const char *type
, const char *name
,
55 const UDataInfo
*pInfo
) {
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
68 UBiDiProps
*bdp
=(UBiDiProps
*)context
;
69 uprv_memcpy(bdp
->formatVersion
, pInfo
->formatVersion
, 4);
77 ubidi_openData(UBiDiProps
*bdpProto
,
78 const uint8_t *bin
, int32_t length
, UErrorCode
*pErrorCode
) {
82 bdpProto
->indexes
=(const int32_t *)bin
;
83 if( (length
>=0 && length
<16*4) ||
84 bdpProto
->indexes
[UBIDI_IX_INDEX_TOP
]<16
86 /* length or indexes[] too short for minimum indexes[] length of 16 */
87 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
90 size
=bdpProto
->indexes
[UBIDI_IX_INDEX_TOP
]*4;
92 if(length
>=size
&& length
>=bdpProto
->indexes
[UBIDI_IX_LENGTH
]) {
95 /* length too short for indexes[] or for the whole data length */
96 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
101 /* from here on, assume that the sizes of the items fit into the total length */
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
)) {
112 size
=4*bdpProto
->indexes
[UBIDI_IX_MIRROR_LENGTH
];
113 bdpProto
->mirrors
=(const uint32_t *)bin
;
117 size
=bdpProto
->indexes
[UBIDI_IX_JG_LIMIT
]-bdpProto
->indexes
[UBIDI_IX_JG_START
];
118 bdpProto
->jgArray
=bin
;
121 /* allocate, copy, and return the new UBiDiProps */
122 bdp
=(UBiDiProps
*)uprv_malloc(sizeof(UBiDiProps
));
124 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
127 uprv_memcpy(bdp
, bdpProto
, sizeof(UBiDiProps
));
132 U_CAPI UBiDiProps
* U_EXPORT2
133 ubidi_openProps(UErrorCode
*pErrorCode
) {
134 UBiDiProps bdpProto
={ NULL
}, *bdp
;
136 bdpProto
.mem
=udata_openChoice(NULL
, UBIDI_DATA_TYPE
, UBIDI_DATA_NAME
, isAcceptable
, &bdpProto
, pErrorCode
);
137 if(U_FAILURE(*pErrorCode
)) {
143 udata_getMemory(bdpProto
.mem
),
144 udata_getLength(bdpProto
.mem
),
146 if(U_FAILURE(*pErrorCode
)) {
147 udata_close(bdpProto
.mem
);
154 U_CAPI UBiDiProps
* U_EXPORT2
155 ubidi_openBinary(const uint8_t *bin
, int32_t length
, UErrorCode
*pErrorCode
) {
156 UBiDiProps bdpProto
={ NULL
};
157 const DataHeader
*hdr
;
159 if(U_FAILURE(*pErrorCode
)) {
163 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
167 /* check the header */
168 if(length
>=0 && length
<20) {
169 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
172 hdr
=(const DataHeader
*)bin
;
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
))
178 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
182 bin
+=hdr
->dataHeader
.headerSize
;
184 length
-=hdr
->dataHeader
.headerSize
;
186 return ubidi_openData(&bdpProto
, bin
, length
, pErrorCode
);
191 U_CAPI
void U_EXPORT2
192 ubidi_closeProps(UBiDiProps
*bdp
) {
194 #if !UBIDI_HARDCODE_DATA
195 udata_close(bdp
->mem
);
201 /* UBiDiProps singleton ----------------------------------------------------- */
203 static UBiDiProps
*gBdp
=NULL
, *gBdpDummy
=NULL
;
204 #if !UBIDI_HARDCODE_DATA
205 static UErrorCode gErrorCode
=U_ZERO_ERROR
;
206 static int8_t gHaveData
=0;
209 static UBool U_CALLCONV
210 ubidi_cleanup(void) {
211 ubidi_closeProps(gBdp
);
213 ubidi_closeProps(gBdpDummy
);
215 #if !UBIDI_HARDCODE_DATA
216 gErrorCode
=U_ZERO_ERROR
;
222 U_CAPI
const UBiDiProps
* U_EXPORT2
223 ubidi_getSingleton(UErrorCode
*pErrorCode
) {
224 #if UBIDI_HARDCODE_DATA
225 if(U_FAILURE(*pErrorCode
)) {
228 return &ubidi_props_singleton
;
232 if(U_FAILURE(*pErrorCode
)) {
236 UMTX_CHECK(NULL
, gHaveData
, haveData
);
239 /* data was loaded */
241 } else if(haveData
<0) {
242 /* data loading failed */
243 *pErrorCode
=gErrorCode
;
245 } else /* haveData==0 */ {
247 UBiDiProps
*bdp
=ubidi_openProps(pErrorCode
);
248 if(U_FAILURE(*pErrorCode
)) {
250 gErrorCode
=*pErrorCode
;
254 /* set the static variables */
260 ucln_common_registerCleanup(UCLN_COMMON_UBIDI
, ubidi_cleanup
);
264 ubidi_closeProps(bdp
);
270 U_CAPI
const UBiDiProps
* U_EXPORT2
271 ubidi_getDummy(UErrorCode
*pErrorCode
) {
274 if(U_FAILURE(*pErrorCode
)) {
278 UMTX_CHECK(NULL
, gBdpDummy
, bdp
);
281 /* the dummy object was already created */
283 } else /* bdp==NULL */ {
284 /* create the dummy object */
287 bdp
=(UBiDiProps
*)uprv_malloc(sizeof(UBiDiProps
)+UBIDI_IX_TOP
*4+UTRIE_DUMMY_SIZE
);
289 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
292 uprv_memset(bdp
, 0, sizeof(UBiDiProps
)+UBIDI_IX_TOP
*4);
294 bdp
->indexes
=indexes
=(int32_t *)(bdp
+1);
295 indexes
[UBIDI_IX_INDEX_TOP
]=UBIDI_IX_TOP
;
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
)) {
304 bdp
->formatVersion
[0]=1;
305 bdp
->formatVersion
[2]=UTRIE_SHIFT
;
306 bdp
->formatVersion
[3]=UTRIE_INDEX_SHIFT
;
308 /* set the static variables */
310 if(gBdpDummy
==NULL
) {
313 ucln_common_registerCleanup(UCLN_COMMON_UBIDI
, ubidi_cleanup
);
322 /* set of property starts for UnicodeSet ------------------------------------ */
324 static 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
);
332 U_CAPI
void U_EXPORT2
333 ubidi_addPropertyStarts(const UBiDiProps
*bdp
, const USetAdder
*sa
, UErrorCode
*pErrorCode
) {
335 UChar32 c
, start
, limit
;
337 const uint8_t *jgArray
;
340 if(U_FAILURE(*pErrorCode
)) {
344 /* add the start code point of each same-value range of the trie */
345 utrie_enum(&bdp
->trie
, NULL
, _enumPropertyStartsRange
, sa
);
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);
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
;
362 sa
->add(sa
->set
, start
);
368 /* add the limit code point if the last value was not 0 (it is now start==limit) */
369 sa
->add(sa
->set
, limit
);
372 /* add code points with hardcoded properties, plus the ones following them */
374 /* (none right now) */
377 /* data access primitives --------------------------------------------------- */
379 /* UTRIE_GET16() itself validates c */
380 #define GET_PROPS(bdp, c, result) \
381 UTRIE_GET16(&(bdp)->trie, c, result);
383 /* property access functions ------------------------------------------------ */
386 ubidi_getMaxValue(const UBiDiProps
*bdp
, UProperty which
) {
393 max
=bdp
->indexes
[UBIDI_MAX_VALUES_INDEX
];
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
;
402 return -1; /* undefined */
406 U_CAPI UCharDirection U_EXPORT2
407 ubidi_getClass(const UBiDiProps
*bdp
, UChar32 c
) {
409 GET_PROPS(bdp
, c
, props
);
410 return (UCharDirection
)UBIDI_GET_CLASS(props
);
413 U_CAPI UBool U_EXPORT2
414 ubidi_isMirrored(const UBiDiProps
*bdp
, UChar32 c
) {
416 GET_PROPS(bdp
, c
, props
);
417 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_IS_MIRRORED_SHIFT
);
420 U_CAPI UChar32 U_EXPORT2
421 ubidi_getMirror(const UBiDiProps
*bdp
, UChar32 c
) {
425 GET_PROPS(bdp
, c
, props
);
426 delta
=((int16_t)props
)>>UBIDI_MIRROR_DELTA_SHIFT
;
427 if(delta
!=UBIDI_ESC_MIRROR_DELTA
) {
430 /* look for mirror code point in the mirrors[] table */
431 const uint32_t *mirrors
;
436 mirrors
=bdp
->mirrors
;
437 length
=bdp
->indexes
[UBIDI_IX_MIRROR_LENGTH
];
440 for(i
=0; i
<length
; ++i
) {
442 c2
=UBIDI_GET_MIRROR_CODE_POINT(m
);
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
)]);
451 /* c not found, return it itself */
456 U_CAPI UBool U_EXPORT2
457 ubidi_isBidiControl(const UBiDiProps
*bdp
, UChar32 c
) {
459 GET_PROPS(bdp
, c
, props
);
460 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_BIDI_CONTROL_SHIFT
);
463 U_CAPI UBool U_EXPORT2
464 ubidi_isJoinControl(const UBiDiProps
*bdp
, UChar32 c
) {
466 GET_PROPS(bdp
, c
, props
);
467 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_JOIN_CONTROL_SHIFT
);
470 U_CAPI UJoiningType U_EXPORT2
471 ubidi_getJoiningType(const UBiDiProps
*bdp
, UChar32 c
) {
473 GET_PROPS(bdp
, c
, props
);
474 return (UJoiningType
)((props
&UBIDI_JT_MASK
)>>UBIDI_JT_SHIFT
);
477 U_CAPI UJoiningGroup U_EXPORT2
478 ubidi_getJoiningGroup(const UBiDiProps
*bdp
, UChar32 c
) {
479 UChar32 start
, limit
;
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
];
486 return U_JG_NO_JOINING_GROUP
;
490 /* public API (see uchar.h) ------------------------------------------------- */
492 U_CAPI UCharDirection U_EXPORT2
493 u_charDirection(UChar32 c
) {
494 UErrorCode errorCode
=U_ZERO_ERROR
;
495 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
497 return ubidi_getClass(bdp
, c
);
499 return U_LEFT_TO_RIGHT
;
503 U_CAPI UBool U_EXPORT2
504 u_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
));
510 U_CAPI UChar32 U_EXPORT2
511 u_charMirror(UChar32 c
) {
512 UErrorCode errorCode
=U_ZERO_ERROR
;
513 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
515 return ubidi_getMirror(bdp
, c
);