]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/cintltst/udatatst.c
ICU-6.2.22.tar.gz
[apple/icu.git] / icuSources / test / cintltst / udatatst.c
index d1614bb1f4bcab3483109bf89d7605c7d7309f55..674348ca4f5d2b00d4751855ddd70816f474446a 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1998-2003, International Business Machines Corporation and
+ * Copyright (c) 1998-2004, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 /*
@@ -14,6 +14,7 @@
 */
 
 #include "unicode/utypes.h"
+#include "unicode/putil.h"
 #include "unicode/udata.h"
 #include "unicode/uchar.h"
 #include "unicode/ucnv.h"
@@ -22,6 +23,7 @@
 #include "cmemory.h"
 #include "cstring.h"
 #include "filestrm.h"
+#include "udatamem.h"
 #include "cintltst.h"
 
 #include <sys/types.h>
 #include <unistd.h>
 #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_swp.h"
+#include "ucnv_bld.h"
+#include "unormimp.h"
+#include "sprpimpl.h"
+#include "propname.h"
+#include "rbbidata.h"
+
+/* other definitions and prototypes */
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
 static void TestUDataOpen(void);
 static void TestUDataOpenChoiceDemo1(void);
 static void TestUDataOpenChoiceDemo2(void);
@@ -45,6 +66,7 @@ static void TestUDataSetAppData(void);
 static void TestErrorConditions(void);
 static void TestAppData(void);
 static void TestICUDataName(void);
+static void TestSwapData(void);
 
 void addUDataTest(TestNode** root);
 
@@ -60,7 +82,7 @@ addUDataTest(TestNode** root)
     addTest(root, &TestErrorConditions, "udatatst/TestErrorConditions");
     addTest(root, &TestAppData, "udatatst/TestAppData" );
     addTest(root, &TestICUDataName, "udatatst/TestICUDataName" );
-
+    addTest(root, &TestSwapData, "udatatst/TestSwapData" );
 }
 
 #if 0
