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 */