tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

store.c (23248B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *
      6 *   Copyright (C) 1999-2014, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 *******************************************************************************
     10 *   file name:  store.c
     11 *   encoding:   UTF-8
     12 *   tab size:   8 (not used)
     13 *   indentation:4
     14 *
     15 *   created on: 2003-02-06
     16 *   created by: Ram Viswanadha
     17 *
     18 */
     19 
     20 #include <stdbool.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include "unicode/utypes.h"
     24 #include "cmemory.h"
     25 #include "cstring.h"
     26 #include "filestrm.h"
     27 #include "toolutil.h"
     28 #include "unicode/udata.h"
     29 #include "unicode/utf16.h"
     30 #include "utrie.h"
     31 #include "unewdata.h"
     32 #include "gensprep.h"
     33 #include "uhash.h"
     34 
     35 
     36 #define DO_DEBUG_OUT 0
     37 
     38 
     39 /*
     40 * StringPrep profile file format ------------------------------------
     41 *
     42 * The file format prepared and written here contains a 16-bit trie and a mapping table.
     43 *
     44 * Before the data contents described below, there are the headers required by
     45 * the udata API for loading ICU data. Especially, a UDataInfo structure
     46 * precedes the actual data. It contains platform properties values and the
     47 * file format version.
     48 *
     49 * The following is a description of format version 2.
     50 *
     51 * Data contents:
     52 *
     53 * The contents is a parsed, binary form of RFC3454 and possibly
     54 * NormalizationCorrections.txt depending on the options specified on the profile.
     55 *
     56 * Any Unicode code point from 0 to 0x10ffff can be looked up to get
     57 * the trie-word, if any, for that code point. This means that the input
     58 * to the lookup are 21-bit unsigned integers, with not all of the
     59 * 21-bit range used.
     60 *
     61 * *.spp files customarily begin with a UDataInfo structure, see udata.h and .c.
     62 * After that there are the following structures:
     63 *
     64 * int32_t indexes[_SPREP_INDEX_TOP];           -- _SPREP_INDEX_TOP=16, see enum in sprpimpl.h file
     65 *
     66 * UTrie stringPrepTrie;                        -- size in bytes=indexes[_SPREP_INDEX_TRIE_SIZE]
     67 *
     68 * uint16_t mappingTable[];                     -- Contains the sequence of code units that the code point maps to
     69 *                                                 size in bytes = indexes[_SPREP_INDEX_MAPPING_DATA_SIZE]
     70 *
     71 * The indexes array contains the following values:
     72 *  indexes[_SPREP_INDEX_TRIE_SIZE]                  -- The size of the StringPrep trie in bytes
     73 *  indexes[_SPREP_INDEX_MAPPING_DATA_SIZE]          -- The size of the mappingTable in bytes
     74 *  indexes[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION]  -- The index of Unicode version of last entry in NormalizationCorrections.txt
     75 *  indexes[_SPREP_ONE_UCHAR_MAPPING_INDEX_START]    -- The starting index of 1 UChar  mapping index in the mapping table
     76 *  indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START]   -- The starting index of 2 UChars mapping index in the mapping table
     77 *  indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START] -- The starting index of 3 UChars mapping index in the mapping table
     78 *  indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START]  -- The starting index of 4 UChars mapping index in the mapping table
     79 *  indexes[_SPREP_OPTIONS]                          -- Bit set of options to turn on in the profile, e.g: USPREP_NORMALIZATION_ON, USPREP_CHECK_BIDI_ON
     80 *
     81 *
     82 * StringPrep Trie :
     83 *
     84 * The StringPrep tries is a 16-bit trie that contains data for the profile.
     85 * Each code point is associated with a value (trie-word) in the trie.
     86 *
     87 * - structure of data words from the trie
     88 *
     89 *  i)  A value greater than or equal to _SPREP_TYPE_THRESHOLD (0xFFF0)
     90 *      represents the type associated with the code point
     91 *      if(trieWord >= _SPREP_TYPE_THRESHOLD){
     92 *          type = trieWord - 0xFFF0;
     93 *      }
     94 *      The type can be :
     95 *             USPREP_UNASSIGNED
     96 *             USPREP_PROHIBITED
     97 *             USPREP_DELETE
     98 *
     99 *  ii) A value less than _SPREP_TYPE_THRESHOLD means the type is USPREP_MAP and
    100 *      contains distribution described below
    101 *
    102 *      0       -  ON : The code point is prohibited (USPREP_PROHIBITED). This is to allow for codepoint that are both prohibited and mapped.
    103 *      1       -  ON : The value in the next 14 bits is an index into the mapping table
    104 *                 OFF: The value in the next 14 bits is an delta value from the code point
    105 *      2..15   -  Contains data as described by bit 1. If all bits are set
    106 *                 (value = _SPREP_MAX_INDEX_VALUE) then the type is USPREP_DELETE
    107 *
    108 *
    109 * Mapping Table:
    110 * The data in mapping table is sorted according to the length of the mapping sequence.
    111 * If the type of the code point is USPREP_MAP and value in trie word is an index, the index
    112 * is compared with start indexes of sequence length start to figure out the length according to
    113 * the following algorithm:
    114 *
    115 *              if(       index >= indexes[_SPREP_ONE_UCHAR_MAPPING_INDEX_START] &&
    116 *                        index < indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START]){
    117 *                   length = 1;
    118 *               }else if(index >= indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START] &&
    119 *                        index < indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START]){
    120 *                   length = 2;
    121 *               }else if(index >= indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START] &&
    122 *                        index < indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START]){
    123 *                   length = 3;
    124 *               }else{
    125 *                   // The first position in the mapping table contains the length
    126 *                   // of the sequence
    127 *                   length = mappingTable[index++];
    128 *
    129 *               }
    130 *
    131 */
    132 
    133 /* file data ---------------------------------------------------------------- */
    134 /* indexes[] value names */
    135 
    136 #if UCONFIG_NO_IDNA
    137 
    138 /* dummy UDataInfo cf. udata.h */
    139 static UDataInfo dataInfo = {
    140    sizeof(UDataInfo),
    141    0,
    142 
    143    U_IS_BIG_ENDIAN,
    144    U_CHARSET_FAMILY,
    145    U_SIZEOF_UCHAR,
    146    0,
    147 
    148    { 0, 0, 0, 0 },                 /* dummy dataFormat */
    149    { 0, 0, 0, 0 },                 /* dummy formatVersion */
    150    { 0, 0, 0, 0 }                  /* dummy dataVersion */
    151 };
    152 
    153 #else
    154 
    155 static int32_t indexes[_SPREP_INDEX_TOP]={ 0 };
    156 
    157 static uint16_t* mappingData= NULL;
    158 static int32_t mappingDataCapacity = 0; /* we skip the first index in mapping data */
    159 static int16_t currentIndex = 0; /* the current index into the data trie */
    160 static int32_t maxLength = 0;  /* maximum length of mapping string */
    161 
    162 
    163 /* UDataInfo cf. udata.h */
    164 static UDataInfo dataInfo={
    165    sizeof(UDataInfo),
    166    0,
    167 
    168    U_IS_BIG_ENDIAN,
    169    U_CHARSET_FAMILY,
    170    U_SIZEOF_UCHAR,
    171    0,
    172 
    173    { 0x53, 0x50, 0x52, 0x50 },                 /* dataFormat="SPRP" */
    174    { 3, 2, UTRIE_SHIFT, UTRIE_INDEX_SHIFT },   /* formatVersion */
    175    { 3, 2, 0, 0 }                              /* dataVersion (Unicode version) */
    176 };
    177 void
    178 setUnicodeVersion(const char *v) {
    179    UVersionInfo version;
    180    u_versionFromString(version, v);
    181    uprv_memcpy(dataInfo.dataVersion, version, 4);
    182 }
    183 
    184 void
    185 setUnicodeVersionNC(UVersionInfo version){
    186    uint32_t univer = version[0] << 24;
    187    univer += version[1] << 16;
    188    univer += version[2] << 8;
    189    univer += version[3];
    190    indexes[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION] = univer;
    191 }
    192 static UNewTrie *sprepTrie;
    193 
    194 #define MAX_DATA_LENGTH 11500
    195 
    196 
    197 #define SPREP_DELTA_RANGE_POSITIVE_LIMIT              8191
    198 #define SPREP_DELTA_RANGE_NEGATIVE_LIMIT              -8192
    199 
    200 
    201 extern void
    202 init(void) {
    203 
    204    sprepTrie = (UNewTrie *)uprv_calloc(1, sizeof(UNewTrie));
    205 
    206    /* initialize the two tries */
    207    if(NULL==utrie_open(sprepTrie, NULL, MAX_DATA_LENGTH, 0, 0, false)) {
    208        fprintf(stderr, "error: failed to initialize tries\n");
    209        exit(U_MEMORY_ALLOCATION_ERROR);
    210    }
    211 }
    212 
    213 static UHashtable* hashTable = NULL;
    214 
    215 
    216 typedef struct ValueStruct {
    217    UChar* mapping;
    218    int16_t length;
    219    UStringPrepType type;
    220 } ValueStruct;
    221 
    222 /* Callback for deleting the value from the hashtable */
    223 static void U_CALLCONV valueDeleter(void* obj){
    224    ValueStruct* value = (ValueStruct*) obj;
    225    uprv_free(value->mapping);
    226    uprv_free(value);
    227 }
    228 
    229 /* Callback for hashing the entry */
    230 static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
    231    return  parm.integer;
    232 }
    233 
    234 /* Callback for comparing two entries */
    235 static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
    236    return p1.integer != p2.integer;
    237 }
    238 
    239 
    240 static void
    241 storeMappingData(void){
    242 
    243    int32_t pos = UHASH_FIRST;
    244    const UHashElement* element = NULL;
    245    ValueStruct* value  = NULL;
    246    int32_t codepoint = 0;
    247    int32_t elementCount = 0;
    248    int32_t writtenElementCount = 0;
    249    int32_t mappingLength = 1; /* minimum mapping length */
    250    int32_t oldMappingLength = 0;
    251    uint16_t trieWord =0;
    252    int32_t limitIndex = 0;
    253 
    254    if (hashTable == NULL) {
    255        return;
    256    }
    257    elementCount = uhash_count(hashTable);
    258 
    259 /*initialize the mapping data */
    260    mappingData = (uint16_t*) uprv_calloc(mappingDataCapacity, U_SIZEOF_UCHAR);
    261 
    262    while(writtenElementCount < elementCount){
    263 
    264        while( (element = uhash_nextElement(hashTable, &pos))!=NULL){
    265 
    266            codepoint = element->key.integer;
    267            value = (ValueStruct*)element->value.pointer;
    268 
    269            /* store the start of indexes */
    270            if(oldMappingLength != mappingLength){
    271                /* Assume that index[] is used according to the enums defined */
    272                if(oldMappingLength <=_SPREP_MAX_INDEX_TOP_LENGTH){
    273                    indexes[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION+mappingLength] = currentIndex;
    274                }
    275                if(oldMappingLength <= _SPREP_MAX_INDEX_TOP_LENGTH &&
    276                   mappingLength == _SPREP_MAX_INDEX_TOP_LENGTH +1){
    277 
    278                    limitIndex = currentIndex;
    279 
    280                }
    281                oldMappingLength = mappingLength;
    282            }
    283 
    284            if(value->length == mappingLength){
    285                uint32_t savedTrieWord = 0;
    286                trieWord = currentIndex << 2;
    287                /* turn on the 2nd bit to signal that the following bits contain an index */
    288                trieWord += 0x02;
    289 
    290                if(trieWord > _SPREP_TYPE_THRESHOLD){
    291                    fprintf(stderr,"trieWord cannot contain value greater than 0x%04X.\n",_SPREP_TYPE_THRESHOLD);
    292                    exit(U_ILLEGAL_CHAR_FOUND);
    293                }
    294                /* figure out if the code point has type already stored */
    295                savedTrieWord= utrie_get32(sprepTrie,codepoint,NULL);
    296                if(savedTrieWord!=0){
    297                    if((savedTrieWord- _SPREP_TYPE_THRESHOLD) == USPREP_PROHIBITED){
    298                        /* turn on the first bit in trie word */
    299                        trieWord += 0x01;
    300                    }else{
    301                        /*
    302                         * the codepoint has value something other than prohibited
    303                         * and a mapping .. error!
    304                         */
    305                        fprintf(stderr,"Type for codepoint \\U%08X already set!.\n", (int)codepoint);
    306                        exit(U_ILLEGAL_ARGUMENT_ERROR);
    307                    }
    308                }
    309 
    310                /* now set the value in the trie */
    311                if(!utrie_set32(sprepTrie,codepoint,trieWord)){
    312                    fprintf(stderr,"Could not set the value for code point.\n");
    313                    exit(U_ILLEGAL_ARGUMENT_ERROR);
    314                }
    315 
    316                /* written the trie word for the codepoint... increment the count*/
    317                writtenElementCount++;
    318 
    319                /* sanity check are we exceeding the max number allowed */
    320                if(currentIndex+value->length+1 > _SPREP_MAX_INDEX_VALUE){
    321                    fprintf(stderr, "Too many entries in the mapping table %i. Maximum allowed is %i\n",
    322                        currentIndex+value->length, _SPREP_MAX_INDEX_VALUE);
    323                    exit(U_INDEX_OUTOFBOUNDS_ERROR);
    324                }
    325 
    326                /* copy the mapping data */
    327                /* write the length */
    328                if(mappingLength > _SPREP_MAX_INDEX_TOP_LENGTH ){
    329                     /* the cast here is safe since we donot expect the length to be > 65535 */
    330                     mappingData[currentIndex++] = (uint16_t) mappingLength;
    331                }
    332                /* copy the contents to mappindData array */
    333                u_memmove(mappingData+currentIndex, value->mapping, value->length);
    334                currentIndex += value->length;
    335                if (currentIndex > mappingDataCapacity) {
    336                    /* If this happens there is a bug in the computation of the mapping data size in storeMapping() */
    337                    fprintf(stderr, "gensprep, fatal error at %s, %d.  Aborting.\n", __FILE__, __LINE__);
    338                    exit(U_INTERNAL_PROGRAM_ERROR);
    339                }
    340            }
    341        }
    342        mappingLength++;
    343        pos = -1;
    344    }
    345    /* set the last length for range check */
    346    if(mappingLength <= _SPREP_MAX_INDEX_TOP_LENGTH){
    347        indexes[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION+mappingLength] = currentIndex+1;
    348    }else{
    349        indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START] = limitIndex;
    350    }
    351 
    352 }
    353 
    354 extern void setOptions(int32_t options){
    355    indexes[_SPREP_OPTIONS] = options;
    356 }
    357 extern void
    358 storeMapping(uint32_t codepoint, uint32_t* mapping,int32_t length,
    359             UStringPrepType type, UErrorCode* status){
    360 
    361 
    362    UChar* map = NULL;
    363    int16_t adjustedLen=0, i, j;
    364    uint16_t trieWord = 0;
    365    ValueStruct *value = NULL;
    366    uint32_t savedTrieWord = 0;
    367 
    368    /* initialize the hashtable */
    369    if(hashTable==NULL){
    370        hashTable = uhash_open(hashEntry, compareEntries, NULL, status);
    371        uhash_setValueDeleter(hashTable, valueDeleter);
    372    }
    373 
    374    /* figure out if the code point has type already stored */
    375    savedTrieWord= utrie_get32(sprepTrie,codepoint,NULL);
    376    if(savedTrieWord!=0){
    377        if((savedTrieWord- _SPREP_TYPE_THRESHOLD) == USPREP_PROHIBITED){
    378            /* turn on the first bit in trie word */
    379            trieWord += 0x01;
    380        }else{
    381            /*
    382             * the codepoint has value something other than prohibited
    383             * and a mapping .. error!
    384             */
    385            fprintf(stderr,"Type for codepoint \\U%08X already set!.\n", (int)codepoint);
    386            exit(U_ILLEGAL_ARGUMENT_ERROR);
    387        }
    388    }
    389 
    390    /* figure out the real length */
    391    for(i=0; i<length; i++){
    392        adjustedLen += U16_LENGTH(mapping[i]);
    393    }
    394 
    395    if(adjustedLen == 0){
    396        trieWord = (uint16_t)(_SPREP_MAX_INDEX_VALUE << 2);
    397        /* make sure that the value of trieWord is less than the threshold */
    398        if(trieWord < _SPREP_TYPE_THRESHOLD){
    399            /* now set the value in the trie */
    400            if(!utrie_set32(sprepTrie,codepoint,trieWord)){
    401                fprintf(stderr,"Could not set the value for code point.\n");
    402                exit(U_ILLEGAL_ARGUMENT_ERROR);
    403            }
    404            /* value is set so just return */
    405            return;
    406        }else{
    407            fprintf(stderr,"trieWord cannot contain value greater than threshold 0x%04X.\n",_SPREP_TYPE_THRESHOLD);
    408            exit(U_ILLEGAL_CHAR_FOUND);
    409        }
    410    }
    411 
    412    if(adjustedLen == 1){
    413        /* calculate the delta */
    414        int16_t delta = (int16_t)((int32_t)codepoint - (int16_t) mapping[0]);
    415        if(delta >= SPREP_DELTA_RANGE_NEGATIVE_LIMIT && delta <= SPREP_DELTA_RANGE_POSITIVE_LIMIT){
    416 
    417            trieWord = delta;
    418            trieWord <<= 2;
    419 
    420 
    421            /* make sure that the second bit is OFF */
    422            if((trieWord & 0x02) != 0 ){
    423                fprintf(stderr,"The second bit in the trie word is not zero while storing a delta.\n");
    424                exit(U_INTERNAL_PROGRAM_ERROR);
    425            }
    426            /* make sure that the value of trieWord is less than the threshold */
    427            if(trieWord < _SPREP_TYPE_THRESHOLD){
    428                /* now set the value in the trie */
    429                if(!utrie_set32(sprepTrie,codepoint,trieWord)){
    430                    fprintf(stderr,"Could not set the value for code point.\n");
    431                    exit(U_ILLEGAL_ARGUMENT_ERROR);
    432                }
    433                /* value is set so just return */
    434                return;
    435            }
    436        }
    437        /*
    438         * if the delta is not in the given range or if the trieWord is larger than the threshold
    439         * just fall through for storing the mapping in the mapping table
    440         */
    441    }
    442 
    443    map = (UChar*) uprv_calloc(adjustedLen + 1, U_SIZEOF_UCHAR);
    444 
    445    for (i=0, j=0; i<length; i++) {
    446        U16_APPEND_UNSAFE(map, j, mapping[i]);
    447    }
    448 
    449    value = (ValueStruct*) uprv_malloc(sizeof(ValueStruct));
    450    value->mapping = map;
    451    value->type    = type;
    452    value->length  = adjustedLen;
    453    if(value->length > _SPREP_MAX_INDEX_TOP_LENGTH){
    454        mappingDataCapacity++;
    455    }
    456    if(maxLength < value->length){
    457        maxLength = value->length;
    458    }
    459    uhash_iput(hashTable,codepoint,value,status);
    460    mappingDataCapacity += adjustedLen;
    461 
    462    if(U_FAILURE(*status)){
    463        fprintf(stderr, "Failed to put entries into the hash table. Error: %s\n", u_errorName(*status));
    464        exit(*status);
    465    }
    466 }
    467 
    468 
    469 extern void
    470 storeRange(uint32_t start, uint32_t end, UStringPrepType type, UErrorCode* status){
    471    (void)status; // suppress compiler warnings about unused variable
    472    uint16_t trieWord = 0;
    473 
    474    if((int)(_SPREP_TYPE_THRESHOLD + type) > 0xFFFF){
    475        fprintf(stderr,"trieWord cannot contain value greater than 0xFFFF.\n");
    476        exit(U_ILLEGAL_CHAR_FOUND);
    477    }
    478    trieWord = (_SPREP_TYPE_THRESHOLD + type); /* the top 4 bits contain the value */
    479    if(start == end){
    480        uint32_t savedTrieWord = utrie_get32(sprepTrie, start, NULL);
    481        if(savedTrieWord>0){
    482            if(savedTrieWord < _SPREP_TYPE_THRESHOLD && type == USPREP_PROHIBITED){
    483                /*
    484                 * A mapping is stored in the trie word
    485                 * and the only other possible type that a
    486                 * code point can have is USPREP_PROHIBITED
    487                 *
    488                 */
    489 
    490                /* turn on the 0th bit in the savedTrieWord */
    491                savedTrieWord += 0x01;
    492 
    493                /* the downcast is safe since we only save 16 bit values */
    494                trieWord = (uint16_t)savedTrieWord;
    495 
    496                /* make sure that the value of trieWord is less than the threshold */
    497                if(trieWord < _SPREP_TYPE_THRESHOLD){
    498                    /* now set the value in the trie */
    499                    if(!utrie_set32(sprepTrie,start,trieWord)){
    500                        fprintf(stderr,"Could not set the value for code point.\n");
    501                        exit(U_ILLEGAL_ARGUMENT_ERROR);
    502                    }
    503                    /* value is set so just return */
    504                    return;
    505                }else{
    506                    fprintf(stderr,"trieWord cannot contain value greater than threshold 0x%04X.\n",_SPREP_TYPE_THRESHOLD);
    507                    exit(U_ILLEGAL_CHAR_FOUND);
    508                }
    509 
    510            }else if(savedTrieWord != trieWord){
    511                fprintf(stderr,"Value for codepoint \\U%08X already set!.\n", (int)start);
    512                exit(U_ILLEGAL_ARGUMENT_ERROR);
    513            }
    514            /* if savedTrieWord == trieWord .. fall through and set the value */
    515        }
    516        if(!utrie_set32(sprepTrie,start,trieWord)){
    517            fprintf(stderr,"Could not set the value for code point \\U%08X.\n", (int)start);
    518            exit(U_ILLEGAL_ARGUMENT_ERROR);
    519        }
    520    }else{
    521        if(!utrie_setRange32(sprepTrie, start, end+1, trieWord, false)){
    522            fprintf(stderr,"Value for certain codepoint already set.\n");
    523            exit(U_ILLEGAL_CHAR_FOUND);
    524        }
    525    }
    526 
    527 }
    528 
    529 /* folding value: just store the offset (16 bits) if there is any non-0 entry */
    530 static uint32_t U_CALLCONV
    531 getFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset) {
    532    uint32_t value;
    533    UChar32 limit=0;
    534    UBool inBlockZero;
    535 
    536    limit=start+0x400;
    537    while(start<limit) {
    538        value=utrie_get32(trie, start, &inBlockZero);
    539        if(inBlockZero) {
    540            start+=UTRIE_DATA_BLOCK_LENGTH;
    541        } else if(value!=0) {
    542            return (uint32_t)offset;
    543        } else {
    544            ++start;
    545        }
    546    }
    547    return 0;
    548 
    549 }
    550 
    551 #endif /* #if !UCONFIG_NO_IDNA */
    552 
    553 extern void
    554 generateData(const char *dataDir, const char* bundleName) {
    555    static uint8_t sprepTrieBlock[100000];
    556 
    557    UNewDataMemory *pData;
    558    UErrorCode errorCode=U_ZERO_ERROR;
    559    int32_t size, dataLength;
    560    char* fileName = (char*) uprv_malloc(uprv_strlen(bundleName) +100);
    561 
    562 #if UCONFIG_NO_IDNA
    563 
    564    size=0;
    565 
    566 #else
    567 
    568    int32_t sprepTrieSize;
    569 
    570    /* sort and add mapping data */
    571    storeMappingData();
    572 
    573    sprepTrieSize=utrie_serialize(sprepTrie, sprepTrieBlock, sizeof(sprepTrieBlock), getFoldedValue, true, &errorCode);
    574    if(U_FAILURE(errorCode)) {
    575        fprintf(stderr, "error: utrie_serialize(sprep trie) failed, %s\n", u_errorName(errorCode));
    576        exit(errorCode);
    577    }
    578 
    579    size = sprepTrieSize + mappingDataCapacity*U_SIZEOF_UCHAR + sizeof(indexes);
    580    if(beVerbose) {
    581        printf("size of sprep trie              %5u bytes\n", (int)sprepTrieSize);
    582        printf("size of " U_ICUDATA_NAME "_%s." DATA_TYPE " contents: %ld bytes\n", bundleName,(long)size);
    583        printf("size of mapping data array %5u bytes\n",(int)mappingDataCapacity * U_SIZEOF_UCHAR);
    584        printf("Number of code units in mappingData (currentIndex) are: %i \n", currentIndex);
    585        printf("Maximum length of the mapping string is : %i \n", (int)maxLength);
    586    }
    587 
    588 #endif
    589 
    590    fileName[0]=0;
    591    uprv_strcat(fileName,bundleName);
    592    /* write the data */
    593    pData=udata_create(dataDir, DATA_TYPE, fileName, &dataInfo,
    594                       haveCopyright ? U_COPYRIGHT_STRING : NULL, &errorCode);
    595    if(U_FAILURE(errorCode)) {
    596        fprintf(stderr, "gensprep: unable to create the output file, error %d\n", errorCode);
    597        exit(errorCode);
    598    }
    599 
    600 #if !UCONFIG_NO_IDNA
    601 
    602    indexes[_SPREP_INDEX_TRIE_SIZE]=sprepTrieSize;
    603    indexes[_SPREP_INDEX_MAPPING_DATA_SIZE]=mappingDataCapacity*U_SIZEOF_UCHAR;
    604 
    605    udata_writeBlock(pData, indexes, sizeof(indexes));
    606    udata_writeBlock(pData, sprepTrieBlock, sprepTrieSize);
    607    udata_writeBlock(pData, mappingData, indexes[_SPREP_INDEX_MAPPING_DATA_SIZE]);
    608 
    609 
    610 #endif
    611 
    612    /* finish up */
    613    dataLength=udata_finish(pData, &errorCode);
    614    if(U_FAILURE(errorCode)) {
    615        fprintf(stderr, "gensprep: error %d writing the output file\n", errorCode);
    616        exit(errorCode);
    617    }
    618 
    619    if(dataLength!=size) {
    620        fprintf(stderr, "gensprep error: data length %ld != calculated size %ld\n",
    621            (long)dataLength, (long)size);
    622        exit(U_INTERNAL_PROGRAM_ERROR);
    623    }
    624 
    625 #if !UCONFIG_NO_IDNA
    626    /* done with writing the data .. close the hashtable */
    627    if (hashTable != NULL) {
    628        uhash_close(hashTable);
    629    }
    630 #endif
    631 
    632    uprv_free(fileName);
    633 }
    634 
    635 #if !UCONFIG_NO_IDNA
    636 
    637 extern void
    638 cleanUpData(void) {
    639    uprv_free(mappingData);
    640    utrie_close(sprepTrie);
    641    uprv_free(sprepTrie);
    642 }
    643 
    644 #endif /* #if !UCONFIG_NO_IDNA */
    645 
    646 /*
    647 * Hey, Emacs, please set the following:
    648 *
    649 * Local Variables:
    650 * indent-tabs-mode: nil
    651 * End:
    652 *
    653 */