| /******************************************************************** |
| * 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 "cbiditst.h" |
| #include "cstring.h" |
| /* the following include is needed for sprintf */ |
| #include <stdio.h> |
| |
| #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, const 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, doReorderingModeBidiTest, "complex/bidi/TestReorderingMode"); |
| addTest(root, doReorderRunsTest, "complex/bidi/TestReorderRunsOnly"); |
| addTest(root, doBidiStreamingTest, "complex/bidi/TestStreamingMode"); |
| addTest(root, doBidiClassOverrideTest, "complex/bidi/TestClassOverride"); |
| |
| 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"); |
| } |
| |
| /* verify that the exemplar characters have the expected bidi classes */ |
| static void |
| charFromDirPropTest(void) { |
| int32_t i; |
| |
| initCharFromDirProps(); |
| |
| for(i=0; i<U_CHAR_DIRECTION_COUNT; ++i) { |
| if(u_charDirection(charFromDirProp[i])!=(UCharDirection)i) { |
| log_err("\nu_charDirection(charFromDirProp[%d]=U+%04x)==%d!=%d\n", |
| i, charFromDirProp[i], u_charDirection(charFromDirProp[i]), i); |
| } |
| } |
| } |
| |
| static void |
| doBiDiTest() { |
| UBiDi *pBiDi, *pLine=NULL; |
| UErrorCode errorCode=U_ZERO_ERROR; |
| |
| log_verbose("\n*** bidi regression test ***\n"); |
| |
| pBiDi=ubidi_openSized(MAXLEN, 0, &errorCode); |
| if(pBiDi!=NULL) { |
| pLine=ubidi_open(); |
| if(pLine!=NULL) { |
| doTests(pBiDi, pLine, FALSE); |
| doTests(pBiDi, pLine, TRUE); |
| } else { |
| log_err("ubidi_open() returned NULL, out of memory\n"); |
| } |
| } else { |
| log_err("ubidi_openSized() returned NULL, errorCode %s\n", myErrorName(errorCode)); |
| } |
| |
| if(pLine!=NULL) { |
| ubidi_close(pLine); |
| } |
| if(pBiDi!=NULL) { |
| ubidi_close(pBiDi); |
| } |
| |
| log_verbose("\n*** bidi regression test finished ***\n"); |
| } |
| |
| static void |
| doTests(UBiDi *pBiDi, UBiDi *pLine, UBool countRunsFirst) { |
| int i; |
| UChar string[MAXLEN]; |
| UErrorCode errorCode; |
| int32_t lineStart; |
| UBiDiLevel paraLevel; |
| |
| for(i=0; i<bidiTestCount; ++i) { |
| errorCode=U_ZERO_ERROR; |
| getStringFromDirProps(tests[i].text, tests[i].length, string); |
| paraLevel=tests[i].paraLevel; |
| ubidi_setPara(pBiDi, string, -1, paraLevel, NULL, &errorCode); |
| if(U_SUCCESS(errorCode)) { |
| log_verbose("ubidi_setPara(tests[%d], paraLevel %d) ok, direction %d paraLevel=%d\n", |
| i, paraLevel, ubidi_getDirection(pBiDi), ubidi_getParaLevel(pBiDi)); |
| lineStart=tests[i].lineStart; |
| if(lineStart==-1) { |
| doTest(pBiDi, i, tests+i, 0, countRunsFirst); |
| } else { |
| ubidi_setLine(pBiDi, lineStart, tests[i].lineLimit, pLine, &errorCode); |
| if(U_SUCCESS(errorCode)) { |
| log_verbose("ubidi_setLine(%d, %d) ok, direction %d paraLevel=%d\n", |
| lineStart, tests[i].lineLimit, ubidi_getDirection(pLine), ubidi_getParaLevel(pLine)); |
| doTest(pLine, i, tests+i, lineStart, countRunsFirst); |
| } else { |
| log_err("ubidi_setLine(tests[%d], %d, %d) failed with errorCode %s\n", |
| i, lineStart, tests[i].lineLimit, myErrorName(errorCode)); |
| } |
| } |
| } else { |
| log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n", |
| i, paraLevel, myErrorName(errorCode)); |
| } |
| } |
| } |
| |
| static const char columns[62] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| |
| #define TABLE_SIZE 256 |
| static UBool tablesInitialized = FALSE; |
| static UChar pseudoToUChar[TABLE_SIZE]; |
| static uint8_t UCharToPseudo[TABLE_SIZE]; /* used for Unicode chars < 0x0100 */ |
| static uint8_t UCharToPseud2[TABLE_SIZE]; /* used for Unicode chars >=0x0100 */ |
| |
| static void buildPseudoTables(void) |
| /* |
| The rules for pseudo-Bidi are as follows: |
| - [ == LRE |
| - ] == RLE |
| - { == LRO |
| - } == RLO |
| - ^ == PDF |
| - @ == LRM |
| - & == RLM |
| - A-F == Arabic Letters 0631-0636 |
| - G-Z == Hebrew letters 05d7-05e6 |
| - W-Z == Unassigned RTL 08d0-08d3 |
| - 0-5 == western digits 0030-0035 |
| - 6-9 == Arabic-Indic digits 0666-0669 |
| - ` == Combining Grave Accent 0300 (NSM) |
| - ~ == Delete 007f (BN) |
| - | == Paragraph Separator 2029 (B) |
| - _ == Info Separator 1 001f (S) |
| All other characters represent themselves as Latin-1, with the corresponding |
| Bidi properties. |
| */ |
| { |
| int i; |
| UChar uchar; |
| uint8_t c; |
| /* initialize all tables to unknown */ |
| for (i=0; i < TABLE_SIZE; i++) { |
| pseudoToUChar[i] = 0xFFFD; |
| UCharToPseudo[i] = '?'; |
| UCharToPseud2[i] = '?'; |
| } |
| /* initialize non letters or digits */ |
| pseudoToUChar[(uint8_t) 0 ] = 0x0000; UCharToPseudo[0x00] = (uint8_t) 0 ; |
| pseudoToUChar[(uint8_t)' '] = 0x0020; UCharToPseudo[0x20] = (uint8_t)' '; |
| pseudoToUChar[(uint8_t)'!'] = 0x0021; UCharToPseudo[0x21] = (uint8_t)'!'; |
| pseudoToUChar[(uint8_t)'"'] = 0x0022; UCharToPseudo[0x22] = (uint8_t)'"'; |
| pseudoToUChar[(uint8_t)'#'] = 0x0023; UCharToPseudo[0x23] = (uint8_t)'#'; |
| pseudoToUChar[(uint8_t)'$'] = 0x0024; UCharToPseudo[0x24] = (uint8_t)'$'; |
| pseudoToUChar[(uint8_t)'%'] = 0x0025; UCharToPseudo[0x25] = (uint8_t)'%'; |
| pseudoToUChar[(uint8_t)'\'']= 0x0027; UCharToPseudo[0x27] = (uint8_t)'\''; |
| pseudoToUChar[(uint8_t)'('] = 0x0028; UCharToPseudo[0x28] = (uint8_t)'('; |
| pseudoToUChar[(uint8_t)')'] = 0x0029; UCharToPseudo[0x29] = (uint8_t)')'; |
| pseudoToUChar[(uint8_t)'*'] = 0x002A; UCharToPseudo[0x2A] = (uint8_t)'*'; |
| pseudoToUChar[(uint8_t)'+'] = 0x002B; UCharToPseudo[0x2B] = (uint8_t)'+'; |
| pseudoToUChar[(uint8_t)','] = 0x002C; UCharToPseudo[0x2C] = (uint8_t)','; |
| pseudoToUChar[(uint8_t)'-'] = 0x002D; UCharToPseudo[0x2D] = (uint8_t)'-'; |
| pseudoToUChar[(uint8_t)'.'] = 0x002E; UCharToPseudo[0x2E] = (uint8_t)'.'; |
| pseudoToUChar[(uint8_t)'/'] = 0x002F; UCharToPseudo[0x2F] = (uint8_t)'/'; |
| pseudoToUChar[(uint8_t)':'] = 0x003A; UCharToPseudo[0x3A] = (uint8_t)':'; |
| pseudoToUChar[(uint8_t)';'] = 0x003B; UCharToPseudo[0x3B] = (uint8_t)';'; |
| pseudoToUChar[(uint8_t)'<'] = 0x003C; UCharToPseudo[0x3C] = (uint8_t)'<'; |
| pseudoToUChar[(uint8_t)'='] = 0x003D; UCharToPseudo[0x3D] = (uint8_t)'='; |
| pseudoToUChar[(uint8_t)'>'] = 0x003E; UCharToPseudo[0x3E] = (uint8_t)'>'; |
| pseudoToUChar[(uint8_t)'?'] = 0x003F; UCharToPseudo[0x3F] = (uint8_t)'?'; |
| pseudoToUChar[(uint8_t)'\\']= 0x005C; UCharToPseudo[0x5C] = (uint8_t)'\\'; |
| /* initialize specially used characters */ |
| pseudoToUChar[(uint8_t)'`'] = 0x0300; UCharToPseud2[0x00] = (uint8_t)'`'; /* NSM */ |
| pseudoToUChar[(uint8_t)'@'] = 0x200E; UCharToPseud2[0x0E] = (uint8_t)'@'; /* LRM */ |
| pseudoToUChar[(uint8_t)'&'] = 0x200F; UCharToPseud2[0x0F] = (uint8_t)'&'; /* RLM */ |
| pseudoToUChar[(uint8_t)'_'] = 0x001F; UCharToPseudo[0x1F] = (uint8_t)'_'; /* S */ |
| pseudoToUChar[(uint8_t)'|'] = 0x2029; UCharToPseud2[0x29] = (uint8_t)'|'; /* B */ |
| pseudoToUChar[(uint8_t)'['] = 0x202A; UCharToPseud2[0x2A] = (uint8_t)'['; /* LRE */ |
| pseudoToUChar[(uint8_t)']'] = 0x202B; UCharToPseud2[0x2B] = (uint8_t)']'; /* RLE */ |
| pseudoToUChar[(uint8_t)'^'] = 0x202C; UCharToPseud2[0x2C] = (uint8_t)'^'; /* PDF */ |
| pseudoToUChar[(uint8_t)'{'] = 0x202D; UCharToPseud2[0x2D] = (uint8_t)'{'; /* LRO */ |
| pseudoToUChar[(uint8_t)'}'] = 0x202E; UCharToPseud2[0x2E] = (uint8_t)'}'; /* RLO */ |
| pseudoToUChar[(uint8_t)'~'] = 0x007F; UCharToPseudo[0x7F] = (uint8_t)'~'; /* BN */ |
| /* initialize western digits */ |
| for (i = 0, uchar = 0x0030; i < 6; i++, uchar++) { |
| c = (uint8_t)columns[i]; |
| pseudoToUChar[c] = uchar; |
| UCharToPseudo[uchar & 0x00ff] = c; |
| } |
| /* initialize Hindi digits */ |
| for (i = 6, uchar = 0x0666; i < 10; i++, uchar++) { |
| c = (uint8_t)columns[i]; |
| pseudoToUChar[c] = uchar; |
| UCharToPseud2[uchar & 0x00ff] = c; |
| } |
| /* initialize Arabic letters */ |
| for (i = 10, uchar = 0x0631; i < 16; i++, uchar++) { |
| c = (uint8_t)columns[i]; |
| pseudoToUChar[c] = uchar; |
| UCharToPseud2[uchar & 0x00ff] = c; |
| } |
| /* initialize Hebrew letters */ |
| for (i = 16, uchar = 0x05D7; i < 32; i++, uchar++) { |
| c = (uint8_t)columns[i]; |
| pseudoToUChar[c] = uchar; |
| UCharToPseud2[uchar & 0x00ff] = c; |
| } |
| /* initialize Unassigned code points */ |
| for (i = 32, uchar=0x08D0; i < 36; i++, uchar++) { |
| c = (uint8_t)columns[i]; |
| pseudoToUChar[c] = uchar; |
| UCharToPseud2[uchar & 0x00ff] = c; |
| } |
| /* initialize Latin lower case letters */ |
| for (i = 36, uchar = 0x0061; i < 62; i++, uchar++) { |
| c = (uint8_t)columns[i]; |
| pseudoToUChar[c] = uchar; |
| UCharToPseudo[uchar & 0x00ff] = c; |
| } |
| tablesInitialized = TRUE; |
| } |
| |
| /*----------------------------------------------------------------------*/ |
| |
| static int pseudoToU16( const int length, const char * input, UChar * output ) |
| /* This function converts a pseudo-Bidi string into a UChar string. |
| It returns the length of the UChar string. |
| */ |
| { |
| int i; |
| if (!tablesInitialized) { |
| buildPseudoTables(); |
| } |
| for (i = 0; i < length; i++) |
| output[i] = pseudoToUChar[(uint8_t)input[i]]; |
| return length; |
| } |
| |
| /*----------------------------------------------------------------------*/ |
| |
| static int u16ToPseudo( const int length, const UChar * input, char * output ) |
| /* This function converts a UChar string into a pseudo-Bidi string. |
| It returns the length of the pseudo-Bidi string. |
| */ |
| { |
| int i; |
| UChar uchar; |
| if (!tablesInitialized) { |
| buildPseudoTables(); |
| } |
| for (i = 0; i < length; i++) |
| { |
| uchar = input[i]; |
| output[i] = uchar < 0x0100 ? UCharToPseudo[uchar] : |
| UCharToPseud2[uchar & 0x00ff]; |
| } |
| output[length] = '\0'; |
| return length; |
| } |
| |
| static char * formatLevels(UBiDi *bidi, char *buffer) { |
| UErrorCode ec = U_ZERO_ERROR; |
| const UBiDiLevel* gotLevels = ubidi_getLevels(bidi, &ec); |
| int len = ubidi_getLength(bidi); |
| char c; |
| int i, k; |
| |
| if(U_FAILURE(ec)) { |
| strcpy(buffer, "BAD LEVELS"); |
| return buffer; |
| } |
| for (i=0; i<len; i++) { |
| k = gotLevels[i]; |
| if (k >= sizeof columns) |
| c = '+'; |
| else |
| c = columns[k]; |
| buffer[i] = c; |
| } |
| buffer[len] = '\0'; |
| return buffer; |
| } |
| |
| static void TestReorder(){ |
| static const char* const logicalOrder[] ={ |
| "del(KC)add(K.C.&)", |
| "del(QDVT) add(BVDL)", |
| "del(PQ)add(R.S.)T)U.&", |
| "del(LV)add(L.V.) L.V.&", |
| "day 0 R DPDHRVR dayabbr", |
| "day 1 H DPHPDHDA dayabbr", |
| "day 2 L DPBLENDA dayabbr", |
| "day 3 J DPJQVM dayabbr", |
| "day 4 I DPIQNF dayabbr", |
| "day 5 M DPMEG dayabbr", |
| "helloDPMEG", |
| "hello WXYZ" |
| }; |
| static const char* const visualOrder[]={ |
| "del(CK)add(&.C.K)", |
| "del(TVDQ) add(LDVB)", |
| "del(QP)add(&.U(T(.S.R", |
| "del(VL)add(&.V.L (.V.L", |
| "day 0 RVRHDPD R dayabbr", |
| "day 1 ADHDPHPD H dayabbr", |
| "day 2 ADNELBPD L dayabbr", |
| "day 3 MVQJPD J dayabbr", |
| "day 4 FNQIPD I dayabbr", |
| "day 5 GEMPD M dayabbr", |
| "helloGEMPD", |
| "hello ZYXW" |
| }; |
| static const char* const visualOrder1[]={ |
| ")K.C.&(dda)KC(led", |
| ")BVDL(dda )QDVT(led", |
| "R.S.(T(U.&(dda)PQ(led", |
| "L.V.( L.V.&(dda)LV(led", |
| "rbbayad R DPDHRVR 0 yad", |
| "rbbayad H DPHPDHDA 1 yad", |
| "rbbayad L DPBLENDA 2 yad", |
| "rbbayad J DPJQVM 3 yad", |
| "rbbayad I DPIQNF 4 yad", |
| "rbbayad M DPMEG 5 yad", |
| "DPMEGolleh", |
| "WXYZ olleh" |
| }; |
| |
| static const char* const visualOrder2[]={ |
| "@)@K.C.&@(dda)@KC@(led", |
| "@)@BVDL@(dda )@QDVT@(led", |
| "R.S.)T)U.&@(dda)@PQ@(led", |
| "L.V.) L.V.&@(dda)@LV@(led", |
| "rbbayad @R DPDHRVR@ 0 yad", |
| "rbbayad @H DPHPDHDA@ 1 yad", |
| "rbbayad @L DPBLENDA@ 2 yad", |
| "rbbayad @J DPJQVM@ 3 yad", |
| "rbbayad @I DPIQNF@ 4 yad", |
| "rbbayad @M DPMEG@ 5 yad", |
| "DPMEGolleh", |
| "WXYZ@ olleh" |
| }; |
| static const char* const visualOrder3[]={ |
| ")K.C.&(KC)dda(led", |
| ")BVDL(ddaQDVT) (led", |
| "R.S.)T)U.&(PQ)dda(led", |
| "L.V.) L.V.&(LV)dda(led", |
| "rbbayad DPDHRVR R 0 yad", |
| "rbbayad DPHPDHDA H 1 yad", |
| "rbbayad DPBLENDA L 2 yad", |
| "rbbayad DPJQVM J 3 yad", |
| "rbbayad DPIQNF I 4 yad", |
| "rbbayad DPMEG M 5 yad", |
| "DPMEGolleh", |
| "WXYZ olleh" |
| }; |
| static const char* const visualOrder4[]={ |
| "del(add(CK(.C.K)", |
| "del( (TVDQadd(LDVB)", |
| "del(add(QP(.U(T(.S.R", |
| "del(add(VL(.V.L (.V.L", |
| "day 0 R RVRHDPD dayabbr", |
| "day 1 H ADHDPHPD dayabbr", |
| "day 2 L ADNELBPD dayabbr", |
| "day 3 J MVQJPD dayabbr", |
| "day 4 I FNQIPD dayabbr", |
| "day 5 M GEMPD dayabbr", |
| "helloGEMPD", |
| "hello ZYXW" |
| }; |
| char formatChars[MAXLEN]; |
| UErrorCode ec = U_ZERO_ERROR; |
| UBiDi* bidi = ubidi_open(); |
| int i; |
| for(i=0;i<LENGTHOF(logicalOrder);i++){ |
| int32_t srcSize = (int32_t)strlen(logicalOrder[i]); |
| int32_t destSize = srcSize*2; |
| UChar src[MAXLEN]; |
| UChar dest[MAXLEN]; |
| char chars[MAXLEN]; |
| pseudoToU16(srcSize,logicalOrder[i],src); |
| ec = U_ZERO_ERROR; |
| ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec); |
| if(U_FAILURE(ec)){ |
| log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n", |
| i, UBIDI_DEFAULT_LTR, u_errorName(ec)); |
| } |
| /* try pre-flighting */ |
| destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING,&ec); |
| if(ec!=U_BUFFER_OVERFLOW_ERROR){ |
| log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec)); |
| }else if(destSize!=srcSize){ |
| log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize); |
| }else{ |
| ec= U_ZERO_ERROR; |
| } |
| destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING,&ec); |
| u16ToPseudo(destSize,dest,chars); |
| if(destSize!=srcSize){ |
| log_err("ubidi_writeReordered() destSize and srcSize do not match\n"); |
| }else if(strcmp(visualOrder[i],chars)!=0){ |
| log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING.\n" |
| "Input : %s\nExpected: %s\nGot : %s\nLevels : %s\nAt Index: %d\n", |
| logicalOrder[i],visualOrder[i],chars,formatLevels(bidi, formatChars),i); |
| } |
| } |
| |
| for(i=0;i<LENGTHOF(logicalOrder);i++){ |
| int32_t srcSize = (int32_t)strlen(logicalOrder[i]); |
| int32_t destSize = srcSize*2; |
| UChar src[MAXLEN]; |
| UChar dest[MAXLEN]; |
| char chars[MAXLEN]; |
| pseudoToU16(srcSize,logicalOrder[i],src); |
| ec = U_ZERO_ERROR; |
| ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec); |
| if(U_FAILURE(ec)){ |
| log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n", |
| i, UBIDI_DEFAULT_LTR, u_errorName(ec)); |
| } |
| /* try pre-flighting */ |
| destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE,&ec); |
| if(ec!=U_BUFFER_OVERFLOW_ERROR){ |
| log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec)); |
| }else if(destSize!=srcSize){ |
| log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize); |
| }else{ |
| ec= U_ZERO_ERROR; |
| } |
| destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE,&ec); |
| u16ToPseudo(destSize,dest,chars); |
| if(destSize!=srcSize){ |
| log_err("ubidi_writeReordered() destSize and srcSize do not match\n"); |
| }else if(strcmp(visualOrder1[i],chars)!=0){ |
| log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING+UBIDI_OUTPUT_REVERSE.\n" |
| "Input : %s\nExpected: %s\nGot : %s\nLevels : %s\nAt Index: %d\n", |
| logicalOrder[i],visualOrder1[i],chars,formatLevels(bidi, formatChars),i); |
| } |
| } |
| |
| for(i=0;i<LENGTHOF(logicalOrder);i++){ |
| int32_t srcSize = (int32_t)strlen(logicalOrder[i]); |
| int32_t destSize = srcSize*2; |
| UChar src[MAXLEN]; |
| UChar dest[MAXLEN]; |
| char chars[MAXLEN]; |
| pseudoToU16(srcSize,logicalOrder[i],src); |
| ec = U_ZERO_ERROR; |
| ubidi_setInverse(bidi,TRUE); |
| ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR ,NULL,&ec); |
| if(U_FAILURE(ec)){ |
| log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n", |
| i, UBIDI_DEFAULT_LTR, u_errorName(ec)); |
| } |
| /* try pre-flighting */ |
| destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE,&ec); |
| if(ec!=U_BUFFER_OVERFLOW_ERROR){ |
| log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec)); |
| }else{ |
| ec= U_ZERO_ERROR; |
| } |
| destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE,&ec); |
| u16ToPseudo(destSize,dest,chars); |
| if(strcmp(visualOrder2[i],chars)!=0){ |
| log_err("ubidi_writeReordered() did not give expected results for UBIDI_INSERT_LRM_FOR_NUMERIC+UBIDI_OUTPUT_REVERSE.\n" |
| "Input : %s\nExpected: %s\nGot : %s\nLevels : %s\nAt Index: %d\n", |
| logicalOrder[i],visualOrder2[i],chars,formatLevels(bidi, formatChars),i); |
| } |
| } |
| /* Max Explicit level */ |
| for(i=0;i<LENGTHOF(logicalOrder);i++){ |
| int32_t srcSize = (int32_t)strlen(logicalOrder[i]); |
| int32_t destSize = srcSize*2; |
| UChar src[MAXLEN]; |
| UChar dest[MAXLEN]; |
| char chars[MAXLEN]; |
| UBiDiLevel levels[UBIDI_MAX_EXPLICIT_LEVEL]={1,2,3,4,5,6,7,8,9,10}; |
| pseudoToU16(srcSize,logicalOrder[i],src); |
| ec = U_ZERO_ERROR; |
| ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR,levels,&ec); |
| if(U_FAILURE(ec)){ |
| log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n", |
| i, UBIDI_MAX_EXPLICIT_LEVEL, u_errorName(ec)); |
| } |
| /* try pre-flighting */ |
| destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_OUTPUT_REVERSE,&ec); |
| if(ec!=U_BUFFER_OVERFLOW_ERROR){ |
| log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec)); |
| }else if(destSize!=srcSize){ |
| log_err("Pre-flighting did not give expected size: Expected: %d. Got: %d \n",srcSize,destSize); |
| }else{ |
| ec = U_ZERO_ERROR; |
| } |
| destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_OUTPUT_REVERSE,&ec); |
| u16ToPseudo(destSize,dest,chars); |
| if(destSize!=srcSize){ |
| log_err("ubidi_writeReordered() destSize and srcSize do not match. Dest Size = %d Source Size = %d\n",destSize,srcSize ); |
| }else if(strcmp(visualOrder3[i],chars)!=0){ |
| log_err("ubidi_writeReordered() did not give expected results for UBIDI_OUTPUT_REVERSE.\n" |
| "Input : %s\nExpected: %s\nGot : %s\nLevels : %s\nAt Index: %d\n", |
| logicalOrder[i],visualOrder3[i],chars,formatLevels(bidi, formatChars),i); |
| } |
| } |
| for(i=0;i<LENGTHOF(logicalOrder);i++){ |
| int32_t srcSize = (int32_t)strlen(logicalOrder[i]); |
| int32_t destSize = srcSize*2; |
| UChar src[MAXLEN]; |
| UChar dest[MAXLEN]; |
| char chars[MAXLEN]; |
| UBiDiLevel levels[UBIDI_MAX_EXPLICIT_LEVEL]={1,2,3,4,5,6,7,8,9,10}; |
| pseudoToU16(srcSize,logicalOrder[i],src); |
| ec = U_ZERO_ERROR; |
| ubidi_setPara(bidi,src,srcSize,UBIDI_DEFAULT_LTR,levels,&ec); |
| if(U_FAILURE(ec)){ |
| log_err("ubidi_setPara(tests[%d], paraLevel %d) failed with errorCode %s\n", |
| i, UBIDI_MAX_EXPLICIT_LEVEL, u_errorName(ec)); |
| } |
| /* try pre-flighting */ |
| destSize = ubidi_writeReordered(bidi,dest,0,UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS,&ec); |
| if(ec!=U_BUFFER_OVERFLOW_ERROR){ |
| log_err("Pre-flighting did not give expected error: Expected: U_BUFFER_OVERFLOW_ERROR. Got: %s \n",u_errorName(ec)); |
| }else{ |
| ec= U_ZERO_ERROR; |
| } |
| destSize=ubidi_writeReordered(bidi,dest,destSize+1,UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS,&ec); |
| u16ToPseudo(destSize,dest,chars); |
| if(strcmp(visualOrder4[i],chars)!=0){ |
| log_err("ubidi_writeReordered() did not give expected results for UBIDI_DO_MIRRORING+UBIDI_REMOVE_BIDI_CONTROLS.\n" |
| "Input : %s\nExpected: %s\nGot : %s\nLevels : %s\nAt Index: %d\n", |
| logicalOrder[i],visualOrder4[i],chars,formatLevels(bidi, formatChars),i); |
| } |
| } |
| ubidi_close(bidi); |
| } |
| |
| static void |
| doTest(UBiDi *pBiDi, int testNumber, const BiDiTestData *test, int32_t lineStart, UBool countRunsFirst) { |
| const uint8_t *dirProps=test->text+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; i<len; ++i) { |
| log_verbose("%3d %3d %.*s%-3s @%d\n", |
| i, ubidi_getLevelAt(pBiDi, i), ubidi_getLevelAt(pBiDi, i), levelString, |
| dirPropNames[dirProps[i]], |
| ubidi_getVisualIndex(pBiDi, i, &errorCode)); |
| } |
| |
| log_verbose("\n-----levels:"); |
| for(i=0; i<len; ++i) { |
| if(i>0) { |
| log_verbose(","); |
| } |
| log_verbose(" %d", ubidi_getLevelAt(pBiDi, i)); |
| } |
| |
| log_verbose("\n--reordered:"); |
| for(i=0; i<len; ++i) { |
| if(i>0) { |
| 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; i<len; ++i) { |
| if(levels[i]!=ubidi_getLevelAt(pBiDi, i)) { |
| log_err("ubidi_getLevelAt(tests[%d], %d): wrong level %d, expected %d\n", testNumber, i, ubidi_getLevelAt(pBiDi, i), levels[i]); |
| return; |
| } |
| } |
| |
| for(i=0; i<len; ++i) { |
| logicalIndex=ubidi_getVisualIndex(pBiDi, i, &errorCode); |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_getVisualIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode)); |
| return; |
| } |
| if(visualMap[i]!=logicalIndex) { |
| log_err("ubidi_getVisualIndex(tests[%d], %d): wrong index %d\n", testNumber, i, logicalIndex); |
| return; |
| } |
| } |
| |
| if (! countRunsFirst) { |
| runCount=ubidi_countRuns(pBiDi, &errorCode); |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode)); |
| return; |
| } |
| } |
| |
| for(logicalIndex=0; logicalIndex<len;) { |
| level=ubidi_getLevelAt(pBiDi, logicalIndex); |
| ubidi_getLogicalRun(pBiDi, logicalIndex, &logicalIndex, &level2); |
| if(level!=level2) { |
| log_err("ubidi_getLogicalRun(tests[%d], run ending at index %d): wrong level %d\n", testNumber, logicalIndex, level2); |
| } |
| if(--runCount<0) { |
| log_err("\nubidi_getLogicalRun(tests[%d]): wrong number of runs compared to %d=ubidi_getRunCount()\n", testNumber, ubidi_countRuns(pBiDi, &errorCode)); |
| return; |
| } |
| } |
| if(runCount!=0) { |
| log_err("\nubidi_getLogicalRun(tests[%d]): wrong number of runs compared to %d=ubidi_getRunCount()\n", testNumber, ubidi_countRuns(pBiDi, &errorCode)); |
| return; |
| } |
| |
| log_verbose("\n\n"); |
| } |
| |
| static void |
| testReordering(UBiDi *pBiDi, int testNumber) { |
| int32_t |
| logicalMap1[MAXLEN], logicalMap2[MAXLEN], logicalMap3[MAXLEN], |
| visualMap1[MAXLEN], visualMap2[MAXLEN], visualMap3[MAXLEN], visualMap4[MAXLEN]; |
| UErrorCode errorCode=U_ZERO_ERROR; |
| const UBiDiLevel *levels; |
| int32_t i, length=ubidi_getLength(pBiDi), |
| destLength=ubidi_getResultLength(pBiDi); |
| int32_t runCount, visualIndex, logicalStart, runLength; |
| UBool odd; |
| |
| if(length<=0) { |
| return; |
| } |
| |
| /* get the logical and visual maps from the object */ |
| ubidi_getLogicalMap(pBiDi, logicalMap1, &errorCode); |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_getLogicalMap(tests[%d]): error %s\n", testNumber, myErrorName(errorCode)); |
| return; |
| } |
| |
| ubidi_getVisualMap(pBiDi, visualMap1, &errorCode); |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_getVisualMap(tests[%d]): error %s\n", testNumber, myErrorName(errorCode)); |
| return; |
| } |
| |
| /* invert them both */ |
| ubidi_invertMap(logicalMap1, visualMap2, length); |
| ubidi_invertMap(visualMap1, logicalMap2, destLength); |
| |
| /* get them from the levels array, too */ |
| levels=ubidi_getLevels(pBiDi, &errorCode); |
| |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_getLevels(tests[%d]): error %s\n", testNumber, myErrorName(errorCode)); |
| return; |
| } |
| |
| ubidi_reorderLogical(levels, length, logicalMap3); |
| ubidi_reorderVisual(levels, length, visualMap3); |
| |
| /* get the visual map from the runs, too */ |
| runCount=ubidi_countRuns(pBiDi, &errorCode); |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_countRuns(tests[%d]): error %s\n", testNumber, myErrorName(errorCode)); |
| return; |
| } |
| log_verbose("\n----%2d runs:", runCount); |
| visualIndex=0; |
| for(i=0; i<runCount; ++i) { |
| odd=(UBool)ubidi_getVisualRun(pBiDi, i, &logicalStart, &runLength); |
| log_verbose(" (%c @%d[%d])", odd ? 'R' : 'L', logicalStart, runLength); |
| if(UBIDI_LTR==odd) { |
| do { /* LTR */ |
| visualMap4[visualIndex++]=logicalStart++; |
| } while(--runLength>0); |
| } 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; i<length; ++i) { |
| log_verbose("%4d", logicalMap1[i]); |
| } |
| log_verbose("\n"); |
| for(i=0; i<length; ++i) { |
| log_verbose("%4d", logicalMap2[i]); |
| } |
| log_verbose("\n"); |
| for(i=0; i<length; ++i) { |
| log_verbose("%4d", logicalMap3[i]); |
| } |
| |
| log_verbose("\nvisual maps:\n"); |
| for(i=0; i<destLength; ++i) { |
| log_verbose("%4d", visualMap1[i]); |
| } |
| log_verbose("\n"); |
| for(i=0; i<destLength; ++i) { |
| log_verbose("%4d", visualMap2[i]); |
| } |
| log_verbose("\n"); |
| for(i=0; i<length; ++i) { |
| log_verbose("%4d", visualMap3[i]); |
| } |
| log_verbose("\n"); |
| for(i=0; i<length; ++i) { |
| log_verbose("%4d", visualMap4[i]); |
| } |
| log_verbose("\n"); |
| |
| /* check that the indexes are the same between these and ubidi_getLogical/VisualIndex() */ |
| for(i=0; i<length; ++i) { |
| if(logicalMap1[i]!=logicalMap2[i]) { |
| log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=logicalMap2[i] at i=%d\n", testNumber, i); |
| break; |
| } |
| if(logicalMap1[i]!=logicalMap3[i]) { |
| log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=logicalMap3[i] at i=%d\n", testNumber, i); |
| break; |
| } |
| |
| if(visualMap1[i]!=visualMap2[i]) { |
| log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap2[i] at i=%d\n", testNumber, i); |
| break; |
| } |
| if(visualMap1[i]!=visualMap3[i]) { |
| log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap3[i] at i=%d\n", testNumber, i); |
| break; |
| } |
| if(visualMap1[i]!=visualMap4[i]) { |
| log_err("bidi reordering error in tests[%d]: visualMap1[i]!=visualMap4[i] at i=%d\n", testNumber, i); |
| break; |
| } |
| |
| if(logicalMap1[i]!=ubidi_getVisualIndex(pBiDi, i, &errorCode)) { |
| log_err("bidi reordering error in tests[%d]: logicalMap1[i]!=ubidi_getVisualIndex(i) at i=%d\n", testNumber, i); |
| break; |
| } |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_getVisualIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode)); |
| break; |
| } |
| if(visualMap1[i]!=ubidi_getLogicalIndex(pBiDi, i, &errorCode)) { |
| log_err("bidi reordering error in tests[%d]: visualMap1[i]!=ubidi_getLogicalIndex(i) at i=%d\n", testNumber, i); |
| break; |
| } |
| if(U_FAILURE(errorCode)) { |
| log_err("ubidi_getLogicalIndex(tests[%d], %d): error %s\n", testNumber, i, myErrorName(errorCode)); |
| break; |
| } |
| } |
| } |
| |
| static void TestFailureRecovery(void) { |
| UErrorCode status; |
| |
| status = U_FILE_ACCESS_ERROR; |
| if (ubidi_writeReordered(NULL, NULL, 0, 0, &status) != 0) { |
| log_err("ubidi_writeReordered did not return 0 when passed a failing UErrorCode\n"); |
| } |
| if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &status) != 0) { |
| log_err("ubidi_writeReverse did not return 0 when passed a failing UErrorCode\n"); |
| } |
| status = U_ZERO_ERROR; |
| if (ubidi_writeReordered(NULL, NULL, 0, 0, &status) != 0 || status != U_ILLEGAL_ARGUMENT_ERROR) { |
| log_err("ubidi_writeReordered did not fail as expected\n"); |
| } |
| status = U_ZERO_ERROR; |
| if (ubidi_writeReverse(NULL, 0, NULL, 0, 0, &status) != 0 || status != U_ILLEGAL_ARGUMENT_ERROR) { |
| log_err("ubidi_writeReverse did not fail as expected\n"); |
| } |
| } |
| |
| static void TestMultipleParagraphs(void) { |
| static const char* const text = "__ABC\\u001c" /* Para #0 offset 0 */ |
| "__\\u05d0DE\\u001c" /* 1 6 */ |
| "__123\\u001c" /* 2 12 */ |
| "\\u000d\\u000a" /* 3 18 */ |
| "FG\\u000d" /* 4 20 */ |
| "\\u000d" /* 5 23 */ |
| "HI\\u000d\\u000a" /* 6 24 */ |
| "\\u000d\\u000a" /* 7 28 */ |
| "\\u000a" /* 8 30 */ |
| "\\u000a" /* 9 31 */ |
| "JK\\u001c"; /* 10 32 */ |
| static const int32_t paraCount=11; |
| static const int32_t paraBounds[]={0, 6, 12, 18, 20, 23, 24, 28, 30, 31, 32, 35}; |
| static const UBiDiLevel paraLevels[]={UBIDI_LTR, UBIDI_RTL, UBIDI_DEFAULT_LTR, UBIDI_DEFAULT_RTL, 22, 23}; |
| static const UBiDiLevel multiLevels[6][11] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
| {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
| {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
| {0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0}, |
| {22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22}, |
| {23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23}}; |
| static const char* const text2 = "\\u05d0 1-2\\u001c\\u0630 1-2\\u001c1-2"; |
| static const UBiDiLevel levels2[] = {1,1,2,2,2,0, 1,1,2,1,2,0, 2,2,2}; |
| UBiDiLevel gotLevel; |
| const UBiDiLevel* gotLevels; |
| UBool orderParagraphsLTR; |
| UChar src[MAXLEN]; |
| UErrorCode errorCode=U_ZERO_ERROR; |
| UBiDi* pBidi=ubidi_open(); |
| UBiDi* pLine; |
| int32_t srcSize, count, paraStart, paraLimit, paraIndex, length; |
| int i, j, k; |
| |
| u_unescape(text, src, MAXLEN); |
| srcSize=u_strlen(src); |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode); |
| if(U_FAILURE(errorCode)){ |
| log_err("ubidi_setPara failed, paraLevel=%d, errorCode %s\n", |
| UBIDI_LTR, u_errorName(errorCode)); |
| ubidi_close(pBidi); |
| return; |
| } |
| /* check paragraph count and boundaries */ |
| if (paraCount!=(count=ubidi_countParagraphs(pBidi))) { |
| log_err("ubidi_countParagraphs returned %d, should be %d\n", |
| count, paraCount); |
| } |
| for (i=0; i<paraCount; i++) { |
| ubidi_getParagraphByIndex(pBidi, i, ¶Start, ¶Limit, NULL, &errorCode); |
| if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) { |
| log_err("Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n", |
| i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]); |
| } |
| } |
| errorCode=U_ZERO_ERROR; |
| /* check with last paragraph not terminated by B */ |
| src[srcSize-1]='L'; |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_LTR, NULL, &errorCode); |
| if(U_FAILURE(errorCode)){ |
| log_err("2nd ubidi_setPara failed, paraLevel=%d, errorCode %s\n", |
| UBIDI_LTR, u_errorName(errorCode)); |
| ubidi_close(pBidi); |
| return; |
| } |
| if (paraCount!=(count=ubidi_countParagraphs(pBidi))) { |
| log_err("2nd ubidi_countParagraphs returned %d, should be %d\n", |
| count, paraCount); |
| } |
| i=paraCount-1; |
| ubidi_getParagraphByIndex(pBidi, i, ¶Start, ¶Limit, NULL, &errorCode); |
| if ((paraStart!=paraBounds[i]) || (paraLimit!=paraBounds[i+1])) { |
| log_err("2nd Found boundaries of paragraph %d: %d-%d; expected: %d-%d\n", |
| i, paraStart, paraLimit, paraBounds[i], paraBounds[i+1]); |
| } |
| errorCode=U_ZERO_ERROR; |
| /* check paraLevel for all paragraphs under various paraLevel specs */ |
| for (k=0; k<6; k++) { |
| ubidi_setPara(pBidi, src, srcSize, paraLevels[k], NULL, &errorCode); |
| for (i=0; i<paraCount; i++) { |
| paraIndex=ubidi_getParagraph(pBidi, paraBounds[i], NULL, NULL, &gotLevel, &errorCode); |
| if (paraIndex!=i) { |
| log_err("For paraLevel=%d paragraph=%d, found paragraph index=%d expected=%d\n", |
| paraLevels[k], i, paraIndex, i); |
| } |
| if (gotLevel!=multiLevels[k][i]) { |
| log_err("For paraLevel=%d paragraph=%d, found level=%d expected %d\n", |
| paraLevels[k], i, gotLevel, multiLevels[k][i]); |
| } |
| } |
| gotLevel=ubidi_getParaLevel(pBidi); |
| if (gotLevel!=multiLevels[k][0]) { |
| log_err("For paraLevel=%d getParaLevel=%d, expected %d\n", |
| paraLevels[k], gotLevel, multiLevels[k][0]); |
| } |
| } |
| errorCode=U_ZERO_ERROR; |
| /* check that the result of ubidi_getParaLevel changes if the first |
| * paragraph has a different level |
| */ |
| src[0]=0x05d2; /* Hebrew letter Gimel */ |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_LTR, NULL, &errorCode); |
| gotLevel=ubidi_getParaLevel(pBidi); |
| if (gotLevel!=UBIDI_RTL) { |
| log_err("For paraLevel=UBIDI_DEFAULT_LTR getParaLevel=%d, expected=%d\n", |
| gotLevel, UBIDI_RTL); |
| } |
| errorCode=U_ZERO_ERROR; |
| /* check that line cannot overlap paragraph boundaries */ |
| pLine=ubidi_open(); |
| i=paraBounds[1]; |
| k=paraBounds[2]+1; |
| ubidi_setLine(pBidi, i, k, pLine, &errorCode); |
| if (U_SUCCESS(errorCode)) { |
| log_err("For line limits %d-%d got success %s\n", |
| i, k, u_errorName(errorCode)); |
| } |
| errorCode=U_ZERO_ERROR; |
| i=paraBounds[1]; |
| k=paraBounds[2]; |
| ubidi_setLine(pBidi, i, k, pLine, &errorCode); |
| if (U_FAILURE(errorCode)) { |
| log_err("For line limits %d-%d got error %s\n", |
| i, k, u_errorName(errorCode)); |
| errorCode=U_ZERO_ERROR; |
| } |
| /* check level of block separator at end of paragraph when orderParagraphsLTR==FALSE */ |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode); |
| /* get levels through para Bidi block */ |
| gotLevels=ubidi_getLevels(pBidi, &errorCode); |
| if (U_FAILURE(errorCode)) { |
| log_err("Error on Para getLevels %s\n", u_errorName(errorCode)); |
| ubidi_close(pLine); |
| ubidi_close(pBidi); |
| return; |
| } |
| for (i=26; i<32; i++) { |
| if (gotLevels[i]!=UBIDI_RTL) { |
| log_err("For char %d(%04x), level=%d, expected=%d\n", |
| i, src[i], gotLevels[i], UBIDI_RTL); |
| } |
| } |
| /* get levels through para Line block */ |
| i=paraBounds[1]; |
| k=paraBounds[2]; |
| ubidi_setLine(pBidi, i, k, pLine, &errorCode); |
| if (U_FAILURE(errorCode)) { |
| log_err("For line limits %d-%d got error %s\n", |
| i, k, u_errorName(errorCode)); |
| ubidi_close(pLine); |
| ubidi_close(pBidi); |
| return; |
| } |
| paraIndex=ubidi_getParagraph(pLine, i, ¶Start, ¶Limit, &gotLevel, &errorCode); |
| gotLevels=ubidi_getLevels(pLine, &errorCode); |
| if (U_FAILURE(errorCode)) { |
| log_err("Error on Line getLevels %s\n", u_errorName(errorCode)); |
| ubidi_close(pLine); |
| ubidi_close(pBidi); |
| return; |
| } |
| length=ubidi_getLength(pLine); |
| if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=UBIDI_RTL)) { |
| log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, " |
| "level of separator=%d expected=%d\n", |
| paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], UBIDI_RTL); |
| } |
| orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi); |
| if (orderParagraphsLTR) { |
| log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, FALSE); |
| } |
| ubidi_orderParagraphsLTR(pBidi, TRUE); |
| orderParagraphsLTR=ubidi_isOrderParagraphsLTR(pBidi); |
| if (!orderParagraphsLTR) { |
| log_err("Found orderParagraphsLTR=%d expected=%d\n", orderParagraphsLTR, TRUE); |
| } |
| /* check level of block separator at end of paragraph when orderParagraphsLTR==TRUE */ |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode); |
| /* get levels through para Bidi block */ |
| gotLevels=ubidi_getLevels(pBidi, &errorCode); |
| for (i=26; i<32; i++) { |
| if (gotLevels[i]!=0) { |
| log_err("For char %d(%04x), level=%d, expected=%d\n", |
| i, src[i], gotLevels[i], 0); |
| } |
| } |
| errorCode=U_ZERO_ERROR; |
| /* get levels through para Line block */ |
| i=paraBounds[1]; |
| k=paraBounds[2]; |
| ubidi_setLine(pBidi, paraStart, paraLimit, pLine, &errorCode); |
| paraIndex=ubidi_getParagraph(pLine, i, ¶Start, ¶Limit, &gotLevel, &errorCode); |
| gotLevels=ubidi_getLevels(pLine, &errorCode); |
| length=ubidi_getLength(pLine); |
| if ((gotLevel!=UBIDI_RTL) || (gotLevels[length-1]!=0)) { |
| log_err("For paragraph %d with limits %d-%d, paraLevel=%d expected=%d, " |
| "level of separator=%d expected=%d\n", |
| paraIndex, paraStart, paraLimit, gotLevel, UBIDI_RTL, gotLevels[length-1], 0); |
| log_verbose("levels="); |
| for (count=0; count<length; count++) { |
| log_verbose(" %d", gotLevels[count]); |
| } |
| log_verbose("\n"); |
| } |
| |
| /* test that the concatenation of separate invocations of the bidi code |
| * on each individual paragraph in order matches the levels array that |
| * results from invoking bidi once over the entire multiparagraph tests |
| * (with orderParagraphsLTR false, of course) |
| */ |
| u_unescape(text, src, MAXLEN); /* restore original content */ |
| srcSize=u_strlen(src); |
| ubidi_orderParagraphsLTR(pBidi, FALSE); |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_DEFAULT_RTL, NULL, &errorCode); |
| gotLevels=ubidi_getLevels(pBidi, &errorCode); |
| for (i=0; i<paraCount; i++) { |
| /* use pLine for individual paragraphs */ |
| paraStart = paraBounds[i]; |
| length = paraBounds[i+1] - paraStart; |
| ubidi_setPara(pLine, src+paraStart, length, UBIDI_DEFAULT_RTL, NULL, &errorCode); |
| for (j=0; j<length; j++) { |
| if ((k=ubidi_getLevelAt(pLine, j)) != (gotLevel=gotLevels[paraStart+j])) { |
| log_err("Checking paragraph concatenation: for paragraph=%d, " |
| "char=%d(%04x), level=%d, expected=%d\n", |
| i, j, src[paraStart+j], k, gotLevel); |
| } |
| } |
| } |
| |
| /* ensure that leading numerics in a paragraph are not treated as arabic |
| numerals because of arabic text in a preceding paragraph |
| */ |
| u_unescape(text2, src, MAXLEN); |
| srcSize=u_strlen(src); |
| ubidi_orderParagraphsLTR(pBidi, TRUE); |
| ubidi_setPara(pBidi, src, srcSize, UBIDI_RTL, NULL, &errorCode); |
| gotLevels=ubidi_getLevels(pBidi, &errorCode); |
| for (i=0; i<srcSize; i++) { |
| if (gotLevels[i]!=levels2[i]) { |
| log_err("Checking leading numerics: for char %d(%04x), level=%d, expected=%d\n", |
| i, src[i], gotLevels[i], levels2[i]); |
| } |
| } |
| |
| /* check handling of whitespace before end of paragraph separator when |
| * orderParagraphsLTR==TRUE, when last paragraph has, and lacks, a terminating B |
| */ |
| u_memset(src, 0x0020, MAXLEN); |
| srcSize = 5; |
| ubidi_orderParagraphsLTR(pBidi, TRUE); |
| for (i=0x001c; i<=0x0020; i+=(0x0020-0x001c)) { |
| src[4]=i; /* with and without terminating B */ |
| for (j=0x0041; j<=0x05d0; j+=(0x05d0-0x0041)) { |
| src[0]=j; /* leading 'A' or Alef */ |
| for (gotLevel=4; gotLevel<=5; gotLevel++) { |
| /* test even and odd paraLevel */ |
| ubidi_setPara(pBidi, src, srcSize, gotLevel, NULL, &errorCode); |
| gotLevels=ubidi_getLevels(pBidi, &errorCode); |
| for (k=1; k<=3; k++) { |
| if (gotLevels[k]!=gotLevel) { |
| log_err("Checking trailing spaces: for leading_char=%04x, " |
| "last_char=%04x, index=%d, level=%d, expected=%d\n", |
| src[0], src[4], k, gotLevels[k], gotLevel); |
| } |
| } |
| } |
| } |
| } |
| |
| ubidi_close(pLine); |
| ubidi_close(pBidi); |
| } |
| |
| |
| /* inverse BiDi ------------------------------------------------------------- */ |
| |
| static int countRoundtrips=0, countNonRoundtrips=0; |
| |
| #define STRING_TEST_CASE(s) { (s), LENGTHOF(s) } |
| |
| static void |
| doInverseBiDiTest() { |
| static const UChar |
| string0[]={ 0x6c, 0x61, 0x28, 0x74, 0x69, 0x6e, 0x20, 0x5d0, 0x5d1, 0x29, 0x5d2, 0x5d3 }, |
| string1[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x31, 0x32, 0x33 }, |
| string2[]={ 0x6c, 0x61, 0x74, 0x20, 0x5d0, 0x28, 0x5d1, 0x5d2, 0x20, 0x31, 0x29, 0x32, 0x33 }, |
| string3[]={ 0x31, 0x32, 0x33, 0x20, 0x5d0, 0x5d1, 0x5d2, 0x20, 0x34, 0x35, 0x36 }, |
| string4[]={ 0x61, 0x62, 0x20, 0x61, 0x62, 0x20, 0x661, 0x662 }; |
| |
| static const struct { |
| const UChar *s; |
| int32_t length; |
| } testCases[]={ |
| STRING_TEST_CASE(string0), |
| STRING_TEST_CASE(string1), |
| STRING_TEST_CASE(string2), |
| STRING_TEST_CASE(string3), |
| STRING_TEST_CASE(string4) |
| }; |
| |
| UBiDi *pBiDi; |
| UErrorCode errorCode; |
| int i; |
| |
| pBiDi=ubidi_open(); |
| if(pBiDi==NULL) { |
| log_err("unable to open a UBiDi object (out of memory)\n"); |
| return; |
| } |
| |
| log_verbose("inverse BiDi: testInverseBiDi(L) with %u test cases ---\n", LENGTHOF(testCases)); |
| for(i=0; i<LENGTHOF(testCases); ++i) { |
| errorCode=U_ZERO_ERROR; |
| testInverseBiDi(pBiDi, testCases[i].s, testCases[i].length, 0, &errorCode); |
| } |
| |
| log_verbose("inverse BiDi: testInverseBiDi(R) with %u test cases ---\n", LENGTHOF(testCases)); |
| for(i=0; i<LENGTHOF(testCases); ++i) { |
| errorCode=U_ZERO_ERROR; |
| testInverseBiDi(pBiDi, testCases[i].s, testCases[i].length, 1, &errorCode); |
| } |
| |
| testManyInverseBiDi(pBiDi, 0); |
| testManyInverseBiDi(pBiDi, 1); |
| |
| ubidi_close(pBiDi); |
| |
| log_verbose("inverse BiDi: rountrips: %5u\nnon-roundtrips: %5u\n", countRoundtrips, countNonRoundtrips); |
| |
| testWriteReverse(); |
| } |
| |
| #define COUNT_REPEAT_SEGMENTS 6 |
| |
| static const UChar repeatSegments[COUNT_REPEAT_SEGMENTS][2]={ |
| { 0x61, 0x62 }, /* L */ |
| { 0x5d0, 0x5d1 }, /* R */ |
| { 0x627, 0x628 }, /* AL */ |
| { 0x31, 0x32 }, /* EN */ |
| { 0x661, 0x662 }, /* AN */ |
| { 0x20, 0x20 } /* WS (N) */ |
| }; |
| |
| static void |
| testManyInverseBiDi(UBiDi *pBiDi, UBiDiLevel direction) { |
| UChar text[8]={ 0, 0, 0x20, 0, 0, 0x20, 0, 0 }; |
| int i, j, k; |
| UErrorCode errorCode; |
| |
| log_verbose("inverse BiDi: testManyInverseBiDi(%c) - test permutations of text snippets ---\n", direction==0 ? 'L' : 'R'); |
| for(i=0; i<COUNT_REPEAT_SEGMENTS; ++i) { |
| text[0]=repeatSegments[i][0]; |
| text[1]=repeatSegments[i][1]; |
| for(j=0; j<COUNT_REPEAT_SEGMENTS; ++j) { |
| text[3]=repeatSegments[j][0]; |
| text[4]=repeatSegments[j][1]; |
| for(k=0; k<COUNT_REPEAT_SEGMENTS; ++k) { |
| text[6]=repeatSegments[k][0]; |
| text[7]=repeatSegments[k][1]; |
| |
| errorCode=U_ZERO_ERROR; |
| log_verbose("inverse BiDi: testManyInverseBiDi()[%u %u %u]\n", i, j, k); |
| testInverseBiDi(pBiDi, text, 8, direction, &errorCode); |
| } |
| } |
| } |
| } |
| |
| static void |
| testInverseBiDi(UBiDi *pBiDi, const UChar *src, int32_t srcLength, |
| UBiDiLevel direction, UErrorCode *pErrorCode) { |
| UChar visualLTR[MAXLEN], logicalDest[MAXLEN], visualDest[MAXLEN]; |
| int32_t ltrLength, logicalLength, visualLength; |
| |
| if(direction==0) { |
| log_verbose("inverse BiDi: testInverseBiDi(L)\n"); |
| |
| /* convert visual to logical */ |
| ubidi_setInverse(pBiDi, TRUE); |
| if (!ubidi_isInverse(pBiDi)) { |
| log_err("Error while doing ubidi_setInverse(TRUE)\n"); |
| } |
| ubidi_setPara(pBiDi, src, srcLength, 0, NULL, pErrorCode); |
| if (src != ubidi_getText(pBiDi)) { |
| log_err("Wrong value returned by ubidi_getText\n"); |
| } |
| logicalLength=ubidi_writeReordered(pBiDi, logicalDest, LENGTHOF(logicalDest), |
| UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode); |
| log_verbose(" v "); |
| printUnicode(src, srcLength, ubidi_getLevels(pBiDi, pErrorCode)); |
| log_verbose("\n"); |
| |
| /* convert back to visual LTR */ |
| ubidi_setInverse(pBiDi, FALSE); |
| if (ubidi_isInverse(pBiDi)) { |
| log_err("Error while doing ubidi_setInverse(FALSE)\n"); |
| } |
| ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode); |
| visualLength=ubidi_writeReordered(pBiDi, visualDest, LENGTHOF(visualDest), |
| UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS, pErrorCode); |
| } else { |
| log_verbose("inverse BiDi: testInverseBiDi(R)\n"); |
| |
| /* reverse visual from RTL to LTR */ |
| ltrLength=ubidi_writeReverse(src, srcLength, visualLTR, LENGTHOF(visualLTR), 0, pErrorCode); |
| log_verbose(" vr"); |
| printUnicode(src, srcLength, NULL); |
| log_verbose("\n"); |
| |
| /* convert visual RTL to logical */ |
| ubidi_setInverse(pBiDi, TRUE); |
| ubidi_setPara(pBiDi, visualLTR, ltrLength, 0, NULL, pErrorCode); |
| logicalLength=ubidi_writeReordered(pBiDi, logicalDest, LENGTHOF(logicalDest), |
| UBIDI_DO_MIRRORING|UBIDI_INSERT_LRM_FOR_NUMERIC, pErrorCode); |
| log_verbose(" vl"); |
| printUnicode(visualLTR, ltrLength, ubidi_getLevels(pBiDi, pErrorCode)); |
| log_verbose("\n"); |
| |
| /* convert back to visual RTL */ |
| ubidi_setInverse(pBiDi, FALSE); |
| ubidi_setPara(pBiDi, logicalDest, logicalLength, 0, NULL, pErrorCode); |
| visualLength=ubidi_writeReordered(pBiDi, visualDest, LENGTHOF(visualDest), |
| UBIDI_DO_MIRRORING|UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_OUTPUT_REVERSE, pErrorCode); |
| } |
| log_verbose(" l "); |
| printUnicode(logicalDest, logicalLength, ubidi_getLevels(pBiDi, pErrorCode)); |
| log_verbose("\n"); |
| log_verbose(" v "); |
| printUnicode(visualDest, visualLength, NULL); |
| log_verbose("\n"); |
| |
| /* check and print results */ |
| if(U_FAILURE(*pErrorCode)) { |
| log_err("inverse BiDi: *** error %s\n" |
| " turn on verbose mode to see details\n", u_errorName(*pErrorCode)); |
| } else if(srcLength==visualLength && memcmp(src, visualDest, srcLength*U_SIZEOF_UCHAR)==0) { |
| ++countRoundtrips; |
| log_verbose(" + roundtripped\n"); |
| } else { |
| ++countNonRoundtrips; |
| log_verbose(" * did not roundtrip\n"); |
| log_err("inverse BiDi: transformation visual->logical->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) || 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)); |
| } |
| |
| 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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) || 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(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; i<length; ++i) { |
| buffer[i]=charFromDirProp[dirProps[i]]; |
| } |
| buffer[length]=0; |
| return buffer; |
| } |
| |
| static void |
| printUnicode(const UChar *s, int32_t length, const UBiDiLevel *levels) { |
| int32_t i; |
| |
| log_verbose("{ "); |
| for(i=0; i<length; ++i) { |
| if(levels!=NULL) { |
| log_verbose("%4x.%u ", s[i], levels[i]); |
| } else { |
| log_verbose("%4x ", s[i]); |
| } |
| } |
| log_verbose(" }"); |
| } |
| |
| /* new BIDI API */ |
| |
| /* Reordering Mode BiDi --------------------------------------------------------- */ |
| |
| static const UBiDiLevel paraLevels[] = { UBIDI_LTR, UBIDI_RTL }; |
| |
| static UBool |
| assertSuccessful(const char* message, UErrorCode* rc) { |
| if (rc != NULL && U_FAILURE(*rc)) { |
| log_err("%s() failed with error %s.\n", message, myErrorName(*rc)); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| static UBool |
| assertStringsEqual(const char* expected, const char* actual, const char* src, |
| const char* mode, const char* option, UBiDi* pBiDi) { |
| if (uprv_strcmp(expected, actual)) { |
| char formatChars[MAXLEN]; |
| log_err("\nActual and expected output mismatch.\n" |
| "%20s %s\n%20s %s\n%20s %s\n%20s %s\n%20s %d %s\n%20s %u\n%20s %d %s\n", |
| "Input:", src, |
| "Actual output:", actual, |
| "Expected output:", expected, |
| "Levels:", formatLevels(pBiDi, formatChars), |
| "Reordering mode:", ubidi_getReorderingMode(pBiDi), mode, |
| "Paragraph level:", ubidi_getParaLevel(pBiDi), |
| "Reordering option:", ubidi_getReorderingOptions(pBiDi), option); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| static UBiDi* |
| getBiDiObject(void) { |
| UBiDi* pBiDi = ubidi_open(); |
| if (pBiDi == NULL) { |
| log_err("Unable to allocate a UBiDi object. Tests are skipped.\n"); |
| } |
| return pBiDi; |
| } |
| |
| #define MAKE_ITEMS(val) val, #val |
| |
| static const struct { |
| uint32_t value; |
| const char* description; |
| } |
| modes[] = { |
| { MAKE_ITEMS(UBIDI_REORDER_GROUP_NUMBERS_WITH_R) }, |
| { MAKE_ITEMS(UBIDI_REORDER_INVERSE_LIKE_DIRECT) }, |
| { MAKE_ITEMS(UBIDI_REORDER_NUMBERS_SPECIAL) }, |
| { MAKE_ITEMS(UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) }, |
| { MAKE_ITEMS(UBIDI_REORDER_INVERSE_NUMBERS_AS_L) } |
| }, |
| options[] = { |
| { MAKE_ITEMS(UBIDI_OPTION_INSERT_MARKS) }, |
| { MAKE_ITEMS(0) } |
| }; |
| |
| #define TC_COUNT LENGTHOF(textIn) |
| #define MODES_COUNT LENGTHOF(modes) |
| #define OPTIONS_COUNT LENGTHOF(options) |
| #define LEVELS_COUNT LENGTHOF(paraLevels) |
| |
| static const char* const textIn[] = { |
| /* (0) 123 */ |
| "123", |
| /* (1) .123->4.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 int32_t 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 int32_t 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[] = { |
| {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"}, |
| {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}}, |
| {"abcGHI", {{"GHIabc", "GHIabc"}, {"GHIabc", "GHIabc"}}, {0, 0}}, |
| {"a.>67->", {{"<-67<.a", "<-67<.a"}, {"<-67<.a", "<-67<.a"}}, {0, 0}}, |
| {"-=%$123/ *", {{"* /%$123=-", "* /%$123=-"}, |
| {"* /%$123=-", "* /%$123=-"}}, {0, 0}}, |
| {"abc->12..>JKL", {{"JKL<..12<-abc", "JKL<..abc->12"}, |
| {"JKL<..12<-abc", "JKL<..abc->12"}}, {0, 0}}, |
| {"JKL->12..>abc", {{"abc<..JKL->12", "abc<..12<-JKL"}, |
| {"abc<..JKL->12", "abc<..12<-JKL"}}, {0, 0}}, |
| {"123->abc", {{"abc<-123", "abc<-123"}, |
| {"abc&<-123", "abc<-123"}}, {1, 0}}, |
| {"123->JKL", {{"JKL<-123", "123->JKL"}, |
| {"JKL<-123", "JKL<-@123"}}, {0, 1}}, |
| {"*>12.>34->JKL", {{"JKL<-34<.12<*", "12.>34->JKL<*"}, |
| {"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", {{"$%123=-abc/ *", "abc-=$%123/ *"}, |
| {"$%123=-abc/ *", "abc-=$%123/ *"}}, {0, 0}}, |
| {"* /$%def-=123", {{"123=-def%$/ *", "def-=123%$/ *"}, |
| {"123=-def%$/ *", "def-=123%$/ *"}}, {0, 0}}, |
| {"-=GHI* /123%$", {{"GHI* /123%$=-", "123%$/ *GHI=-"}, |
| {"GHI* /123%$=-", "123%$/ *GHI=-"}}, {0, 0}}, |
| {"-=%$JKL* /123", {{"JKL* /%$123=-", "123/ *JKL$%=-"}, |
| {"JKL* /%$123=-", "123/ *JKL$%=-"}}, {0, 0}}, |
| {"ab =#CD *?450", {{"CD *?450#= ab", "450?* CD#= ab"}, |
| {"CD *?450#= ab", "450?* CD#= ab"}}, {0, 0}}, |
| {"ab 234 896 de", {{"de 896 ab 234", "de 896 ab 234"}, |
| {"ab 234 @896@ de", "de 896 ab 234"}}, {0, 0}}, |
| {"abc-=%$LMN* /123", {{"LMN* /%$123=-abc", "123/ *LMN$%=-abc"}, |
| {"LMN* /%$123=-abc", "123/ *LMN$%=-abc"}}, {0, 0}}, |
| {"123->JKL&MN&P", {{"JKLMNP<-123", "123->JKLMNP"}, |
| {"JKLMNP<-123", "JKLMNP<-@123"}}, {0, 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; |
| if(!pL2VBiDi) { |
| ubidi_close(pBiDi); /* in case this one was allocated */ |
| return; |
| } |
| 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_REMOVE_CONTROLS |
| : UBIDI_OPTION_INSERT_MARKS); |
| for (i = 0, nCases = LENGTHOF(testCases); i < nCases; i++) { |
| srcLen = strlen(testCases[i].textIn); |
| pseudoToU16(srcLen, testCases[i].textIn, src); |
| for(j = 0; j < 2; j++) { |
| 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; |
| uint32_t modeValue, modeBack, optionValue, optionBack; |
| 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(); |
| if(!pBiDi3) { |
| ubidi_close(pBiDi); /* in case this one was allocated */ |
| ubidi_close(pBiDi2); /* in case this one was allocated */ |
| return; |
| } |
| |
| 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++) { |
| modeValue = modes[mode].value; |
| ubidi_setReorderingMode(pBiDi, modeValue); |
| modeBack = ubidi_getReorderingMode(pBiDi); |
| if (modeValue != modeBack) { |
| log_err("Error while setting reordering mode to %d, returned %d\n", |
| modeValue, modeBack); |
| } |
| |
| for (option = 0; option < OPTIONS_COUNT; option++) { |
| optionValue = options[option].value; |
| ubidi_setReorderingOptions(pBiDi, optionValue); |
| optionBack = ubidi_getReorderingOptions(pBiDi); |
| if (optionValue != optionBack) { |
| log_err("Error while setting reordering option to %d, returned %d\n", |
| optionValue, optionBack); |
| } |
| |
| 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 && |
| memcmp(context, expectedContext, sizeOfContext)) { |
| log_err("Callback context content doesn't match the expected one.\n"); |
| } |
| } |
| |
| static void doBidiClassOverrideTest(void) { |
| static const char* const textSrc = "JIH.>12->a \\u05D0\\u05D1 6 ABC78"; |
| static const char* const textResult = "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, textSrcSize = (int32_t)uprv_strlen(textSrc); |
| char* destChars = NULL; |
| |
| log_verbose("\n*** Bidi class override test ***\n"); |
| |
| pBiDi = getBiDiObject(); |
| if(!pBiDi) { |
| return; |
| } |
| |
| ubidi_getClassCallback(pBiDi, &oldFn, &oldContext); |
| verifyCallbackParams(oldFn, oldContext, NULL, NULL, 0); |
| |
| ubidi_setClassCallback(pBiDi, newFn, textSrc, &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, textSrc, textSrcSize); |
| |
| ubidi_setClassCallback(pBiDi, newFn, textSrc, &oldFn, &oldContext, &rc); |
| if (!assertSuccessful("ubidi_setClassCallback", &rc)) { |
| ubidi_close(pBiDi); |
| return; |
| } |
| verifyCallbackParams(oldFn, oldContext, newFn, textSrc, textSrcSize); |
| |
| srcLen = u_unescape(textSrc, 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(textResult, destChars)) { |
| log_err("\nActual and expected output mismatch.\n" |
| "%20s %s\n%20s %s\n%20s %s\n", |
| "Input:", textSrc, "Actual output:", destChars, |
| "Expected output:", textResult); |
| } |
| else { |
| log_verbose("\nClass override test OK\n"); |
| } |
| ubidi_close(pBiDi); |
| } |
| |
| static char * formatMap(const int32_t * map, int len, char * buffer) |
| { |
| int32_t 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 (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 (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 (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 (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; |
| } |
| |