1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
5 // created: 2018aug08 Markus W. Scherer
7 #include "unicode/utypes.h"
9 #include "ucptrie_impl.h"
12 #include "utrie2_impl.h"
14 // These functions for swapping different generations of ICU code point tries are here
15 // so that their implementation files need not depend on swapper code,
16 // need not depend on each other, and so that other swapper code
17 // need not depend on other trie code.
21 constexpr int32_t ASCII_LIMIT
= 0x80;
25 U_CAPI
int32_t U_EXPORT2
26 utrie_swap(const UDataSwapper
*ds
,
27 const void *inData
, int32_t length
, void *outData
,
28 UErrorCode
*pErrorCode
) {
29 const UTrieHeader
*inTrie
;
34 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
37 if(ds
==NULL
|| inData
==NULL
|| (length
>=0 && outData
==NULL
)) {
38 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
42 /* setup and swapping */
43 if(length
>=0 && (uint32_t)length
<sizeof(UTrieHeader
)) {
44 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
48 inTrie
=(const UTrieHeader
*)inData
;
49 trie
.signature
=ds
->readUInt32(inTrie
->signature
);
50 trie
.options
=ds
->readUInt32(inTrie
->options
);
51 trie
.indexLength
=udata_readInt32(ds
, inTrie
->indexLength
);
52 trie
.dataLength
=udata_readInt32(ds
, inTrie
->dataLength
);
54 if( trie
.signature
!=0x54726965 ||
55 (trie
.options
&UTRIE_OPTIONS_SHIFT_MASK
)!=UTRIE_SHIFT
||
56 ((trie
.options
>>UTRIE_OPTIONS_INDEX_SHIFT
)&UTRIE_OPTIONS_SHIFT_MASK
)!=UTRIE_INDEX_SHIFT
||
57 trie
.indexLength
<UTRIE_BMP_INDEX_LENGTH
||
58 (trie
.indexLength
&(UTRIE_SURROGATE_BLOCK_COUNT
-1))!=0 ||
59 trie
.dataLength
<UTRIE_DATA_BLOCK_LENGTH
||
60 (trie
.dataLength
&(UTRIE_DATA_GRANULARITY
-1))!=0 ||
61 ((trie
.options
&UTRIE_OPTIONS_LATIN1_IS_LINEAR
)!=0 && trie
.dataLength
<(UTRIE_DATA_BLOCK_LENGTH
+0x100))
63 *pErrorCode
=U_INVALID_FORMAT_ERROR
; /* not a UTrie */
67 dataIs32
=(UBool
)((trie
.options
&UTRIE_OPTIONS_DATA_IS_32_BIT
)!=0);
68 size
=sizeof(UTrieHeader
)+trie
.indexLength
*2+trie
.dataLength
*(dataIs32
?4:2);
74 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
78 outTrie
=(UTrieHeader
*)outData
;
81 ds
->swapArray32(ds
, inTrie
, sizeof(UTrieHeader
), outTrie
, pErrorCode
);
83 /* swap the index and the data */
85 ds
->swapArray16(ds
, inTrie
+1, trie
.indexLength
*2, outTrie
+1, pErrorCode
);
86 ds
->swapArray32(ds
, (const uint16_t *)(inTrie
+1)+trie
.indexLength
, trie
.dataLength
*4,
87 (uint16_t *)(outTrie
+1)+trie
.indexLength
, pErrorCode
);
89 ds
->swapArray16(ds
, inTrie
+1, (trie
.indexLength
+trie
.dataLength
)*2, outTrie
+1, pErrorCode
);
96 U_CAPI
int32_t U_EXPORT2
97 utrie2_swap(const UDataSwapper
*ds
,
98 const void *inData
, int32_t length
, void *outData
,
99 UErrorCode
*pErrorCode
) {
100 const UTrie2Header
*inTrie
;
102 int32_t dataLength
, size
;
103 UTrie2ValueBits valueBits
;
105 if(U_FAILURE(*pErrorCode
)) {
108 if(ds
==NULL
|| inData
==NULL
|| (length
>=0 && outData
==NULL
)) {
109 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
113 /* setup and swapping */
114 if(length
>=0 && length
<(int32_t)sizeof(UTrie2Header
)) {
115 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
119 inTrie
=(const UTrie2Header
*)inData
;
120 trie
.signature
=ds
->readUInt32(inTrie
->signature
);
121 trie
.options
=ds
->readUInt16(inTrie
->options
);
122 trie
.indexLength
=ds
->readUInt16(inTrie
->indexLength
);
123 trie
.shiftedDataLength
=ds
->readUInt16(inTrie
->shiftedDataLength
);
125 valueBits
=(UTrie2ValueBits
)(trie
.options
&UTRIE2_OPTIONS_VALUE_BITS_MASK
);
126 dataLength
=(int32_t)trie
.shiftedDataLength
<<UTRIE2_INDEX_SHIFT
;
128 if( trie
.signature
!=UTRIE2_SIG
||
129 valueBits
<0 || UTRIE2_COUNT_VALUE_BITS
<=valueBits
||
130 trie
.indexLength
<UTRIE2_INDEX_1_OFFSET
||
131 dataLength
<UTRIE2_DATA_START_OFFSET
133 *pErrorCode
=U_INVALID_FORMAT_ERROR
; /* not a UTrie */
137 size
=sizeof(UTrie2Header
)+trie
.indexLength
*2;
139 case UTRIE2_16_VALUE_BITS
:
142 case UTRIE2_32_VALUE_BITS
:
146 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
151 UTrie2Header
*outTrie
;
154 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
158 outTrie
=(UTrie2Header
*)outData
;
160 /* swap the header */
161 ds
->swapArray32(ds
, &inTrie
->signature
, 4, &outTrie
->signature
, pErrorCode
);
162 ds
->swapArray16(ds
, &inTrie
->options
, 12, &outTrie
->options
, pErrorCode
);
164 /* swap the index and the data */
166 case UTRIE2_16_VALUE_BITS
:
167 ds
->swapArray16(ds
, inTrie
+1, (trie
.indexLength
+dataLength
)*2, outTrie
+1, pErrorCode
);
169 case UTRIE2_32_VALUE_BITS
:
170 ds
->swapArray16(ds
, inTrie
+1, trie
.indexLength
*2, outTrie
+1, pErrorCode
);
171 ds
->swapArray32(ds
, (const uint16_t *)(inTrie
+1)+trie
.indexLength
, dataLength
*4,
172 (uint16_t *)(outTrie
+1)+trie
.indexLength
, pErrorCode
);
175 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
183 U_CAPI
int32_t U_EXPORT2
184 ucptrie_swap(const UDataSwapper
*ds
,
185 const void *inData
, int32_t length
, void *outData
,
186 UErrorCode
*pErrorCode
) {
187 const UCPTrieHeader
*inTrie
;
189 int32_t dataLength
, size
;
190 UCPTrieValueWidth valueWidth
;
192 if(U_FAILURE(*pErrorCode
)) {
195 if(ds
==nullptr || inData
==nullptr || (length
>=0 && outData
==nullptr)) {
196 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
200 /* setup and swapping */
201 if(length
>=0 && length
<(int32_t)sizeof(UCPTrieHeader
)) {
202 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
206 inTrie
=(const UCPTrieHeader
*)inData
;
207 trie
.signature
=ds
->readUInt32(inTrie
->signature
);
208 trie
.options
=ds
->readUInt16(inTrie
->options
);
209 trie
.indexLength
=ds
->readUInt16(inTrie
->indexLength
);
210 trie
.dataLength
= ds
->readUInt16(inTrie
->dataLength
);
212 UCPTrieType type
= (UCPTrieType
)((trie
.options
>> 6) & 3);
213 valueWidth
= (UCPTrieValueWidth
)(trie
.options
& UCPTRIE_OPTIONS_VALUE_BITS_MASK
);
214 dataLength
= ((int32_t)(trie
.options
& UCPTRIE_OPTIONS_DATA_LENGTH_MASK
) << 4) | trie
.dataLength
;
216 int32_t minIndexLength
= type
== UCPTRIE_TYPE_FAST
?
217 UCPTRIE_BMP_INDEX_LENGTH
: UCPTRIE_SMALL_INDEX_LENGTH
;
218 if( trie
.signature
!=UCPTRIE_SIG
||
219 type
> UCPTRIE_TYPE_SMALL
||
220 (trie
.options
& UCPTRIE_OPTIONS_RESERVED_MASK
) != 0 ||
221 valueWidth
> UCPTRIE_VALUE_BITS_8
||
222 trie
.indexLength
< minIndexLength
||
223 dataLength
< ASCII_LIMIT
225 *pErrorCode
=U_INVALID_FORMAT_ERROR
; /* not a UCPTrie */
229 size
=sizeof(UCPTrieHeader
)+trie
.indexLength
*2;
231 case UCPTRIE_VALUE_BITS_16
:
234 case UCPTRIE_VALUE_BITS_32
:
237 case UCPTRIE_VALUE_BITS_8
:
241 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
246 UCPTrieHeader
*outTrie
;
249 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
253 outTrie
=(UCPTrieHeader
*)outData
;
255 /* swap the header */
256 ds
->swapArray32(ds
, &inTrie
->signature
, 4, &outTrie
->signature
, pErrorCode
);
257 ds
->swapArray16(ds
, &inTrie
->options
, 12, &outTrie
->options
, pErrorCode
);
259 /* swap the index and the data */
261 case UCPTRIE_VALUE_BITS_16
:
262 ds
->swapArray16(ds
, inTrie
+1, (trie
.indexLength
+dataLength
)*2, outTrie
+1, pErrorCode
);
264 case UCPTRIE_VALUE_BITS_32
:
265 ds
->swapArray16(ds
, inTrie
+1, trie
.indexLength
*2, outTrie
+1, pErrorCode
);
266 ds
->swapArray32(ds
, (const uint16_t *)(inTrie
+1)+trie
.indexLength
, dataLength
*4,
267 (uint16_t *)(outTrie
+1)+trie
.indexLength
, pErrorCode
);
269 case UCPTRIE_VALUE_BITS_8
:
270 ds
->swapArray16(ds
, inTrie
+1, trie
.indexLength
*2, outTrie
+1, pErrorCode
);
271 if(inTrie
!=outTrie
) {
272 uprv_memmove((outTrie
+1)+trie
.indexLength
, (inTrie
+1)+trie
.indexLength
, dataLength
);
276 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
287 * Gets the trie version from 32-bit-aligned memory containing the serialized form
288 * of a UTrie (version 1), a UTrie2 (version 2), or a UCPTrie (version 3).
290 * @param data a pointer to 32-bit-aligned memory containing the serialized form of a trie
291 * @param length the number of bytes available at data;
292 * can be more than necessary (see return value)
293 * @param anyEndianOk If FALSE, only platform-endian serialized forms are recognized.
294 * If TRUE, opposite-endian serialized forms are recognized as well.
295 * @return the trie version of the serialized form, or 0 if it is not
296 * recognized as a serialized trie
299 getVersion(const void *data
, int32_t length
, UBool anyEndianOk
) {
301 if(length
<16 || data
==nullptr || (U_POINTER_MASK_LSB(data
, 3)!=0)) {
304 signature
=*(const uint32_t *)data
;
305 if(signature
==UCPTRIE_SIG
) {
308 if(anyEndianOk
&& signature
==UCPTRIE_OE_SIG
) {
311 if(signature
==UTRIE2_SIG
) {
314 if(anyEndianOk
&& signature
==UTRIE2_OE_SIG
) {
317 if(signature
==UTRIE_SIG
) {
320 if(anyEndianOk
&& signature
==UTRIE_OE_SIG
) {
328 U_CAPI
int32_t U_EXPORT2
329 utrie_swapAnyVersion(const UDataSwapper
*ds
,
330 const void *inData
, int32_t length
, void *outData
,
331 UErrorCode
*pErrorCode
) {
332 if(U_FAILURE(*pErrorCode
)) { return 0; }
333 switch(getVersion(inData
, length
, TRUE
)) {
335 return utrie_swap(ds
, inData
, length
, outData
, pErrorCode
);
337 return utrie2_swap(ds
, inData
, length
, outData
, pErrorCode
);
339 return ucptrie_swap(ds
, inData
, length
, outData
, pErrorCode
);
341 *pErrorCode
=U_INVALID_FORMAT_ERROR
;