X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b75a7d8f3b4adbae880cab104ce2c6a50eee4db2..HEAD:/icuSources/test/cintltst/udatatst.c diff --git a/icuSources/test/cintltst/udatatst.c b/icuSources/test/cintltst/udatatst.c index d1614bb1..5c57d5aa 100644 --- a/icuSources/test/cintltst/udatatst.c +++ b/icuSources/test/cintltst/udatatst.c @@ -1,66 +1,105 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /******************************************************************** * COPYRIGHT: - * Copyright (c) 1998-2003, International Business Machines Corporation and + * Copyright (c) 1998-2016, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /* -* File test.c +* File udatatst.c * * Modification History: * * Date Name Description * 02/22/2000 Madhu Creation -******************************************************************************* +****************************************************************************** */ #include "unicode/utypes.h" +#include "unicode/putil.h" #include "unicode/udata.h" +#include "unicode/ucal.h" #include "unicode/uchar.h" #include "unicode/ucnv.h" #include "unicode/ures.h" #include "unicode/ustring.h" +#include "unicode/uclean.h" #include "cmemory.h" #include "cstring.h" #include "filestrm.h" +#include "udatamem.h" #include "cintltst.h" - -#include -#include -#include +#include "ubrkimpl.h" +#include "toolutil.h" /* for uprv_fileExists() */ #include #include -#ifdef WIN32 -#include -#else -#include -#endif +/* includes for TestSwapData() */ +#include "udataswp.h" + +/* swapping implementations in common */ +#include "uresdata.h" +#include "ucnv_io.h" +#include "uprops.h" +#include "ucase.h" +#include "ucol_imp.h" +#include "ucol_swp.h" +#include "ucnv_bld.h" +#include "sprpimpl.h" +#include "rbbidata.h" + +/* swapping implementation in i18n */ +#include "uspoof_impl.h" + +U_CAPI int32_t U_EXPORT2 +unorm2_swap(const UDataSwapper *ds, + const void *inData, int32_t length, void *outData, + UErrorCode *pErrorCode); +/* other definitions and prototypes */ + +#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION static void TestUDataOpen(void); static void TestUDataOpenChoiceDemo1(void); static void TestUDataOpenChoiceDemo2(void); static void TestUDataGetInfo(void); static void TestUDataGetMemory(void); -static void TestUDataSetAppData(void); static void TestErrorConditions(void); static void TestAppData(void); +static void TestSwapData(void); +#endif +static void TestUDataSetAppData(void); static void TestICUDataName(void); +static void PointerTableOfContents(void); +static void SetBadCommonData(void); +static void TestUDataFileAccess(void); +#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION +static void TestTZDataDir(void); +#endif void addUDataTest(TestNode** root); void addUDataTest(TestNode** root) { +#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION addTest(root, &TestUDataOpen, "udatatst/TestUDataOpen" ); addTest(root, &TestUDataOpenChoiceDemo1, "udatatst/TestUDataOpenChoiceDemo1"); addTest(root, &TestUDataOpenChoiceDemo2, "udatatst/TestUDataOpenChoiceDemo2"); addTest(root, &TestUDataGetInfo, "udatatst/TestUDataGetInfo" ); addTest(root, &TestUDataGetMemory, "udatatst/TestUDataGetMemory" ); - addTest(root, &TestUDataSetAppData, "udatatst/TestUDataSetAppData" ); addTest(root, &TestErrorConditions, "udatatst/TestErrorConditions"); addTest(root, &TestAppData, "udatatst/TestAppData" ); + addTest(root, &TestSwapData, "udatatst/TestSwapData" ); +#endif + addTest(root, &TestUDataSetAppData, "udatatst/TestUDataSetAppData" ); addTest(root, &TestICUDataName, "udatatst/TestICUDataName" ); - + addTest(root, &PointerTableOfContents, "udatatst/PointerTableOfContents" ); + addTest(root, &SetBadCommonData, "udatatst/SetBadCommonData" ); + addTest(root, &TestUDataFileAccess, "udatatst/TestUDataFileAccess" ); +#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION + addTest(root, &TestTZDataDir, "udatatst/TestTZDataDir" ); +#endif } #if 0 @@ -76,72 +115,121 @@ static void lots_of_mallocs() } #endif +#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION static void TestUDataOpen(){ UDataMemory *result; UErrorCode status=U_ZERO_ERROR; const char* memMap[][2]={ - {"tz", "icu"}, + {"root", "res"}, {"cnvalias", "icu"}, {"unames", "icu"}, {"ibm-37_P100-1995", "cnv"} }; - const char* name = "test"; - const char* type = "icu"; - const char dirSepString[] = {U_FILE_SEP_CHAR, 0}; + const char* name = "test"; + const char* type = "icu"; + const char dirSepString[] = {U_FILE_SEP_CHAR, 0}; + const char pathSepString[] = {U_PATH_SEP_CHAR, 0}; + char* path=(char*)malloc(sizeof(char) * (strlen(ctest_dataOutDir()) + strlen(U_ICUDATA_NAME) - + strlen("/build")+1 ) ); + + strlen("/build/tmp/..")+1 ) ); char *icuDataFilePath = 0; - struct stat stat_buf; const char* testPath=loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + free(path); + return; + } /* lots_of_mallocs(); */ - - strcat(strcpy(path, ctest_dataOutDir()), U_ICUDATA_NAME); - - log_verbose("Testing udata_open()\n"); + log_verbose("Testing udata_open(%s)\n", testPath); result=udata_open(testPath, type, name, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_open() failed for path = %s, name=%s, type=%s, \n errorcode=%s\n", testPath, name, type, myErrorName(status)); + log_data_err("FAIL: udata_open() failed for path = %s, name=%s, type=%s, \n errorcode=%s\n", testPath, name, type, myErrorName(status)); } else { log_verbose("PASS: udata_open worked\n"); udata_close(result); } - /* If the ICU system common data file is present in this confiugration, - * verify that udata_open can explicitly fetch items from it. - * If packaging mode == dll, the file may not exist. So, if the file is - * missing, skip this test without error. - */ - icuDataFilePath = (char *)malloc(strlen(path) + 10); - strcpy(icuDataFilePath, path); - strcat(icuDataFilePath, ".dat"); - /* lots_of_mallocs(); */ - if (stat(icuDataFilePath, &stat_buf) == 0) { - int i; - log_verbose("Testing udata_open() on %s\n", icuDataFilePath); - for(i=0; i 0) { - close(fileHandle); +static char *safeGetICUDataDirectory() { + const char *dataDir = u_getDataDirectory(); /* Returned string vanashes with u_cleanup */ + char *retStr = NULL; + if (dataDir != NULL) { + retStr = (char *)malloc(strlen(dataDir)+1); + strcpy(retStr, dataDir); + } + return retStr; +} + +static void TestUDataFileAccess(){ + UErrorCode status; + char *icuDataDir; + icuDataDir = safeGetICUDataDirectory(); /* save icu data dir, so we can put it back + * after doing u_cleanup(). */ + + /** UDATA_NO_FILES, ICU does not access the file system for data loading. */ + status=U_ZERO_ERROR; + u_cleanup(); + udata_setFileAccess(UDATA_NO_FILES,&status); + u_init(&status); + if(U_FAILURE(status) && *icuDataDir == 0){ + log_data_err("udata_setFileAccess(UDATA_NO_FILES) failed with ICU_DATA=\"\" err=%s\n", u_errorName(status)); } - free(filePath); - return; + + /** UDATA_ONLY_PACKAGES, ICU only loads data from packages, not from single files. */ + status=U_ZERO_ERROR; + u_cleanup(); + udata_setFileAccess(UDATA_ONLY_PACKAGES,&status); + u_init(&status); + + /** UDATA_PACKAGES_FIRST, ICU loads data from packages first, and only from single files + if the data cannot be found in a package. */ + status=U_ZERO_ERROR; + u_cleanup(); + udata_setFileAccess(UDATA_PACKAGES_FIRST,&status); + u_init(&status); + + /** UDATA_FILES_FIRST, ICU looks for data in single files first, then in packages. (default) */ + status=U_ZERO_ERROR; + u_cleanup(); + udata_setFileAccess(UDATA_FILES_FIRST,&status); + u_init(&status); + + /** An alias for the default access mode. */ + status=U_ZERO_ERROR; + u_cleanup(); + udata_setFileAccess(UDATA_DEFAULT_ACCESS,&status); + u_setDataDirectory(icuDataDir); + u_init(&status); + if(U_FAILURE(status)){ + log_err_status(status, "%s\n", u_errorName(status)); + } + free(icuDataDir); + ctest_resetICU(); } @@ -360,6 +558,7 @@ static UBool U_CALLCONV isAcceptable1(void *context, const char *type, const char *name, const UDataInfo *pInfo) { + (void)context; // suppress compiler warnings about unused variable if( pInfo->size>=20 && pInfo->isBigEndian==U_IS_BIG_ENDIAN && @@ -392,6 +591,7 @@ static UBool U_CALLCONV isAcceptable2(void *context, const char *type, const char *name, const UDataInfo *pInfo){ + (void)context; // suppress compiler warnings about unused variable UVersionInfo unicodeVersion; u_getUnicodeVersion(unicodeVersion); @@ -420,6 +620,7 @@ static UBool U_CALLCONV isAcceptable3(void *context, const char *type, const char *name, const UDataInfo *pInfo){ + (void)context; // suppress compiler warnings about unused variable if( pInfo->size>=20 && pInfo->isBigEndian==U_IS_BIG_ENDIAN && @@ -441,51 +642,79 @@ isAcceptable3(void *context, } +#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION static void TestUDataOpenChoiceDemo1() { UDataMemory *result; UErrorCode status=U_ZERO_ERROR; - + const char* name[]={ "cnvalias", "unames", - "test" + "test", + "nam" }; const char* type="icu"; const char* testPath="testdata"; + const char* fullTestDataPath = loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + return; + } result=udata_openChoice(NULL, "icu", name[0], isAcceptable1, NULL, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_openChoice() failed name=%s, type=%s, \n errorcode=%s\n", name[0], type, myErrorName(status)); + log_data_err("FAIL: udata_openChoice() failed name=%s, type=%s, \n errorcode=%s\n", name[0], type, myErrorName(status)); } else { log_verbose("PASS: udata_openChoice worked\n"); udata_close(result); } + status=U_ZERO_ERROR; result=udata_openChoice(NULL, type, name[1], isAcceptable1, NULL, &status); if(U_FAILURE(status)){ status=U_ZERO_ERROR; result=udata_openChoice(NULL, type, name[1], isAcceptable2, NULL, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_openChoice() failed name=%s, type=%s, \n errorcode=%s\n", name[1], type, myErrorName(status)); + log_data_err("FAIL: udata_openChoice() failed name=%s, type=%s, \n errorcode=%s\n", name[1], type, myErrorName(status)); } } + else { + log_err("FAIL: udata_openChoice() unexpectedly passed. name=%s, type=%s, \n errorcode=%s\n", name[1], type, myErrorName(status)); + } if(U_SUCCESS(status)){ udata_close(result); } + status=U_ZERO_ERROR; result=udata_openChoice(testPath, type, name[2], isAcceptable1, NULL, &status); if(U_FAILURE(status)){ status=U_ZERO_ERROR; result=udata_openChoice(testPath, type, name[2], isAcceptable3, NULL, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_openChoice() failed path=%s name=%s, type=%s, \n errorcode=%s\n", testPath, name[2], type, myErrorName(status)); + log_data_err("FAIL: udata_openChoice() failed path=%s name=%s, type=%s, \n errorcode=%s\n", testPath, name[2], type, myErrorName(status)); } } + else { + log_err("FAIL: udata_openChoice() unexpectedly passed. name=%s, type=%s, \n errorcode=%s\n", name[2], type, myErrorName(status)); + } if(U_SUCCESS(status)){ udata_close(result); } + + status=U_ZERO_ERROR; + type="typ"; + result=udata_openChoice(fullTestDataPath, type, name[3], isAcceptable1, NULL, &status); + if(status != U_INVALID_FORMAT_ERROR){ + log_err("FAIL: udata_openChoice() did not fail as expected. name=%s, type=%s, \n errorcode=%s\n", name[3], type, myErrorName(status)); + } + + status=U_USELESS_COLLATOR_ERROR; + result=udata_openChoice(fullTestDataPath, type, name[3], isAcceptable1, NULL, &status); + if(status != U_USELESS_COLLATOR_ERROR){ + log_err("FAIL: udata_openChoice() did not fail as expected. name=%s, type=%s, \n errorcode=%s\n", name[3], type, myErrorName(status)); + } } static UBool U_CALLCONV @@ -523,10 +752,14 @@ static void TestUDataOpenChoiceDemo2() { const char* name="test"; const char* type="icu"; const char* path = loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + return; + } result=udata_openChoice(path, type, name, isAcceptable, &p, &status); if(U_FAILURE(status)){ - log_err("failed to load data at p=%s t=%s n=%s, isAcceptable", path, type, name); + log_data_err("failed to load data at p=%s t=%s n=%s, isAcceptable", path, type, name); } if(U_SUCCESS(status) ) { udata_close(result); @@ -542,12 +775,12 @@ static void TestUDataOpenChoiceDemo2() { p++; } else { - log_err("FAIL: failed to either load the data or to reject the loaded data. ERROR=%s\n", myErrorName(status) ); + log_data_err("FAIL: failed to either load the data or to reject the loaded data. ERROR=%s\n", myErrorName(status) ); } } else if(p == 2) { if(U_FAILURE(status)) { - log_err("FAIL: failed to load the data and accept it. ERROR=%s\n", myErrorName(status) ); + log_data_err("FAIL: failed to load the data and accept it. ERROR=%s\n", myErrorName(status) ); } else { log_verbose("Loads the data and accepts it for p==2 as expected\n"); @@ -557,7 +790,6 @@ static void TestUDataOpenChoiceDemo2() { } } - static void TestUDataGetInfo() { UDataMemory *result; @@ -581,11 +813,15 @@ static void TestUDataGetInfo() { const char* type="icu"; const char* testPath=loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + return; + } log_verbose("Testing udata_getInfo() for cnvalias.icu\n"); result=udata_open(NULL, "icu", name, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_open() failed for path = NULL, name=%s, type=%s, \n errorcode=%s\n", name, type, myErrorName(status)); + log_data_err("FAIL: udata_open() failed for path = NULL, name=%s, type=%s, \n errorcode=%s\n", name, type, myErrorName(status)); return; } udata_getInfo(result, &dataInfo); @@ -609,7 +845,7 @@ static void TestUDataGetInfo() { log_verbose("Testing udata_getInfo() for test.icu\n"); result=udata_open(testPath, type, name2, &status); if(U_FAILURE(status)) { - log_err("FAIL: udata_open() failed for path=%s name2=%s, type=%s, \n errorcode=%s\n", testPath, name2, type, myErrorName(status)); + log_data_err("FAIL: udata_open() failed for path=%s name2=%s, type=%s, \n errorcode=%s\n", testPath, name2, type, myErrorName(status)); return; } udata_getInfo(result, &dataInfo); @@ -643,12 +879,16 @@ static void TestUDataGetMemory() { const char* name2="test"; const char* testPath = loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + return; + } type="icu"; log_verbose("Testing udata_getMemory() for \"cnvalias.icu\"\n"); result=udata_openChoice(NULL, type, name, isAcceptable1, NULL, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_openChoice() failed for name=%s, type=%s, \n errorcode=%s\n", name, type, myErrorName(status)); + log_data_err("FAIL: udata_openChoice() failed for name=%s, type=%s, \n errorcode=%s\n", name, type, myErrorName(status)); return; } table=(const int32_t *)udata_getMemory(result); @@ -663,7 +903,7 @@ static void TestUDataGetMemory() { log_verbose("Testing udata_getMemory for \"test.icu\"()\n"); result=udata_openChoice(testPath, type, name2, isAcceptable3, NULL, &status); if(U_FAILURE(status)){ - log_err("FAIL: udata_openChoice() failed for path=%s name=%s, type=%s, \n errorcode=%s\n", testPath, name2, type, myErrorName(status)); + log_data_err("FAIL: udata_openChoice() failed for path=%s name=%s, type=%s, \n errorcode=%s\n", testPath, name2, type, myErrorName(status)); return; } intValue=(uint16_t *)udata_getMemory(result); @@ -698,13 +938,17 @@ static void TestErrorConditions(){ const char* type="icu"; const char *testPath = loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + return; + } status = U_ILLEGAL_ARGUMENT_ERROR; /*Try udata_open with status != U_ZERO_ERROR*/ log_verbose("Testing udata_open() with status != U_ZERO_ERROR\n"); result=udata_open(testPath, type, name, &status); if(result != NULL){ - log_err("FAIL: udata_open() is supposed to fail for path = %s, name=%s, type=%s, \n errorcode !=U_ZERO_ERROR\n", testPath, name, type); + log_data_err("FAIL: udata_open() is supposed to fail for path = %s, name=%s, type=%s, \n errorcode !=U_ZERO_ERROR\n", testPath, name, type); udata_close(result); } else { @@ -790,86 +1034,91 @@ static void TestErrorConditions(){ /* Test whether apps and ICU can each have their own root.res */ static void TestAppData() { - UResourceBundle *icu, *app; - UResourceBundle *tmp = NULL; - UResourceBundle *tmp2 = NULL; - - const UChar *appString; - const UChar *icuString; - - int32_t len; - - UErrorCode status = U_ZERO_ERROR; - char testMsgBuf[256]; - - const char* testPath=loadTestData(&status); - - icu = ures_open(NULL, "root", &status); - if(U_FAILURE(status)) - { - log_err("%s:%d: Couldn't open root ICU bundle- %s", __FILE__, __LINE__, u_errorName(status)); - return; - } - /* log_info("Open icu root: %s size_%d\n", u_errorName(status), ures_getSize(icu)); */ - status = U_ZERO_ERROR; - - app = ures_open(testPath, "root", &status); - if(U_FAILURE(status)) - { - log_err("%s:%d: Couldn't open app ICU bundle [%s]- %s", __FILE__, __LINE__, testPath, u_errorName(status)); - return; - } - /* log_info("Open app: %s, size %d\n", u_errorName(status), ures_getSize(app)); */ - - tmp = ures_getByKey(icu, "Version", tmp, &status); - if(U_FAILURE(status)) - { - log_err("%s:%d: Couldn't get Version string from ICU root bundle- %s", __FILE__, __LINE__, u_errorName(status)); - return; - } - - icuString = ures_getString(tmp, &len, &status); - if(U_FAILURE(status)) - { - log_err("%s:%d: Couldn't get string from Version string from ICU root bundle- %s", __FILE__, __LINE__, u_errorName(status)); - return; - } - /* log_info("icuString=%p - %s\n", icuString, austrdup(icuString)); */ - - - tmp2 = ures_getByKey(app, "Version", tmp2, &status); - if(U_FAILURE(status)) - { - log_err("%s:%d: Couldn't get Version string from App root bundle- %s", __FILE__, __LINE__, u_errorName(status)); - return; - } - - appString = ures_getString(tmp2, &len, &status); - if(U_FAILURE(status)) - { - log_err("%s:%d: Couldn't get string from Version string from App root bundle- %s", __FILE__, __LINE__, u_errorName(status)); - return; - } - - /* log_info("appString=%p - %s\n", appString, austrdup(appString)); */ - - - if(!u_strcmp(icuString, appString)) - { - log_err("%s:%d: Error! Expected ICU and App root version strings to be DIFFERENT but they are both %s and %s\n", __FILE__, __LINE__, austrdup(icuString), - austrdup(appString)); - } - else - { - log_verbose("%s:%d: appstr=%s, icustr=%s\n", __FILE__, - __LINE__, u_austrcpy(testMsgBuf, appString), u_austrcpy(testMsgBuf, icuString)); - } - - ures_close(tmp); - ures_close(tmp2); - ures_close(icu); - ures_close(app); + UResourceBundle *icu, *app; + UResourceBundle *tmp = NULL; + UResourceBundle *tmp2 = NULL; + + const UChar *appString; + const UChar *icuString; + + int32_t len; + + UErrorCode status = U_ZERO_ERROR; + char testMsgBuf[256]; + + const char* testPath=loadTestData(&status); + if(U_FAILURE(status)) { + log_data_err("Could not load testdata.dat, status = %s\n", u_errorName(status)); + return; + } + + icu = ures_open(NULL, "root", &status); + if(U_FAILURE(status)) + { + log_data_err("%s:%d: Couldn't open root ICU bundle- %s", __FILE__, __LINE__, u_errorName(status)); + return; + } + /* log_info("Open icu root: %s size_%d\n", u_errorName(status), ures_getSize(icu)); */ + status = U_ZERO_ERROR; + + app = ures_open(testPath, "root", &status); + if(U_FAILURE(status)) + { + log_data_err("%s:%d: Couldn't open app ICU bundle [%s]- %s", __FILE__, __LINE__, testPath, u_errorName(status)); + return; + } + /* log_info("Open app: %s, size %d\n", u_errorName(status), ures_getSize(app)); */ + + tmp = ures_getByKey(icu, "Version", tmp, &status); + if(U_FAILURE(status)) + { + log_err("%s:%d: Couldn't get Version string from ICU root bundle- %s", __FILE__, __LINE__, u_errorName(status)); + return; + } + + icuString = ures_getString(tmp, &len, &status); + if(U_FAILURE(status)) + { + log_err("%s:%d: Couldn't get string from Version string from ICU root bundle- %s", __FILE__, __LINE__, u_errorName(status)); + return; + } + /* log_info("icuString=%p - %s\n", icuString, austrdup(icuString)); */ + + + tmp2 = ures_getByKey(app, "Version", tmp2, &status); + if(U_FAILURE(status)) + { + log_err("%s:%d: Couldn't get Version string from App root bundle- %s", __FILE__, __LINE__, u_errorName(status)); + return; + } + + appString = ures_getString(tmp2, &len, &status); + if(U_FAILURE(status)) + { + log_err("%s:%d: Couldn't get string from Version string from App root bundle- %s", __FILE__, __LINE__, u_errorName(status)); + return; + } + + /* log_info("appString=%p - %s\n", appString, austrdup(appString)); */ + + + if(!u_strcmp(icuString, appString)) + { + log_err("%s:%d: Error! Expected ICU and App root version strings to be DIFFERENT but they are both %s and %s\n", __FILE__, __LINE__, austrdup(icuString), + austrdup(appString)); + } + else + { + log_verbose("%s:%d: appstr=%s, icustr=%s\n", __FILE__, + __LINE__, u_austrcpy(testMsgBuf, appString), u_austrcpy(testMsgBuf, icuString)); + } + + ures_close(tmp); + ures_close(tmp2); + ures_close(icu); + ures_close(app); } +#endif static void TestICUDataName() { @@ -888,7 +1137,7 @@ static void TestICUDataName() switch(U_CHARSET_FAMILY) { case U_ASCII_FAMILY: - switch(U_IS_BIG_ENDIAN) + switch((int)U_IS_BIG_ENDIAN) { case 1: typeChar = 'b'; @@ -906,10 +1155,10 @@ static void TestICUDataName() break; } - sprintf(expectDataName, "%s%d%d%c", + /* Only major number is needed. */ + sprintf(expectDataName, "%s%d%c", "icudt", (int)icuVersion[0], - (int)icuVersion[1], typeChar); log_verbose("Expected: %s\n", expectDataName); @@ -945,3 +1194,682 @@ static void TestICUDataName() #endif } + +/* test data swapping ------------------------------------------------------- */ + +#if U_PLATFORM == U_PF_OS400 +/* See comments in genccode.c on when this special implementation can be removed. */ +static const struct { + double bogus; + const char *bytes; +} gOffsetTOCAppDataItem1={ 0.0, /* alignment bytes */ + "\x00\x14" /* sizeof(UDataInfo) *//* MappedData { */ + "\xda" + "\x27" /* } */ + "\x00\x14" /* sizeof(UDataInfo) *//* UDataInfo { */ + "\0\0" + "\1" /* U_IS_BIG_ENDIAN */ + "\1" /* U_CHARSET_FAMILY */ + "\2" /* U_SIZEOF_WHAR_T */ + "\0" + "\x31\x31\x31\x31" + "\0\0\0\0" + "\0\0\0\0" /* } */ +}; +#else +static const struct { + double bogus; + MappedData bytes1; + UDataInfo bytes2; + uint8_t bytes3; +} gOffsetTOCAppDataItem1={ + 0.0, /* alignment bytes */ + { sizeof(UDataInfo), 0xda, 0x27 }, /* MappedData */ + + {sizeof(UDataInfo), + 0, + + U_IS_BIG_ENDIAN, + U_CHARSET_FAMILY, + sizeof(UChar), + 0, + + {0x31, 0x31, 0x31, 0x31}, /* dataFormat="1111" */ + {0, 0, 0, 0}, /* formatVersion */ + {0, 0, 0, 0}}, /* dataVersion */ + 0 +}; +#endif + +static const UChar gOffsetTOCGarbage[] = { /* "I have been very naughty!" */ + 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6E, 0x61, 0x75, 0x67, 0x68, 0x74, 0x79, 0x21 +}; + +/* Original source: icu/source/tools/genccode */ +static const struct { + uint16_t headerSize; + uint8_t magic1, magic2; + UDataInfo info; + char padding[8]; + uint32_t count, reserved; + const struct { + const char *const name; + const void *const data; + } toc[3]; +} gOffsetTOCAppData_dat = { + 32, /* headerSize */ + 0xda, /* magic1, (see struct MappedData in udata.c) */ + 0x27, /* magic2 */ + { /*UDataInfo */ + sizeof(UDataInfo), /* size */ + 0, /* reserved */ + U_IS_BIG_ENDIAN, + U_CHARSET_FAMILY, + sizeof(UChar), + 0, /* reserved */ + { /* data format identifier */ + 0x54, 0x6f, 0x43, 0x50}, /* "ToCP" */ + {1, 0, 0, 0}, /* format version major, minor, milli, micro */ + {0, 0, 0, 0} /* dataVersion */ + }, + {0,0,0,0,0,0,0,0}, /* Padding[8] */ + 3, /* count */ + 0, /* Reserved */ + { /* TOC structure */ + { "OffsetTOCAppData/a/b", &gOffsetTOCAppDataItem1 }, + { "OffsetTOCAppData/gOffsetTOCAppDataItem1", &gOffsetTOCAppDataItem1 }, + { "OffsetTOCAppData/gOffsetTOCGarbage", &gOffsetTOCGarbage } + } +}; + +/* Unfortunately, dictionaries are in a C++ header */ +U_CAPI int32_t U_EXPORT2 +udict_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData, UErrorCode *pErrorCode); + +/* test cases for maximum data swapping code coverage */ +static const struct { + const char *name, *type; + UDataSwapFn *swapFn; +} swapCases[]={ + /* resource bundles */ + + /* resource bundle with many data types */ + {"*testtypes", "res", ures_swap}, + /* resource bundle with collation data */ + {"ja", "res", ures_swap}, + /* resource bundle with options-only collation data */ + {"ru", "res", ures_swap}, + {"el", "res", ures_swap}, + /* ICU's root */ + {"root", "res", ures_swap}, + /* Test a 32-bit key table. This is large. */ + {"*testtable32", "res", ures_swap}, + + /* ICU 4.2 resource bundle - data format 1.2 (little-endian ASCII) */ + {"*old_l_testtypes", "res", ures_swap}, + /* same for big-endian EBCDIC */ + {"*old_e_testtypes", "res", ures_swap}, + +#if !UCONFIG_NO_COLLATION + /* standalone collation data files */ + {"ucadata", "icu", ucol_swap}, +#if 0 + /* Starting with ICU 53, the "inverse UCA" data is integrated into ucadata.icu. */ + {"invuca", "icu", ucol_swapInverseUCA}, +#endif +#endif + +#if !UCONFIG_NO_LEGACY_CONVERSION + /* conversion table files */ + + /* SBCS conversion table file without extension */ + {"ibm-913_P100-2000", "cnv", ucnv_swap}, + /* EBCDIC_STATEFUL conversion table file with extension */ + {"ibm-1390_P110-2003", "cnv", ucnv_swap}, + /* DBCS extension-only conversion table file */ + {"ibm-16684_P110-2003", "cnv", ucnv_swap}, + /* EUC-TW (3-byte) conversion table file without extension */ + {"ibm-964_P110-1999", "cnv", ucnv_swap}, + /* GB 18030 (4-byte) conversion table file without extension */ + {"gb18030", "cnv", ucnv_swap}, + /* MBCS conversion table file with extension */ + {"*test4x", "cnv", ucnv_swap}, + /* + * MBCS conversion table file without extension, + * to test swapping and preflighting of UTF-8-friendly mbcsIndex[]. + */ + {"jisx-212", "cnv", ucnv_swap}, +#endif + +#if !UCONFIG_NO_CONVERSION + /* alias table */ + {"cnvalias", "icu", ucnv_swapAliases}, +#endif + +#if !UCONFIG_NO_IDNA + {"rfc3491", "spp", usprep_swap}, +#endif + +#if !UCONFIG_NO_BREAK_ITERATION + {"char", "brk", ubrk_swap}, + {"thaidict", "dict",udict_swap}, +#endif + +#if 0 + /* + * Starting with ICU 4.8, the Unicode property (value) aliases data + * is hardcoded in the ICU4C common library. + * The swapper was moved to the toolutil library for swapping for ICU4J. + */ + /* Unicode properties */ + {"pnames", "icu", upname_swap}, +#endif + +#if 0 + /* + * Starting with ICU4C 3.4, the core Unicode properties files + * (uprops.icu, ucase.icu, ubidi.icu, unorm.icu) + * are hardcoded in the common DLL and therefore not included + * in the data package any more. + * Their swapping code is moved from the common DLL to the icuswap tool so that + * we need not jump through hoops (like adding snapshots of these files + * to testdata) for code coverage in tests. + * See Jitterbug 4497. + * + * ICU4C 4.4 adds normalization data files again, e.g., nfkc.nrm. + */ + {"uprops", "icu", uprops_swap}, + {"ucase", "icu", ucase_swap}, + {"ubidi", "icu", ubidi_swap}, +#endif +#if !UCONFIG_NO_NORMALIZATION && !UCONFIG_ONLY_COLLATION + {"nfkc", "nrm", unorm2_swap}, +#if !UCONFIG_NO_REGULAR_EXPRESSIONS + {"confusables", "cfu", uspoof_swap}, /* spoof data missing without regex */ +#endif + +#endif + {"unames", "icu", uchar_swapNames} + /* the last item should not be #if'ed so that it can reliably omit the last comma */ +}; + +/* Large enough for the largest swappable data item. */ +#define SWAP_BUFFER_SIZE 1800000 + +static void U_CALLCONV +printError(void *context, const char *fmt, va_list args) { + (void)context; // suppress compiler warnings about unused variable + vlog_info("[swap] ", fmt, args); + log_err("\n"); /* Register error */ +} + +static void +TestSwapCase(UDataMemory *pData, const char *name, + UDataSwapFn *swapFn, + uint8_t *buffer, uint8_t *buffer2) { + UDataSwapper *ds; + const void *inData, *inHeader; + int32_t length, dataLength, length2, headerLength; + + UErrorCode errorCode; + UErrorCode badStatus; + + UBool inEndian, oppositeEndian; + uint8_t inCharset, oppositeCharset; + + /* First we check that swapFn handles failures as expected. */ + errorCode = U_UNSUPPORTED_ERROR; + length = swapFn(NULL, NULL, 0, buffer, &errorCode); + if (length != 0 || errorCode != U_UNSUPPORTED_ERROR) { + log_err("%s() did not fail as expected - %s\n", name, u_errorName(errorCode)); + } + errorCode = U_ZERO_ERROR; + length = swapFn(NULL, NULL, 0, buffer, &errorCode); + if (length != 0 || errorCode != U_ILLEGAL_ARGUMENT_ERROR) { + log_err("%s() did not fail as expected with bad arguments - %s\n", name, u_errorName(errorCode)); + } + + + /* Continue with the rest of the tests. */ + errorCode = U_ZERO_ERROR; + inData=udata_getMemory(pData); + + /* + * get the data length if possible, to verify that swapping and preflighting + * handles the entire data + */ + dataLength=udata_getLength(pData); + + /* + * get the header and its length + * all of the swap implementation functions require the header to be included + */ + inHeader=udata_getRawMemory(pData); + headerLength=(int32_t)((const char *)inData-(const char *)inHeader); + + /* first swap to opposite endianness but same charset family */ + errorCode=U_ZERO_ERROR; + ds=udata_openSwapperForInputData(inHeader, headerLength, + !U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); + if(U_FAILURE(errorCode)) { + log_err("udata_openSwapperForInputData(%s->!isBig+same charset) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + + inEndian=ds->inIsBigEndian; + inCharset=ds->inCharset; + + oppositeEndian=!inEndian; + oppositeCharset= inCharset==U_ASCII_FAMILY ? U_EBCDIC_FAMILY : U_ASCII_FAMILY; + + /* make this test work with data files that are built for a different platform */ + if(inEndian!=U_IS_BIG_ENDIAN || inCharset!=U_CHARSET_FAMILY) { + udata_closeSwapper(ds); + ds=udata_openSwapper(inEndian, inCharset, oppositeEndian, inCharset, &errorCode); + if(U_FAILURE(errorCode)) { + log_err("udata_openSwapper(%s->!isBig+same charset) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + } + + /* + Check error checking of swappable data not specific to this swapper. + This should always fail. + */ + badStatus = U_ZERO_ERROR; + length=swapFn(ds, &gOffsetTOCAppData_dat, -1, NULL, &badStatus); + if(badStatus != U_UNSUPPORTED_ERROR) { + log_err("swapFn(%s->!isBig+same charset) unexpectedly succeeded on bad data - %s\n", + name, u_errorName(errorCode)); + udata_closeSwapper(ds); + return; + } + + /* Now allow errors to be printed */ + ds->printError=printError; + + /* preflight the length */ + length=swapFn(ds, inHeader, -1, NULL, &errorCode); + if(U_FAILURE(errorCode)) { + log_err("swapFn(preflight %s->!isBig+same charset) failed - %s\n", + name, u_errorName(errorCode)); + udata_closeSwapper(ds); + return; + } + + /* compare the preflighted length against the data length */ + if(dataLength>=0 && (length+15)<(headerLength+dataLength)) { + log_err("swapFn(preflight %s->!isBig+same charset) length too small: %d < data length %d\n", + name, length, (headerLength+dataLength)); + udata_closeSwapper(ds); + return; + } + + /* swap, not in-place */ + length2=swapFn(ds, inHeader, length, buffer, &errorCode); + udata_closeSwapper(ds); + if(U_FAILURE(errorCode)) { + log_err("swapFn(%s->!isBig+same charset) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + + /* compare the swap length against the preflighted length */ + if(length2!=length) { + log_err("swapFn(%s->!isBig+same charset) length differs from preflighting: %d != preflighted %d\n", + name, length2, length); + return; + } + + /* next swap to opposite charset family */ + ds=udata_openSwapper(oppositeEndian, inCharset, + oppositeEndian, oppositeCharset, + &errorCode); + if(U_FAILURE(errorCode)) { + log_err("udata_openSwapper(%s->!isBig+other charset) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + ds->printError=printError; + + /* swap in-place */ + length2=swapFn(ds, buffer, length, buffer, &errorCode); + udata_closeSwapper(ds); + if(U_FAILURE(errorCode)) { + log_err("swapFn(%s->!isBig+other charset) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + + /* compare the swap length against the original length */ + if(length2!=length) { + log_err("swapFn(%s->!isBig+other charset) length differs from original: %d != original %d\n", + name, length2, length); + return; + } + + /* finally swap to original platform values */ + ds=udata_openSwapper(oppositeEndian, oppositeCharset, + inEndian, inCharset, + &errorCode); + if(U_FAILURE(errorCode)) { + log_err("udata_openSwapper(%s->back to original) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + ds->printError=printError; + + /* swap, not in-place */ + length2=swapFn(ds, buffer, length, buffer2, &errorCode); + udata_closeSwapper(ds); + if(U_FAILURE(errorCode)) { + log_err("swapFn(%s->back to original) failed - %s\n", + name, u_errorName(errorCode)); + return; + } + + /* compare the swap length against the original length */ + if(length2!=length) { + log_err("swapFn(%s->back to original) length differs from original: %d != original %d\n", + name, length2, length); + return; + } + + /* compare the final contents with the original */ + if(0!=uprv_memcmp(inHeader, buffer2, length)) { + const uint8_t *original; + uint8_t diff[8]; + int32_t i, j; + + log_err("swapFn(%s->back to original) contents differs from original\n", + name); + + /* find the first difference */ + original=(const uint8_t *)inHeader; + for(i=0; ilength) { + length2=length; + } + + /* print the original bytes */ + uprv_memset(diff, 0, sizeof(diff)); + for(j=i; jprintError=printErrorToString; + ds->printErrorContext=name; + udata_printError(ds, "This %s a %s", "is", "test"); + udata_closeSwapper(ds); + if (strcmp(name, "This is a test") != 0) { + log_err("udata_printError can't properly print error messages. Got = %s\n", name); + } + errorCode = U_USELESS_COLLATOR_ERROR; + ds=udata_openSwapperForInputData(NULL, 0, + !U_IS_BIG_ENDIAN, U_ASCII_FAMILY, + &errorCode); + if (ds != NULL || errorCode != U_USELESS_COLLATOR_ERROR) { + log_err("udata_openSwapperForInputData should have returned NULL with bad argument\n", name); + } + errorCode=U_ZERO_ERROR; + ds=udata_openSwapperForInputData(NULL, 0, + !U_IS_BIG_ENDIAN, U_ASCII_FAMILY, + &errorCode); + if (ds != NULL || errorCode != U_ILLEGAL_ARGUMENT_ERROR) { + log_err("udata_openSwapperForInputData should have returned NULL with bad argument\n", name); + } + errorCode=U_ZERO_ERROR; + memset(buffer, 0, sizeof(2*SWAP_BUFFER_SIZE)); + ds=udata_openSwapperForInputData(buffer, 2*SWAP_BUFFER_SIZE, + !U_IS_BIG_ENDIAN, U_ASCII_FAMILY, + &errorCode); + if (ds != NULL || errorCode != U_UNSUPPORTED_ERROR) { + log_err("udata_openSwapperForInputData should have returned NULL with bad argument\n", name); + } + errorCode=U_ZERO_ERROR; + + /* Test argument checking. ucol_swap is normally tested via ures_swap, and isn't normally called directly. */ +#if !UCONFIG_NO_COLLATION + ucol_swap(NULL, NULL, -1, NULL, &errorCode); + if (errorCode != U_ILLEGAL_ARGUMENT_ERROR) { + log_err("ucol_swap did not fail as expected\n", name); + } + errorCode=U_ZERO_ERROR; +#endif + + for(i=0; i