1fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/*
2fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*******************************************************************************
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Copyright (C) 2013-2014, International Business Machines
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Corporation and others.  All Rights Reserved.
5fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*******************************************************************************
6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* collationdatareader.cpp
7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*
8fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* created on: 2013feb07
9fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* created by: Markus W. Scherer
10fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/
11fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
12fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/utypes.h"
13fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
14fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#if !UCONFIG_NO_COLLATION
15fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/ucol.h"
17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/udata.h"
18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/uscript.h"
19fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cmemory.h"
20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collation.h"
21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationdata.h"
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationdatareader.h"
23fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationfastlatin.h"
24fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationkeys.h"
25fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationrootelements.h"
26fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationsettings.h"
27fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationtailoring.h"
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "normalizer2impl.h"
29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uassert.h"
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "ucmndata.h"
31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "utrie2.h"
32fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusnamespace {
38fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusint32_t getIndex(const int32_t *indexes, int32_t length, int32_t i) {
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return (i < length) ? indexes[i] : -1;
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
42fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}  // namespace
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationDataReader::read(const CollationTailoring *base, const uint8_t *inBytes, int32_t inLength,
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                          CollationTailoring &tailoring, UErrorCode &errorCode) {
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(base != NULL) {
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(inBytes == NULL || (0 <= inLength && inLength < 24)) {
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
52fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const DataHeader *header = reinterpret_cast<const DataHeader *>(inBytes);
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!(header->dataHeader.magic1 == 0xda && header->dataHeader.magic2 == 0x27 &&
56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                isAcceptable(tailoring.version, NULL, NULL, &header->info))) {
57fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(base->getUCAVersion() != tailoring.getUCAVersion()) {
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_COLLATOR_VERSION_MISMATCH;
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
64fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t headerLength = header->dataHeader.headerSize;
65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        inBytes += headerLength;
66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(inLength >= 0) {
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            inLength -= headerLength;
68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
70fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(inBytes == NULL || (0 <= inLength && inLength < 8)) {
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
75fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const int32_t *inIndexes = reinterpret_cast<const int32_t *>(inBytes);
76fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t indexesLength = inIndexes[IX_INDEXES_LENGTH];
77fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(indexesLength < 2 || (0 <= inLength && inLength < indexesLength * 4)) {
78fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;  // Not enough indexes.
79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
80fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Assume that the tailoring data is in initial state,
83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // with NULL pointers and 0 lengths.
84fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
85fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Set pointers to non-empty data parts.
86fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Do this in order of their byte offsets. (Should help porting to Java.)
87fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
88fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t index;  // one of the indexes[] slots
89fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t offset;  // byte offset for the index part
90fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t length;  // number of bytes in the index part
91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
92fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(indexesLength > IX_TOTAL_SIZE) {
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        length = inIndexes[IX_TOTAL_SIZE];
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(indexesLength > IX_REORDER_CODES_OFFSET) {
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        length = inIndexes[indexesLength - 1];
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        length = 0;  // only indexes, and inLength was already checked for them
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(0 <= inLength && inLength < length) {
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;
101fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
102fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
104fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const CollationData *baseData = base == NULL ? NULL : base->data;
105fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const int32_t *reorderCodes = NULL;
106fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t reorderCodesLength = 0;
107fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_REORDER_CODES_OFFSET;
108fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
109fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
110fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 4) {
111fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(baseData == NULL) {
112fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // We assume for collation settings that
113fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // the base data does not have a reordering.
114fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
115fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
116fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
117fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        reorderCodes = reinterpret_cast<const int32_t *>(inBytes + offset);
118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        reorderCodesLength = length / 4;
119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // There should be a reorder table only if there are reorder codes.
122fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // However, when there are reorder codes the reorder table may be omitted to reduce
123fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // the data size.
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const uint8_t *reorderTable = NULL;
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_REORDER_TABLE_OFFSET;
126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
127fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
128fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 256) {
129fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(reorderCodesLength == 0) {
130fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;  // Reordering table without reordering codes.
131fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
132fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
133fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        reorderTable = inBytes + offset;
134fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
135fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // If we have reorder codes, then build the reorderTable at the end,
136fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // when the CollationData is otherwise complete.
137fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
138fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
139fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(baseData != NULL && baseData->numericPrimary != (inIndexes[IX_OPTIONS] & 0xff000000)) {
140fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;
141fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
142fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
143fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    CollationData *data = NULL;  // Remains NULL if there are no mappings.
144fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
145fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_TRIE_OFFSET;
146fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
147fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
148fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 8) {
149fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!tailoring.ensureOwnedData(errorCode)) { return; }
150fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data = tailoring.ownedData;
151fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->base = baseData;
152fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->numericPrimary = inIndexes[IX_OPTIONS] & 0xff000000;
153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->trie = tailoring.trie = utrie2_openFromSerialized(
154fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UTRIE2_32_VALUE_BITS, inBytes + offset, length, NULL,
155fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            &errorCode);
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_FAILURE(errorCode)) { return; }
157fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(baseData != NULL) {
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Use the base data. Only the settings are tailored.
159fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        tailoring.data = baseData;
160fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;  // No mappings.
162fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
163fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
164fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
165fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_CES_OFFSET;
166fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
167fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 8) {
169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL) {
170fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;  // Tailored ces without tailored trie.
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
172fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->ces = reinterpret_cast<const int64_t *>(inBytes + offset);
174fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->cesLength = length / 8;
175fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
176fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
177fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_CE32S_OFFSET;
178fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
179fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
180fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 4) {
181fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL) {
182fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;  // Tailored ce32s without tailored trie.
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->ce32s = reinterpret_cast<const uint32_t *>(inBytes + offset);
186fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->ce32sLength = length / 4;
187fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
188fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
189fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t jamoCE32sStart = getIndex(inIndexes, indexesLength, IX_JAMO_CE32S_START);
190fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(jamoCE32sStart >= 0) {
191fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL || data->ce32s == NULL) {
192fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;  // Index into non-existent ce32s[].
193fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
194fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
195fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->jamoCE32s = data->ce32s + jamoCE32sStart;
196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(data == NULL) {
197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Nothing to do.
198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(baseData != NULL) {
199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->jamoCE32s = baseData->jamoCE32s;
200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;  // No Jamo CE32s for Hangul processing.
202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
204fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
205fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_ROOT_ELEMENTS_OFFSET;
206fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
207fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
208fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 4) {
209fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        length /= 4;
210fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL || length <= CollationRootElements::IX_SEC_TER_BOUNDARIES) {
211fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
212fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
213fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
214fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->rootElements = reinterpret_cast<const uint32_t *>(inBytes + offset);
215fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->rootElementsLength = length;
216fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uint32_t commonSecTer = data->rootElements[CollationRootElements::IX_COMMON_SEC_AND_TER_CE];
217fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(commonSecTer != Collation::COMMON_SEC_AND_TER_CE) {
218fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
219fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
220fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
221fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uint32_t secTerBoundaries = data->rootElements[CollationRootElements::IX_SEC_TER_BOUNDARIES];
222fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if((secTerBoundaries >> 24) < CollationKeys::SEC_COMMON_HIGH) {
223fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // [fixed last secondary common byte] is too low,
224fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // and secondary weights would collide with compressed common secondaries.
225fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
226fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
227fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
228fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
229fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
230fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_CONTEXTS_OFFSET;
231fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
232fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
233fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 2) {
234fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL) {
235fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;  // Tailored contexts without tailored trie.
236fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
237fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
238fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->contexts = reinterpret_cast<const UChar *>(inBytes + offset);
239fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->contextsLength = length / 2;
240fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
241fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
242fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_UNSAFE_BWD_OFFSET;
243fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
244fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
245fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 2) {
246fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL) {
247fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
248fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
249fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
250fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(baseData == NULL) {
251fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // Create the unsafe-backward set for the root collator.
252fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // Include all non-zero combining marks and trail surrogates.
253fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // We do this at load time, rather than at build time,
254fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // to simplify Unicode version bootstrapping:
255fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // The root data builder only needs the new FractionalUCA.txt data,
256fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // but it need not be built with a version of ICU already updated to
257fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // the corresponding new Unicode Character Database.
258fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            //
259fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // The following is an optimized version of
260fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // new UnicodeSet("[[:^lccc=0:][\\udc00-\\udfff]]").
261fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // It is faster and requires fewer code dependencies.
262fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            tailoring.unsafeBackwardSet = new UnicodeSet(0xdc00, 0xdfff);  // trail surrogates
263fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(tailoring.unsafeBackwardSet == NULL) {
264fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                errorCode = U_MEMORY_ALLOCATION_ERROR;
265fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                return;
266fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
267fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            data->nfcImpl.addLcccChars(*tailoring.unsafeBackwardSet);
268fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
269fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // Clone the root collator's set contents.
270fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            tailoring.unsafeBackwardSet = static_cast<UnicodeSet *>(
271fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                baseData->unsafeBackwardSet->cloneAsThawed());
272fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(tailoring.unsafeBackwardSet == NULL) {
273fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                errorCode = U_MEMORY_ALLOCATION_ERROR;
274fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                return;
275fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
276fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
277fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Add the ranges from the data file to the unsafe-backward set.
278fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        USerializedSet sset;
279fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const uint16_t *unsafeData = reinterpret_cast<const uint16_t *>(inBytes + offset);
280fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!uset_getSerializedSet(&sset, unsafeData, length / 2)) {
281fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
282fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
283fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
284fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t count = uset_getSerializedRangeCount(&sset);
285fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        for(int32_t i = 0; i < count; ++i) {
286fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UChar32 start, end;
287fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uset_getSerializedRange(&sset, i, &start, &end);
288fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            tailoring.unsafeBackwardSet->add(start, end);
289fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
290fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Mark each lead surrogate as "unsafe"
291fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // if any of its 1024 associated supplementary code points is "unsafe".
292fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UChar32 c = 0x10000;
293fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        for(UChar lead = 0xd800; lead < 0xdc00; ++lead, c += 0x400) {
294fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(!tailoring.unsafeBackwardSet->containsNone(c, c + 0x3ff)) {
295fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                tailoring.unsafeBackwardSet->add(lead);
296fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
297fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
298fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        tailoring.unsafeBackwardSet->freeze();
299fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->unsafeBackwardSet = tailoring.unsafeBackwardSet;
300fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(data == NULL) {
301fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Nothing to do.
302fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(baseData != NULL) {
303fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // No tailoring-specific data: Alias the root collator's set.
304fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->unsafeBackwardSet = baseData->unsafeBackwardSet;
305fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
306fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;  // No unsafeBackwardSet.
307fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
308fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
309fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
310fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // If the fast Latin format version is different,
311fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // or the version is set to 0 for "no fast Latin table",
312fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // then just always use the normal string comparison path.
313fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(data != NULL) {
314fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->fastLatinTable = NULL;
315fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->fastLatinTableLength = 0;
316fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(((inIndexes[IX_OPTIONS] >> 16) & 0xff) == CollationFastLatin::VERSION) {
317fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            index = IX_FAST_LATIN_TABLE_OFFSET;
318fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            offset = getIndex(inIndexes, indexesLength, index);
319fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            length = getIndex(inIndexes, indexesLength, index + 1) - offset;
320fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(length >= 2) {
321fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                data->fastLatinTable = reinterpret_cast<const uint16_t *>(inBytes + offset);
322fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                data->fastLatinTableLength = length / 2;
323fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if((*data->fastLatinTable >> 8) != CollationFastLatin::VERSION) {
324fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    errorCode = U_INVALID_FORMAT_ERROR;  // header vs. table version mismatch
325fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    return;
326fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
327fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else if(baseData != NULL) {
328fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                data->fastLatinTable = baseData->fastLatinTable;
329fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                data->fastLatinTableLength = baseData->fastLatinTableLength;
330fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
331fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
332fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
333fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
334fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_SCRIPTS_OFFSET;
335fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
336fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
337fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 2) {
338fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL) {
339fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
340fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
341fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
342fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->scripts = reinterpret_cast<const uint16_t *>(inBytes + offset);
343fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->scriptsLength = length / 2;
344fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(data == NULL) {
345fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Nothing to do.
346fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(baseData != NULL) {
347fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->scripts = baseData->scripts;
348fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->scriptsLength = baseData->scriptsLength;
349fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
350fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
351fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    index = IX_COMPRESSIBLE_BYTES_OFFSET;
352fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    offset = getIndex(inIndexes, indexesLength, index);
353fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    length = getIndex(inIndexes, indexesLength, index + 1) - offset;
354fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(length >= 256) {
355fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(data == NULL) {
356fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_INVALID_FORMAT_ERROR;
357fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
358fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
359fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->compressibleBytes = reinterpret_cast<const UBool *>(inBytes + offset);
360fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(data == NULL) {
361fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Nothing to do.
362fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if(baseData != NULL) {
363fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        data->compressibleBytes = baseData->compressibleBytes;
364fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
365fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;  // No compressibleBytes[].
366fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
367fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
368fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
369fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const CollationSettings &ts = *tailoring.settings;
370fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t options = inIndexes[IX_OPTIONS] & 0xffff;
371fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint16_t fastLatinPrimaries[CollationFastLatin::LATIN_LIMIT];
372fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t fastLatinOptions = CollationFastLatin::getOptions(
373fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            tailoring.data, ts, fastLatinPrimaries, LENGTHOF(fastLatinPrimaries));
374fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(options == ts.options && ts.variableTop != 0 &&
375fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            reorderCodesLength == ts.reorderCodesLength &&
376fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uprv_memcmp(reorderCodes, ts.reorderCodes, reorderCodesLength * 4) == 0 &&
377fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            fastLatinOptions == ts.fastLatinOptions &&
378fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            (fastLatinOptions < 0 ||
379fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                uprv_memcmp(fastLatinPrimaries, ts.fastLatinPrimaries,
380fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            sizeof(fastLatinPrimaries)) == 0)) {
381fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
382fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
383fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
384fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    CollationSettings *settings = SharedObject::copyOnWrite(tailoring.settings);
385fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(settings == NULL) {
386fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_MEMORY_ALLOCATION_ERROR;
387fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
388fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
389fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    settings->options = options;
390fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Set variableTop from options and scripts data.
391fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    settings->variableTop = tailoring.data->getLastPrimaryForGroup(
392fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UCOL_REORDER_CODE_FIRST + settings->getMaxVariable());
393fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(settings->variableTop == 0) {
394fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_INVALID_FORMAT_ERROR;
395fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
396fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
397fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
398fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(reorderCodesLength == 0 || reorderTable != NULL) {
399fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        settings->aliasReordering(reorderCodes, reorderCodesLength, reorderTable);
400fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
401fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uint8_t table[256];
402fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        baseData->makeReorderTable(reorderCodes, reorderCodesLength, table, errorCode);
403fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(U_FAILURE(errorCode)) { return; }
404fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!settings->setReordering(reorderCodes, reorderCodesLength,table)) {
405fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            errorCode = U_MEMORY_ALLOCATION_ERROR;
406fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
407fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
408fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
409fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
410fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    settings->fastLatinOptions = CollationFastLatin::getOptions(
411fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        tailoring.data, *settings,
412fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        settings->fastLatinPrimaries, LENGTHOF(settings->fastLatinPrimaries));
413fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
414fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
415fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool U_CALLCONV
416fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationDataReader::isAcceptable(void *context,
417fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                  const char * /* type */, const char * /*name*/,
418fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                  const UDataInfo *pInfo) {
419fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(
420fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->size >= 20 &&
421fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->isBigEndian == U_IS_BIG_ENDIAN &&
422fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->charsetFamily == U_CHARSET_FAMILY &&
423fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->dataFormat[0] == 0x55 &&  // dataFormat="UCol"
424fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->dataFormat[1] == 0x43 &&
425fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->dataFormat[2] == 0x6f &&
426fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->dataFormat[3] == 0x6c &&
427fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        pInfo->formatVersion[0] == 4
428fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ) {
429fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UVersionInfo *version = static_cast<UVersionInfo *>(context);
430fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(version != NULL) {
431fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uprv_memcpy(version, pInfo->dataVersion, 4);
432fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
433fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return TRUE;
434fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
435fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
436fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
437fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
438fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
439fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
440fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
441fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif  // !UCONFIG_NO_COLLATION
442