2 *******************************************************************************
4 * Copyright (C) 2004-2008, 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 #if UBIDI_HARDCODE_DATA
45 /* ubidi_props_data.c is machine-generated by genbidi --csource */
46 #include "ubidi_props_data.c"
50 static UBool U_CALLCONV
51 isAcceptable(void *context
,
52 const char *type
, const char *name
,
53 const UDataInfo
*pInfo
) {
56 pInfo
->isBigEndian
==U_IS_BIG_ENDIAN
&&
57 pInfo
->charsetFamily
==U_CHARSET_FAMILY
&&
58 pInfo
->dataFormat
[0]==UBIDI_FMT_0
&& /* dataFormat="BiDi" */
59 pInfo
->dataFormat
[1]==UBIDI_FMT_1
&&
60 pInfo
->dataFormat
[2]==UBIDI_FMT_2
&&
61 pInfo
->dataFormat
[3]==UBIDI_FMT_3
&&
62 pInfo
->formatVersion
[0]==1 &&
63 pInfo
->formatVersion
[2]==UTRIE_SHIFT
&&
64 pInfo
->formatVersion
[3]==UTRIE_INDEX_SHIFT
66 UBiDiProps
*bdp
=(UBiDiProps
*)context
;
67 uprv_memcpy(bdp
->formatVersion
, pInfo
->formatVersion
, 4);
75 ubidi_openData(UBiDiProps
*bdpProto
,
76 const uint8_t *bin
, int32_t length
, UErrorCode
*pErrorCode
) {
80 bdpProto
->indexes
=(const int32_t *)bin
;
81 if( (length
>=0 && length
<16*4) ||
82 bdpProto
->indexes
[UBIDI_IX_INDEX_TOP
]<16
84 /* length or indexes[] too short for minimum indexes[] length of 16 */
85 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
88 size
=bdpProto
->indexes
[UBIDI_IX_INDEX_TOP
]*4;
90 if(length
>=size
&& length
>=bdpProto
->indexes
[UBIDI_IX_LENGTH
]) {
93 /* length too short for indexes[] or for the whole data length */
94 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
99 /* from here on, assume that the sizes of the items fit into the total length */
101 /* unserialize the trie, after indexes[] */
102 size
=bdpProto
->indexes
[UBIDI_IX_TRIE_SIZE
];
103 utrie_unserialize(&bdpProto
->trie
, bin
, size
, pErrorCode
);
104 if(U_FAILURE(*pErrorCode
)) {
110 size
=4*bdpProto
->indexes
[UBIDI_IX_MIRROR_LENGTH
];
111 bdpProto
->mirrors
=(const uint32_t *)bin
;
115 size
=bdpProto
->indexes
[UBIDI_IX_JG_LIMIT
]-bdpProto
->indexes
[UBIDI_IX_JG_START
];
116 bdpProto
->jgArray
=bin
;
119 /* allocate, copy, and return the new UBiDiProps */
120 bdp
=(UBiDiProps
*)uprv_malloc(sizeof(UBiDiProps
));
122 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
125 uprv_memcpy(bdp
, bdpProto
, sizeof(UBiDiProps
));
131 ubidi_openProps(UErrorCode
*pErrorCode
) {
132 UBiDiProps bdpProto
={ NULL
}, *bdp
;
134 bdpProto
.mem
=udata_openChoice(NULL
, UBIDI_DATA_TYPE
, UBIDI_DATA_NAME
, isAcceptable
, &bdpProto
, pErrorCode
);
135 if(U_FAILURE(*pErrorCode
)) {
141 udata_getMemory(bdpProto
.mem
),
142 udata_getLength(bdpProto
.mem
),
144 if(U_FAILURE(*pErrorCode
)) {
145 udata_close(bdpProto
.mem
);
153 ubidi_openBinary(const uint8_t *bin
, int32_t length
, UErrorCode
*pErrorCode
) {
154 UBiDiProps bdpProto
={ NULL
};
155 const DataHeader
*hdr
;
157 if(U_FAILURE(*pErrorCode
)) {
161 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
165 /* check the header */
166 if(length
>=0 && length
<20) {
167 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
170 hdr
=(const DataHeader
*)bin
;
172 !(hdr
->dataHeader
.magic1
==0xda && hdr
->dataHeader
.magic2
==0x27 &&
173 hdr
->info
.isBigEndian
==U_IS_BIG_ENDIAN
&&
174 isAcceptable(&bdpProto
, UBIDI_DATA_TYPE
, UBIDI_DATA_NAME
, &hdr
->info
))
176 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
180 bin
+=hdr
->dataHeader
.headerSize
;
182 length
-=hdr
->dataHeader
.headerSize
;
184 return ubidi_openData(&bdpProto
, bin
, length
, pErrorCode
);
190 ubidi_closeProps(UBiDiProps
*bdp
) {
192 #if !UBIDI_HARDCODE_DATA
193 udata_close(bdp
->mem
);
199 /* UBiDiProps singleton ----------------------------------------------------- */
201 #if !UBIDI_HARDCODE_DATA
202 static UBiDiProps
*gBdpDummy
=NULL
;
203 static UBiDiProps
*gBdp
=NULL
;
204 static UErrorCode gErrorCode
=U_ZERO_ERROR
;
205 static int8_t gHaveData
=0;
207 static UBool U_CALLCONV
208 ubidi_cleanup(void) {
209 ubidi_closeProps(gBdpDummy
);
211 ubidi_closeProps(gBdp
);
213 gErrorCode
=U_ZERO_ERROR
;
219 U_CFUNC
const UBiDiProps
*
220 ubidi_getSingleton(UErrorCode
*pErrorCode
) {
221 #if UBIDI_HARDCODE_DATA
222 if(U_FAILURE(*pErrorCode
)) {
225 return &ubidi_props_singleton
;
229 if(U_FAILURE(*pErrorCode
)) {
233 UMTX_CHECK(NULL
, gHaveData
, haveData
);
236 /* data was loaded */
238 } else if(haveData
<0) {
239 /* data loading failed */
240 *pErrorCode
=gErrorCode
;
242 } else /* haveData==0 */ {
244 UBiDiProps
*bdp
=ubidi_openProps(pErrorCode
);
245 if(U_FAILURE(*pErrorCode
)) {
247 gErrorCode
=*pErrorCode
;
251 /* set the static variables */
257 ucln_common_registerCleanup(UCLN_COMMON_UBIDI
, ubidi_cleanup
);
261 ubidi_closeProps(bdp
);
267 #if !UBIDI_HARDCODE_DATA
268 U_CAPI
const UBiDiProps
*
269 ubidi_getDummy(UErrorCode
*pErrorCode
) {
272 if(U_FAILURE(*pErrorCode
)) {
276 UMTX_CHECK(NULL
, gBdpDummy
, bdp
);
279 /* the dummy object was already created */
281 } else /* bdp==NULL */ {
282 /* create the dummy object */
285 bdp
=(UBiDiProps
*)uprv_malloc(sizeof(UBiDiProps
)+UBIDI_IX_TOP
*4+UTRIE_DUMMY_SIZE
);
287 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
290 uprv_memset(bdp
, 0, sizeof(UBiDiProps
)+UBIDI_IX_TOP
*4);
292 bdp
->indexes
=indexes
=(int32_t *)(bdp
+1);
293 indexes
[UBIDI_IX_INDEX_TOP
]=UBIDI_IX_TOP
;
295 indexes
[UBIDI_IX_TRIE_SIZE
]=
296 utrie_unserializeDummy(&bdp
->trie
, indexes
+UBIDI_IX_TOP
, UTRIE_DUMMY_SIZE
, 0, 0, TRUE
, pErrorCode
);
297 if(U_FAILURE(*pErrorCode
)) {
302 bdp
->formatVersion
[0]=1;
303 bdp
->formatVersion
[2]=UTRIE_SHIFT
;
304 bdp
->formatVersion
[3]=UTRIE_INDEX_SHIFT
;
306 /* set the static variables */
308 if(gBdpDummy
==NULL
) {
311 ucln_common_registerCleanup(UCLN_COMMON_UBIDI
, ubidi_cleanup
);
321 /* set of property starts for UnicodeSet ------------------------------------ */
323 static UBool U_CALLCONV
324 _enumPropertyStartsRange(const void *context
, UChar32 start
, UChar32 limit
, uint32_t value
) {
325 /* add the start code point to the USet */
326 const USetAdder
*sa
=(const USetAdder
*)context
;
327 sa
->add(sa
->set
, start
);
332 ubidi_addPropertyStarts(const UBiDiProps
*bdp
, const USetAdder
*sa
, UErrorCode
*pErrorCode
) {
334 UChar32 c
, start
, limit
;
336 const uint8_t *jgArray
;
339 if(U_FAILURE(*pErrorCode
)) {
343 /* add the start code point of each same-value range of the trie */
344 utrie_enum(&bdp
->trie
, NULL
, _enumPropertyStartsRange
, sa
);
346 /* add the code points from the bidi mirroring table */
347 length
=bdp
->indexes
[UBIDI_IX_MIRROR_LENGTH
];
348 for(i
=0; i
<length
; ++i
) {
349 c
=UBIDI_GET_MIRROR_CODE_POINT(bdp
->mirrors
[i
]);
350 sa
->addRange(sa
->set
, c
, c
+1);
353 /* add the code points from the Joining_Group array where the value changes */
354 start
=bdp
->indexes
[UBIDI_IX_JG_START
];
355 limit
=bdp
->indexes
[UBIDI_IX_JG_LIMIT
];
356 jgArray
=bdp
->jgArray
;
361 sa
->add(sa
->set
, start
);
367 /* add the limit code point if the last value was not 0 (it is now start==limit) */
368 sa
->add(sa
->set
, limit
);
371 /* add code points with hardcoded properties, plus the ones following them */
373 /* (none right now) */
376 /* data access primitives --------------------------------------------------- */
378 /* UTRIE_GET16() itself validates c */
379 #define GET_PROPS(bdp, c, result) \
380 UTRIE_GET16(&(bdp)->trie, c, result);
382 /* property access functions ------------------------------------------------ */
385 ubidi_getMaxValue(const UBiDiProps
*bdp
, UProperty which
) {
392 max
=bdp
->indexes
[UBIDI_MAX_VALUES_INDEX
];
394 case UCHAR_BIDI_CLASS
:
395 return (max
&UBIDI_CLASS_MASK
);
396 case UCHAR_JOINING_GROUP
:
397 return (max
&UBIDI_MAX_JG_MASK
)>>UBIDI_MAX_JG_SHIFT
;
398 case UCHAR_JOINING_TYPE
:
399 return (max
&UBIDI_JT_MASK
)>>UBIDI_JT_SHIFT
;
401 return -1; /* undefined */
405 U_CAPI UCharDirection
406 ubidi_getClass(const UBiDiProps
*bdp
, UChar32 c
) {
408 GET_PROPS(bdp
, c
, props
);
409 return (UCharDirection
)UBIDI_GET_CLASS(props
);
413 ubidi_isMirrored(const UBiDiProps
*bdp
, UChar32 c
) {
415 GET_PROPS(bdp
, c
, props
);
416 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_IS_MIRRORED_SHIFT
);
420 ubidi_getMirror(const UBiDiProps
*bdp
, UChar32 c
) {
424 GET_PROPS(bdp
, c
, props
);
425 delta
=((int16_t)props
)>>UBIDI_MIRROR_DELTA_SHIFT
;
426 if(delta
!=UBIDI_ESC_MIRROR_DELTA
) {
429 /* look for mirror code point in the mirrors[] table */
430 const uint32_t *mirrors
;
435 mirrors
=bdp
->mirrors
;
436 length
=bdp
->indexes
[UBIDI_IX_MIRROR_LENGTH
];
439 for(i
=0; i
<length
; ++i
) {
441 c2
=UBIDI_GET_MIRROR_CODE_POINT(m
);
443 /* found c, return its mirror code point using the index in m */
444 return UBIDI_GET_MIRROR_CODE_POINT(mirrors
[UBIDI_GET_MIRROR_INDEX(m
)]);
450 /* c not found, return it itself */
456 ubidi_isBidiControl(const UBiDiProps
*bdp
, UChar32 c
) {
458 GET_PROPS(bdp
, c
, props
);
459 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_BIDI_CONTROL_SHIFT
);
463 ubidi_isJoinControl(const UBiDiProps
*bdp
, UChar32 c
) {
465 GET_PROPS(bdp
, c
, props
);
466 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_JOIN_CONTROL_SHIFT
);
470 ubidi_getJoiningType(const UBiDiProps
*bdp
, UChar32 c
) {
472 GET_PROPS(bdp
, c
, props
);
473 return (UJoiningType
)((props
&UBIDI_JT_MASK
)>>UBIDI_JT_SHIFT
);
476 U_CFUNC UJoiningGroup
477 ubidi_getJoiningGroup(const UBiDiProps
*bdp
, UChar32 c
) {
478 UChar32 start
, limit
;
480 start
=bdp
->indexes
[UBIDI_IX_JG_START
];
481 limit
=bdp
->indexes
[UBIDI_IX_JG_LIMIT
];
482 if(start
<=c
&& c
<limit
) {
483 return (UJoiningGroup
)bdp
->jgArray
[c
-start
];
485 return U_JG_NO_JOINING_GROUP
;
489 /* public API (see uchar.h) ------------------------------------------------- */
491 U_CFUNC UCharDirection
492 u_charDirection(UChar32 c
) {
493 UErrorCode errorCode
=U_ZERO_ERROR
;
494 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
496 return ubidi_getClass(bdp
, c
);
498 return U_LEFT_TO_RIGHT
;
503 u_isMirrored(UChar32 c
) {
504 UErrorCode errorCode
=U_ZERO_ERROR
;
505 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
506 return (UBool
)(bdp
!=NULL
&& ubidi_isMirrored(bdp
, c
));
510 u_charMirror(UChar32 c
) {
511 UErrorCode errorCode
=U_ZERO_ERROR
;
512 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
514 return ubidi_getMirror(bdp
, c
);