2 *******************************************************************************
4 * Copyright (C) 2005-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: swapimpl.cpp
10 * tab size: 8 (not used)
13 * created on: 2005may05
14 * created by: Markus W. Scherer
16 * Data file swapping functions moved here from the common library
17 * because some data is hardcoded in ICU4C and needs not be swapped any more.
18 * Moving the functions here simplifies testing (for code coverage) because
19 * we need not jump through hoops (like adding snapshots of these files
22 * The declarations for these functions remain in the internal header files
23 * in icu/source/common/
26 #include "unicode/utypes.h"
27 #include "unicode/putil.h"
28 #include "unicode/udata.h"
37 /* swapping implementations in common */
43 #include "ubidi_props.h"
52 /* swapping implementations in i18n */
56 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
58 /* Unicode properties data swapping ----------------------------------------- */
60 U_CAPI
int32_t U_EXPORT2
61 uprops_swap(const UDataSwapper
*ds
,
62 const void *inData
, int32_t length
, void *outData
,
63 UErrorCode
*pErrorCode
) {
64 const UDataInfo
*pInfo
;
65 int32_t headerSize
, i
;
67 int32_t dataIndexes
[UPROPS_INDEX_COUNT
];
68 const int32_t *inData32
;
70 /* udata_swapDataHeader checks the arguments */
71 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
72 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
76 /* check data format and format version */
77 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
79 pInfo
->dataFormat
[0]==0x55 && /* dataFormat="UPro" */
80 pInfo
->dataFormat
[1]==0x50 &&
81 pInfo
->dataFormat
[2]==0x72 &&
82 pInfo
->dataFormat
[3]==0x6f &&
83 (pInfo
->formatVersion
[0]==3 || pInfo
->formatVersion
[0]==4) &&
84 pInfo
->formatVersion
[2]==UTRIE_SHIFT
&&
85 pInfo
->formatVersion
[3]==UTRIE_INDEX_SHIFT
87 udata_printError(ds
, "uprops_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not a Unicode properties file\n",
88 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
89 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
90 pInfo
->formatVersion
[0]);
91 *pErrorCode
=U_UNSUPPORTED_ERROR
;
95 /* the properties file must contain at least the indexes array */
96 if(length
>=0 && (length
-headerSize
)<(int32_t)sizeof(dataIndexes
)) {
97 udata_printError(ds
, "uprops_swap(): too few bytes (%d after header) for a Unicode properties file\n",
99 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
103 /* read the indexes */
104 inData32
=(const int32_t *)((const char *)inData
+headerSize
);
105 for(i
=0; i
<UPROPS_INDEX_COUNT
; ++i
) {
106 dataIndexes
[i
]=udata_readInt32(ds
, inData32
[i
]);
110 * comments are copied from the data format description in genprops/store.c
111 * indexes[] constants are in uprops.h
116 if((length
-headerSize
)<(4*dataIndexes
[UPROPS_RESERVED_INDEX
])) {
117 udata_printError(ds
, "uprops_swap(): too few bytes (%d after header) for a Unicode properties file\n",
119 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
123 outData32
=(int32_t *)((char *)outData
+headerSize
);
125 /* copy everything for inaccessible data (padding) */
126 if(inData32
!=outData32
) {
127 uprv_memcpy(outData32
, inData32
, 4*dataIndexes
[UPROPS_RESERVED_INDEX
]);
130 /* swap the indexes[16] */
131 ds
->swapArray32(ds
, inData32
, 4*UPROPS_INDEX_COUNT
, outData32
, pErrorCode
);
134 * swap the main properties UTrie
135 * PT serialized properties trie, see utrie.h (byte size: 4*(i0-16))
138 inData32
+UPROPS_INDEX_COUNT
,
139 4*(dataIndexes
[UPROPS_PROPS32_INDEX
]-UPROPS_INDEX_COUNT
),
140 outData32
+UPROPS_INDEX_COUNT
,
144 * swap the properties and exceptions words
145 * P const uint32_t props32[i1-i0];
146 * E const uint32_t exceptions[i2-i1];
149 inData32
+dataIndexes
[UPROPS_PROPS32_INDEX
],
150 4*(dataIndexes
[UPROPS_EXCEPTIONS_TOP_INDEX
]-dataIndexes
[UPROPS_PROPS32_INDEX
]),
151 outData32
+dataIndexes
[UPROPS_PROPS32_INDEX
],
156 * U const UChar uchars[2*(i3-i2)];
159 inData32
+dataIndexes
[UPROPS_EXCEPTIONS_TOP_INDEX
],
160 4*(dataIndexes
[UPROPS_ADDITIONAL_TRIE_INDEX
]-dataIndexes
[UPROPS_EXCEPTIONS_TOP_INDEX
]),
161 outData32
+dataIndexes
[UPROPS_EXCEPTIONS_TOP_INDEX
],
165 * swap the additional UTrie
166 * i3 additionalTrieIndex; -- 32-bit unit index to the additional trie for more properties
169 inData32
+dataIndexes
[UPROPS_ADDITIONAL_TRIE_INDEX
],
170 4*(dataIndexes
[UPROPS_ADDITIONAL_VECTORS_INDEX
]-dataIndexes
[UPROPS_ADDITIONAL_TRIE_INDEX
]),
171 outData32
+dataIndexes
[UPROPS_ADDITIONAL_TRIE_INDEX
],
175 * swap the properties vectors
176 * PV const uint32_t propsVectors[(i6-i4)/i5][i5]==uint32_t propsVectors[i6-i4];
179 inData32
+dataIndexes
[UPROPS_ADDITIONAL_VECTORS_INDEX
],
180 4*(dataIndexes
[UPROPS_RESERVED_INDEX
]-dataIndexes
[UPROPS_ADDITIONAL_VECTORS_INDEX
]),
181 outData32
+dataIndexes
[UPROPS_ADDITIONAL_VECTORS_INDEX
],
185 /* i6 reservedItemIndex; -- 32-bit unit index to the top of the properties vectors table */
186 return headerSize
+4*dataIndexes
[UPROPS_RESERVED_INDEX
];
189 /* Unicode case mapping data swapping --------------------------------------- */
191 U_CAPI
int32_t U_EXPORT2
192 ucase_swap(const UDataSwapper
*ds
,
193 const void *inData
, int32_t length
, void *outData
,
194 UErrorCode
*pErrorCode
) {
195 const UDataInfo
*pInfo
;
198 const uint8_t *inBytes
;
201 const int32_t *inIndexes
;
204 int32_t i
, offset
, count
, size
;
206 /* udata_swapDataHeader checks the arguments */
207 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
208 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
212 /* check data format and format version */
213 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
215 pInfo
->dataFormat
[0]==UCASE_FMT_0
&& /* dataFormat="cAsE" */
216 pInfo
->dataFormat
[1]==UCASE_FMT_1
&&
217 pInfo
->dataFormat
[2]==UCASE_FMT_2
&&
218 pInfo
->dataFormat
[3]==UCASE_FMT_3
&&
219 pInfo
->formatVersion
[0]==1 &&
220 pInfo
->formatVersion
[2]==UTRIE_SHIFT
&&
221 pInfo
->formatVersion
[3]==UTRIE_INDEX_SHIFT
223 udata_printError(ds
, "ucase_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as case mapping data\n",
224 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
225 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
226 pInfo
->formatVersion
[0]);
227 *pErrorCode
=U_UNSUPPORTED_ERROR
;
231 inBytes
=(const uint8_t *)inData
+headerSize
;
232 outBytes
=(uint8_t *)outData
+headerSize
;
234 inIndexes
=(const int32_t *)inBytes
;
239 udata_printError(ds
, "ucase_swap(): too few bytes (%d after header) for case mapping data\n",
241 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
246 /* read the first 16 indexes (ICU 3.2/format version 1: UCASE_IX_TOP==16, might grow) */
247 for(i
=0; i
<16; ++i
) {
248 indexes
[i
]=udata_readInt32(ds
, inIndexes
[i
]);
251 /* get the total length of the data */
252 size
=indexes
[UCASE_IX_LENGTH
];
256 udata_printError(ds
, "ucase_swap(): too few bytes (%d after header) for all of case mapping data\n",
258 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
262 /* copy the data for inaccessible bytes */
263 if(inBytes
!=outBytes
) {
264 uprv_memcpy(outBytes
, inBytes
, size
);
269 /* swap the int32_t indexes[] */
270 count
=indexes
[UCASE_IX_INDEX_TOP
]*4;
271 ds
->swapArray32(ds
, inBytes
, count
, outBytes
, pErrorCode
);
275 count
=indexes
[UCASE_IX_TRIE_SIZE
];
276 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
279 /* swap the uint16_t exceptions[] and unfold[] */
280 count
=(indexes
[UCASE_IX_EXC_LENGTH
]+indexes
[UCASE_IX_UNFOLD_LENGTH
])*2;
281 ds
->swapArray16(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
284 U_ASSERT(offset
==size
);
287 return headerSize
+size
;
290 /* Unicode bidi/shaping data swapping --------------------------------------- */
292 U_CAPI
int32_t U_EXPORT2
293 ubidi_swap(const UDataSwapper
*ds
,
294 const void *inData
, int32_t length
, void *outData
,
295 UErrorCode
*pErrorCode
) {
296 const UDataInfo
*pInfo
;
299 const uint8_t *inBytes
;
302 const int32_t *inIndexes
;
305 int32_t i
, offset
, count
, size
;
307 /* udata_swapDataHeader checks the arguments */
308 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
309 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
313 /* check data format and format version */
314 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
316 pInfo
->dataFormat
[0]==UBIDI_FMT_0
&& /* dataFormat="BiDi" */
317 pInfo
->dataFormat
[1]==UBIDI_FMT_1
&&
318 pInfo
->dataFormat
[2]==UBIDI_FMT_2
&&
319 pInfo
->dataFormat
[3]==UBIDI_FMT_3
&&
320 pInfo
->formatVersion
[0]==1 &&
321 pInfo
->formatVersion
[2]==UTRIE_SHIFT
&&
322 pInfo
->formatVersion
[3]==UTRIE_INDEX_SHIFT
324 udata_printError(ds
, "ubidi_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as bidi/shaping data\n",
325 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
326 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
327 pInfo
->formatVersion
[0]);
328 *pErrorCode
=U_UNSUPPORTED_ERROR
;
332 inBytes
=(const uint8_t *)inData
+headerSize
;
333 outBytes
=(uint8_t *)outData
+headerSize
;
335 inIndexes
=(const int32_t *)inBytes
;
340 udata_printError(ds
, "ubidi_swap(): too few bytes (%d after header) for bidi/shaping data\n",
342 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
347 /* read the first 16 indexes (ICU 3.4/format version 1: UBIDI_IX_TOP==16, might grow) */
348 for(i
=0; i
<16; ++i
) {
349 indexes
[i
]=udata_readInt32(ds
, inIndexes
[i
]);
352 /* get the total length of the data */
353 size
=indexes
[UBIDI_IX_LENGTH
];
357 udata_printError(ds
, "ubidi_swap(): too few bytes (%d after header) for all of bidi/shaping data\n",
359 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
363 /* copy the data for inaccessible bytes */
364 if(inBytes
!=outBytes
) {
365 uprv_memcpy(outBytes
, inBytes
, size
);
370 /* swap the int32_t indexes[] */
371 count
=indexes
[UBIDI_IX_INDEX_TOP
]*4;
372 ds
->swapArray32(ds
, inBytes
, count
, outBytes
, pErrorCode
);
376 count
=indexes
[UBIDI_IX_TRIE_SIZE
];
377 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
380 /* swap the uint32_t mirrors[] */
381 count
=indexes
[UBIDI_IX_MIRROR_LENGTH
]*4;
382 ds
->swapArray32(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
385 /* just skip the uint8_t jgArray[] */
386 count
=indexes
[UBIDI_IX_JG_LIMIT
]-indexes
[UBIDI_IX_JG_START
];
389 U_ASSERT(offset
==size
);
392 return headerSize
+size
;
395 /* Unicode normalization data swapping -------------------------------------- */
397 #if !UCONFIG_NO_NORMALIZATION
399 U_CAPI
int32_t U_EXPORT2
400 unorm_swap(const UDataSwapper
*ds
,
401 const void *inData
, int32_t length
, void *outData
,
402 UErrorCode
*pErrorCode
) {
403 const UDataInfo
*pInfo
;
406 const uint8_t *inBytes
;
409 const int32_t *inIndexes
;
412 int32_t i
, offset
, count
, size
;
414 /* udata_swapDataHeader checks the arguments */
415 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
416 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
420 /* check data format and format version */
421 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
423 pInfo
->dataFormat
[0]==0x4e && /* dataFormat="Norm" */
424 pInfo
->dataFormat
[1]==0x6f &&
425 pInfo
->dataFormat
[2]==0x72 &&
426 pInfo
->dataFormat
[3]==0x6d &&
427 pInfo
->formatVersion
[0]==2
429 udata_printError(ds
, "unorm_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as unorm.icu\n",
430 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
431 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
432 pInfo
->formatVersion
[0]);
433 *pErrorCode
=U_UNSUPPORTED_ERROR
;
437 inBytes
=(const uint8_t *)inData
+headerSize
;
438 outBytes
=(uint8_t *)outData
+headerSize
;
440 inIndexes
=(const int32_t *)inBytes
;
445 udata_printError(ds
, "unorm_swap(): too few bytes (%d after header) for unorm.icu\n",
447 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
452 /* read the first 32 indexes (ICU 2.8/format version 2.2: _NORM_INDEX_TOP==32, might grow) */
453 for(i
=0; i
<32; ++i
) {
454 indexes
[i
]=udata_readInt32(ds
, inIndexes
[i
]);
457 /* calculate the total length of the data */
459 32*4+ /* size of indexes[] */
460 indexes
[_NORM_INDEX_TRIE_SIZE
]+
461 indexes
[_NORM_INDEX_UCHAR_COUNT
]*2+
462 indexes
[_NORM_INDEX_COMBINE_DATA_COUNT
]*2+
463 indexes
[_NORM_INDEX_FCD_TRIE_SIZE
]+
464 indexes
[_NORM_INDEX_AUX_TRIE_SIZE
]+
465 indexes
[_NORM_INDEX_CANON_SET_COUNT
]*2;
469 udata_printError(ds
, "unorm_swap(): too few bytes (%d after header) for all of unorm.icu\n",
471 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
475 /* copy the data for inaccessible bytes */
476 if(inBytes
!=outBytes
) {
477 uprv_memcpy(outBytes
, inBytes
, size
);
482 /* swap the indexes[] */
484 ds
->swapArray32(ds
, inBytes
, count
, outBytes
, pErrorCode
);
487 /* swap the main UTrie */
488 count
=indexes
[_NORM_INDEX_TRIE_SIZE
];
489 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
492 /* swap the uint16_t extraData[] and the uint16_t combiningTable[] */
493 count
=(indexes
[_NORM_INDEX_UCHAR_COUNT
]+indexes
[_NORM_INDEX_COMBINE_DATA_COUNT
])*2;
494 ds
->swapArray16(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
497 /* swap the FCD UTrie */
498 count
=indexes
[_NORM_INDEX_FCD_TRIE_SIZE
];
500 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
504 /* swap the aux UTrie */
505 count
=indexes
[_NORM_INDEX_AUX_TRIE_SIZE
];
507 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
511 /* swap the uint16_t combiningTable[] */
512 count
=indexes
[_NORM_INDEX_CANON_SET_COUNT
]*2;
513 ds
->swapArray16(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
517 return headerSize
+size
;
522 /* swap any data (except a .dat package) ------------------------------------ */
524 static const struct {
525 uint8_t dataFormat
[4];
528 { { 0x52, 0x65, 0x73, 0x42 }, ures_swap
}, /* dataFormat="ResB" */
529 #if !UCONFIG_NO_LEGACY_CONVERSION
530 { { 0x63, 0x6e, 0x76, 0x74 }, ucnv_swap
}, /* dataFormat="cnvt" */
532 #if !UCONFIG_NO_CONVERSION
533 { { 0x43, 0x76, 0x41, 0x6c }, ucnv_swapAliases
}, /* dataFormat="CvAl" */
536 { { 0x53, 0x50, 0x52, 0x50 }, usprep_swap
}, /* dataFormat="SPRP" */
538 /* insert data formats here, descending by expected frequency of occurrence */
539 { { 0x55, 0x50, 0x72, 0x6f }, uprops_swap
}, /* dataFormat="UPro" */
541 { { UCASE_FMT_0
, UCASE_FMT_1
, UCASE_FMT_2
, UCASE_FMT_3
},
542 ucase_swap
}, /* dataFormat="cAsE" */
544 { { UBIDI_FMT_0
, UBIDI_FMT_1
, UBIDI_FMT_2
, UBIDI_FMT_3
},
545 ubidi_swap
}, /* dataFormat="BiDi" */
547 #if !UCONFIG_NO_NORMALIZATION
548 { { 0x4e, 0x6f, 0x72, 0x6d }, unorm_swap
}, /* dataFormat="Norm" */
550 #if !UCONFIG_NO_COLLATION
551 { { 0x55, 0x43, 0x6f, 0x6c }, ucol_swap
}, /* dataFormat="UCol" */
552 { { 0x49, 0x6e, 0x76, 0x43 }, ucol_swapInverseUCA
},/* dataFormat="InvC" */
554 #if !UCONFIG_NO_BREAK_ITERATION
555 { { 0x42, 0x72, 0x6b, 0x20 }, ubrk_swap
}, /* dataFormat="Brk " */
556 { { 0x54, 0x72, 0x44, 0x63 }, triedict_swap
}, /* dataFormat="TrDc " */
558 { { 0x70, 0x6e, 0x61, 0x6d }, upname_swap
}, /* dataFormat="pnam" */
559 { { 0x75, 0x6e, 0x61, 0x6d }, uchar_swapNames
} /* dataFormat="unam" */
562 U_CAPI
int32_t U_EXPORT2
563 udata_swap(const UDataSwapper
*ds
,
564 const void *inData
, int32_t length
, void *outData
,
565 UErrorCode
*pErrorCode
) {
566 char dataFormatChars
[4];
567 const UDataInfo
*pInfo
;
568 int32_t headerSize
, i
, swappedLength
;
570 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
575 * Preflight the header first; checks for illegal arguments, too.
576 * Do not swap the header right away because the format-specific swapper
577 * will swap it, get the headerSize again, and also use the header
578 * information. Otherwise we would have to pass some of the information
579 * and not be able to use the UDataSwapFn signature.
581 headerSize
=udata_swapDataHeader(ds
, inData
, -1, NULL
, pErrorCode
);
584 * If we wanted udata_swap() to also handle non-loadable data like a UTrie,
585 * then we could check here for further known magic values and structures.
587 if(U_FAILURE(*pErrorCode
)) {
588 return 0; /* the data format was not recognized */
591 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
594 /* convert the data format from ASCII to Unicode to the system charset */
596 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
597 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3]
600 if(uprv_isInvariantUString(u
, 4)) {
601 u_UCharsToChars(u
, dataFormatChars
, 4);
603 dataFormatChars
[0]=dataFormatChars
[1]=dataFormatChars
[2]=dataFormatChars
[3]='?';
607 /* dispatch to the swap function for the dataFormat */
608 for(i
=0; i
<LENGTHOF(swapFns
); ++i
) {
609 if(0==memcmp(swapFns
[i
].dataFormat
, pInfo
->dataFormat
, 4)) {
610 swappedLength
=swapFns
[i
].swapFn(ds
, inData
, length
, outData
, pErrorCode
);
612 if(U_FAILURE(*pErrorCode
)) {
613 udata_printError(ds
, "udata_swap(): failure swapping data format %02x.%02x.%02x.%02x (\"%c%c%c%c\") - %s\n",
614 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
615 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
616 dataFormatChars
[0], dataFormatChars
[1],
617 dataFormatChars
[2], dataFormatChars
[3],
618 u_errorName(*pErrorCode
));
619 } else if(swappedLength
<(length
-15)) {
620 /* swapped less than expected */
621 udata_printError(ds
, "udata_swap() warning: swapped only %d out of %d bytes - data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
622 swappedLength
, length
,
623 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
624 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
625 dataFormatChars
[0], dataFormatChars
[1],
626 dataFormatChars
[2], dataFormatChars
[3],
627 u_errorName(*pErrorCode
));
630 return swappedLength
;
634 /* the dataFormat was not recognized */
635 udata_printError(ds
, "udata_swap(): unknown data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
636 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
637 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
638 dataFormatChars
[0], dataFormatChars
[1],
639 dataFormatChars
[2], dataFormatChars
[3]);
641 *pErrorCode
=U_UNSUPPORTED_ERROR
;