static UConverterSelector * serializeAndUnserialize(UConverterSelector *sel, char **buffer, UErrorCode *status) { char *new_buffer; int32_t ser_len, ser_len2; /* preflight */ ser_len = ucnvsel_serialize(sel, NULL, 0, status); if (*status != U_BUFFER_OVERFLOW_ERROR) { log_err("ucnvsel_serialize(preflighting) failed: %s\n", u_errorName(*status)); return sel; } new_buffer = (char *)uprv_malloc(ser_len); *status = U_ZERO_ERROR; ser_len2 = ucnvsel_serialize(sel, new_buffer, ser_len, status); if (U_FAILURE(*status) || ser_len != ser_len2) { log_err("ucnvsel_serialize() failed: %s\n", u_errorName(*status)); uprv_free(new_buffer); return sel; } ucnvsel_close(sel); uprv_free(*buffer); *buffer = new_buffer; sel = ucnvsel_openFromSerialized(new_buffer, ser_len, status); if (U_FAILURE(*status)) { log_err("ucnvsel_openFromSerialized() failed: %s\n", u_errorName(*status)); return NULL; } return sel; }
/* unserialize a selector */ U_CAPI UConverterSelector* U_EXPORT2 ucnvsel_openFromSerialized(const void* buffer, int32_t length, UErrorCode* status) { // check if already failed if (U_FAILURE(*status)) { return NULL; } // ensure args make sense! const uint8_t *p = (const uint8_t *)buffer; if (length <= 0 || (length > 0 && (p == NULL || (U_POINTER_MASK_LSB(p, 3) != 0))) ) { *status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // header if (length < 32) { // not even enough space for a minimal header *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } const DataHeader *pHeader = (const DataHeader *)p; if (!( pHeader->dataHeader.magic1==0xda && pHeader->dataHeader.magic2==0x27 && pHeader->info.dataFormat[0] == 0x43 && pHeader->info.dataFormat[1] == 0x53 && pHeader->info.dataFormat[2] == 0x65 && pHeader->info.dataFormat[3] == 0x6c )) { /* header not valid or dataFormat not recognized */ *status = U_INVALID_FORMAT_ERROR; return NULL; } if (pHeader->info.formatVersion[0] != 1) { *status = U_UNSUPPORTED_ERROR; return NULL; } uint8_t* swapped = NULL; if (pHeader->info.isBigEndian != U_IS_BIG_ENDIAN || pHeader->info.charsetFamily != U_CHARSET_FAMILY ) { // swap the data UDataSwapper *ds = udata_openSwapperForInputData(p, length, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, status); int32_t totalSize = ucnvsel_swap(ds, p, -1, NULL, status); if (U_FAILURE(*status)) { udata_closeSwapper(ds); return NULL; } if (length < totalSize) { udata_closeSwapper(ds); *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } swapped = (uint8_t*)uprv_malloc(totalSize); if (swapped == NULL) { udata_closeSwapper(ds); *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } ucnvsel_swap(ds, p, length, swapped, status); udata_closeSwapper(ds); if (U_FAILURE(*status)) { uprv_free(swapped); return NULL; } p = swapped; pHeader = (const DataHeader *)p; } if (length < (pHeader->dataHeader.headerSize + 16 * 4)) { // not even enough space for the header and the indexes uprv_free(swapped); *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } p += pHeader->dataHeader.headerSize; length -= pHeader->dataHeader.headerSize; // indexes const int32_t *indexes = (const int32_t *)p; if (length < indexes[UCNVSEL_INDEX_SIZE]) { uprv_free(swapped); *status = U_INDEX_OUTOFBOUNDS_ERROR; return NULL; } p += UCNVSEL_INDEX_COUNT * 4; // create and populate the selector object UConverterSelector* sel = (UConverterSelector*)uprv_malloc(sizeof(UConverterSelector)); char **encodings = (char **)uprv_malloc( indexes[UCNVSEL_INDEX_NAMES_COUNT] * sizeof(char *)); if (sel == NULL || encodings == NULL) { uprv_free(swapped); uprv_free(sel); uprv_free(encodings); *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } uprv_memset(sel, 0, sizeof(UConverterSelector)); sel->pvCount = indexes[UCNVSEL_INDEX_PV_COUNT]; sel->encodings = encodings; sel->encodingsCount = indexes[UCNVSEL_INDEX_NAMES_COUNT]; sel->encodingStrLength = indexes[UCNVSEL_INDEX_NAMES_LENGTH]; sel->swapped = swapped; // trie sel->trie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS, p, indexes[UCNVSEL_INDEX_TRIE_SIZE], NULL, status); p += indexes[UCNVSEL_INDEX_TRIE_SIZE]; if (U_FAILURE(*status)) { ucnvsel_close(sel); return NULL; } // bit vectors sel->pv = (uint32_t *)p; p += sel->pvCount * 4; // encoding names char* s = (char*)p; for (int32_t i = 0; i < sel->encodingsCount; ++i) { sel->encodings[i] = s; s += uprv_strlen(s) + 1; } p += sel->encodingStrLength; return sel; }
static void TestSelector() { TestText text; USet* excluded_sets[3] = { NULL }; int32_t i, testCaseIdx; if (!getAvailableNames()) { return; } if (!text_open(&text)) { releaseAvailableNames();; } excluded_sets[0] = uset_openEmpty(); for(i = 1 ; i < 3 ; i++) { excluded_sets[i] = uset_open(i*30, i*30+500); } for(testCaseIdx = 0; testCaseIdx < UPRV_LENGTHOF(getEncodingsFns); testCaseIdx++) { int32_t excluded_set_id; int32_t num_encodings; const char **encodings = getEncodingsFns[testCaseIdx](&num_encodings); if (getTestOption(QUICK_OPTION) && num_encodings > 25) { uprv_free((void *)encodings); continue; } /* * for(excluded_set_id = 0 ; excluded_set_id < 3 ; excluded_set_id++) * * This loop was replaced by the following statement because * the loop made the test run longer without adding to the code coverage. * The handling of the exclusion set is independent of the * set of encodings, so there is no need to test every combination. */ excluded_set_id = testCaseIdx % UPRV_LENGTHOF(excluded_sets); { UConverterSelector *sel_rt, *sel_fb; char *buffer_fb = NULL; UErrorCode status = U_ZERO_ERROR; sel_rt = ucnvsel_open(encodings, num_encodings, excluded_sets[excluded_set_id], UCNV_ROUNDTRIP_SET, &status); if (num_encodings == gCountAvailable) { /* test the special "all converters" parameter values */ sel_fb = ucnvsel_open(NULL, 0, excluded_sets[excluded_set_id], UCNV_ROUNDTRIP_AND_FALLBACK_SET, &status); } else if (uset_isEmpty(excluded_sets[excluded_set_id])) { /* test that a NULL set gives the same results as an empty set */ sel_fb = ucnvsel_open(encodings, num_encodings, NULL, UCNV_ROUNDTRIP_AND_FALLBACK_SET, &status); } else { sel_fb = ucnvsel_open(encodings, num_encodings, excluded_sets[excluded_set_id], UCNV_ROUNDTRIP_AND_FALLBACK_SET, &status); } if (U_FAILURE(status)) { log_err("ucnv_sel_open(encodings %ld) failed - %s\n", testCaseIdx, u_errorName(status)); ucnvsel_close(sel_rt); uprv_free((void *)encodings); continue; } text_reset(&text); for (;;) { UBool *manual_rt, *manual_fb; static UChar utf16[10000]; char *s; int32_t length8, length16; s = text_nextString(&text, &length8); if (s == NULL || (getTestOption(QUICK_OPTION) && text.number > 3)) { break; } manual_rt = getResultsManually(encodings, num_encodings, s, length8, excluded_sets[excluded_set_id], UCNV_ROUNDTRIP_SET); manual_fb = getResultsManually(encodings, num_encodings, s, length8, excluded_sets[excluded_set_id], UCNV_ROUNDTRIP_AND_FALLBACK_SET); /* UTF-8 with length */ status = U_ZERO_ERROR; verifyResult(ucnvsel_selectForUTF8(sel_rt, s, length8, &status), manual_rt); verifyResult(ucnvsel_selectForUTF8(sel_fb, s, length8, &status), manual_fb); /* UTF-8 NUL-terminated */ verifyResult(ucnvsel_selectForUTF8(sel_rt, s, -1, &status), manual_rt); verifyResult(ucnvsel_selectForUTF8(sel_fb, s, -1, &status), manual_fb); u_strFromUTF8(utf16, UPRV_LENGTHOF(utf16), &length16, s, length8, &status); if (U_FAILURE(status)) { log_err("error converting the test text (string %ld) to UTF-16 - %s\n", (long)text.number, u_errorName(status)); } else { if (text.number == 0) { sel_fb = serializeAndUnserialize(sel_fb, &buffer_fb, &status); } if (U_SUCCESS(status)) { /* UTF-16 with length */ verifyResult(ucnvsel_selectForString(sel_rt, utf16, length16, &status), manual_rt); verifyResult(ucnvsel_selectForString(sel_fb, utf16, length16, &status), manual_fb); /* UTF-16 NUL-terminated */ verifyResult(ucnvsel_selectForString(sel_rt, utf16, -1, &status), manual_rt); verifyResult(ucnvsel_selectForString(sel_fb, utf16, -1, &status), manual_fb); } } uprv_free(manual_rt); uprv_free(manual_fb); } ucnvsel_close(sel_rt); ucnvsel_close(sel_fb); uprv_free(buffer_fb); } uprv_free((void *)encodings); } releaseAvailableNames(); text_close(&text); for(i = 0 ; i < 3 ; i++) { uset_close(excluded_sets[i]); } }