16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*******************************************************************************
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   Copyright (C) 2008-2011, International Business Machines
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   Corporation, Google and others.  All Rights Reserved.
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*******************************************************************************
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*/
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Author : eldawy@google.com (Mohamed Eldawy)
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// ucnvsel.cpp
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Purpose: To generate a list of encodings capable of handling
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// a given Unicode text
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Started 09-April-2008
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * \file
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * This is an implementation of an encoding selector.
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The goal is, given a unicode string, find the encodings
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * this string can be mapped to. To make processing faster
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * a trie is built when you call ucnvsel_open() that
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * stores all encodings a codepoint can map to
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/ucnvsel.h"
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_CONVERSION
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <string.h>
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uchar.h"
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uniset.h"
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/ucnv.h"
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/ustring.h"
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uchriter.h"
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "utrie2.h"
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "propsvec.h"
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "ucmndata.h"
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uenumimp.h"
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cmemory.h"
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cstring.h"
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_USE
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstruct UConverterSelector {
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UTrie2 *trie;              // 16 bit trie containing offsets into pv
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint32_t* pv;              // table of bits!
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t pvCount;
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  char** encodings;          // which encodings did user ask to use?
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t encodingsCount;
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t encodingStrLength;
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint8_t* swapped;
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UBool ownPv, ownEncodingStrings;
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic void generateSelectorData(UConverterSelector* result,
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                 UPropsVectors *upvec,
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                 const USet* excludedCodePoints,
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                 const UConverterUnicodeSet whichSet,
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                 UErrorCode* status) {
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return;
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t columns = (result->encodingsCount+31)/32;
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // set errorValue to all-ones
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (int32_t col = 0; col < columns; col++) {
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    upvec_setValue(upvec, UPVEC_ERROR_VALUE_CP, UPVEC_ERROR_VALUE_CP,
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   col, ~0, ~0, status);
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (int32_t i = 0; i < result->encodingsCount; ++i) {
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uint32_t mask;
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uint32_t column;
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t item_count;
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t j;
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UConverter* test_converter = ucnv_open(result->encodings[i], status);
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(*status)) {
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return;
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    USet* unicode_point_set;
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    unicode_point_set = uset_open(1, 0);  // empty set
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnv_getUnicodeSet(test_converter, unicode_point_set,
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                       whichSet, status);
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(*status)) {
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      ucnv_close(test_converter);
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return;
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    column = i / 32;
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    mask = 1 << (i%32);
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // now iterate over intervals on set i!
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    item_count = uset_getItemCount(unicode_point_set);
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (j = 0; j < item_count; ++j) {
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar32 start_char;
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar32 end_char;
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UErrorCode smallStatus = U_ZERO_ERROR;
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uset_getItem(unicode_point_set, j, &start_char, &end_char, NULL, 0,
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   &smallStatus);
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (U_FAILURE(smallStatus)) {
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // this will be reached for the converters that fill the set with
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // strings. Those should be ignored by our system
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      } else {
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        upvec_setValue(upvec, start_char, end_char, column, ~0, mask,
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                       status);
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnv_close(test_converter);
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uset_close(unicode_point_set);
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(*status)) {
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return;
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // handle excluded encodings! Simply set their values to all 1's in the upvec
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (excludedCodePoints) {
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t item_count = uset_getItemCount(excludedCodePoints);
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t j = 0; j < item_count; ++j) {
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar32 start_char;
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar32 end_char;
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uset_getItem(excludedCodePoints, j, &start_char, &end_char, NULL, 0,
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   status);
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      for (int32_t col = 0; col < columns; col++) {
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        upvec_setValue(upvec, start_char, end_char, col, ~0, ~0,
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      status);
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // alright. Now, let's put things in the same exact form you'd get when you
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // unserialize things.
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->trie = upvec_compactToUTrie2WithRowIndexes(upvec, status);
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->pv = upvec_cloneArray(upvec, &result->pvCount, NULL, status);
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->pvCount *= columns;  // number of uint32_t = rows * columns
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->ownPv = TRUE;
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* open a selector. If converterListSize is 0, build for all converters.
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org   If excludedCodePoints is NULL, don't exclude any codepoints */
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI UConverterSelector* U_EXPORT2
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_open(const char* const*  converterList, int32_t converterListSize,
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             const USet* excludedCodePoints,
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             const UConverterUnicodeSet whichSet, UErrorCode* status) {
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // ensure args make sense!
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (converterListSize < 0 || (converterList == NULL && converterListSize != 0)) {
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_ILLEGAL_ARGUMENT_ERROR;
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // allocate a new converter
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  LocalUConverterSelectorPointer newSelector(
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    (UConverterSelector*)uprv_malloc(sizeof(UConverterSelector)));
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (newSelector.isNull()) {
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memset(newSelector.getAlias(), 0, sizeof(UConverterSelector));
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (converterListSize == 0) {
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    converterList = NULL;
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    converterListSize = ucnv_countAvailable();
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  newSelector->encodings =
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    (char**)uprv_malloc(converterListSize * sizeof(char*));
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (!newSelector->encodings) {
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  newSelector->encodings[0] = NULL;  // now we can call ucnvsel_close()
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // make a backup copy of the list of converters
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t totalSize = 0;
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t i;
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (i = 0; i < converterListSize; i++) {
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    totalSize +=
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      (int32_t)uprv_strlen(converterList != NULL ? converterList[i] : ucnv_getAvailableName(i)) + 1;
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // 4-align the totalSize to 4-align the size of the serialized form
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t encodingStrPadding = totalSize & 3;
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (encodingStrPadding != 0) {
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    encodingStrPadding = 4 - encodingStrPadding;
1936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
1946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  newSelector->encodingStrLength = totalSize += encodingStrPadding;
1956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  char* allStrings = (char*) uprv_malloc(totalSize);
1966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (!allStrings) {
1976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
1986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
1996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (i = 0; i < converterListSize; i++) {
2026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    newSelector->encodings[i] = allStrings;
2036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_strcpy(newSelector->encodings[i],
2046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                converterList != NULL ? converterList[i] : ucnv_getAvailableName(i));
2056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    allStrings += uprv_strlen(newSelector->encodings[i]) + 1;
2066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  while (encodingStrPadding > 0) {
2086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *allStrings++ = 0;
2096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    --encodingStrPadding;
2106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  newSelector->ownEncodingStrings = TRUE;
2136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  newSelector->encodingsCount = converterListSize;
2146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UPropsVectors *upvec = upvec_open((converterListSize+31)/32, status);
2156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  generateSelectorData(newSelector.getAlias(), upvec, excludedCodePoints, whichSet, status);
2166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  upvec_close(upvec);
2176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
2196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
2206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return newSelector.orphan();
2236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* close opened selector */
2266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void U_EXPORT2
2276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_close(UConverterSelector *sel) {
2286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (!sel) {
2296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return;
2306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (sel->ownEncodingStrings) {
2326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(sel->encodings[0]);
2336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(sel->encodings);
2356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (sel->ownPv) {
2366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(sel->pv);
2376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  utrie2_close(sel->trie);
2396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(sel->swapped);
2406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(sel);
2416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UDataInfo dataInfo = {
2446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sizeof(UDataInfo),
2456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  0,
2466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  U_IS_BIG_ENDIAN,
2486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  U_CHARSET_FAMILY,
2496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  U_SIZEOF_UCHAR,
2506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  0,
2516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  { 0x43, 0x53, 0x65, 0x6c },   /* dataFormat="CSel" */
2536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  { 1, 0, 0, 0 },               /* formatVersion */
2546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  { 0, 0, 0, 0 }                /* dataVersion */
2556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
2566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgenum {
2586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UCNVSEL_INDEX_TRIE_SIZE,      // trie size in bytes
2596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UCNVSEL_INDEX_PV_COUNT,       // number of uint32_t in the bit vectors
2606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UCNVSEL_INDEX_NAMES_COUNT,    // number of encoding names
2616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UCNVSEL_INDEX_NAMES_LENGTH,   // number of encoding name bytes including padding
2626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UCNVSEL_INDEX_SIZE = 15,      // bytes following the DataHeader
2636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UCNVSEL_INDEX_COUNT = 16
2646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
2656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
2676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Serialized form of a UConverterSelector, formatVersion 1:
2686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
2696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The serialized form begins with a standard ICU DataHeader with a UDataInfo
2706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * as the template above.
2716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * This is followed by:
2726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   int32_t indexes[UCNVSEL_INDEX_COUNT];          // see index entry constants above
2736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   serialized UTrie2;                             // indexes[UCNVSEL_INDEX_TRIE_SIZE] bytes
2746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   uint32_t pv[indexes[UCNVSEL_INDEX_PV_COUNT]];  // bit vectors
2756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   char* encodingNames[indexes[UCNVSEL_INDEX_NAMES_LENGTH]];  // NUL-terminated strings + padding
2766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
2776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* serialize a selector */
2796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI int32_t U_EXPORT2
2806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_serialize(const UConverterSelector* sel,
2816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                  void* buffer, int32_t bufferCapacity, UErrorCode* status) {
2826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
2836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
2846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
2856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // ensure args make sense!
2876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint8_t *p = (uint8_t *)buffer;
2886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (bufferCapacity < 0 ||
2896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      (bufferCapacity > 0 && (p == NULL || (U_POINTER_MASK_LSB(p, 3) != 0)))
2906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ) {
2916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_ILLEGAL_ARGUMENT_ERROR;
2926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
2936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // add up the size of the serialized form
2956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t serializedTrieSize = utrie2_serialize(sel->trie, NULL, 0, status);
2966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (*status != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(*status)) {
2976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
2986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
2996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  *status = U_ZERO_ERROR;
3006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  DataHeader header;
3026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memset(&header, 0, sizeof(header));
3036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  header.dataHeader.headerSize = (uint16_t)((sizeof(header) + 15) & ~15);
3046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  header.dataHeader.magic1 = 0xda;
3056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  header.dataHeader.magic2 = 0x27;
3066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memcpy(&header.info, &dataInfo, sizeof(dataInfo));
3076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t indexes[UCNVSEL_INDEX_COUNT] = {
3096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    serializedTrieSize,
3106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sel->pvCount,
3116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sel->encodingsCount,
3126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sel->encodingStrLength
3136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  };
3146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t totalSize =
3166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    header.dataHeader.headerSize +
3176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    (int32_t)sizeof(indexes) +
3186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    serializedTrieSize +
3196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sel->pvCount * 4 +
3206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sel->encodingStrLength;
3216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  indexes[UCNVSEL_INDEX_SIZE] = totalSize - header.dataHeader.headerSize;
3226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (totalSize > bufferCapacity) {
3236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_BUFFER_OVERFLOW_ERROR;
3246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return totalSize;
3256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
3266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // ok, save!
3276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t length = header.dataHeader.headerSize;
3286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memcpy(p, &header, sizeof(header));
3296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memset(p + sizeof(header), 0, length - sizeof(header));
3306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += length;
3316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  length = (int32_t)sizeof(indexes);
3336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memcpy(p, indexes, length);
3346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += length;
3356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  utrie2_serialize(sel->trie, p, serializedTrieSize, status);
3376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += serializedTrieSize;
3386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  length = sel->pvCount * 4;
3406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memcpy(p, sel->pv, length);
3416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += length;
3426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memcpy(p, sel->encodings[0], sel->encodingStrLength);
3446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += sel->encodingStrLength;
3456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return totalSize;
3476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
3506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * swap a selector into the desired Endianness and Asciiness of
3516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * the system. Just as FYI, selectors are always saved in the format
3526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * of the system that created them. They are only converted if used
3536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * on another system. In other words, selectors created on different
3546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * system can be different even if the params are identical (endianness
3556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * and Asciiness differences only)
3566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
3576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param ds pointer to data swapper containing swapping info
3586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param inData pointer to incoming data
3596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param length length of inData in bytes
3606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param outData pointer to output data. Capacity should
3616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *                be at least equal to capacity of inData
3626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @param status an in/out ICU UErrorCode
3636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * @return 0 on failure, number of bytes swapped on success
3646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *         number of bytes swapped can be smaller than length
3656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
3666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic int32_t
3676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_swap(const UDataSwapper *ds,
3686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             const void *inData, int32_t length,
3696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             void *outData, UErrorCode *status) {
3706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  /* udata_swapDataHeader checks the arguments */
3716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t headerSize = udata_swapDataHeader(ds, inData, length, outData, status);
3726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(U_FAILURE(*status)) {
3736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
3746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
3756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  /* check data format and format version */
3776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData + 4);
3786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(!(
3796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pInfo->dataFormat[0] == 0x43 &&  /* dataFormat="CSel" */
3806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pInfo->dataFormat[1] == 0x53 &&
3816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pInfo->dataFormat[2] == 0x65 &&
3826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pInfo->dataFormat[3] == 0x6c
3836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  )) {
3846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    udata_printError(ds, "ucnvsel_swap(): data format %02x.%02x.%02x.%02x is not recognized as UConverterSelector data\n",
3856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     pInfo->dataFormat[0], pInfo->dataFormat[1],
3866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     pInfo->dataFormat[2], pInfo->dataFormat[3]);
3876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_INVALID_FORMAT_ERROR;
3886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
3896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
3906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(pInfo->formatVersion[0] != 1) {
3916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    udata_printError(ds, "ucnvsel_swap(): format version %02x is not supported\n",
3926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     pInfo->formatVersion[0]);
3936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_UNSUPPORTED_ERROR;
3946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
3956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
3966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(length >= 0) {
3986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    length -= headerSize;
3996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(length < 16*4) {
4006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      udata_printError(ds, "ucnvsel_swap(): too few bytes (%d after header) for UConverterSelector data\n",
4016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                       length);
4026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      *status = U_INDEX_OUTOFBOUNDS_ERROR;
4036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return 0;
4046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const uint8_t *inBytes = (const uint8_t *)inData + headerSize;
4086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint8_t *outBytes = (uint8_t *)outData + headerSize;
4096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  /* read the indexes */
4116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const int32_t *inIndexes = (const int32_t *)inBytes;
4126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t indexes[16];
4136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t i;
4146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for(i = 0; i < 16; ++i) {
4156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    indexes[i] = udata_readInt32(ds, inIndexes[i]);
4166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  /* get the total length of the data */
4196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t size = indexes[UCNVSEL_INDEX_SIZE];
4206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(length >= 0) {
4216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(length < size) {
4226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      udata_printError(ds, "ucnvsel_swap(): too few bytes (%d after header) for all of UConverterSelector data\n",
4236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                       length);
4246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      *status = U_INDEX_OUTOFBOUNDS_ERROR;
4256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return 0;
4266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* copy the data for inaccessible bytes */
4296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(inBytes != outBytes) {
4306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uprv_memcpy(outBytes, inBytes, size);
4316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t offset = 0, count;
4346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* swap the int32_t indexes[] */
4366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    count = UCNVSEL_INDEX_COUNT*4;
4376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ds->swapArray32(ds, inBytes, count, outBytes, status);
4386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offset += count;
4396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* swap the UTrie2 */
4416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    count = indexes[UCNVSEL_INDEX_TRIE_SIZE];
4426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    utrie2_swap(ds, inBytes + offset, count, outBytes + offset, status);
4436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offset += count;
4446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* swap the uint32_t pv[] */
4466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    count = indexes[UCNVSEL_INDEX_PV_COUNT]*4;
4476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ds->swapArray32(ds, inBytes + offset, count, outBytes + offset, status);
4486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offset += count;
4496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* swap the encoding names */
4516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    count = indexes[UCNVSEL_INDEX_NAMES_LENGTH];
4526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ds->swapInvChars(ds, inBytes + offset, count, outBytes + offset, status);
4536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    offset += count;
4546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_ASSERT(offset == size);
4566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return headerSize + size;
4596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* unserialize a selector */
4626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI UConverterSelector* U_EXPORT2
4636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_openFromSerialized(const void* buffer, int32_t length, UErrorCode* status) {
4646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
4656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
4666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
4676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // ensure args make sense!
4696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const uint8_t *p = (const uint8_t *)buffer;
4706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (length <= 0 ||
4716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      (length > 0 && (p == NULL || (U_POINTER_MASK_LSB(p, 3) != 0)))
4726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ) {
4736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_ILLEGAL_ARGUMENT_ERROR;
4746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
4756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // header
4776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (length < 32) {
4786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // not even enough space for a minimal header
4796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_INDEX_OUTOFBOUNDS_ERROR;
4806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
4816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const DataHeader *pHeader = (const DataHeader *)p;
4836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (!(
4846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader->dataHeader.magic1==0xda &&
4856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader->dataHeader.magic2==0x27 &&
4866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader->info.dataFormat[0] == 0x43 &&
4876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader->info.dataFormat[1] == 0x53 &&
4886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader->info.dataFormat[2] == 0x65 &&
4896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader->info.dataFormat[3] == 0x6c
4906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  )) {
4916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* header not valid or dataFormat not recognized */
4926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_INVALID_FORMAT_ERROR;
4936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
4946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (pHeader->info.formatVersion[0] != 1) {
4966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_UNSUPPORTED_ERROR;
4976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
4986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
4996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint8_t* swapped = NULL;
5006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (pHeader->info.isBigEndian != U_IS_BIG_ENDIAN ||
5016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      pHeader->info.charsetFamily != U_CHARSET_FAMILY
5026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ) {
5036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // swap the data
5046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UDataSwapper *ds =
5056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      udata_openSwapperForInputData(p, length, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, status);
5066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t totalSize = ucnvsel_swap(ds, p, -1, NULL, status);
5076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(*status)) {
5086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      udata_closeSwapper(ds);
5096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return NULL;
5106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (length < totalSize) {
5126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      udata_closeSwapper(ds);
5136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      *status = U_INDEX_OUTOFBOUNDS_ERROR;
5146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return NULL;
5156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    swapped = (uint8_t*)uprv_malloc(totalSize);
5176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (swapped == NULL) {
5186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      udata_closeSwapper(ds);
5196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      *status = U_MEMORY_ALLOCATION_ERROR;
5206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return NULL;
5216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnvsel_swap(ds, p, length, swapped, status);
5236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    udata_closeSwapper(ds);
5246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(*status)) {
5256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uprv_free(swapped);
5266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return NULL;
5276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    p = swapped;
5296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pHeader = (const DataHeader *)p;
5306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
5316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (length < (pHeader->dataHeader.headerSize + 16 * 4)) {
5326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // not even enough space for the header and the indexes
5336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(swapped);
5346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_INDEX_OUTOFBOUNDS_ERROR;
5356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
5366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
5376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += pHeader->dataHeader.headerSize;
5386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  length -= pHeader->dataHeader.headerSize;
5396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // indexes
5406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const int32_t *indexes = (const int32_t *)p;
5416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (length < indexes[UCNVSEL_INDEX_SIZE]) {
5426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(swapped);
5436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_INDEX_OUTOFBOUNDS_ERROR;
5446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
5456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
5466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += UCNVSEL_INDEX_COUNT * 4;
5476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // create and populate the selector object
5486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UConverterSelector* sel = (UConverterSelector*)uprv_malloc(sizeof(UConverterSelector));
5496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  char **encodings =
5506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    (char **)uprv_malloc(
5516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      indexes[UCNVSEL_INDEX_NAMES_COUNT] * sizeof(char *));
5526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (sel == NULL || encodings == NULL) {
5536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(swapped);
5546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(sel);
5556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(encodings);
5566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
5576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
5586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
5596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memset(sel, 0, sizeof(UConverterSelector));
5606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->pvCount = indexes[UCNVSEL_INDEX_PV_COUNT];
5616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->encodings = encodings;
5626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->encodingsCount = indexes[UCNVSEL_INDEX_NAMES_COUNT];
5636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->encodingStrLength = indexes[UCNVSEL_INDEX_NAMES_LENGTH];
5646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->swapped = swapped;
5656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // trie
5666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->trie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
5676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                        p, indexes[UCNVSEL_INDEX_TRIE_SIZE], NULL,
5686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                        status);
5696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += indexes[UCNVSEL_INDEX_TRIE_SIZE];
5706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
5716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnvsel_close(sel);
5726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
5736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
5746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // bit vectors
5756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel->pv = (uint32_t *)p;
5766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += sel->pvCount * 4;
5776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // encoding names
5786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  char* s = (char*)p;
5796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (int32_t i = 0; i < sel->encodingsCount; ++i) {
5806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sel->encodings[i] = s;
5816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    s += uprv_strlen(s) + 1;
5826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
5836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  p += sel->encodingStrLength;
5846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return sel;
5866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// a bunch of functions for the enumeration thingie! Nothing fancy here. Just
5896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// iterate over the selected encodings
5906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstruct Enumerator {
5916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int16_t* index;
5926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int16_t length;
5936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int16_t cur;
5946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const UConverterSelector* sel;
5956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
5966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CDECL_BEGIN
5986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic void U_CALLCONV
6006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_close_selector_iterator(UEnumeration *enumerator) {
6016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(((Enumerator*)(enumerator->context))->index);
6026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(enumerator->context);
6036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(enumerator);
6046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic int32_t U_CALLCONV
6086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_count_encodings(UEnumeration *enumerator, UErrorCode *status) {
6096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
6106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
6116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
6126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return ((Enumerator*)(enumerator->context))->length;
6146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const char* U_CALLCONV ucnvsel_next_encoding(UEnumeration* enumerator,
6186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                 int32_t* resultLength,
6196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                 UErrorCode* status) {
6206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
6216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
6226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
6236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int16_t cur = ((Enumerator*)(enumerator->context))->cur;
6266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const UConverterSelector* sel;
6276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  const char* result;
6286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (cur >= ((Enumerator*)(enumerator->context))->length) {
6296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
6306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  sel = ((Enumerator*)(enumerator->context))->sel;
6326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result = sel->encodings[((Enumerator*)(enumerator->context))->index[cur] ];
6336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ((Enumerator*)(enumerator->context))->cur++;
6346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (resultLength) {
6356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *resultLength = (int32_t)uprv_strlen(result);
6366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return result;
6386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic void U_CALLCONV ucnvsel_reset_iterator(UEnumeration* enumerator,
6416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                           UErrorCode* status) {
6426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
6436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
6446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return ;
6456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ((Enumerator*)(enumerator->context))->cur = 0;
6476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CDECL_END
6506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UEnumeration defaultEncodings = {
6536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  NULL,
6546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NULL,
6556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnvsel_close_selector_iterator,
6566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnvsel_count_encodings,
6576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uenum_unextDefault,
6586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnvsel_next_encoding,
6596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ucnvsel_reset_iterator
6606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
6616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// internal fn to intersect two sets of masks
6646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// returns whether the mask has reduced to all zeros
6656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UBool intersectMasks(uint32_t* dest, const uint32_t* source1, int32_t len) {
6666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t i;
6676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint32_t oredDest = 0;
6686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (i = 0 ; i < len ; ++i) {
6696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    oredDest |= (dest[i] &= source1[i]);
6706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return oredDest == 0;
6726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// internal fn to count how many 1's are there in a mask
6756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// algorithm taken from  http://graphics.stanford.edu/~seander/bithacks.html
6766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic int16_t countOnes(uint32_t* mask, int32_t len) {
6776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t i, totalOnes = 0;
6786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  for (i = 0 ; i < len ; ++i) {
6796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uint32_t ent = mask[i];
6806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (; ent; totalOnes++)
6816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    {
6826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      ent &= ent - 1; // clear the least significant bit set
6836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
6856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return totalOnes;
6866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* internal function! */
6906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UEnumeration *selectForMask(const UConverterSelector* sel,
6916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   uint32_t *mask, UErrorCode *status) {
6926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // this is the context we will use. Store a table of indices to which
6936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // encodings are legit.
6946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  struct Enumerator* result = (Enumerator*)uprv_malloc(sizeof(Enumerator));
6956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (result == NULL) {
6966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(mask);
6976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
6986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
6996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->index = NULL;  // this will be allocated later!
7016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->length = result->cur = 0;
7026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  result->sel = sel;
7036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
7056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (en == NULL) {
7066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // TODO(markus): Combine Enumerator and UEnumeration into one struct.
7076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(mask);
7086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(result);
7096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
7106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  memcpy(en, &defaultEncodings, sizeof(UEnumeration));
7136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  en->context = result;
7146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t columns = (sel->encodingsCount+31)/32;
7166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int16_t numOnes = countOnes(mask, columns);
7176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // now, we know the exact space we need for index
7186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (numOnes > 0) {
7196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result->index = (int16_t*) uprv_malloc(numOnes * sizeof(int16_t));
7206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t i, j;
7226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int16_t k = 0;
7236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (j = 0 ; j < columns; j++) {
7246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uint32_t v = mask[j];
7256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      for (i = 0 ; i < 32 && k < sel->encodingsCount; i++, k++) {
7266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if ((v & 1) != 0) {
7276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          result->index[result->length++] = k;
7286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
7296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        v >>= 1;
7306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
7316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  } //otherwise, index will remain NULL (and will never be touched by
7336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //the enumerator code anyway)
7346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_free(mask);
7356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return en;
7366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* check a string against the selector - UTF16 version */
7396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI UEnumeration * U_EXPORT2
7406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_selectForString(const UConverterSelector* sel,
7416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        const UChar *s, int32_t length, UErrorCode *status) {
7426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
7436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
7446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // ensure args make sense!
7476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (sel == NULL || (s == NULL && length != 0)) {
7486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_ILLEGAL_ARGUMENT_ERROR;
7496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t columns = (sel->encodingsCount+31)/32;
7536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint32_t* mask = (uint32_t*) uprv_malloc(columns * 4);
7546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (mask == NULL) {
7556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
7566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memset(mask, ~0, columns *4);
7596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(s!=NULL) {
7616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UChar *limit;
7626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (length >= 0) {
7636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      limit = s + length;
7646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
7656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      limit = NULL;
7666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (limit == NULL ? *s != 0 : s != limit) {
7696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar32 c;
7706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uint16_t pvIndex;
7716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UTRIE2_U16_NEXT16(sel->trie, s, limit, c, pvIndex);
7726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (intersectMasks(mask, sel->pv+pvIndex, columns)) {
7736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
7746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
7756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return selectForMask(sel, mask, status);
7786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* check a string against the selector - UTF8 version */
7816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI UEnumeration * U_EXPORT2
7826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgucnvsel_selectForUTF8(const UConverterSelector* sel,
7836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      const char *s, int32_t length, UErrorCode *status) {
7846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // check if already failed
7856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (U_FAILURE(*status)) {
7866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  // ensure args make sense!
7896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (sel == NULL || (s == NULL && length != 0)) {
7906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_ILLEGAL_ARGUMENT_ERROR;
7916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
7936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  int32_t columns = (sel->encodingsCount+31)/32;
7956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uint32_t* mask = (uint32_t*) uprv_malloc(columns * 4);
7966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (mask == NULL) {
7976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    *status = U_MEMORY_ALLOCATION_ERROR;
7986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
8006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  uprv_memset(mask, ~0, columns *4);
8016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (length < 0) {
8036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    length = (int32_t)uprv_strlen(s);
8046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
8056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if(s!=NULL) {
8076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const char *limit = s + length;
8086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (s != limit) {
8106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      uint16_t pvIndex;
8116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UTRIE2_U8_NEXT16(sel->trie, s, limit, pvIndex);
8126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (intersectMasks(mask, sel->pv+pvIndex, columns)) {
8136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
8146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
8156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
8176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return selectForMask(sel, mask, status);
8186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif  // !UCONFIG_NO_CONVERSION
821