/******************************************************************** * COPYRIGHT: * Copyright (c) 1997-2006, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /* file name: cbiditst.cpp * encoding: US-ASCII * tab size: 8 (not used) * indentation:4 * * created on: 1999sep27 * created by: Markus W. Scherer */ #include "cintltst.h" #include "unicode/utypes.h" #include "unicode/uchar.h" #include "unicode/ustring.h" #include "unicode/ubidi.h" #include "unicode/ushape.h" #include "cmemory.h" #include "cbiditst.h" #include "cstring.h" /* the following include is needed for sprintf */ #include #define MAXLEN MAX_STRING_LENGTH #define LENGTHOF(array) (sizeof(array)/sizeof((array)[0])) /* prototypes ---------------------------------------------------------------*/ static void charFromDirPropTest(void); static void doBiDiTest(void); static void doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst); static void doTest(UBiDi *pBiDi, int testNumber, BiDiTestData *test, int32_t lineStart, UBool countRunsFirst); static void testReordering(UBiDi *pBiDi, int testNumber); static void doInverseBiDiTest(void); static void testManyInverseBiDi(UBiDi *pBiDi, UBiDiLevel direction); static void testInverseBiDi(UBiDi *pBiDi, const UChar *src, int32_t srcLength, UBiDiLevel direction, UErrorCode *pErrorCode); static void testWriteReverse(void); static void doArabicShapingTest(void); static void doLamAlefSpecialVLTRArabicShapingTest(void); static void doTashkeelSpecialVLTRArabicShapingTest(void); static void doLOGICALArabicDeShapingTest(void); static void TestReorder(void); static void TestFailureRecovery(void); static void TestMultipleParagraphs(void); /* new BIDI API */ static void doReorderingModeBidiTest(void); static void doReorderRunsTest(void); static void doBidiStreamingTest(void); static void doBidiClassOverrideTest(void); static const char* inverseBasic(UBiDi *pBiDi, const UChar *src, int32_t srcLen, uint32_t option, UBiDiLevel level, char *result); static UBool assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex, const char *srcChars, const char *destChars, const UChar *dest, int32_t destLen, int mode, int option, UBiDiLevel level); static UBool checkResultLength(UBiDi *pBiDi, const char *srcChars, const char *destChars, const UChar *dest, int32_t destLen, const char *mode, const char *option, UBiDiLevel level); static UBool testMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src, const char *dest, const char *mode, const char* option, UBiDiLevel level, UBool forward); /* helpers ------------------------------------------------------------------ */ static const char *levelString="..............................................................."; static void initCharFromDirProps(void); static UChar * getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer); static void printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels); /* regression tests ---------------------------------------------------------*/ void addComplexTest(TestNode** root); void addComplexTest(TestNode** root) { addTest(root, charFromDirPropTest, "complex/bidi/charFromDirPropTest"); addTest(root, doBiDiTest, "complex/bidi/BiDiTest"); addTest(root, doInverseBiDiTest, "complex/bidi/inverse"); addTest(root, TestReorder,"complex/bidi/TestReorder"); addTest(root, TestFailureRecovery,"complex/bidi/TestFailureRecovery"); addTest(root, TestMultipleParagraphs,"complex/bidi/multipleParagraphs"); addTest(root, doArabicShapingTest, "complex/arabic-shaping/ArabicShapingTest"); addTest(root, doLamAlefSpecialVLTRArabicShapingTest, "complex/arabic-shaping/lamalef"); addTest(root, doTashkeelSpecialVLTRArabicShapingTest, "complex/arabic-shaping/tashkeel"); addTest(root, doLOGICALArabicDeShapingTest, "complex/arabic-shaping/unshaping"); /* new BIDI API */ addTest(root, doReorderingModeBidiTest, "complex/new-bidi-api/TestReorderingMode"); addTest(root, doReorderRunsTest, "complex/new-bidi-api/TestReorderRunsOnly"); addTest(root, doBidiStreamingTest, "complex/new-bidi-api/TestStreamingMode"); addTest(root, doBidiClassOverrideTest, "complex/new-bidi-api/TestClassOverride"); } /* verify that the exemplar characters have the expected bidi classes */ static void charFromDirPropTest(void) { int32_t i; initCharFromDirProps(); for(i=0; itext+lineStart; const UBiDiLevel *levels=test->levels; const uint8_t *visualMap=test->visualMap; int32_t i, len=ubidi_getLength(pBiDi), logicalIndex, runCount = 0; UErrorCode errorCode=U_ZERO_ERROR; UBiDiLevel level, level2; if (countRunsFirst) { log_verbose("Calling ubidi_countRuns() first.\n"); runCount = ubidi_countRuns(pBiDi, &errorCode); if(U_FAILURE(errorCode)) { log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode)); return; } } else { log_verbose("Calling ubidi_getLogicalMap() first.\n"); } testReordering(pBiDi, testNumber); for(i=0; i0) { log_verbose(","); } log_verbose(" %d", ubidi_getLevelAt(pBiDi, i)); } log_verbose("\n--reordered:"); for(i=0; i0) { log_verbose(","); } log_verbose(" %d", ubidi_getVisualIndex(pBiDi, i, &errorCode)); } log_verbose("\n"); if(test->direction!=ubidi_getDirection(pBiDi)) { log_err("ubidi_getDirection(tests[%d]): wrong direction %d\n", testNumber, ubidi_getDirection(pBiDi)); } if(test->resultLevel!=ubidi_getParaLevel(pBiDi)) { log_err("ubidi_getParaLevel(tests[%d]): wrong paragraph level %d\n", testNumber, ubidi_getParaLevel(pBiDi)); } for(i=0; i0); } else { logicalStart+=runLength; /* logicalLimit */ do { /* RTL */ visualMap4[visualIndex++]=--logicalStart; } while(--runLength>0); } } log_verbose("\n"); /* print all the maps */ log_verbose("logical maps:\n"); for(i=0; ilogical->visual did not roundtrip the text;\n" " turn on verbose mode to see details\n"); } } static void testWriteReverse() { /* U+064e and U+0650 are combining marks (Mn) */ static const UChar forward[]={ 0x200f, 0x627, 0x64e, 0x650, 0x20, 0x28, 0x31, 0x29 }, reverseKeepCombining[]={ 0x29, 0x31, 0x28, 0x20, 0x627, 0x64e, 0x650, 0x200f }, reverseRemoveControlsKeepCombiningDoMirror[]={ 0x28, 0x31, 0x29, 0x20, 0x627, 0x64e, 0x650 }; UChar reverse[10]; UErrorCode errorCode; int32_t length; /* test ubidi_writeReverse() with "interesting" options */ errorCode=U_ZERO_ERROR; length=ubidi_writeReverse(forward, LENGTHOF(forward), reverse, LENGTHOF(reverse), UBIDI_KEEP_BASE_COMBINING, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(reverseKeepCombining) || uprv_memcmp(reverse, reverseKeepCombining, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in ubidi_writeReverse(UBIDI_KEEP_BASE_COMBINING): length=%d (should be %d), error code %s\n", length, LENGTHOF(reverseKeepCombining), u_errorName(errorCode)); } uprv_memset(reverse, 0xa5, LENGTHOF(reverse)*U_SIZEOF_UCHAR); errorCode=U_ZERO_ERROR; length=ubidi_writeReverse(forward, LENGTHOF(forward), reverse, LENGTHOF(reverse), UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror) || uprv_memcmp(reverse, reverseRemoveControlsKeepCombiningDoMirror, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in ubidi_writeReverse(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING):\n" " length=%d (should be %d), error code %s\n", length, LENGTHOF(reverseRemoveControlsKeepCombiningDoMirror), u_errorName(errorCode)); } } /* arabic shaping ----------------------------------------------------------- */ static void doArabicShapingTest() { static const UChar source[]={ 0x31, /* en:1 */ 0x627, /* arabic:alef */ 0x32, /* en:2 */ 0x6f3, /* an:3 */ 0x61, /* latin:a */ 0x34, /* en:4 */ 0 }, en2an[]={ 0x661, 0x627, 0x662, 0x6f3, 0x61, 0x664, 0 }, an2en[]={ 0x31, 0x627, 0x32, 0x33, 0x61, 0x34, 0 }, logical_alen2an_init_lr[]={ 0x31, 0x627, 0x662, 0x6f3, 0x61, 0x34, 0 }, logical_alen2an_init_al[]={ 0x6f1, 0x627, 0x6f2, 0x6f3, 0x61, 0x34, 0 }, reverse_alen2an_init_lr[]={ 0x661, 0x627, 0x32, 0x6f3, 0x61, 0x34, 0 }, reverse_alen2an_init_al[]={ 0x6f1, 0x627, 0x32, 0x6f3, 0x61, 0x6f4, 0 }; UChar dest[8]; UErrorCode errorCode; int32_t length; /* test number shaping */ /* european->arabic */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || uprv_memcmp(dest, en2an, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(en2an)\n"); } /* arabic->european */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, -1, dest, LENGTHOF(dest), U_SHAPE_DIGITS_AN2EN|U_SHAPE_DIGIT_TYPE_AN_EXTENDED, &errorCode); if(U_FAILURE(errorCode) || length!=u_strlen(source) || uprv_memcmp(dest, an2en, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(an2en)\n"); } /* european->arabic with context, logical order, initial state not AL */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || uprv_memcmp(dest, logical_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(logical_alen2an_init_lr)\n"); } /* european->arabic with context, logical order, initial state AL */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || uprv_memcmp(dest, logical_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(logical_alen2an_init_al)\n"); } /* european->arabic with context, reverse order, initial state not AL */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_ALEN2AN_INIT_LR|U_SHAPE_DIGIT_TYPE_AN|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || uprv_memcmp(dest, reverse_alen2an_init_lr, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(reverse_alen2an_init_lr)\n"); } /* european->arabic with context, reverse order, initial state AL */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_ALEN2AN_INIT_AL|U_SHAPE_DIGIT_TYPE_AN_EXTENDED|U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || uprv_memcmp(dest, reverse_alen2an_init_al, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(reverse_alen2an_init_al)\n"); } /* test noop */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), 0, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(source) || uprv_memcmp(dest, source, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(noop)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, 0, dest, LENGTHOF(dest), U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(U_FAILURE(errorCode) || length!=0) { log_err("failure in u_shapeArabic(en2an, sourceLength=0), returned %d/%s\n", u_errorName(errorCode), LENGTHOF(source)); } /* preflight digit shaping */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), NULL, 0, U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=LENGTHOF(source)) { log_err("failure in u_shapeArabic(en2an preflighting), returned %d/%s instead of %d/U_BUFFER_OVERFLOW_ERROR\n", length, u_errorName(errorCode), LENGTHOF(source)); } /* test illegal arguments */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(NULL, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(source=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, -2, dest, LENGTHOF(dest), U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(sourceLength=-2), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), NULL, LENGTHOF(dest), U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(dest=NULL), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, -1, U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(destSize=-1), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_RESERVED|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(U_SHAPE_DIGITS_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_RESERVED, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), (UChar *)(source+2), LENGTHOF(dest), /* overlap source and destination */ U_SHAPE_DIGITS_EN2AN|U_SHAPE_DIGIT_TYPE_AN, &errorCode); if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) { log_err("failure in u_shapeArabic(U_SHAPE_DIGIT_TYPE_RESERVED), returned %s instead of U_ILLEGAL_ARGUMENT_ERROR\n", u_errorName(errorCode)); } } static void doLamAlefSpecialVLTRArabicShapingTest() { static const UChar source[]={ /*a*/ 0x20 ,0x646,0x622,0x644,0x627,0x20, /*b*/ 0x646,0x623,0x64E,0x644,0x627,0x20, /*c*/ 0x646,0x627,0x670,0x644,0x627,0x20, /*d*/ 0x646,0x622,0x653,0x644,0x627,0x20, /*e*/ 0x646,0x625,0x655,0x644,0x627,0x20, /*f*/ 0x646,0x622,0x654,0x644,0x627,0x20, /*g*/ 0xFEFC,0x639 }, shape_near[]={ 0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20, 0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20, 0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20, 0xfefc,0xfecb }, shape_at_end[]={ 0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670, 0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d, 0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20,0x20,0x20,0x20 }, shape_at_begin[]={ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76, 0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d, 0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb }, shape_grow_shrink[]={ 0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5, 0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9, 0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb }, shape_excepttashkeel_near[]={ 0x20,0xfee5,0x20,0xfef5,0xfe8d,0x20,0xfee5,0x20,0xfe76,0xfef7,0xfe8d,0x20, 0xfee5,0x20,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x20,0x653,0xfef5,0xfe8d,0x20, 0xfee5,0x20,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x20,0x654,0xfef5,0xfe8d,0x20, 0xfefc,0xfecb }, shape_excepttashkeel_at_end[]={ 0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5, 0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9, 0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb,0x20,0x20,0x20, 0x20,0x20,0x20 }, shape_excepttashkeel_at_begin[]={ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76, 0xfef7,0xfe8d,0x20,0xfee5,0x670,0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d, 0x20,0xfee5,0x655,0xfef9,0xfe8d,0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb }, shape_excepttashkeel_grow_shrink[]={ 0x20,0xfee5,0xfef5,0xfe8d,0x20,0xfee5,0xfe76,0xfef7,0xfe8d,0x20,0xfee5,0x670, 0xfefb,0xfe8d,0x20,0xfee5,0x653,0xfef5,0xfe8d,0x20,0xfee5,0x655,0xfef9,0xfe8d, 0x20,0xfee5,0x654,0xfef5,0xfe8d,0x20,0xfefc,0xfecb }; UChar dest[38]; UErrorCode errorCode; int32_t length; errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_near) || uprv_memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_near)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_at_end) || uprv_memcmp(dest, shape_at_end, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_at_end)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_at_begin) || uprv_memcmp(dest, shape_at_begin, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_at_begin)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_GROW_SHRINK| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || uprv_memcmp(dest, shape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_grow_shrink)\n"); } /* ==================== U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED ==================== */ errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_near) || uprv_memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_near)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_END| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_at_end) || uprv_memcmp(dest,shape_excepttashkeel_at_end , length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_end)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_at_begin) || uprv_memcmp(dest, shape_excepttashkeel_at_begin, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_at_begin)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_GROW_SHRINK| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || uprv_memcmp(dest, shape_excepttashkeel_grow_shrink, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(LAMALEF shape_excepttashkeel_grow_shrink)\n"); } } static void doTashkeelSpecialVLTRArabicShapingTest() { static const UChar source[]={ 0x64A,0x628,0x631,0x639,0x20, 0x64A,0x628,0x651,0x631,0x64E,0x639,0x20, 0x64C,0x64A,0x628,0x631,0x64F,0x639,0x20, 0x628,0x670,0x631,0x670,0x639,0x20, 0x628,0x653,0x631,0x653,0x639,0x20, 0x628,0x654,0x631,0x654,0x639,0x20, 0x628,0x655,0x631,0x655,0x639,0x20, }, shape_near[]={ 0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe77,0xfecb, 0x20,0xfe72,0xfef2,0xfe91,0xfeae,0xfe79,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670, 0xfecb,0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654, 0xfecb,0x20,0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20 }, shape_excepttashkeel_near[]={ 0xfef2,0xfe91,0xfeae,0xfecb,0x20,0xfef2,0xfe91,0xfe7c,0xfeae,0xfe76,0xfecb,0x20, 0xfe72,0xfef2,0xfe91,0xfeae,0xfe78,0xfecb,0x20,0xfe8f,0x670,0xfeae,0x670,0xfecb, 0x20,0xfe8f,0x653,0xfeae,0x653,0xfecb,0x20,0xfe8f,0x654,0xfeae,0x654,0xfecb,0x20, 0xfe8f,0x655,0xfeae,0x655,0xfecb,0x20 }; UChar dest[43]; UErrorCode errorCode; int32_t length; errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_near) || uprv_memcmp(dest, shape_near, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(TASHKEEL shape_near)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED|U_SHAPE_LENGTH_FIXED_SPACES_NEAR| U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(shape_excepttashkeel_near) || uprv_memcmp(dest, shape_excepttashkeel_near, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(TASHKEEL shape_excepttashkeel_near)\n"); } } static void doLOGICALArabicDeShapingTest() { static const UChar source[]={ 0x0020,0x0020,0x0020,0xFE8D,0xFEF5,0x0020,0xFEE5,0x0020,0xFE8D,0xFEF7,0x0020, 0xFED7,0xFEFC,0x0020,0xFEE1,0x0020,0xFE8D,0xFEDF,0xFECC,0xFEAE,0xFE91,0xFEF4, 0xFE94,0x0020,0xFE8D,0xFEDF,0xFEA4,0xFEAE,0xFE93,0x0020,0x0020,0x0020,0x0020 }, unshape_near[]={ 0x20,0x20,0x20,0x627,0x644,0x622,0x646,0x20,0x627,0x644,0x623,0x642,0x644,0x627, 0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631, 0x629,0x20,0x20,0x20,0x20 }, unshape_at_end[]={ 0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642, 0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627, 0x644,0x62d,0x631,0x629,0x20 }, unshape_at_begin[]={ 0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642,0x644,0x627,0x20, 0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627,0x644,0x62d,0x631, 0x629,0x20,0x20,0x20,0x20 }, unshape_grow_shrink[]={ 0x20,0x20,0x20,0x627,0x644,0x622,0x20,0x646,0x20,0x627,0x644,0x623,0x20,0x642, 0x644,0x627,0x20,0x645,0x20,0x627,0x644,0x639,0x631,0x628,0x64a,0x629,0x20,0x627, 0x644,0x62d,0x631,0x629,0x20,0x20,0x20,0x20 }; UChar dest[36]; UErrorCode errorCode; int32_t length; errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR| U_SHAPE_TEXT_DIRECTION_LOGICAL, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(unshape_near) || uprv_memcmp(dest, unshape_near, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(unshape_near)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_END| U_SHAPE_TEXT_DIRECTION_LOGICAL, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(unshape_at_end) || uprv_memcmp(dest, unshape_at_end, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(unshape_at_end)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING| U_SHAPE_TEXT_DIRECTION_LOGICAL, &errorCode); if(U_FAILURE(errorCode) || length!=LENGTHOF(unshape_at_begin) || uprv_memcmp(dest, unshape_at_begin, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(unshape_at_begin)\n"); } errorCode=U_ZERO_ERROR; length=u_shapeArabic(source, LENGTHOF(source), dest, LENGTHOF(dest), U_SHAPE_LETTERS_UNSHAPE|U_SHAPE_LENGTH_GROW_SHRINK| U_SHAPE_TEXT_DIRECTION_LOGICAL, &errorCode); if(U_FAILURE(errorCode) || uprv_memcmp(dest, unshape_grow_shrink, length*U_SIZEOF_UCHAR)!=0) { log_err("failure in u_shapeArabic(unshape_grow_shrink)\n"); } } /* helpers ------------------------------------------------------------------ */ static void initCharFromDirProps() { static const UVersionInfo ucd401={ 4, 0, 1, 0 }; static UVersionInfo ucdVersion={ 0, 0, 0, 0 }; /* lazy initialization */ if(ucdVersion[0]>0) { return; } u_getUnicodeVersion(ucdVersion); if(uprv_memcmp(ucdVersion, ucd401, sizeof(UVersionInfo))>=0) { /* Unicode 4.0.1 changes bidi classes for +-/ */ charFromDirProp[U_EUROPEAN_NUMBER_SEPARATOR]=0x2b; /* change ES character from / to + */ } } /* return a string with characters according to the desired directional properties */ static UChar * getStringFromDirProps(const uint8_t *dirProps, int32_t length, UChar *buffer) { int32_t i; initCharFromDirProps(); /* this part would have to be modified for UTF-x */ for(i=0; i4.5 ".123->4.5", // (2) 678 "678", // (3) .678->8.9 ".678->8.9", // (4) JIH1.2,3MLK "JIH1.2,3MLK", // (5) FE.>12-> "FE.>12->", // (6) JIH.>12->a "JIH.>12->a", // (7) CBA.>67->89=a "CBA.>67->89=a", // (8) CBA.123->xyz "CBA.123->xyz", // (9) .>12->xyz ".>12->xyz", // (10) a.>67->xyz "a.>67->xyz", // (11) 123JIH "123JIH", // (12) 123 JIH "123 JIH" }; static const char* const textOut[] = { // TC 0: 123 "123", // (0) // TC 1: .123->4.5 ".123->4.5", // (1) "4.5<-123.", // (2) // TC 2: 678 "678", // (3) // TC 3: .678->8.9 ".8.9<-678", // (4) "8.9<-678.", // (5) ".678->8.9", // (6) // TC 4: MLK1.2,3JIH "KLM1.2,3HIJ", // (7) // TC 5: FE.>12-> "12<.EF->", // (8) "<-12<.EF", // (9) "EF.>@12->", // (10) // TC 6: JIH.>12->a "12<.HIJ->a", // (11) "a<-12<.HIJ", // (12) "HIJ.>@12->a", // (13) "a&<-12<.HIJ", // (14) // TC 7: CBA.>67->89=a "ABC.>@67->89=a", // (15) "a=89<-67<.ABC", // (16) "a&=89<-67<.ABC", // (17) "89<-67<.ABC=a", // (18) // TC 8: CBA.123->xyz "123.ABC->xyz", // (19) "xyz<-123.ABC", // (20) "ABC.@123->xyz", // (21) "xyz&<-123.ABC", // (22) // TC 9: .>12->xyz ".>12->xyz", // (23) "xyz<-12<.", // (24) "xyz&<-12<.", // (25) // TC 10: a.>67->xyz "a.>67->xyz", // (26) "a.>@67@->xyz", // (27) "xyz<-67<.a", // (28) // TC 11: 123JIH "123HIJ", // (29) "HIJ123", // (30) // TC 12: 123 JIH "123 HIJ", // (31) "HIJ 123", // (32) }; #define NO UBIDI_MAP_NOWHERE #define MAX_MAP_LENGTH 20 static const int forwardMap[][MAX_MAP_LENGTH] = { // TC 0: 123 { 0, 1, 2 }, // (0) // TC 1: .123->4.5 { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // (1) { 8, 5, 6, 7, 4, 3, 0, 1, 2 }, // (2) // TC 2: 678 { 0, 1, 2 }, // (3) // TC 3: .678->8.9 { 0, 6, 7, 8, 5, 4, 1, 2, 3 }, // (4) { 8, 5, 6, 7, 4, 3, 0, 1, 2 }, // (5) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // (6) // TC 4: MLK1.2,3JIH { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 }, // (7) // TC 5: FE.>12-> { 5, 4, 3, 2, 0, 1, 6, 7 }, // (8) { 7, 6, 5, 4, 2, 3, 1, 0 }, // (9) { 1, 0, 2, 3, 5, 6, 7, 8 }, // (10) // TC 6: JIH.>12->a { 6, 5, 4, 3, 2, 0, 1, 7, 8, 9 }, // (11) { 9, 8, 7, 6, 5, 3, 4, 2, 1, 0 }, // (12) { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10 }, // (13) { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0 }, // (14) // TC 7: CBA.>67->89=a { 2, 1, 0, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13 }, // (15) { 12, 11, 10, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0 }, // (16) { 13, 12, 11, 10, 9, 7, 8, 6, 5, 3, 4, 2, 0 }, // (17) { 10, 9, 8, 7, 6, 4, 5, 3, 2, 0, 1, 11, 12 }, // (18) // TC 8: CBA.123->xyz { 6, 5, 4, 3, 0, 1, 2, 7, 8, 9, 10, 11 }, // (19) { 11, 10, 9, 8, 5, 6, 7, 4, 3, 0, 1, 2 }, // (20) { 2, 1, 0, 3, 5, 6, 7, 8, 9, 10, 11, 12 }, // (21) { 12, 11, 10, 9, 6, 7, 8, 5, 4, 0, 1, 2 }, // (22) // TC 9: .>12->xyz { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // (23) { 8, 7, 5, 6, 4, 3, 0, 1, 2 }, // (24) { 9, 8, 6, 7, 5, 4, 0, 1, 2 }, // (25) // TC 10: a.>67->xyz { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, // (26) { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11 }, // (27) { 9, 8, 7, 5, 6, 4, 3, 0, 1, 2 }, // (28) // TC 11: 123JIH { 0, 1, 2, 5, 4, 3 }, // (29) { 3, 4, 5, 2, 1, 0 }, // (30) // TC 12: 123 JIH { 0, 1, 2, 3, 6, 5, 4 }, // (31) { 4, 5, 6, 3, 2, 1, 0 }, // (32) }; static const int inverseMap[][MAX_MAP_LENGTH] = { // TC 0: 123 { 0, 1, 2 }, // (0) // TC 1: .123->4.5 { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // (1) { 6, 7, 8, 5, 4, 1, 2, 3, 0 }, // (2) // TC 2: 678 { 0, 1, 2 }, // (3) // TC 3: .678->8.9 { 0, 6, 7, 8, 5, 4, 1, 2, 3 }, // (4) { 6, 7, 8, 5, 4, 1, 2, 3, 0 }, // (5) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // (6) // TC 4: MLK1.2,3JIH { 10, 9, 8, 3, 4, 5, 6, 7, 2, 1, 0 }, // (7) // TC 5: FE.>12-> { 4, 5, 3, 2, 1, 0, 6, 7 }, // (8) { 7, 6, 4, 5, 3, 2, 1, 0 }, // (9) { 1, 0, 2, 3, NO, 4, 5, 6, 7 }, // (10) // TC 6: JIH.>12->a { 5, 6, 4, 3, 2, 1, 0, 7, 8, 9 }, // (11) { 9, 8, 7, 5, 6, 4, 3, 2, 1, 0 }, // (12) { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9 }, // (13) { 9, NO, 8, 7, 5, 6, 4, 3, 2, 1, 0 }, // (14) // TC 7: CBA.>67->89=a { 2, 1, 0, 3, 4, NO, 5, 6, 7, 8, 9, 10, 11, 12 }, // (15) { 12, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 }, // (16) { 12, NO, 11, 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0 }, // (17) { 9, 10, 8, 7, 5, 6, 4, 3, 2, 1, 0, 11, 12 }, // (18) // TC 8: CBA.123->xyz { 4, 5, 6, 3, 2, 1, 0, 7, 8, 9, 10, 11 }, // (19) { 9, 10, 11, 8, 7, 4, 5, 6, 3, 2, 1, 0 }, // (20) { 2, 1, 0, 3, NO, 4, 5, 6, 7, 8, 9, 10, 11 }, // (21) { 9, 10, 11, NO, 8, 7, 4, 5, 6, 3, 2, 1, 0 }, // (22) // TC 9: .>12->xyz { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, // (23) { 6, 7, 8, 5, 4, 2, 3, 1, 0 }, // (24) { 6, 7, 8, NO, 5, 4, 2, 3, 1, 0 }, // (25) // TC 10: a.>67->xyz { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, // (26) { 0, 1, 2, NO, 3, 4, NO, 5, 6, 7, 8, 9 }, // (27) { 7, 8, 9, 6, 5, 3, 4, 2, 1, 0 }, // (28) // TC 11: 123JIH { 0, 1, 2, 5, 4, 3 }, // (29) { 5, 4, 3, 0, 1, 2 }, // (30) // TC 12: 123 JIH { 0, 1, 2, 3, 6, 5, 4 }, // (31) { 6, 5, 4, 3, 0, 1, 2 }, // (32) }; static const char outIndices[TC_COUNT][MODES_COUNT - 1][OPTIONS_COUNT] [LEVELS_COUNT] = { { // TC 0: 123 {{ 0, 0}, { 0, 0}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 0, 0}, { 0, 0}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 0, 0}, { 0, 0}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 0, 0}, { 0, 0}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 1: .123->4.5 {{ 1, 2}, { 1, 2}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 2}, { 1, 2}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 2}, { 1, 2}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 2}, { 1, 2}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 2: 678 {{ 3, 3}, { 3, 3}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 3, 3}, { 3, 3}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 3, 3}, { 3, 3}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 3, 3}, { 3, 3}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 3: .678->8.9 {{ 6, 5}, { 6, 5}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 4, 5}, { 4, 5}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 6, 5}, { 6, 5}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 6, 5}, { 6, 5}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 4: MLK1.2,3JIH {{ 7, 7}, { 7, 7}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 7, 7}, { 7, 7}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 7, 7}, { 7, 7}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 7, 7}, { 7, 7}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 5: FE.>12-> {{ 8, 9}, { 8, 9}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{10, 9}, { 8, 9}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 8, 9}, { 8, 9}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{10, 9}, { 8, 9}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 6: JIH.>12->a {{11, 12}, {11, 12}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{13, 14}, {11, 12}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{11, 12}, {11, 12}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{13, 14}, {11, 12}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 7: CBA.>67->89=a {{18, 16}, {18, 16}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{18, 17}, {18, 16}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{18, 16}, {18, 16}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{15, 17}, {18, 16}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 8: CBA.>124->xyz {{19, 20}, {19, 20}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{21, 22}, {19, 20}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{19, 20}, {19, 20}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{21, 22}, {19, 20}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 9: .>12->xyz {{23, 24}, {23, 24}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{23, 25}, {23, 24}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{23, 24}, {23, 24}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{23, 25}, {23, 24}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 10: a.>67->xyz {{26, 26}, {26, 26}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{26, 27}, {26, 28}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{26, 28}, {26, 28}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{26, 27}, {26, 28}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 11: 124JIH {{30, 30}, {30, 30}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{29, 30}, {29, 30}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{30, 30}, {30, 30}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{30, 30}, {30, 30}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL }, { // TC 12: 124 JIH {{32, 32}, {32, 32}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{31, 32}, {31, 32}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{31, 32}, {31, 32}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{31, 32}, {31, 32}} // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL } }; static UBool assertRoundTrip(UBiDi *pBiDi, int32_t tc, int32_t outIndex, const char *srcChars, const char *destChars, const UChar *dest, int32_t destLen, int mode, int option, UBiDiLevel level) { static const char roundtrip[TC_COUNT][MODES_COUNT][OPTIONS_COUNT] [LEVELS_COUNT] = { { // TC 0: 123 {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 1: .123->4.5 {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 2: 678 {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 3: .678->8.9 {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 0, 0}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 4: MLK1.2,3JIH {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 5: FE.>12-> {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 0, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 6: JIH.>12->a {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 0, 0}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 7: CBA.>67->89=a {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 0, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 0, 0}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 8: CBA.>123->xyz {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 0, 0}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 9: .>12->xyz {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 0}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 10: a.>67->xyz {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 0}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 11: 123JIH {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L }, { // TC 12: 123 JIH {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_GROUP_NUMBERS_WITH_R {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_LIKE_DIRECT {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}}, // UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL {{ 1, 1}, { 1, 1}} // UBIDI_REORDER_INVERSE_NUMBERS_AS_L } }; #define SET_ROUND_TRIP_MODE(mode) \ ubidi_setReorderingMode(pBiDi, mode); \ desc = #mode; \ break; UErrorCode rc = U_ZERO_ERROR; UChar dest2[MAXLEN]; int32_t destLen2; const char* desc; char destChars2[MAXLEN]; char destChars3[MAXLEN]; switch (modes[mode].value) { case UBIDI_REORDER_NUMBERS_SPECIAL: SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) case UBIDI_REORDER_GROUP_NUMBERS_WITH_R: SET_ROUND_TRIP_MODE(UBIDI_REORDER_GROUP_NUMBERS_WITH_R) case UBIDI_REORDER_RUNS_ONLY: SET_ROUND_TRIP_MODE(UBIDI_REORDER_RUNS_ONLY) case UBIDI_REORDER_INVERSE_NUMBERS_AS_L: SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT) case UBIDI_REORDER_INVERSE_LIKE_DIRECT: SET_ROUND_TRIP_MODE(UBIDI_REORDER_DEFAULT) case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL: SET_ROUND_TRIP_MODE(UBIDI_REORDER_NUMBERS_SPECIAL) default: SET_ROUND_TRIP_MODE(UBIDI_REORDER_INVERSE_LIKE_DIRECT) } ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_REMOVE_CONTROLS); ubidi_setPara(pBiDi, dest, destLen, level, NULL, &rc); assertSuccessful("ubidi_setPara", &rc); *dest2 = 0; destLen2 = ubidi_writeReordered(pBiDi, dest2, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered", &rc); u16ToPseudo(destLen, dest, destChars3); u16ToPseudo(destLen2, dest2, destChars2); if (strcmp(srcChars, destChars2)) { if (roundtrip[tc][mode][option][level]) { log_err("\nRound trip failed for case=%d mode=%d option=%d.\n" "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s" "\n%20s %u\n", tc, mode, option, "Original text:", srcChars, "Round-tripped text:", destChars2, "Intermediate text:", destChars3, "Reordering mode:", modes[mode].description, "Reordering option:", options[option].description, "Paragraph level:", level); } else { log_verbose("\nExpected round trip failure for case=%d mode=%d option=%d.\n" "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %s" "\n%20s %u\n", tc, mode, option, "Original text:", srcChars, "Round-tripped text:", destChars2, "Intermediate text:", destChars3, "Reordering mode:", modes[mode].description, "Reordering option:", options[option].description, "Paragraph level:", level); } return FALSE; } if (!checkResultLength(pBiDi, destChars, destChars2, dest2, destLen2, desc, "UBIDI_OPTION_REMOVE_CONTROLS", level)) { return FALSE; } if (outIndex > -1 && !testMaps(pBiDi, outIndex, srcChars, destChars, desc, "UBIDI_OPTION_REMOVE_CONTROLS", level, FALSE)) { return FALSE; } return TRUE; } static UBool checkResultLength(UBiDi *pBiDi, const char *srcChars, const char *destChars, const UChar *dest, int32_t destLen, const char* mode, const char* option, UBiDiLevel level) { int32_t actualLen; if (strcmp(mode, "UBIDI_REORDER_INVERSE_NUMBERS_AS_L") == 0) actualLen = strlen(destChars); else actualLen = ubidi_getResultLength(pBiDi); if (actualLen != destLen) { log_err("\nubidi_getResultLength failed.\n%20s %7d\n%20s %7d\n" "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %u\n", "Expected:", destLen, "Actual:", actualLen, "Input:", srcChars, "Output:", destChars, "Reordering mode:", mode, "Reordering option:", option, "Paragraph level:", level); return FALSE; } return TRUE; } static void doReorderRunsTest(void) { static const struct { const char* textIn; const char* textOut[2][2]; const char noroundtrip[2]; } testCases[] = { {"abcGHI", {{"GHIabc", "GHIabc"}, {"GHIabc", "GHIabc"}}, {0, 0}}, {"-=%$123/ *", {{"* /%$123=-", "* /%$123=-"}, {"* /%$123=-", "* /%$123=-"}}, {0, 0}}, {"abc->12..>JKL", {{"JKL<..abc->12", "JKL<..abc->12"}, {"JKL<..abc->12", "JKL<..abc->12"}}, {0, 0}}, {"JKL->12..>abc", {{"abc<..JKL->12", "abc<..JKL->12"}, {"abc<..JKL->12", "abc<..JKL->12"}}, {0, 0}}, {"123->abc", {{"abc<-123", "abc<-123"}, {"abc&<-123", "abc<-123"}}, {1, 0}}, {"123->JKL", {{"JKL<-123", "JKL<-123"}, {"JKL<-123", "JKL@<-123"}}, {0, 1}}, {"*>12.>34->JKL", {{"JKL<-34<.12<*", "JKL<-34<.12<*"}, {"JKL<-34<.12<*", "JKL@<-34<.12<*"}}, {0, 1}}, {"*>67.>89->JKL", {{"67.>89->JKL<*", "67.>89->JKL<*"}, {"67.>89->JKL<*", "67.>89->JKL<*"}}, {0, 0}}, {"* /abc-=$%123", {{"abc-=$%123/ *", "abc-=$%123/ *"}, {"abc-=$%123/ *", "abc-=$%123/ *"}}, {0, 0}}, {"* /$%def-=123", {{"def-=123%$/ *", "def-=123%$/ *"}, {"def-=123&%$/ *", "def-=123%$/ *"}}, {1, 0}}, {"-=GHI* /123%$", {{"GHI* /123%$=-", "GHI* /123%$=-"}, {"GHI* /123%$=-", "GHI* /123%$=-"}}, {0, 0}}, {"-=%$JKL* /123", {{"JKL* /123$%=-", "JKL* /123$%=-"}, {"JKL* /123&$%=-", "JKL* /123@$%=-"}}, {1, 1}}, {"abc-=%$LMN* /123", {{"LMN* /123$%=-abc", "LMN* /123$%=-abc"}, {"LMN* /123&$%=-abc", "LMN* /123@$%=-abc"}}, {1, 1}} }; UBiDi *pBiDi = getBiDiObject(); UBiDi *pL2VBiDi = getBiDiObject(); UChar src[MAXLEN], dest[MAXLEN], visual1[MAXLEN], visual2[MAXLEN]; char destChars[MAXLEN], vis1Chars[MAXLEN], vis2Chars[MAXLEN]; int32_t srcLen, destLen, vis1Len, vis2Len, option, i, j, nCases; UErrorCode rc = U_ZERO_ERROR; UBiDiLevel level; ubidi_setReorderingMode(pBiDi, UBIDI_REORDER_RUNS_ONLY); ubidi_setReorderingOptions(pL2VBiDi, UBIDI_OPTION_REMOVE_CONTROLS); for (option = 0; option < 2; option++) { ubidi_setReorderingOptions(pBiDi, option==0 ? UBIDI_OPTION_DEFAULT : UBIDI_OPTION_INSERT_MARKS); for (i = 0, nCases = LENGTHOF(testCases); i < nCases; i++) { for(j = 0; j < 2; j++) { srcLen = strlen(testCases[i].textIn); pseudoToU16(srcLen, testCases[i].textIn, src); level = paraLevels[j]; ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc); assertSuccessful("ubidi_setPara", &rc); *dest = 0; destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered", &rc); u16ToPseudo(destLen, dest, destChars); assertStringsEqual(testCases[i].textOut[option][level], destChars, testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY", option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS", pBiDi); if((option==0) && testCases[i].noroundtrip[level]) { continue; } ubidi_setPara(pL2VBiDi, src, srcLen, level, NULL, &rc); assertSuccessful("ubidi_setPara1", &rc); *visual1 = 0; vis1Len = ubidi_writeReordered(pL2VBiDi, visual1, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered1", &rc); u16ToPseudo(vis1Len, visual1, vis1Chars); ubidi_setPara(pL2VBiDi, dest, destLen, level^1, NULL, &rc); assertSuccessful("ubidi_setPara2", &rc); *visual2 = 0; vis2Len = ubidi_writeReordered(pL2VBiDi, visual2, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered2", &rc); u16ToPseudo(vis2Len, visual2, vis2Chars); assertStringsEqual(vis1Chars, vis2Chars, testCases[i].textIn, "UBIDI_REORDER_RUNS_ONLY (2)", option==0 ? "0" : "UBIDI_OPTION_INSERT_MARKS", pBiDi); } } } ubidi_close(pBiDi); ubidi_close(pL2VBiDi); } static void doReorderingModeBidiTest() { UChar src[MAXLEN], dest[MAXLEN]; char destChars[MAXLEN]; UBiDi *pBiDi = NULL, *pBiDi2 = NULL, *pBiDi3 = NULL; UErrorCode rc; int tc, mode, option, level; int32_t srcLen, destLen, index; const char *expectedChars; UBool testOK = TRUE; log_verbose("\n*** Bidi reordering mode test ***\n"); pBiDi = getBiDiObject(); pBiDi2 = getBiDiObject(); pBiDi3 = getBiDiObject(); ubidi_setInverse(pBiDi2, TRUE); for (tc = 0; tc < TC_COUNT; tc++) { const char* srcChars = textIn[tc]; srcLen = strlen(srcChars); pseudoToU16(srcLen, srcChars, src); for (mode = 0; mode < MODES_COUNT; mode++) { ubidi_setReorderingMode(pBiDi, modes[mode].value); for (option = 0; option < OPTIONS_COUNT; option++) { ubidi_setReorderingOptions(pBiDi, options[option].value); for (level = 0; level < LEVELS_COUNT; level++) { log_verbose("starting test %d mode=%d option=%d level=%d\n", tc, modes[mode].value, options[option].value, level); rc = U_ZERO_ERROR; ubidi_setPara(pBiDi, src, srcLen, paraLevels[level], NULL, &rc); assertSuccessful("ubidi_setPara", &rc); *dest = 0; destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered", &rc); u16ToPseudo(destLen, dest, destChars); if (modes[mode].value == UBIDI_REORDER_INVERSE_NUMBERS_AS_L) { index = -1; expectedChars = inverseBasic(pBiDi2, src, srcLen, options[option].value, paraLevels[level], destChars); } else { index = outIndices[tc][mode][option][level]; expectedChars = textOut[index]; } if (!assertStringsEqual(expectedChars, destChars, srcChars, modes[mode].description, options[option].description, pBiDi)) { testOK = FALSE; } else if (options[option].value == UBIDI_OPTION_INSERT_MARKS && !assertRoundTrip(pBiDi3, tc, index, srcChars, destChars, dest, destLen, mode, option, paraLevels[level])) { testOK = FALSE; } else if (!checkResultLength(pBiDi, srcChars, destChars, dest, destLen, modes[mode].description, options[option].description, paraLevels[level])) { testOK = FALSE; } else if (index > -1 && !testMaps(pBiDi, index, srcChars, destChars, modes[mode].description, options[option].description, paraLevels[level], TRUE)) { testOK = FALSE; } } } } } if (testOK == TRUE) { log_verbose("\nReordering mode test OK\n"); } ubidi_close(pBiDi3); ubidi_close(pBiDi2); ubidi_close(pBiDi); } static const char* inverseBasic(UBiDi *pBiDi, const UChar *src, int32_t srcLen, uint32_t option, UBiDiLevel level, char *result) { UErrorCode rc = U_ZERO_ERROR; int32_t destLen; UChar dest2 [MAXLEN]; if (pBiDi == NULL || src == NULL) { return NULL; } ubidi_setReorderingOptions(pBiDi, option); ubidi_setPara(pBiDi, src, srcLen, level, NULL, &rc); assertSuccessful("ubidi_setPara", &rc); *dest2 = 0; destLen = ubidi_writeReordered(pBiDi, dest2, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered", &rc); u16ToPseudo(destLen, dest2, result); return result; } #define NULL_CHAR '\0' static void doBidiStreamingTest() { #define MAXPORTIONS 10 static const struct { const char* textIn; short int chunk; short int nPortions[2]; char portionLens[2][MAXPORTIONS]; const char* message[2]; } testData[] = { { "123\\u000A" "abc45\\u000D" "67890\\u000A" "\\u000D" "02468\\u000D" "ghi", 6, { 6, 6 }, {{ 6, 4, 6, 1, 6, 3}, { 4, 6, 6, 1, 6, 3 }}, {"6, 4, 6, 1, 6, 3", "4, 6, 6, 1, 6, 3"} }, { "abcd\\u000Afgh\\u000D12345\\u000A456", 6, { 4, 4 }, {{ 6, 3, 6, 3 }, { 5, 4, 6, 3 }}, {"6, 3, 6, 3", "5, 4, 6, 3"} }, { "abcd\\u000Afgh\\u000D12345\\u000A45\\u000D", 6, { 4, 4 }, {{ 6, 3, 6, 3 }, { 5, 4, 6, 3 }}, {"6, 3, 6, 3", "5, 4, 6, 3"} }, { "abcde\\u000Afghi", 10, { 1, 2 }, {{ 10 }, { 6, 4 }}, {"10", "6, 4"} } }; UChar src[MAXLEN]; UBiDi *pBiDi = NULL; UChar *pSrc; UErrorCode rc = U_ZERO_ERROR; int32_t srcLen, processedLen, chunk, len, nPortions; int i, j, levelIndex; UBiDiLevel level; int nTests = LENGTHOF(testData), nLevels = LENGTHOF(paraLevels); UBool mismatch, testOK = TRUE; char processedLenStr[MAXPORTIONS * 5]; log_verbose("\n*** Bidi streaming test ***\n"); pBiDi = getBiDiObject(); //ubidi_orderParagraphsLTR(pBiDi, TRUE); for (levelIndex = 0; levelIndex < nLevels; levelIndex++) { for (i = 0; i < nTests; i++) { srcLen = u_unescape(testData[i].textIn, src, MAXLEN); chunk = testData[i].chunk; nPortions = testData[i].nPortions[levelIndex]; level = paraLevels[levelIndex]; *processedLenStr = NULL_CHAR; mismatch = FALSE; ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING); for (j = 0, pSrc = src; j < MAXPORTIONS && srcLen > 0; j++) { len = chunk < srcLen ? chunk : srcLen; ubidi_setPara(pBiDi, pSrc, len, level, NULL, &rc); assertSuccessful("ubidi_setPara", &rc); processedLen = ubidi_getProcessedLength(pBiDi); if (processedLen == 0) { ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_DEFAULT); j--; continue; } ubidi_setReorderingOptions(pBiDi, UBIDI_OPTION_STREAMING); mismatch = j >= nPortions || processedLen != testData[i].portionLens[levelIndex][j]; sprintf(processedLenStr + j * 4, "%4d", processedLen); srcLen -= processedLen, pSrc += processedLen; } if (mismatch || j != nPortions) { testOK = FALSE; log_err("\nProcessed lengths mismatch.\n" "\tParagraph level: %u\n" "\tInput string: %s\n" "\tActually processed portion lengths: { %s }\n" "\tExpected portion lengths : { %s }\n", paraLevels[levelIndex], testData[i].textIn, processedLenStr, testData[i].message[levelIndex]); } } } ubidi_close(pBiDi); if (testOK == TRUE) { log_verbose("\nBiDi streaming test OK\n"); } } U_CDECL_BEGIN static UCharDirection U_CALLCONV overrideBidiClass(const void *context, UChar32 c) { #define DEF U_BIDI_CLASS_DEFAULT static const UCharDirection customClasses[] = { /* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //00-07 DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //08-0F DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //10-17 DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //18-1F DEF, DEF, DEF, DEF, DEF, DEF, R, DEF, //20-27 DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //28-2F EN, EN, EN, EN, EN, EN, AN, AN, //30-37 AN, AN, DEF, DEF, DEF, DEF, DEF, DEF, //38-3F L, AL, AL, AL, AL, AL, AL, R, //40-47 R, R, R, R, R, R, R, R, //48-4F R, R, R, R, R, R, R, R, //50-57 R, R, R, LRE, DEF, RLE, PDF, S, //58-5F NSM, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //60-67 DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //68-6F DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, //70-77 DEF, DEF, DEF, LRO, B, RLO, BN, DEF //78-7F }; static const int nEntries = LENGTHOF(customClasses); return c >= nEntries ? U_BIDI_CLASS_DEFAULT : customClasses[c]; } U_CDECL_END static void verifyCallbackParams(UBiDiClassCallback* fn, const void* context, UBiDiClassCallback* expectedFn, const void* expectedContext, int32_t sizeOfContext) { if (fn != expectedFn) { log_err("Class callback pointer is not set properly.\n"); } if (context != expectedContext) { log_err("Class callback context is not set properly.\n"); } else if (context != NULL && uprv_memcmp(context, expectedContext, sizeOfContext)) { log_err("Callback context content doesn't match the expected one.\n"); } } static void doBidiClassOverrideTest(void) { static const char* const textIn = "JIH.>12->a \\u05D0\\u05D1 6 ABC78"; static const char* const textOut = "12<.HIJ->a 78CBA 6 \\u05D1\\u05D0"; UChar src[MAXLEN], dest[MAXLEN]; UErrorCode rc = U_ZERO_ERROR; UBiDi *pBiDi = NULL; UBiDiClassCallback* oldFn = NULL; UBiDiClassCallback* newFn = overrideBidiClass; const void* oldContext = NULL; int32_t srcLen, destLen, textInSize = (int32_t)uprv_strlen(textIn); char* destChars = NULL; log_verbose("\n*** Bidi class override test ***\n"); pBiDi = getBiDiObject(); ubidi_getClassCallback(pBiDi, &oldFn, &oldContext); verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0); ubidi_setClassCallback(pBiDi, newFn, textIn, &oldFn, &oldContext, &rc); if (!assertSuccessful("ubidi_setClassCallback", &rc)) { ubidi_close(pBiDi); return; } verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0); ubidi_getClassCallback(pBiDi, &oldFn, &oldContext); verifyCallbackParams(oldFn, oldContext, newFn, textIn, textInSize); ubidi_setClassCallback(pBiDi, newFn, textIn, &oldFn, &oldContext, &rc); if (!assertSuccessful("ubidi_setClassCallback", &rc)) { ubidi_close(pBiDi); return; } verifyCallbackParams(oldFn, oldContext, newFn, textIn, textInSize); srcLen = u_unescape(textIn, src, MAXLEN); ubidi_setPara(pBiDi, src, srcLen, UBIDI_LTR, NULL, &rc); assertSuccessful("ubidi_setPara", &rc); destLen = ubidi_writeReordered(pBiDi, dest, MAXLEN, UBIDI_DO_MIRRORING, &rc); assertSuccessful("ubidi_writeReordered", &rc); destChars = aescstrdup(dest, destLen); if (uprv_strcmp(textOut, destChars)) { log_err("\nActual and expected output mismatch.\n" "%20s %s\n%20s %s\n%20s %s\n", "Input:", textIn, "Actual output:", destChars, "Expected output:", textOut); } else { log_verbose("\nClass override test OK\n"); } ubidi_close(pBiDi); } static const char columns[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char * formatMap(const int * map, int len, char * buffer) { int i, k; char c; for (i = 0; i < len; i++) { k = map[i]; if (k < 0) c = '-'; else if (k >= sizeof columns) c = '+'; else c = columns[k]; buffer[i] = c; } buffer[len] = '\0'; return buffer; } static UBool testMaps(UBiDi *pBiDi, int32_t stringIndex, const char *src, const char *dest, const char *mode, const char* option, UBiDiLevel level, UBool forward) { int32_t actualLogicalMap[MAX_MAP_LENGTH]; int32_t actualVisualMap[MAX_MAP_LENGTH]; int32_t getIndexMap[MAX_MAP_LENGTH]; int32_t i, srcLen, resLen, index; const int32_t *expectedLogicalMap, *expectedVisualMap; UErrorCode rc = U_ZERO_ERROR; UBool testOK = TRUE; if (forward) { expectedLogicalMap = forwardMap[stringIndex]; expectedVisualMap = inverseMap[stringIndex]; } else { expectedLogicalMap = inverseMap[stringIndex]; expectedVisualMap = forwardMap[stringIndex]; } ubidi_getLogicalMap(pBiDi, actualLogicalMap, &rc); if (!assertSuccessful("ubidi_getLogicalMap", &rc)) { testOK = FALSE; } srcLen = ubidi_getProcessedLength(pBiDi); if (uprv_memcmp(expectedLogicalMap, actualLogicalMap, srcLen * sizeof(int32_t))) { char expChars[MAX_MAP_LENGTH]; char actChars[MAX_MAP_LENGTH]; log_err("\nubidi_getLogicalMap() returns unexpected map for output string " "index %d\n" "source: %s\n" "dest : %s\n" "Scale : %s\n" "ExpMap: %s\n" "Actual: %s\n" "Paragraph level : %d == %d\n" "Reordering mode : %s == %d\n" "Reordering option: %s == %d\n" "Forward flag : %d\n", stringIndex, src, dest, columns, formatMap(expectedLogicalMap, srcLen, expChars), formatMap(actualLogicalMap, srcLen, actChars), level, ubidi_getParaLevel(pBiDi), mode, ubidi_getReorderingMode(pBiDi), option, ubidi_getReorderingOptions(pBiDi), forward ); testOK = FALSE; } resLen = ubidi_getResultLength(pBiDi); ubidi_getVisualMap(pBiDi, actualVisualMap, &rc); assertSuccessful("ubidi_getVisualMap", &rc); if (uprv_memcmp(expectedVisualMap, actualVisualMap, resLen * sizeof(int32_t))) { char expChars[MAX_MAP_LENGTH]; char actChars[MAX_MAP_LENGTH]; log_err("\nubidi_getVisualMap() returns unexpected map for output string " "index %d\n" "source: %s\n" "dest : %s\n" "Scale : %s\n" "ExpMap: %s\n" "Actual: %s\n" "Paragraph level : %d == %d\n" "Reordering mode : %s == %d\n" "Reordering option: %s == %d\n" "Forward flag : %d\n", stringIndex, src, dest, columns, formatMap(expectedVisualMap, resLen, expChars), formatMap(actualVisualMap, resLen, actChars), level, ubidi_getParaLevel(pBiDi), mode, ubidi_getReorderingMode(pBiDi), option, ubidi_getReorderingOptions(pBiDi), forward ); testOK = FALSE; } for (i = 0; i < srcLen; i++) { index = ubidi_getVisualIndex(pBiDi, i, &rc); assertSuccessful("ubidi_getVisualIndex", &rc); getIndexMap[i] = index; } if (uprv_memcmp(actualLogicalMap, getIndexMap, srcLen * sizeof(int32_t))) { char actChars[MAX_MAP_LENGTH]; char gotChars[MAX_MAP_LENGTH]; log_err("\nMismatch between ubidi_getLogicalMap and ubidi_getVisualIndex for output string " "index %d\n" "source: %s\n" "dest : %s\n" "Scale : %s\n" "ActMap: %s\n" "IdxMap: %s\n" "Paragraph level : %d == %d\n" "Reordering mode : %s == %d\n" "Reordering option: %s == %d\n" "Forward flag : %d\n", stringIndex, src, dest, columns, formatMap(actualLogicalMap, srcLen, actChars), formatMap(getIndexMap, srcLen, gotChars), level, ubidi_getParaLevel(pBiDi), mode, ubidi_getReorderingMode(pBiDi), option, ubidi_getReorderingOptions(pBiDi), forward ); testOK = FALSE; } for (i = 0; i < resLen; i++) { index = ubidi_getLogicalIndex(pBiDi, i, &rc); assertSuccessful("ubidi_getLogicalIndex", &rc); getIndexMap[i] = index; } if (uprv_memcmp(actualVisualMap, getIndexMap, resLen * sizeof(int32_t))) { char actChars[MAX_MAP_LENGTH]; char gotChars[MAX_MAP_LENGTH]; log_err("\nMismatch between ubidi_getVisualMap and ubidi_getLogicalIndex for output string " "index %d\n" "source: %s\n" "dest : %s\n" "Scale : %s\n" "ActMap: %s\n" "IdxMap: %s\n" "Paragraph level : %d == %d\n" "Reordering mode : %s == %d\n" "Reordering option: %s == %d\n" "Forward flag : %d\n", stringIndex, src, dest, columns, formatMap(actualVisualMap, resLen, actChars), formatMap(getIndexMap, resLen, gotChars), level, ubidi_getParaLevel(pBiDi), mode, ubidi_getReorderingMode(pBiDi), option, ubidi_getReorderingOptions(pBiDi), forward ); testOK = FALSE; } return testOK; }