@@ -80,14 +102,17 @@ static void TestUDataOpen(){
     UDataMemory *result;
     UErrorCode status=U_ZERO_ERROR;
     const char* memMap[][2]={
-        {"tz", "icu"},
+        {"root", "res"},
+        {"unorm", "icu"},
         {"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)
@@ -125,11 +150,11 @@ static void TestUDataOpen(){
         int i;
         log_verbose("Testing udata_open() on %s\n", icuDataFilePath);
         for(i=0; i<sizeof(memMap)/sizeof(memMap[0]); i++){
-    /* lots_of_mallocs(); */
+            /* lots_of_mallocs(); */
             status=U_ZERO_ERROR;
             result=udata_open(path, memMap[i][1], memMap[i][0], &status);
             if(U_FAILURE(status)) {
-                log_err("FAIL: udata_open() failed for path = %s, name=%s, type=%s, \n errorcode=%s\n", path, memMap[i][0], memMap[i][1], myErrorName(status));
+                log_data_err("FAIL: udata_open() failed for path = %s, name=%s, type=%s, \n errorcode=%s\n", path, memMap[i][0], memMap[i][1], myErrorName(status));
             } else {
                 log_verbose("PASS: udata_open worked for path = %s, name=%s, type=%s\n",  path, memMap[i][0], memMap[i][1]);
                 udata_close(result);
@@ -161,10 +186,10 @@ static void TestUDataOpen(){
     strcat(icuDataFilePath, dirSepString);
     strcat(icuDataFilePath, U_ICUDATA_NAME);
     strcat(icuDataFilePath, "_");
-    strcat(icuDataFilePath, "tz.icu");
+    strcat(icuDataFilePath, "unorm.icu");
 
     /* lots_of_mallocs(); */
-    if (stat(icuDataFilePath, &stat_buf) == 0)
+/*    if (stat(icuDataFilePath, &stat_buf) == 0)*/
     {
         int i;
         log_verbose("%s exists, so..\n", icuDataFilePath);
@@ -177,18 +202,18 @@ static void TestUDataOpen(){
             status=U_ZERO_ERROR;
             result=udata_open(icuDataFilePath, memMap[i][1], memMap[i][0], &status);
             if(U_FAILURE(status)) {
-                log_err("FAIL: udata_open() failed for path = %s, name=%s, type=%s, \n errorcode=%s\n", icuDataFilePath, memMap[i][0], memMap[i][1], myErrorName(status));
+                log_data_err("FAIL: udata_open() failed for path = %s, name=%s, type=%s, \n errorcode=%s\n", icuDataFilePath, memMap[i][0], memMap[i][1], myErrorName(status));
             } else {
                 log_verbose("PASS: udata_open worked for path = %s, name=%s, type=%s\n",  icuDataFilePath, memMap[i][0], memMap[i][1]);
                 udata_close(result);
             }
         }
     }
-    else
+/*    else
     {
          log_verbose("Skipping tests of udata_open() on %s.  File not present in this configuration.\n",
              icuDataFilePath);
-    }
+    }*/
 
     free(icuDataFilePath);
     icuDataFilePath = NULL;
@@ -252,6 +277,54 @@ static void TestUDataOpen(){
         log_verbose("calling udat_open with non-existing file returned null as expected\n");
     }
 
+    /*
+     *  Try opening data with absurdly long path and name, to trigger buffer size 
+     *   overflow handling code.
+     */
+    {
+        char longTestPath[1024];    /* Implementation goes to heap at length of 128.  */
+        char longName[1024];
+
+        /* Try a very long nonexistent directory path.  
+         * udata_open should still succeed.  Opening with the path will fail,
+         * then fall back to skipping the directory portion of the path.
+         */
+        log_verbose("Testing udata_open() with really long names\n");
+        longTestPath[0] = 0;
+        strcat(longTestPath, "bogus_directory_name");
+        while (strlen(longTestPath) < 500) {
+            strcat(longTestPath, dirSepString);
+            strcat(longTestPath, "bogus_directory_name");
+        }
+        strcat(longTestPath, pathSepString);
+        strcat(longTestPath, testPath);
+        result=udata_open(longTestPath, type, name, &status);
+        if(U_FAILURE(status)){
+            log_err("FAIL: udata_open() failed for path = %s\n name=%s, type=%s, \n errorcode=%s\n",
+                longTestPath, name, type, myErrorName(status));
+        } else {
+            log_verbose("PASS: udata_open worked\n");
+            udata_close(result);
+        }
+
+        /* Try a very long name.  Won't open, but shouldn't blow up.
+         */
+        longName[0] = 0;
+        while (strlen(longName) < 500) {
+            strcat(longName, name);
+            strcat(longName, "_");
+        }
+        strcat(longName, dirSepString);
+        strcat(longName, name);
+
+        result=udata_open(longTestPath, type, longName, &status);
+        if (status != U_FILE_ACCESS_ERROR) {
+            log_err("FAIL: udata_open() failed for path = %s\n name=%s, type=%s, \n errorcode=%s\n",
+                longTestPath, longName, type, myErrorName(status));
+        }
+        udata_close(result);
+    }
+
     free(path);
 }
 
@@ -277,7 +350,7 @@ static void TestUDataSetAppData(){
 
     log_verbose("Testing udata_setAppData() with %s\n", filePath);
 
-#ifdef WIN32
+#if defined(WIN32) || defined(U_CYGWIN)
     fileHandle = open( filePath, O_RDONLY | O_BINARY );
 #else
     fileHandle = open( filePath, O_RDONLY);
@@ -306,7 +379,7 @@ static void TestUDataSetAppData(){
 
     i = read(fileHandle, fileBuf, fileSize);
     if (i != fileSize) {
-        log_err("FAIL: TestUDataSetAppData() error reading file \"%s\".\n", filePath);
+        log_err("FAIL: TestUDataSetAppData() error reading file \"%s\" size=%d read=%d.\n", filePath, fileSize, i);
         goto cleanupAndReturn;
     }
 
@@ -444,7 +517,7 @@ isAcceptable3(void *context,
 static void TestUDataOpenChoiceDemo1() {
     UDataMemory *result;
     UErrorCode status=U_ZERO_ERROR;
-       
+
     const char* name[]={
         "cnvalias",
         "unames",
@@ -945,3 +1018,315 @@ static void TestICUDataName()
 #endif
 
 }
+
+/* test data swapping ------------------------------------------------------- */
+
+/* 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},
+
+    /* ICU 2.6 resource bundle - data format 1.0, without indexes[] (little-endian ASCII) */
+    {"*icu26_testtypes",         "res", ures_swap},
+    /* same for big-endian EBCDIC */
+    {"*icu26e_testtypes",        "res", ures_swap},
+
+#if !UCONFIG_NO_COLLATION
+    /* standalone collation data files */
+    {"ucadata",                  "icu", ucol_swap},
+    {"invuca",                   "icu", ucol_swapInverseUCA},
+#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},
+
+    /* alias table */
+    {"cnvalias",                 "icu", ucnv_swapAliases},
+#endif
+
+#if !UCONFIG_NO_IDNA
+    {"uidna",                    "spp", usprep_swap},
+#endif
+
+#if !UCONFIG_NO_BREAK_ITERATION
+    {"char",                     "brk", ubrk_swap},
+#endif
+
+    /* the last item should not be #if'ed so that it can reliably omit the last comma */
+
+    /* Unicode properties */
+    {"unames",                   "icu", uchar_swapNames},
+    {"pnames",                   "icu", upname_swap},
+#if !UCONFIG_NO_NORMALIZATION
+    {"unorm",                    "icu", unorm_swap},
+#endif
+    {"uprops",                   "icu", uprops_swap},
+    {"ucase",                    "icu", ucase_swap}
+};
+
+#define SWAP_BUFFER_SIZE 1000000
+
+static void U_CALLCONV
+printError(void *context, const char *fmt, va_list args) {
+    vlog_info("[swap] ", fmt, args);
+}
+
+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;
+
+    UBool inEndian, oppositeEndian;
+    uint8_t inCharset, oppositeCharset;
+
+    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;
+        }
+    }
+
+    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; i<length && original[i]==buffer2[i]; ++i) {}
+
+        /* find the next byte that is the same */
+        for(j=i+1; j<length && original[j]!=buffer2[j]; ++j) {}
+        log_info("    difference at index %d=0x%x, until index %d=0x%x\n", i, i, j, j);
+
+        /* round down to the last 4-boundary for better result output */
+        i&=~3;
+        log_info("showing bytes from index %d=0x%x (length %d=0x%x):\n", i, i, length, length);
+
+        /* print 8 bytes but limit to the buffer contents */
+        length2=i+sizeof(diff);
+        if(length2>length) {
+            length2=length;
+        }
+
+        /* print the original bytes */
+        uprv_memset(diff, 0, sizeof(diff));
+        for(j=i; j<length2; ++j) {
+            diff[j-i]=original[j];
+        }
+        log_info("    original: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+            diff[0], diff[1], diff[2], diff[3], diff[4], diff[5], diff[6], diff[7]);
+
+        /* print the swapped bytes */
+        uprv_memset(diff, 0, sizeof(diff));
+        for(j=i; j<length2; ++j) {
+            diff[j-i]=buffer2[j];
+        }
+        log_info("    swapped:  %02x %02x %02x %02x %02x %02x %02x %02x\n",
+            diff[0], diff[1], diff[2], diff[3], diff[4], diff[5], diff[6], diff[7]);
+    }
+}
+
+static void
+TestSwapData() {
+    char name[100];
+    UDataMemory *pData;
+    uint8_t *buffer;
+    const char *pkg, *nm;
+
+    UErrorCode errorCode;
+    int32_t i;
+
+    buffer=(uint8_t *)uprv_malloc(2*SWAP_BUFFER_SIZE);
+    if(buffer==NULL) {
+        log_err("unable to allocate %d bytes\n", 2*SWAP_BUFFER_SIZE);
+        return;
+    }
+
+    for(i=0; i<LENGTHOF(swapCases); ++i) {
+        /* build the name for logging */
+        errorCode=U_ZERO_ERROR;
+        if(swapCases[i].name[0]=='*') {
+            pkg=loadTestData(&errorCode);
+            nm=swapCases[i].name+1;
+            uprv_strcpy(name, "testdata");
+        } else {
+            pkg=NULL;
+            nm=swapCases[i].name;
+            uprv_strcpy(name, "NULL");
+        }
+        uprv_strcat(name, "/");
+        uprv_strcat(name, nm);
+        uprv_strcat(name, ".");
+        uprv_strcat(name, swapCases[i].type);
+
+        pData=udata_open(pkg, swapCases[i].type, nm, &errorCode);
+        if(U_SUCCESS(errorCode)) {
+            TestSwapCase(pData, name, swapCases[i].swapFn, buffer, buffer+SWAP_BUFFER_SIZE);
+            udata_close(pData);
+        } else {
+            log_data_err("udata_open(%s) failed - %s\n",
+                name, u_errorName(errorCode));
+        }
+    }
+
+    uprv_free(buffer);
+}