1f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/*
2f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*******************************************************************************
3f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
4f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Copyright (C) 2003-2010, International Business Machines
5f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Corporation and others.  All Rights Reserved.
6f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
7f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*******************************************************************************
8f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   file name:  ucol_swp.c
9f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   encoding:   US-ASCII
10f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   tab size:   8 (not used)
11f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   indentation:4
12f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
13f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   created on: 2003sep10
14f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   created by: Markus W. Scherer
15f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
16f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Swap collation binaries.
17f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*/
18f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
19f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/udata.h" /* UDataInfo */
20f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "utrie.h"
21f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "udataswp.h"
22f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "cmemory.h"
23f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucol_imp.h"
24f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "ucol_swp.h"
25f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
26f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* swapping ----------------------------------------------------------------- */
27f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
28f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/*
29f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * This performs data swapping for a folded trie (see utrie.c for details).
30f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) */
31f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
32f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
33f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)utrie_swap(const UDataSwapper *ds,
34f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)           const void *inData, int32_t length, void *outData,
35f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)           UErrorCode *pErrorCode) {
36f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UTrieHeader *inTrie;
37f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UTrieHeader trie;
38f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t size;
39f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UBool dataIs32;
40f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
41f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
42f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
43f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
44f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(ds==NULL || inData==NULL || (length>=0 && outData==NULL)) {
45f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
46f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
47f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
48f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
49f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* setup and swapping */
50f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length>=0 && (uint32_t)length<sizeof(UTrieHeader)) {
51f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
52f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
53f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
54f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
55f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inTrie=(const UTrieHeader *)inData;
56f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    trie.signature=ds->readUInt32(inTrie->signature);
57f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    trie.options=ds->readUInt32(inTrie->options);
58f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    trie.indexLength=udata_readInt32(ds, inTrie->indexLength);
59f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    trie.dataLength=udata_readInt32(ds, inTrie->dataLength);
60f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
61f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if( trie.signature!=0x54726965 ||
62f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        (trie.options&UTRIE_OPTIONS_SHIFT_MASK)!=UTRIE_SHIFT ||
63f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ((trie.options>>UTRIE_OPTIONS_INDEX_SHIFT)&UTRIE_OPTIONS_SHIFT_MASK)!=UTRIE_INDEX_SHIFT ||
64f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        trie.indexLength<UTRIE_BMP_INDEX_LENGTH ||
65f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        (trie.indexLength&(UTRIE_SURROGATE_BLOCK_COUNT-1))!=0 ||
66f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        trie.dataLength<UTRIE_DATA_BLOCK_LENGTH ||
67f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        (trie.dataLength&(UTRIE_DATA_GRANULARITY-1))!=0 ||
68f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ((trie.options&UTRIE_OPTIONS_LATIN1_IS_LINEAR)!=0 && trie.dataLength<(UTRIE_DATA_BLOCK_LENGTH+0x100))
69f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ) {
70f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_INVALID_FORMAT_ERROR; /* not a UTrie */
71f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
72f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
73f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
74f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    dataIs32=(UBool)((trie.options&UTRIE_OPTIONS_DATA_IS_32_BIT)!=0);
75f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    size=sizeof(UTrieHeader)+trie.indexLength*2+trie.dataLength*(dataIs32?4:2);
76f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
77f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length>=0) {
78f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UTrieHeader *outTrie;
79f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
80f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(length<size) {
81f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
82f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            return 0;
83f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
84f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
85f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        outTrie=(UTrieHeader *)outData;
86f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
87f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the header */
88f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ds->swapArray32(ds, inTrie, sizeof(UTrieHeader), outTrie, pErrorCode);
89f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
90f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the index and the data */
91f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(dataIs32) {
92f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray16(ds, inTrie+1, trie.indexLength*2, outTrie+1, pErrorCode);
93f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray32(ds, (const uint16_t *)(inTrie+1)+trie.indexLength, trie.dataLength*4,
94f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                     (uint16_t *)(outTrie+1)+trie.indexLength, pErrorCode);
95f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
96f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray16(ds, inTrie+1, (trie.indexLength+trie.dataLength)*2, outTrie+1, pErrorCode);
97f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
98f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
99f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
100f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return size;
101f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
102f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
103f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#if !UCONFIG_NO_COLLATION
104f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
105f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* Modified copy of the beginning of ucol_swapBinary(). */
106f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI UBool U_EXPORT2
107f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_looksLikeCollationBinary(const UDataSwapper *ds,
108f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                              const void *inData, int32_t length) {
109f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const uint8_t *inBytes;
110f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UCATableHeader *inHeader;
111f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCATableHeader header;
112f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
113f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(ds==NULL || inData==NULL || length<-1) {
114f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return FALSE;
115f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
116f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
117f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inBytes=(const uint8_t *)inData;
118f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inHeader=(const UCATableHeader *)inData;
119f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
120f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /*
121f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * The collation binary must contain at least the UCATableHeader,
122f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * starting with its size field.
123f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * sizeof(UCATableHeader)==42*4 in ICU 2.8
124f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * check the length against the header size before reading the size field
125f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     */
126f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uprv_memset(&header, 0, sizeof(header));
127f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length<0) {
128f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.size=udata_readInt32(ds, inHeader->size);
129f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) {
130f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return FALSE;
131f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
132f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
133f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    header.magic=ds->readUInt32(inHeader->magic);
134f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(!(
135f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.magic==UCOL_HEADER_MAGIC &&
136f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        inHeader->formatVersion[0]==3 /*&&
137f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        inHeader->formatVersion[1]>=0*/
138f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    )) {
139f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return FALSE;
140f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
141f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
142f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) {
143f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return FALSE;
144f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
145f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
146f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return TRUE;
147f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
148f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
149f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* swap a header-less collation binary, inside a resource bundle or ucadata.icu */
150f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
151f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_swapBinary(const UDataSwapper *ds,
152f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                const void *inData, int32_t length, void *outData,
153f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                UErrorCode *pErrorCode) {
154f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const uint8_t *inBytes;
155f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint8_t *outBytes;
156f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
157f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UCATableHeader *inHeader;
158f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCATableHeader *outHeader;
159f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UCATableHeader header;
160f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
161f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint32_t count;
162f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
163f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* argument checking in case we were not called from ucol_swap() */
164f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
165f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
166f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
167f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
168f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
169f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
170f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
171f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
172f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inBytes=(const uint8_t *)inData;
173f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    outBytes=(uint8_t *)outData;
174f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
175f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inHeader=(const UCATableHeader *)inData;
176f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    outHeader=(UCATableHeader *)outData;
177f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
178f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /*
179f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * The collation binary must contain at least the UCATableHeader,
180f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * starting with its size field.
181f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * sizeof(UCATableHeader)==42*4 in ICU 2.8
182f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * check the length against the header size before reading the size field
183f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     */
184f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uprv_memset(&header, 0, sizeof(header));
185f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length<0) {
186f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.size=udata_readInt32(ds, inHeader->size);
187f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) {
188f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_printError(ds, "ucol_swapBinary(): too few bytes (%d after header) for collation data\n",
189f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         length);
190f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
191f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
192f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
193f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
194f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    header.magic=ds->readUInt32(inHeader->magic);
195f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(!(
196f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.magic==UCOL_HEADER_MAGIC &&
197f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        inHeader->formatVersion[0]==3 /*&&
198f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        inHeader->formatVersion[1]>=0*/
199f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    )) {
200f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_printError(ds, "ucol_swapBinary(): magic 0x%08x or format version %02x.%02x is not a collation binary\n",
201f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         header.magic,
202f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         inHeader->formatVersion[0], inHeader->formatVersion[1]);
203f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_UNSUPPORTED_ERROR;
204f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
205f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
206f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
207f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) {
208f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_printError(ds, "ucol_swapBinary(): endianness %d or charset %d does not match the swapper\n",
209f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         inHeader->isBigEndian, inHeader->charSetFamily);
210f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_INVALID_FORMAT_ERROR;
211f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
212f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
213f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
214f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length>=0) {
215f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* copy everything, takes care of data that needs no swapping */
216f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(inBytes!=outBytes) {
217f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_memcpy(outBytes, inBytes, header.size);
218f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
219f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
220f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the necessary pieces in the order of their occurrence in the data */
221f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
222f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* read more of the UCATableHeader (the size field was read above) */
223f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.options=                 ds->readUInt32(inHeader->options);
224f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.UCAConsts=               ds->readUInt32(inHeader->UCAConsts);
225f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.contractionUCACombos=    ds->readUInt32(inHeader->contractionUCACombos);
226f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.mappingPosition=         ds->readUInt32(inHeader->mappingPosition);
227f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.expansion=               ds->readUInt32(inHeader->expansion);
228f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.contractionIndex=        ds->readUInt32(inHeader->contractionIndex);
229f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.contractionCEs=          ds->readUInt32(inHeader->contractionCEs);
230f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.contractionSize=         ds->readUInt32(inHeader->contractionSize);
231f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.endExpansionCE=          ds->readUInt32(inHeader->endExpansionCE);
232f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.expansionCESize=         ds->readUInt32(inHeader->expansionCESize);
233f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.endExpansionCECount=     udata_readInt32(ds, inHeader->endExpansionCECount);
234f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.contractionUCACombosSize=udata_readInt32(ds, inHeader->contractionUCACombosSize);
235f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.scriptToLeadByte=        ds->readUInt32(inHeader->scriptToLeadByte);
236f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.leadByteToScript=        ds->readUInt32(inHeader->leadByteToScript);
237f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
238f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the 32-bit integers in the header */
239f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ds->swapArray32(ds, inHeader, (int32_t)((const char *)&inHeader->jamoSpecial-(const char *)inHeader),
240f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           outHeader, pErrorCode);
241f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ds->swapArray32(ds, &(inHeader->scriptToLeadByte), sizeof(header.scriptToLeadByte) + sizeof(header.leadByteToScript),
242f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           &(outHeader->scriptToLeadByte), pErrorCode);
243f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* set the output platform properties */
244f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        outHeader->isBigEndian=ds->outIsBigEndian;
245f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        outHeader->charSetFamily=ds->outCharset;
246f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
247f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the options */
248f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.options!=0) {
249f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray32(ds, inBytes+header.options, header.expansion-header.options,
250f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.options, pErrorCode);
251f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
252f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
253f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the expansions */
254f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.mappingPosition!=0 && header.expansion!=0) {
255f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(header.contractionIndex!=0) {
256f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                /* expansions bounded by contractions */
257f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                count=header.contractionIndex-header.expansion;
258f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            } else {
259f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                /* no contractions: expansions bounded by the main trie */
260f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                count=header.mappingPosition-header.expansion;
261f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
262f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray32(ds, inBytes+header.expansion, (int32_t)count,
263f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.expansion, pErrorCode);
264f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
265f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
266f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the contractions */
267f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.contractionSize!=0) {
268f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            /* contractionIndex: UChar[] */
269f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray16(ds, inBytes+header.contractionIndex, header.contractionSize*2,
270f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.contractionIndex, pErrorCode);
271f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
272f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            /* contractionCEs: CEs[] */
273f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray32(ds, inBytes+header.contractionCEs, header.contractionSize*4,
274f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.contractionCEs, pErrorCode);
275f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
276f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
277f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the main trie */
278f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.mappingPosition!=0) {
279f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            count=header.endExpansionCE-header.mappingPosition;
280f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            utrie_swap(ds, inBytes+header.mappingPosition, (int32_t)count,
281f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                          outBytes+header.mappingPosition, pErrorCode);
282f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
283f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
284f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the max expansion table */
285f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.endExpansionCECount!=0) {
286f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray32(ds, inBytes+header.endExpansionCE, header.endExpansionCECount*4,
287f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.endExpansionCE, pErrorCode);
288f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
289f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
290f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* expansionCESize, unsafeCP, contrEndCP: uint8_t[], no need to swap */
291f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
292f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap UCA constants */
293f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.UCAConsts!=0) {
294f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            /*
295f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             * if UCAConsts!=0 then contractionUCACombos because we are swapping
296f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             * the UCA data file, and we know that the UCA contains contractions
297f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)             */
298f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            count=header.contractionUCACombos-header.UCAConsts;
299f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray32(ds, inBytes+header.UCAConsts, header.contractionUCACombos-header.UCAConsts,
300f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.UCAConsts, pErrorCode);
301f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
302f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
303f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap UCA contractions */
304f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.contractionUCACombosSize!=0) {
305f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            count=header.contractionUCACombosSize*inHeader->contractionUCACombosWidth*U_SIZEOF_UCHAR;
306f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray16(ds, inBytes+header.contractionUCACombos, (int32_t)count,
307f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                               outBytes+header.contractionUCACombos, pErrorCode);
308f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
309f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
310f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the script to lead bytes */
311f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.scriptToLeadByte!=0) {
312f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int indexCount = ds->readUInt16(*((uint16_t*)(inBytes+header.scriptToLeadByte))); // each entry = 2 * uint16
313f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int dataCount = ds->readUInt16(*((uint16_t*)(inBytes+header.scriptToLeadByte + 2))); // each entry = uint16
314f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray16(ds, inBytes+header.scriptToLeadByte,
315f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                4 + (4 * indexCount) + (2 * dataCount),
316f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                outBytes+header.scriptToLeadByte, pErrorCode);
317f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
318f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
319f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the lead byte to scripts */
320f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(header.leadByteToScript!=0) {
321f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int indexCount = ds->readUInt16(*((uint16_t*)(inBytes+header.leadByteToScript))); // each entry = uint16
322f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int dataCount = ds->readUInt16(*((uint16_t*)(inBytes+header.leadByteToScript + 2))); // each entry = uint16
323f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ds->swapArray16(ds, inBytes+header.leadByteToScript,
324f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                4 + (2 * indexCount) + (2 * dataCount),
325f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                                outBytes+header.leadByteToScript, pErrorCode);
326f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
327f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
328f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
329f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return header.size;
330f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
331f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
332f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* swap ICU collation data like ucadata.icu */
333f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
334f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_swap(const UDataSwapper *ds,
335f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)          const void *inData, int32_t length, void *outData,
336f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)          UErrorCode *pErrorCode) {
337f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
338f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UDataInfo *pInfo;
339f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t headerSize, collationSize;
340f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
341f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* udata_swapDataHeader checks the arguments */
342f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
343f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
344f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
345f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
346f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
347f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* check data format and format version */
348f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    pInfo=(const UDataInfo *)((const char *)inData+4);
349f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(!(
350f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[0]==0x55 &&   /* dataFormat="UCol" */
351f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[1]==0x43 &&
352f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[2]==0x6f &&
353f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[3]==0x6c &&
354f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->formatVersion[0]==3 /*&&
355f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->formatVersion[1]>=0*/
356f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    )) {
357f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_printError(ds, "ucol_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not a collation file\n",
358f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         pInfo->dataFormat[0], pInfo->dataFormat[1],
359f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         pInfo->dataFormat[2], pInfo->dataFormat[3],
360f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
361f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_UNSUPPORTED_ERROR;
362f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
363f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
364f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
365f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    collationSize=ucol_swapBinary(ds,
366f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        (const char *)inData+headerSize,
367f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        length>=0 ? length-headerSize : -1,
368f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        (char *)outData+headerSize,
369f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        pErrorCode);
370f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(U_SUCCESS(*pErrorCode)) {
371f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return headerSize+collationSize;
372f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else {
373f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
374f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
375f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
376f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
377f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* swap inverse UCA collation data (invuca.icu) */
378f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CAPI int32_t U_EXPORT2
379f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)ucol_swapInverseUCA(const UDataSwapper *ds,
380f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    const void *inData, int32_t length, void *outData,
381f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    UErrorCode *pErrorCode) {
382f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UDataInfo *pInfo;
383f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t headerSize;
384f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
385f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const uint8_t *inBytes;
386f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    uint8_t *outBytes;
387f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
388f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const InverseUCATableHeader *inHeader;
389f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    InverseUCATableHeader *outHeader;
390f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    InverseUCATableHeader header={ 0,0,0,0,0,{0,0,0,0},{0,0,0,0,0,0,0,0} };
391f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
392f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* udata_swapDataHeader checks the arguments */
393f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
394f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
395f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
396f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
397f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
398f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /* check data format and format version */
399f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    pInfo=(const UDataInfo *)((const char *)inData+4);
400f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(!(
401f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[0]==0x49 &&   /* dataFormat="InvC" */
402f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[1]==0x6e &&
403f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[2]==0x76 &&
404f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->dataFormat[3]==0x43 &&
405f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->formatVersion[0]==2 &&
406f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        pInfo->formatVersion[1]>=1
407f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    )) {
408f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_printError(ds, "ucol_swapInverseUCA(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not an inverse UCA collation file\n",
409f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         pInfo->dataFormat[0], pInfo->dataFormat[1],
410f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         pInfo->dataFormat[2], pInfo->dataFormat[3],
411f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
412f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_UNSUPPORTED_ERROR;
413f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
414f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
415f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
416f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inBytes=(const uint8_t *)inData+headerSize;
417f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    outBytes=(uint8_t *)outData+headerSize;
418f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
419f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    inHeader=(const InverseUCATableHeader *)inBytes;
420f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    outHeader=(InverseUCATableHeader *)outBytes;
421f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
422f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    /*
423f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * The inverse UCA collation binary must contain at least the InverseUCATableHeader,
424f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * starting with its size field.
425f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * sizeof(UCATableHeader)==8*4 in ICU 2.8
426f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     * check the length against the header size before reading the size field
427f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)     */
428f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length<0) {
429f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.byteSize=udata_readInt32(ds, inHeader->byteSize);
430f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else if(
431f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ((length-headerSize)<(8*4) ||
432f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         (uint32_t)(length-headerSize)<(header.byteSize=udata_readInt32(ds, inHeader->byteSize)))
433f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    ) {
434f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        udata_printError(ds, "ucol_swapInverseUCA(): too few bytes (%d after header) for inverse UCA collation data\n",
435f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                         length);
436f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
437f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
438f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
439f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
440f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if(length>=0) {
441f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* copy everything, takes care of data that needs no swapping */
442f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(inBytes!=outBytes) {
443f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            uprv_memcpy(outBytes, inBytes, header.byteSize);
444f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
445f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
446f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the necessary pieces in the order of their occurrence in the data */
447f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
448f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* read more of the InverseUCATableHeader (the byteSize field was read above) */
449f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.tableSize=   ds->readUInt32(inHeader->tableSize);
450f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.contsSize=   ds->readUInt32(inHeader->contsSize);
451f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.table=       ds->readUInt32(inHeader->table);
452f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        header.conts=       ds->readUInt32(inHeader->conts);
453f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
454f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the 32-bit integers in the header */
455f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ds->swapArray32(ds, inHeader, 5*4, outHeader, pErrorCode);
456f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
457f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the inverse table; tableSize counts uint32_t[3] rows */
458f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ds->swapArray32(ds, inBytes+header.table, header.tableSize*3*4,
459f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           outBytes+header.table, pErrorCode);
460f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
461f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /* swap the continuation table; contsSize counts UChars */
462f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        ds->swapArray16(ds, inBytes+header.conts, header.contsSize*U_SIZEOF_UCHAR,
463f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           outBytes+header.conts, pErrorCode);
464f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
465f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
466f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return headerSize+header.byteSize;
467f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
468f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
469f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#endif /* #if !UCONFIG_NO_COLLATION */
470