1b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru**********************************************************************
327f654740f2a26ad62a5c155af9199af9e69b889claireho*   Copyright (C) 2008-2010, International Business Machines
4b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
5b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru**********************************************************************
6b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
7b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
8b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/utypes.h"
9b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/uspoof.h"
10b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/unorm.h"
11b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/uchar.h"
12b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/uniset.h"
13b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "utrie2.h"
14b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "cmemory.h"
15b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "cstring.h"
16b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "udatamem.h"
17b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "umutex.h"
18b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "udataswp.h"
19b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "uassert.h"
20b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "uspoof_impl.h"
21b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
22b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if !UCONFIG_NO_NORMALIZATION
23b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
24b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
25b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_NAMESPACE_BEGIN
26b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
27b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
28b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
29b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofImpl::SpoofImpl(SpoofData *data, UErrorCode &status) :
306d5deb12725f146643d443090dfa11b206df528aJean-Baptiste Queru    fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) , fAllowedLocales(NULL) {
31b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
32b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
33b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
34b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMagic = USPOOF_MAGIC;
35b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fSpoofData = data;
36b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fChecks = USPOOF_ALL_CHECKS;
37b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
38b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (allowedCharsSet == NULL) {
39b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
40b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
41b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    allowedCharsSet->freeze();
42b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedCharsSet = allowedCharsSet;
43b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedLocales  = uprv_strdup("");
44b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
45b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
46b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
47b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofImpl::SpoofImpl() {
48b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMagic = USPOOF_MAGIC;
49b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fSpoofData = NULL;
50b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fChecks = USPOOF_ALL_CHECKS;
51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
52b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    allowedCharsSet->freeze();
53b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedCharsSet = allowedCharsSet;
54b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedLocales  = uprv_strdup("");
55b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
56b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
57b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
58b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Copy Constructor, used by the user level clone() function.
59b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status)  :
60b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) {
61b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
62b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
63b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
64b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMagic = src.fMagic;
65b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fChecks = src.fChecks;
66b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (src.fSpoofData != NULL) {
67b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fSpoofData = src.fSpoofData->addReference();
68b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
69b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fCheckMask = src.fCheckMask;
70b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedCharsSet = static_cast<const UnicodeSet *>(src.fAllowedCharsSet->clone());
71b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fAllowedCharsSet == NULL) {
72b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
73b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
74b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedLocales = uprv_strdup(src.fAllowedLocales);
75b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
76b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
77b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofImpl::~SpoofImpl() {
78b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMagic = 0;                // head off application errors by preventing use of
79b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                               //    of deleted objects.
80b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fSpoofData != NULL) {
81b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fSpoofData->removeReference();   // Will delete if refCount goes to zero.
82b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
83b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    delete fAllowedCharsSet;
84b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free((void *)fAllowedLocales);
85b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
86b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
87b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
88b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  Incoming parameter check on Status and the SpoofChecker object
89b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//    received from the C API.
90b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
91b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruconst SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
92b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
93b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
94b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
95b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (sc == NULL) {
96b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_ILLEGAL_ARGUMENT_ERROR;
97b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
98b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    };
99b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    SpoofImpl *This = (SpoofImpl *)sc;
100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (This->fMagic != USPOOF_MAGIC ||
101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        This->fSpoofData == NULL) {
102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (!SpoofData::validateDataVersion(This->fSpoofData->fRawData, status)) {
106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return This;
109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
110b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofImpl *SpoofImpl::validateThis(USpoofChecker *sc, UErrorCode &status) {
112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return const_cast<SpoofImpl *>
113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        (SpoofImpl::validateThis(const_cast<const USpoofChecker *>(sc), status));
114b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
118b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//--------------------------------------------------------------------------------------
119b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  confusableLookup()    This is the heart of the confusable skeleton generation
121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//                        implementation.
122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//                        Given a source character, produce the corresponding
124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//                        replacement character(s)
125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//---------------------------------------------------------------------------------------
127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint32_t SpoofImpl::confusableLookup(UChar32 inChar, int32_t tableMask, UChar *destBuf) const {
128b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
129b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Binary search the spoof data key table for the inChar
130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t  *low   = fSpoofData->fCFUKeys;
131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t  *mid   = NULL;
132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t  *limit = low + fSpoofData->fRawData->fCFUKeysSize;
13350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UChar32   midc;
134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    do {
13550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int32_t delta = ((int32_t)(limit-low))/2;
136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        mid = low + delta;
137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        midc = *mid & 0x1fffff;
138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (inChar == midc) {
139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            goto foundChar;
140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else if (inChar < midc) {
141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            limit = mid;
142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            low = mid;
144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } while (low < limit-1);
146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    mid = low;
147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    midc = *mid & 0x1fffff;
148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (inChar != midc) {
149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // Char not found.  It maps to itself.
150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int i = 0;
151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U16_APPEND_UNSAFE(destBuf, i, inChar)
152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return i;
153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru  foundChar:
155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t keyFlags = *mid & 0xff000000;
156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if ((keyFlags & tableMask) == 0) {
157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // We found the right key char, but the entry doesn't pertain to the
158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        //  table we need.  See if there is an adjacent key that does
159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (keyFlags & USPOOF_KEY_MULTIPLE_VALUES) {
160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            int32_t *altMid;
161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            for (altMid = mid-1; (*altMid&0x00ffffff) == inChar; altMid--) {
162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                keyFlags = *altMid & 0xff000000;
163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (keyFlags & tableMask) {
164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    mid = altMid;
165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    goto foundKey;
166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            for (altMid = mid+1; (*altMid&0x00ffffff) == inChar; altMid++) {
169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                keyFlags = *altMid & 0xff000000;
170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (keyFlags & tableMask) {
171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    mid = altMid;
172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    goto foundKey;
173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // No key entry for this char & table.
177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // The input char maps to itself.
178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int i = 0;
179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U16_APPEND_UNSAFE(destBuf, i, inChar)
180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return i;
181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru  foundKey:
184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t  stringLen = USPOOF_KEY_LENGTH_FIELD(keyFlags) + 1;
18550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t keyTableIndex = (int32_t)(mid - fSpoofData->fCFUKeys);
186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Value is either a UChar  (for strings of length 1) or
188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //                 an index into the string table (for longer strings)
189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint16_t value = fSpoofData->fCFUValues[keyTableIndex];
190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (stringLen == 1) {
191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        destBuf[0] = value;
192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 1;
193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // String length of 4 from the above lookup is used for all strings of length >= 4.
196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // For these, get the real length from the string lengths table,
197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //   which maps string table indexes to lengths.
198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //   All strings of the same length are stored contiguously in the string table.
199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //   'value' from the lookup above is the starting index for the desired string.
200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t ix;
202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (stringLen == 4) {
203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t stringLengthsLimit = fSpoofData->fRawData->fCFUStringLengthsSize;
204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        for (ix = 0; ix < stringLengthsLimit; ix++) {
205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (fSpoofData->fCFUStringLengths[ix].fLastString >= value) {
206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                stringLen = fSpoofData->fCFUStringLengths[ix].fStrLength;
207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U_ASSERT(ix < stringLengthsLimit);
211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    U_ASSERT(value + stringLen < fSpoofData->fRawData->fCFUStringTableLen);
214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UChar *src = &fSpoofData->fCFUStrings[value];
215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (ix=0; ix<stringLen; ix++) {
216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        destBuf[ix] = src[ix];
217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return stringLen;
219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//---------------------------------------------------------------------------------------
223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  wholeScriptCheck()
225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//      Input text is already normalized to NFKD
227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//      Return the set of scripts, each of which can represent something that is
228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//             confusable with the input text.  The script of the input text
229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//             is included; input consisting of characters from a single script will
230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//             always produce a result consisting of a set containing that script.
231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//---------------------------------------------------------------------------------------
233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid SpoofImpl::wholeScriptCheck(
234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const UChar *text, int32_t length, ScriptSet *result, UErrorCode &status) const {
235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t       inputIdx = 0;
237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UChar32       c;
238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UTrie2 *table =
240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        (fChecks & USPOOF_ANY_CASE) ? fSpoofData->fAnyCaseTrie : fSpoofData->fLowerCaseTrie;
241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    result->setAll();
242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (inputIdx < length) {
243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U16_NEXT(text, inputIdx, length, c);
244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uint32_t index = utrie2_get32(table, c);
245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (index == 0) {
246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            // No confusables in another script for this char.
247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            // TODO:  we should change the data to have sets with just the single script
248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            //        bit for the script of this char.  Gets rid of this special case.
249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            //        Until then, grab the script from the char and intersect it with the set.
250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            UScriptCode cpScript = uscript_getScript(c, &status);
251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            U_ASSERT(cpScript > USCRIPT_INHERITED);
252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            result->intersect(cpScript);
253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else if (index == 1) {
254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            // Script == Common or Inherited.  Nothing to do.
255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            result->intersect(fSpoofData->fScriptSets[index]);
257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UnicodeSet    allowedChars;
264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UnicodeSet    *tmpSet = NULL;
265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char    *locStart = localesList;
266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char    *locEnd = NULL;
267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char    *localesListEnd = localesList + uprv_strlen(localesList);
268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t        localeListCount = 0;   // Number of locales provided by caller.
269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Loop runs once per locale from the localesList, a comma separated list of locales.
271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    do {
272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        locEnd = uprv_strchr(locStart, ',');
273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (locEnd == NULL) {
274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            locEnd = localesListEnd;
275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*locStart == ' ') {
277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            locStart++;
278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const char *trimmedEnd = locEnd-1;
280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (trimmedEnd > locStart && *trimmedEnd == ' ') {
281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            trimmedEnd--;
282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (trimmedEnd <= locStart) {
284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
28650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart));
287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        localeListCount++;
288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // We have one locale from the locales list.
290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // Add the script chars for this locale to the accumulating set of allowed chars.
291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        // If the locale is no good, we will be notified back via status.
292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        addScriptChars(locale, &allowedChars, status);
293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free((void *)locale);
294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(status)) {
295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        locStart = locEnd + 1;
298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } while (locStart < localesListEnd);
299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // If our caller provided an empty list of locales, we disable the allowed characters checking
301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (localeListCount == 0) {
302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free((void *)fAllowedLocales);
303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fAllowedLocales = uprv_strdup("");
304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpSet = new UnicodeSet(0, 0x10ffff);
305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (fAllowedLocales == NULL || tmpSet == NULL) {
306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            status = U_MEMORY_ALLOCATION_ERROR;
307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return;
308b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
309b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpSet->freeze();
310b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        delete fAllowedCharsSet;
311b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fAllowedCharsSet = tmpSet;
312b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fCheckMask &= ~USPOOF_CHAR_LIMIT;
313b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
314b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
317b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Add all common and inherited characters to the set of allowed chars.
318b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UnicodeSet tempSet;
319b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status);
320b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    allowedChars.addAll(tempSet);
321b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status);
322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    allowedChars.addAll(tempSet);
323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // If anything went wrong, we bail out without changing
325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // the state of the spoof checker.
326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
330b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Store the updated spoof checker state.
331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    tmpSet = static_cast<UnicodeSet *>(allowedChars.clone());
332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *tmpLocalesList = uprv_strdup(localesList);
333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tmpSet == NULL || tmpLocalesList == NULL) {
334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free((void *)fAllowedLocales);
338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedLocales = tmpLocalesList;
339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    tmpSet->freeze();
340b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    delete fAllowedCharsSet;
341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAllowedCharsSet = tmpSet;
342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fCheckMask |= USPOOF_CHAR_LIMIT;
343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruconst char * SpoofImpl::getAllowedLocales(UErrorCode &/*status*/) {
347b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return fAllowedLocales;
348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
349b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
351b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Given a locale (a language), add all the characters from all of the scripts used with that language
352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// to the allowedChars UnicodeSet
353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid SpoofImpl::addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status) {
355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UScriptCode scripts[30];
356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t numScripts = uscript_getCode(locale, scripts, sizeof(scripts)/sizeof(UScriptCode), &status);
358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (status == U_USING_DEFAULT_WARNING) {
362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_ILLEGAL_ARGUMENT_ERROR;
363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UnicodeSet tmpSet;
366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t    i;
367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i=0; i<numScripts; i++) {
368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpSet.applyIntPropertyValue(UCHAR_SCRIPT, scripts[i], status);
369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        allowedChars->addAll(tmpSet);
370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint32_t SpoofImpl::scriptScan
375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        (const UChar *text, int32_t length, int32_t &pos, UErrorCode &status) const {
376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t       inputIdx = 0;
380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UChar32       c;
381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t       scriptCount = 0;
382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UScriptCode   lastScript = USCRIPT_INVALID_CODE;
383b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UScriptCode   sc = USCRIPT_INVALID_CODE;
384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while ((inputIdx < length || length == -1) && scriptCount < 2) {
385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U16_NEXT(text, inputIdx, length, c);
386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (c == 0 && length == -1) {
387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
389b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        sc = uscript_getScript(c, &status);
390b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (sc == USCRIPT_COMMON || sc == USCRIPT_INHERITED || sc == USCRIPT_UNKNOWN) {
391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            continue;
392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (sc != lastScript) {
394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           scriptCount++;
395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           lastScript = sc;
396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (scriptCount == 2) {
399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pos = inputIdx;
400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return scriptCount;
402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Convert a text format hex number.  Utility function used by builder code.  Static.
406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Input: UChar *string text.  Output: a UChar32
407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Input has been pre-checked, and will have no non-hex chars.
408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// The number must fall in the code point range of 0..0x10ffff
409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Static Function.
410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruUChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status) {
411b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    U_ASSERT(limit-start > 0);
415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t val = 0;
416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int i;
417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i=start; i<limit; i++) {
418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int digitVal = s[i] - 0x30;
419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (digitVal>9) {
420b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            digitVal = 0xa + (s[i] - 0x41);  // Upper Case 'A'
421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (digitVal>15) {
423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            digitVal = 0xa + (s[i] - 0x61);  // Lower Case 'a'
424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U_ASSERT(digitVal <= 0xf);
426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        val <<= 4;
427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        val += digitVal;
428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (val > 0x10ffff) {
430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_PARSE_ERROR;
431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        val = 0;
432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return (UChar32)val;
434b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//----------------------------------------------------------------------------------------------
439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//   class SpoofData Implementation
441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//----------------------------------------------------------------------------------------------
443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruUBool SpoofData::validateDataVersion(const SpoofDataHeader *rawData, UErrorCode &status) {
446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status) ||
447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        rawData == NULL ||
448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        rawData->fMagic != USPOOF_MAGIC ||
449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        rawData->fFormatVersion[0] > 1 ||
450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        rawData->fFormatVersion[1] > 0) {
451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
454b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  SpoofData::getDefault() - return a wrapper around the spoof data that is
459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//                           baked into the default ICU data.
460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofData *SpoofData::getDefault(UErrorCode &status) {
462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // TODO:  Cache it.  Lazy create, keep until cleanup.
463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
464b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UDataMemory *udm = udata_open(NULL, "cfu", "confusables", &status);
465b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    SpoofData *This = new SpoofData(udm, status);
469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        delete This;
471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (This == NULL) {
474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return This;
477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofData::SpoofData(UDataMemory *udm, UErrorCode &status)
481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reset();
483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
484b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
485b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData = reinterpret_cast<SpoofDataHeader *>
487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   ((char *)(udm->pHeader) + udm->pHeader->dataHeader.headerSize);
488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fUDM = udm;
489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    validateDataVersion(fRawData, status);
490b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    initPtrs(status);
491b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
492b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
493b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status)
495b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
496b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reset();
497b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
498b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
499b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if ((size_t)length < sizeof(SpoofDataHeader)) {
501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
502b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
504b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    void *ncData = const_cast<void *>(data);
505b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData = static_cast<SpoofDataHeader *>(ncData);
506b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (length < fRawData->fLength) {
507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    validateDataVersion(fRawData, status);
511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    initPtrs(status);
512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// Spoof Data constructor for use from data builder.
516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//   Initializes a new, empty data area that will be populated later.
517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofData::SpoofData(UErrorCode &status) {
518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reset();
519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fDataOwned = true;
523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRefCount = 1;
524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // The spoof header should already be sized to be a multiple of 16 bytes.
526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Just in case it's not, round it up.
527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t initialSize = (sizeof(SpoofDataHeader) + 15) & ~15;
528b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    U_ASSERT(initialSize == sizeof(SpoofDataHeader));
529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData = static_cast<SpoofDataHeader *>(uprv_malloc(initialSize));
531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMemLimit = initialSize;
532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fRawData == NULL) {
533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_MEMORY_ALLOCATION_ERROR;
534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memset(fRawData, 0, initialSize);
537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData->fMagic = USPOOF_MAGIC;
539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData->fFormatVersion[0] = 1;
540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData->fFormatVersion[1] = 0;
541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData->fFormatVersion[2] = 0;
542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData->fFormatVersion[3] = 0;
543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    initPtrs(status);
544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru// reset() - initialize all fields.
547b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//           Should be updated if any new fields are added.
548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//           Called by constructors to put things in a known initial state.
549b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid SpoofData::reset() {
550b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fRawData = NULL;
551b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fDataOwned = FALSE;
552b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fUDM      = NULL;
553b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fMemLimit = 0;
554b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fRefCount = 1;
555b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fCFUKeys = NULL;
556b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fCFUValues = NULL;
557b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fCFUStringLengths = NULL;
558b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fCFUStrings = NULL;
559b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fAnyCaseTrie = NULL;
560b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fLowerCaseTrie = NULL;
561b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru   fScriptSets = NULL;
562b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
563b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
564b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
565b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  SpoofData::initPtrs()
566b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            Initialize the pointers to the various sections of the raw data.
567b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
568b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            This function is used both during the Trie building process (multiple
569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            times, as the individual data sections are added), and
570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            during the opening of a Spoof Checker from prebuilt data.
571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
572b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            The pointers for non-existent data sections (identified by an offset of 0)
573b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            are set to NULL.
574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
575b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            Note:  During building the data, adding each new data section
576b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            reallocs the raw data area, which likely relocates it, which
577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            in turn requires reinitializing all of the pointers into it, hence
578b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//            multiple calls to this function during building.
579b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
580b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid SpoofData::initPtrs(UErrorCode &status) {
581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fCFUKeys = NULL;
582b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fCFUValues = NULL;
583b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fCFUStringLengths = NULL;
584b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fCFUStrings = NULL;
585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
586b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
587b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
588b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fRawData->fCFUKeys != 0) {
589b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fCFUKeys = (int32_t *)((char *)fRawData + fRawData->fCFUKeys);
590b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fRawData->fCFUStringIndex != 0) {
592b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fCFUValues = (uint16_t *)((char *)fRawData + fRawData->fCFUStringIndex);
593b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
594b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fRawData->fCFUStringLengths != 0) {
595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fCFUStringLengths = (SpoofStringLengthsElement *)((char *)fRawData + fRawData->fCFUStringLengths);
596b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
597b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fRawData->fCFUStringTable != 0) {
598b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fCFUStrings = (UChar *)((char *)fRawData + fRawData->fCFUStringTable);
599b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
600b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fAnyCaseTrie ==  NULL && fRawData->fAnyCaseTrie != 0) {
602b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fAnyCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
603b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            (char *)fRawData + fRawData->fAnyCaseTrie, fRawData->fAnyCaseTrieLength, NULL, &status);
604b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
605b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fLowerCaseTrie ==  NULL && fRawData->fLowerCaseTrie != 0) {
606b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fLowerCaseTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
607b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            (char *)fRawData + fRawData->fLowerCaseTrie, fRawData->fLowerCaseTrieLength, NULL, &status);
608b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
609b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
610b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fRawData->fScriptSets != 0) {
611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fScriptSets = (ScriptSet *)((char *)fRawData + fRawData->fScriptSets);
612b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
613b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
614b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
615b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
616b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofData::~SpoofData() {
617b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    utrie2_close(fAnyCaseTrie);
618b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fAnyCaseTrie = NULL;
619b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    utrie2_close(fLowerCaseTrie);
620b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fLowerCaseTrie = NULL;
621b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fDataOwned) {
622b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(fRawData);
623b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
624b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData = NULL;
625b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fUDM != NULL) {
626b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        udata_close(fUDM);
627b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
628b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fUDM = NULL;
629b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
630b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
631b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
632b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid SpoofData::removeReference() {
633b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (umtx_atomic_dec(&fRefCount) == 0) {
634b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        delete this;
635b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
636b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
637b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
638b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
639b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruSpoofData *SpoofData::addReference() {
640b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_atomic_inc(&fRefCount);
641b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return this;
642b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
643b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
644b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
645b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid *SpoofData::reserveSpace(int32_t numBytes,  UErrorCode &status) {
646b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
647b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
648b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
649b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (!fDataOwned) {
650b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        U_ASSERT(FALSE);
651b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_INTERNAL_PROGRAM_ERROR;
652b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
653b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
654b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
655b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    numBytes = (numBytes + 15) & ~15;   // Round up to a multiple of 16
656b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t returnOffset = fMemLimit;
657b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fMemLimit += numBytes;
658b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData = static_cast<SpoofDataHeader *>(uprv_realloc(fRawData, fMemLimit));
659b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fRawData->fLength = fMemLimit;
660b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memset((char *)fRawData + returnOffset, 0, numBytes);
661b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    initPtrs(status);
662b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return (char *)fRawData + returnOffset;
663b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
664b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
665b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
666b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//----------------------------------------------------------------------------
667b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
668b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  ScriptSet implementation
669b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
670b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//----------------------------------------------------------------------------
671b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruScriptSet::ScriptSet() {
672b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
673b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] = 0;
674b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
675b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
676b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
677b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruScriptSet::~ScriptSet() {
678b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
679b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
680b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruUBool ScriptSet::operator == (const ScriptSet &other) {
681b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
682b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (bits[i] != other.bits[i]) {
683b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
684b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
685b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
686b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
687b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
688b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
689b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid ScriptSet::Union(UScriptCode script) {
690b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t index = script / 32;
691b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t bit   = 1 << (script & 31);
692b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    U_ASSERT(index < sizeof(bits)*4);
693b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    bits[index] |= bit;
694b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
695b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
696b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
697b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid ScriptSet::Union(const ScriptSet &other) {
698b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
699b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] |= other.bits[i];
700b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
701b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
702b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
703b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid ScriptSet::intersect(const ScriptSet &other) {
704b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
705b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] &= other.bits[i];
706b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
707b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
708b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
709b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid ScriptSet::intersect(UScriptCode script) {
710b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t index = script / 32;
711b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t bit   = 1 << (script & 31);
712b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    U_ASSERT(index < sizeof(bits)*4);
713b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t i;
714b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i=0; i<index; i++) {
715b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] = 0;
716b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
717b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    bits[index] &= bit;
718b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i=index+1; i<sizeof(bits)/sizeof(uint32_t); i++) {
719b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] = 0;
720b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
721b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
722b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
723b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
724b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruScriptSet & ScriptSet::operator =(const ScriptSet &other) {
725b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
726b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] = other.bits[i];
727b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
728b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return *this;
729b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
730b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
731b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
732b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid ScriptSet::setAll() {
733b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
734b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] = 0xffffffffu;
735b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
736b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
737b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
738b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
739b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruvoid ScriptSet::resetAll() {
740b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
741b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bits[i] = 0;
742b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
743b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
744b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
745b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint32_t ScriptSet::countMembers() {
746b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // This bit counter is good for sparse numbers of '1's, which is
747b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //  very much the case that we will usually have.
748b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t count = 0;
749b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (uint32_t i=0; i<sizeof(bits)/sizeof(uint32_t); i++) {
750b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uint32_t x = bits[i];
751b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (x > 0) {
752b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            count++;
753b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            x &= (x - 1);    // and off the least significant one bit.
754b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
755b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
756b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return count;
757b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
758b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
759b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
760b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
761b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//-----------------------------------------------------------------------------
762b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
763b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  NFKDBuffer Implementation.
764b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
765b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//-----------------------------------------------------------------------------
766b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
767b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruNFKDBuffer::NFKDBuffer(const UChar *text, int32_t length, UErrorCode &status) {
768b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fNormalizedText = NULL;
769b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fNormalizedTextLength = 0;
770b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fOriginalText = text;
771b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
772b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
773b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
774b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fNormalizedText = fSmallBuf;
775b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fNormalizedTextLength = unorm_normalize(
776b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        text, length, UNORM_NFKD, 0, fNormalizedText, USPOOF_STACK_BUFFER_SIZE, &status);
777b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (status == U_BUFFER_OVERFLOW_ERROR) {
778b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        status = U_ZERO_ERROR;
779b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        fNormalizedText = (UChar *)uprv_malloc((fNormalizedTextLength+1)*sizeof(UChar));
780b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (fNormalizedText == NULL) {
781b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            status = U_MEMORY_ALLOCATION_ERROR;
782b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
783b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            fNormalizedTextLength = unorm_normalize(text, length, UNORM_NFKD, 0,
784b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                                        fNormalizedText, fNormalizedTextLength+1, &status);
785b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
786b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
787b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
788b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
789b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
790b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruNFKDBuffer::~NFKDBuffer() {
791b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (fNormalizedText != fSmallBuf) {
792b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(fNormalizedText);
793b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
794b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    fNormalizedText = 0;
795b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
796b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
797b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruconst UChar *NFKDBuffer::getBuffer() {
798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return fNormalizedText;
799b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruint32_t NFKDBuffer::getLength() {
802b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return fNormalizedTextLength;
803b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
804b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
805b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
806b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
807b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
808b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
809b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_NAMESPACE_END
810b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
811b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_NAMESPACE_USE
812b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
813b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//-----------------------------------------------------------------------------
814b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
815b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//  uspoof_swap   -  byte swap and char encoding swap of spoof data
816b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//
817b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru//-----------------------------------------------------------------------------
818b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_CAPI int32_t U_EXPORT2
819b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruuspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
820b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           UErrorCode *status) {
821b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
822b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (status == NULL || U_FAILURE(*status)) {
823b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
824b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
825b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
826b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status=U_ILLEGAL_ARGUMENT_ERROR;
827b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
828b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
829b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
830b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
831b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //  Check that the data header is for spoof data.
832b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //    (Header contents are defined in gencfu.cpp)
833b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
834b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
835b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if(!(  pInfo->dataFormat[0]==0x43 &&   /* dataFormat="Cfu " */
836b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           pInfo->dataFormat[1]==0x66 &&
837b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           pInfo->dataFormat[2]==0x75 &&
838b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           pInfo->dataFormat[3]==0x20 &&
839b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru           pInfo->formatVersion[0]==1  )) {
840b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x "
841b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                             "(format version %02x %02x %02x %02x) is not recognized\n",
842b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                         pInfo->dataFormat[0], pInfo->dataFormat[1],
843b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                         pInfo->dataFormat[2], pInfo->dataFormat[3],
844b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                         pInfo->formatVersion[0], pInfo->formatVersion[1],
845b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                         pInfo->formatVersion[2], pInfo->formatVersion[3]);
846b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status=U_UNSUPPORTED_ERROR;
847b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
848b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
849b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
850b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
851b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Swap the data header.  (This is the generic ICU Data Header, not the uspoof Specific
852b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //                         header).  This swap also conveniently gets us
853b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //                         the size of the ICU d.h., which lets us locate the start
854b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //                         of the uspoof specific data.
855b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
856b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
857b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
858b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
859b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
860b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Get the Spoof Data Header, and check that it appears to be OK.
861b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
862b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
863b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const uint8_t   *inBytes =(const uint8_t *)inData+headerSize;
864b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes;
865b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (ds->readUInt32(spoofDH->fMagic)   != USPOOF_MAGIC ||
866b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ds->readUInt32(spoofDH->fLength)  <  sizeof(SpoofDataHeader))
867b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    {
868b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n");
869b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status=U_UNSUPPORTED_ERROR;
870b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
871b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
872b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
873b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
874b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Prefight operation?  Just return the size
875b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
876b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength);
877b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t totalSize = headerSize + spoofDataLength;
878b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (length < 0) {
879b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return totalSize;
880b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
881b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
882b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
883b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Check that length passed in is consistent with length from Spoof data header.
884b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
885b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (length < totalSize) {
886b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n",
887b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            spoofDataLength);
888b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status=U_INDEX_OUTOFBOUNDS_ERROR;
889b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
890b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
891b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
892b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
893b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
894b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Swap the Data.  Do the data itself first, then the Spoof Data Header, because
895b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //                 we need to reference the header to locate the data, and an
896b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //                 inplace swap of the header leaves it unusable.
897b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
898b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint8_t          *outBytes = (uint8_t *)outData + headerSize;
899b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    SpoofDataHeader  *outputDH = (SpoofDataHeader *)outBytes;
900b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
901b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t   sectionStart;
902b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t   sectionLength;
903b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
904b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
905b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // If not swapping in place, zero out the output buffer before starting.
906b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //    Gaps may exist between the individual sections, and these must be zeroed in
907b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //    the output buffer.  The simplest way to do that is to just zero the whole thing.
908b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
909b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (inBytes != outBytes) {
910b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_memset(outBytes, 0, spoofDataLength);
911b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
912b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
913b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Confusables Keys Section   (fCFUKeys)
914b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fCFUKeys);
915b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4;
916b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
917b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
918b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // String Index Section
919b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fCFUStringIndex);
920b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2;
921b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
922b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
923b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // String Table Section
924b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fCFUStringTable);
925b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2;
926b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
927b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
928b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // String Lengths Section
929b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fCFUStringLengths);
930b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionLength = ds->readUInt32(spoofDH->fCFUStringLengthsSize) * 4;
931b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
932b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
933b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Any Case Trie
934b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fAnyCaseTrie);
935b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionLength = ds->readUInt32(spoofDH->fAnyCaseTrieLength);
936b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
937b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
938b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Lower Case Trie
939b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fLowerCaseTrie);
940b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionLength = ds->readUInt32(spoofDH->fLowerCaseTrieLength);
941b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
942b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
943b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // Script Sets.  The data is an array of int32_t
944b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    sectionStart  = ds->readUInt32(spoofDH->fScriptSets);
94527f654740f2a26ad62a5c155af9199af9e69b889claireho    sectionLength = ds->readUInt32(spoofDH->fScriptSetsLength) * sizeof(ScriptSet);
946b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
947b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
948b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    // And, last, swap the header itself.
949b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //   int32_t   fMagic             // swap this
95027f654740f2a26ad62a5c155af9199af9e69b889claireho    //   uint8_t   fFormatVersion[4]  // Do not swap this, just copy
95127f654740f2a26ad62a5c155af9199af9e69b889claireho    //   int32_t   fLength and all the rest       // Swap the rest, all is 32 bit stuff.
952b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    //
953b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uint32_t magic = ds->readUInt32(spoofDH->fMagic);
954b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
95527f654740f2a26ad62a5c155af9199af9e69b889claireho    uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
95627f654740f2a26ad62a5c155af9199af9e69b889claireho    // swap starting at fLength
95727f654740f2a26ad62a5c155af9199af9e69b889claireho    ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status);
958b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
959b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return totalSize;
960b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
961b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
962b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
963b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
964b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
965