2 *******************************************************************************
4 * Copyright (C) 2004-2007, 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
));
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
);
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
);
192 ubidi_closeProps(UBiDiProps
*bdp
) {
194 #if !UBIDI_HARDCODE_DATA
195 udata_close(bdp
->mem
);
201 /* UBiDiProps singleton ----------------------------------------------------- */
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;
210 static UBool U_CALLCONV
211 ubidi_cleanup(void) {
212 ubidi_closeProps(gBdpDummy
);
214 #if !UBIDI_HARDCODE_DATA
215 ubidi_closeProps(gBdp
);
217 gErrorCode
=U_ZERO_ERROR
;
223 U_CFUNC
const UBiDiProps
*
224 ubidi_getSingleton(UErrorCode
*pErrorCode
) {
225 #if UBIDI_HARDCODE_DATA
226 if(U_FAILURE(*pErrorCode
)) {
229 return &ubidi_props_singleton
;
233 if(U_FAILURE(*pErrorCode
)) {
237 UMTX_CHECK(NULL
, gHaveData
, haveData
);
240 /* data was loaded */
242 } else if(haveData
<0) {
243 /* data loading failed */
244 *pErrorCode
=gErrorCode
;
246 } else /* haveData==0 */ {
248 UBiDiProps
*bdp
=ubidi_openProps(pErrorCode
);
249 if(U_FAILURE(*pErrorCode
)) {
251 gErrorCode
=*pErrorCode
;
255 /* set the static variables */
261 ucln_common_registerCleanup(UCLN_COMMON_UBIDI
, ubidi_cleanup
);
265 ubidi_closeProps(bdp
);
271 U_CAPI
const UBiDiProps
*
272 ubidi_getDummy(UErrorCode
*pErrorCode
) {
275 if(U_FAILURE(*pErrorCode
)) {
279 UMTX_CHECK(NULL
, gBdpDummy
, bdp
);
282 /* the dummy object was already created */
284 } else /* bdp==NULL */ {
285 /* create the dummy object */
288 bdp
=(UBiDiProps
*)uprv_malloc(sizeof(UBiDiProps
)+UBIDI_IX_TOP
*4+UTRIE_DUMMY_SIZE
);
290 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
293 uprv_memset(bdp
, 0, sizeof(UBiDiProps
)+UBIDI_IX_TOP
*4);
295 bdp
->indexes
=indexes
=(int32_t *)(bdp
+1);
296 indexes
[UBIDI_IX_INDEX_TOP
]=UBIDI_IX_TOP
;
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
)) {
305 bdp
->formatVersion
[0]=1;
306 bdp
->formatVersion
[2]=UTRIE_SHIFT
;
307 bdp
->formatVersion
[3]=UTRIE_INDEX_SHIFT
;
309 /* set the static variables */
311 if(gBdpDummy
==NULL
) {
314 ucln_common_registerCleanup(UCLN_COMMON_UBIDI
, ubidi_cleanup
);
323 /* set of property starts for UnicodeSet ------------------------------------ */
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
);
334 ubidi_addPropertyStarts(const UBiDiProps
*bdp
, const USetAdder
*sa
, UErrorCode
*pErrorCode
) {
336 UChar32 c
, start
, limit
;
338 const uint8_t *jgArray
;
341 if(U_FAILURE(*pErrorCode
)) {
345 /* add the start code point of each same-value range of the trie */
346 utrie_enum(&bdp
->trie
, NULL
, _enumPropertyStartsRange
, sa
);
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);
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
;
363 sa
->add(sa
->set
, start
);
369 /* add the limit code point if the last value was not 0 (it is now start==limit) */
370 sa
->add(sa
->set
, limit
);
373 /* add code points with hardcoded properties, plus the ones following them */
375 /* (none right now) */
378 /* data access primitives --------------------------------------------------- */
380 /* UTRIE_GET16() itself validates c */
381 #define GET_PROPS(bdp, c, result) \
382 UTRIE_GET16(&(bdp)->trie, c, result);
384 /* property access functions ------------------------------------------------ */
387 ubidi_getMaxValue(const UBiDiProps
*bdp
, UProperty which
) {
394 max
=bdp
->indexes
[UBIDI_MAX_VALUES_INDEX
];
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
;
403 return -1; /* undefined */
407 U_CAPI UCharDirection
408 ubidi_getClass(const UBiDiProps
*bdp
, UChar32 c
) {
410 GET_PROPS(bdp
, c
, props
);
411 return (UCharDirection
)UBIDI_GET_CLASS(props
);
415 ubidi_isMirrored(const UBiDiProps
*bdp
, UChar32 c
) {
417 GET_PROPS(bdp
, c
, props
);
418 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_IS_MIRRORED_SHIFT
);
422 ubidi_getMirror(const UBiDiProps
*bdp
, UChar32 c
) {
426 GET_PROPS(bdp
, c
, props
);
427 delta
=((int16_t)props
)>>UBIDI_MIRROR_DELTA_SHIFT
;
428 if(delta
!=UBIDI_ESC_MIRROR_DELTA
) {
431 /* look for mirror code point in the mirrors[] table */
432 const uint32_t *mirrors
;
437 mirrors
=bdp
->mirrors
;
438 length
=bdp
->indexes
[UBIDI_IX_MIRROR_LENGTH
];
441 for(i
=0; i
<length
; ++i
) {
443 c2
=UBIDI_GET_MIRROR_CODE_POINT(m
);
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
)]);
452 /* c not found, return it itself */
458 ubidi_isBidiControl(const UBiDiProps
*bdp
, UChar32 c
) {
460 GET_PROPS(bdp
, c
, props
);
461 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_BIDI_CONTROL_SHIFT
);
465 ubidi_isJoinControl(const UBiDiProps
*bdp
, UChar32 c
) {
467 GET_PROPS(bdp
, c
, props
);
468 return (UBool
)UBIDI_GET_FLAG(props
, UBIDI_JOIN_CONTROL_SHIFT
);
472 ubidi_getJoiningType(const UBiDiProps
*bdp
, UChar32 c
) {
474 GET_PROPS(bdp
, c
, props
);
475 return (UJoiningType
)((props
&UBIDI_JT_MASK
)>>UBIDI_JT_SHIFT
);
478 U_CFUNC UJoiningGroup
479 ubidi_getJoiningGroup(const UBiDiProps
*bdp
, UChar32 c
) {
480 UChar32 start
, limit
;
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
];
487 return U_JG_NO_JOINING_GROUP
;
491 /* public API (see uchar.h) ------------------------------------------------- */
493 U_CFUNC UCharDirection
494 u_charDirection(UChar32 c
) {
495 UErrorCode errorCode
=U_ZERO_ERROR
;
496 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
498 return ubidi_getClass(bdp
, c
);
500 return U_LEFT_TO_RIGHT
;
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
));
512 u_charMirror(UChar32 c
) {
513 UErrorCode errorCode
=U_ZERO_ERROR
;
514 const UBiDiProps
*bdp
=ubidi_getSingleton(&errorCode
);
516 return ubidi_getMirror(bdp
, c
);