]> granicus.if.org Git - icu/commitdiff
ICU-11679 merge C BiDi Transform from branch
authorSteven R. Loomis <srl@icu-project.org>
Fri, 9 Sep 2016 16:41:15 +0000 (16:41 +0000)
committerSteven R. Loomis <srl@icu-project.org>
Fri, 9 Sep 2016 16:41:15 +0000 (16:41 +0000)
* fixed from branch: inadvertently removed Unicode attribution from Makefiles
* fixed from branch: Unicode attribution
* bonus: moved icuplug into the 'registration' filter on windows

X-SVN-Rev: 39170

12 files changed:
.gitattributes
.gitignore
icu4c/source/common/Makefile.in
icu4c/source/common/common.vcxproj
icu4c/source/common/common.vcxproj.filters
icu4c/source/common/ubiditransform.c [new file with mode: 0644]
icu4c/source/common/unicode/ubiditransform.h [new file with mode: 0644]
icu4c/source/test/cintltst/Makefile.in
icu4c/source/test/cintltst/calltest.c
icu4c/source/test/cintltst/cbiditransformtst.c [new file with mode: 0644]
icu4c/source/test/cintltst/cintltst.vcxproj
icu4c/source/test/cintltst/cintltst.vcxproj.filters

index b7a57346b8471aef845c32ce6258956ebdb06c76..dde3a76979abe0f524dd63615418ba6181ed7fda 100644 (file)
@@ -51,6 +51,8 @@ README text !eol
 icu4c/icu4c.css -text
 icu4c/source/aclocal.m4 -text
 icu4c/source/allinone/icucheck.bat -text
+icu4c/source/common/ubiditransform.c -text
+icu4c/source/common/unicode/ubiditransform.h -text
 icu4c/source/config/m4/icu-conditional.m4 -text
 icu4c/source/data/curr/pool.res -text
 icu4c/source/data/in/coll/ucadata-implicithan.icu -text
@@ -132,6 +134,7 @@ icu4c/source/samples/ugrep/ugrep.vcxproj -text
 icu4c/source/samples/uresb/resources.vcxproj -text
 icu4c/source/samples/uresb/uresb.vcxproj -text
 icu4c/source/samples/ustring/ustring.vcxproj -text
+icu4c/source/test/cintltst/cbiditransformtst.c -text
 icu4c/source/test/depstest/icu-dependencies-mode.el -text
 icu4c/source/test/iotest/iotest.vcxproj -text
 icu4c/source/test/letest/cletest.vcxproj -text
index bb7a6f9ff66cc9f6ea7974943b99e70c80bdac37..23bd593b58a49a0fc76dfbbe988b3bd277e11e70 100644 (file)
@@ -6,11 +6,15 @@ icu4c/lib64
 icu4c/source/Doxyfile
 icu4c/source/Makefile
 icu4c/source/README
+icu4c/source/allinone/*.db
 icu4c/source/allinone/*.ncb
+icu4c/source/allinone/*.opendb
 icu4c/source/allinone/*.opensdf
 icu4c/source/allinone/*.opt
 icu4c/source/allinone/*.sdf
 icu4c/source/allinone/*.suo
+icu4c/source/allinone/.vs
+icu4c/source/allinone/Debug
 icu4c/source/allinone/ipch
 icu4c/source/autom4te.cache
 icu4c/source/bin
index 25c042926d229d5a9ee392f95c4ebb0f9b5f275c..59ffb7377d7d846aa5dea84c3f4f37bfe6922e8a 100644 (file)
@@ -109,6 +109,7 @@ uidna.o usprep.o uts46.o punycode.o \
 util.o util_props.o parsepos.o locbased.o cwchar.o wintz.o dtintrv.o ucnvsel.o propsvec.o \
 ulist.o uloc_tag.o icudataver.o icuplug.o listformatter.o ulistformatter.o \
 sharedobject.o simpleformatter.o unifiedcache.o uloc_keytype.o \
+ubiditransform.o \
 pluralmap.o
 
 ## Header files to install
index 4574ddad9b376da557a2bd9c00a44d0d862d7512..e6c9acffb497c280c50cca9079e0dc436a6e37a0 100644 (file)
   <ItemGroup>
     <ClCompile Include="filteredbrk.cpp" />
     <ClCompile Include="ubidi.c" />
+    <ClCompile Include="ubiditransform.c" />
     <ClCompile Include="ubidi_props.c" />
     <ClCompile Include="ubidiln.c" />
     <ClCompile Include="ubidiwrt.c" />
     <ClInclude Include="uchar_props_data.h" />
     <ClInclude Include="ucol_data.h" />
     <ClInclude Include="ucol_swp.h" />
+    <ClInclude Include="unicode\ubiditransform.h" />
     <ClInclude Include="unistrappender.h" />
     <ClInclude Include="hash.h" />
     <ClInclude Include="propsvec.h" />
index aebb6cc404c333cf4e41344522dc7c55fc3d6004..56e8c12f04d276633769a6bc7d7df1ad76eb2dc6 100644 (file)
     <ClCompile Include="stringtriebuilder.cpp">
       <Filter>collections</Filter>
     </ClCompile>
-    <ClCompile Include="icuplug.cpp" />
     <ClCompile Include="uloc_keytype.cpp">
       <Filter>locales &amp; resources</Filter>
     </ClCompile>
     <ClCompile Include="filteredbrk.cpp">
       <Filter>break iteration</Filter>
     </ClCompile>
+    <ClCompile Include="icuplug.cpp">
+      <Filter>registration</Filter>
+    </ClCompile>
+    <ClCompile Include="ubiditransform.c">
+      <Filter>bidi</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="ubidi_props.h">
     <ClInclude Include="unicode\filteredbrk.h">
       <Filter>break iteration</Filter>
     </ClInclude>
+    <ClInclude Include="unicode\ubiditransform.h">
+      <Filter>bidi</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="common.rc">
       <Filter>collections</Filter>
     </CustomBuild>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/icu4c/source/common/ubiditransform.c b/icu4c/source/common/ubiditransform.c
new file mode 100644 (file)
index 0000000..c2d8f3c
--- /dev/null
@@ -0,0 +1,528 @@
+/*\r
+******************************************************************************\r
+*\r
+* Copyright (C) 2016 and later: Unicode, Inc. and others.\r
+* License & terms of use: http://www.unicode.org/copyright.html\r
+*\r
+******************************************************************************\r
+*   file name:  ubiditransform.c\r
+*   encoding:   US-ASCII\r
+*   tab size:   8 (not used)\r
+*   indentation:4\r
+*\r
+*   created on: 2016jul24\r
+*   created by: Lina Kemmel\r
+*\r
+*/\r
+\r
+#include "cmemory.h"\r
+#include "unicode/ubidi.h"\r
+#include "unicode/ustring.h"\r
+#include "unicode/ushape.h"\r
+#include "unicode/utf16.h"\r
+#include "ustr_imp.h"\r
+#include "unicode/ubiditransform.h"\r
+\r
+/* Some convenience defines */\r
+#define LTR                     UBIDI_LTR\r
+#define RTL                     UBIDI_RTL\r
+#define LOGICAL                 UBIDI_LOGICAL\r
+#define VISUAL                  UBIDI_VISUAL\r
+#define SHAPE_LOGICAL           U_SHAPE_TEXT_DIRECTION_LOGICAL\r
+#define SHAPE_VISUAL            U_SHAPE_TEXT_DIRECTION_VISUAL_LTR\r
+\r
+#define CHECK_LEN(STR, LEN, ERROR) { \\r
+        if (LEN == 0) return 0; \\r
+        if (LEN < -1) { *(ERROR) = U_ILLEGAL_ARGUMENT_ERROR; return 0; } \\r
+        if (LEN == -1) LEN = u_strlen(STR); \\r
+    } \r
+\r
+#define MAX_ACTIONS     7\r
+\r
+/**\r
+ * Typedef for a pointer to a function, which performs some operation (such as\r
+ * reordering, setting "inverse" mode, character mirroring, etc.). Return value\r
+ * indicates whether the text was changed in the course of this operation or\r
+ * not.\r
+ */\r
+typedef UBool (*UBiDiAction)(UBiDiTransform *, UErrorCode *);\r
+\r
+/**\r
+ * Structure that holds a predefined reordering scheme, including the following\r
+ * information:\r
+ * <ul>\r
+ * <li>an input base direction,</li>\r
+ * <li>an input order,</li>\r
+ * <li>an output base direction,</li>\r
+ * <li>an output order,</li>\r
+ * <li>a digit shaping direction,</li>\r
+ * <li>a letter shaping direction,</li>\r
+ * <li>a base direction that should be applied when the reordering engine is\r
+ *     invoked (which can not always be derived from the caller-defined\r
+ *     options),</li>\r
+ * <li>an array of pointers to functions that accomplish the bidi layout\r
+ *     transformation.</li>\r
+ * </ul>\r
+ */\r
+typedef struct {\r
+    UBiDiLevel        inLevel;               /* input level */\r
+    UBiDiOrder        inOrder;               /* input order */\r
+    UBiDiLevel        outLevel;              /* output level */\r
+    UBiDiOrder        outOrder;              /* output order */\r
+    uint32_t          digitsDir;             /* digit shaping direction */\r
+    uint32_t          lettersDir;            /* letter shaping direction */\r
+    UBiDiLevel        baseLevel;             /* paragraph level to be used with setPara */\r
+    const UBiDiAction actions[MAX_ACTIONS];  /* array of pointers to functions carrying out the transformation */\r
+} ReorderingScheme;\r
+\r
+struct UBiDiTransform {\r
+    UBiDi                   *pBidi;             /* pointer to a UBiDi object */\r
+    const ReorderingScheme  *pActiveScheme;     /* effective reordering scheme */\r
+    UChar                   *src;               /* input text */\r
+    UChar                   *dest;              /* output text */\r
+    uint32_t                srcLength;          /* input text length - not really needed as we are zero-terminated and can u_strlen */\r
+    uint32_t                srcSize;            /* input text capacity excluding the trailing zero */\r
+    uint32_t                destSize;           /* output text capacity */\r
+    uint32_t                *pDestLength;       /* number of UChars written to dest */\r
+    uint32_t                reorderingOptions;  /* reordering options - currently only suppot DO_MIRRORING */\r
+    uint32_t                digits;             /* digit option for ArabicShaping */\r
+    uint32_t                letters;            /* letter option for ArabicShaping */\r
+};\r
+\r
+U_DRAFT UBiDiTransform* U_EXPORT2\r
+ubiditransform_open(UErrorCode *pErrorCode)\r
+{\r
+    UBiDiTransform *pBiDiTransform = NULL;\r
+    if (U_SUCCESS(*pErrorCode)) {\r
+        pBiDiTransform = (UBiDiTransform*) uprv_calloc(1, sizeof(UBiDiTransform));\r
+        if (pBiDiTransform == NULL) {\r
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;\r
+        }\r
+    }\r
+    return pBiDiTransform;\r
+}\r
+\r
+U_DRAFT void U_EXPORT2\r
+ubiditransform_close(UBiDiTransform *pBiDiTransform)\r
+{\r
+    if (pBiDiTransform != NULL) {\r
+        if (pBiDiTransform->pBidi != NULL) {\r
+            ubidi_close(pBiDiTransform->pBidi);\r
+        }\r
+        if (pBiDiTransform->src != NULL) {\r
+            uprv_free(pBiDiTransform->src);\r
+        }\r
+        uprv_free(pBiDiTransform);\r
+    }\r
+}\r
+\r
+/**\r
+ * Performs Bidi resolution of text.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_resolve(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    ubidi_setPara(pTransform->pBidi, pTransform->src, pTransform->srcLength,\r
+            pTransform->pActiveScheme->baseLevel, NULL, pErrorCode);\r
+    return FALSE;\r
+}\r
+\r
+/**\r
+ * Performs basic reordering of text (Logical -> Visual LTR).\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_reorder(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    ubidi_writeReordered(pTransform->pBidi, pTransform->dest, pTransform->destSize,\r
+            pTransform->reorderingOptions, pErrorCode);\r
+\r
+    *pTransform->pDestLength = pTransform->srcLength;\r
+    pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;\r
+    return TRUE;\r
+}\r
+\r
+/**\r
+ * Sets "inverse" mode on the <code>UBiDi</code> object.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_setInverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    ubidi_setInverse(pTransform->pBidi, TRUE);\r
+    ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);\r
+    return FALSE;\r
+}\r
+\r
+/**\r
+ * Sets "runs only" reordering mode indicating a Logical LTR <-> Logical RTL\r
+ * transformation.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_setRunsOnly(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_RUNS_ONLY);\r
+    return FALSE;\r
+}\r
+\r
+/**\r
+ * Performs string reverse.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_reverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    ubidi_writeReverse(pTransform->src, pTransform->srcLength,\r
+            pTransform->dest, pTransform->destSize,\r
+            UBIDI_REORDER_DEFAULT, pErrorCode);\r
+    *pTransform->pDestLength = pTransform->srcLength;\r
+    return TRUE;\r
+}\r
+\r
+/**\r
+ * Applies a new value to the text that serves as input at the current\r
+ * processing step. This value is identical to the original one when we begin\r
+ * the processing, but usually changes as the transformation progresses.\r
+ * \r
+ * @param pTransform A pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param newSrc A pointer whose value is to be used as input text.\r
+ * @param newLength A length of the new text in <code>UChar</code>s.\r
+ * @param newSize A new source capacity in <code>UChar</code>s.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ */\r
+static void\r
+updateSrc(UBiDiTransform *pTransform, const UChar *newSrc, uint32_t newLength,\r
+        uint32_t newSize, UErrorCode *pErrorCode)\r
+{\r
+    if (newSize < newLength) {\r
+        *pErrorCode = U_BUFFER_OVERFLOW_ERROR;\r
+        return;\r
+    }\r
+    if (newSize > pTransform->srcSize) {\r
+        newSize += 50; // allocate slightly more than needed right now\r
+        if (pTransform->src != NULL) {\r
+            uprv_free(pTransform->src);\r
+            pTransform->src = NULL;\r
+        }\r
+        pTransform->src = (UChar *)uprv_malloc(newSize * sizeof(UChar));\r
+        if (pTransform->src == NULL) {\r
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;\r
+            //pTransform->srcLength = pTransform->srcSize = 0;\r
+            return;\r
+        }\r
+        pTransform->srcSize = newSize;\r
+    }\r
+    u_strncpy(pTransform->src, newSrc, newLength);\r
+    pTransform->srcLength = u_terminateUChars(pTransform->src,\r
+               pTransform->srcSize, newLength, pErrorCode);\r
+}\r
+\r
+/**\r
+ * Calls a lower level shaping function.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param options Shaping options.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ */\r
+static void\r
+doShape(UBiDiTransform *pTransform, uint32_t options, UErrorCode *pErrorCode)\r
+{\r
+    *pTransform->pDestLength = u_shapeArabic(pTransform->src,\r
+            pTransform->srcLength, pTransform->dest, pTransform->destSize,\r
+            options, pErrorCode);\r
+}\r
+\r
+/**\r
+ * Performs digit and letter shaping.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_shapeArabic(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    if ((pTransform->letters | pTransform->digits) == 0) {\r
+        return FALSE;\r
+    }\r
+    if (pTransform->pActiveScheme->lettersDir == pTransform->pActiveScheme->digitsDir) {\r
+        doShape(pTransform, pTransform->letters | pTransform->digits | pTransform->pActiveScheme->lettersDir,\r
+                pErrorCode);\r
+    } else {\r
+        doShape(pTransform, pTransform->digits | pTransform->pActiveScheme->digitsDir, pErrorCode);\r
+        if (U_SUCCESS(*pErrorCode)) {\r
+            updateSrc(pTransform, pTransform->dest, *pTransform->pDestLength,\r
+                    *pTransform->pDestLength, pErrorCode);\r
+            doShape(pTransform, pTransform->letters | pTransform->pActiveScheme->lettersDir,\r
+                    pErrorCode);\r
+        }\r
+    }\r
+    return TRUE;\r
+}\r
+\r
+/**\r
+ * Performs character mirroring.\r
+ * \r
+ * @param pTransform Pointer to the <code>UBiDiTransform</code> structure.\r
+ * @param pErrorCode Pointer to the error code value.\r
+ *\r
+ * @return Whether or not this function modifies the text. Besides the return\r
+ * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.\r
+ */\r
+static UBool\r
+action_mirror(UBiDiTransform *pTransform, UErrorCode *pErrorCode)\r
+{\r
+    UChar32 c;\r
+    uint32_t i = 0, j = 0;\r
+    if (0 == (pTransform->reorderingOptions & UBIDI_DO_MIRRORING)) {\r
+        return FALSE;\r
+    }\r
+    if (pTransform->destSize < pTransform->srcLength) {\r
+        *pErrorCode = U_BUFFER_OVERFLOW_ERROR;\r
+        return FALSE;\r
+    }\r
+    do {\r
+        UBool isOdd = ubidi_getLevelAt(pTransform->pBidi, i) & 1;\r
+        U16_NEXT(pTransform->src, i, pTransform->srcLength, c); \r
+        U16_APPEND_UNSAFE(pTransform->dest, j, isOdd ? u_charMirror(c) : c);\r
+    } while (i < pTransform->srcLength);\r
+    \r
+    *pTransform->pDestLength = pTransform->srcLength;\r
+    pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;\r
+    return TRUE;\r
+}\r
+\r
+/**\r
+ * All possible reordering schemes.\r
+ *\r
+ */\r
+static const ReorderingScheme Schemes[] =\r
+{\r
+    /* 0: Logical LTR => Visual LTR */\r
+    {LTR, LOGICAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,\r
+            {action_shapeArabic, action_resolve, action_reorder, NULL}},\r
+    /* 1: Logical RTL => Visual LTR */\r
+    {RTL, LOGICAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,\r
+            {action_resolve, action_reorder, action_shapeArabic, NULL}},\r
+    /* 2: Logical LTR => Visual RTL */\r
+    {LTR, LOGICAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,\r
+            {action_shapeArabic, action_resolve, action_reorder, action_reverse, NULL}},\r
+    /* 3: Logical RTL => Visual RTL */\r
+    {RTL, LOGICAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,\r
+            {action_resolve, action_reorder, action_shapeArabic, action_reverse, NULL}},\r
+    /* 4: Visual LTR => Logical RTL */\r
+    {LTR, VISUAL, RTL, LOGICAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,\r
+            {action_shapeArabic, action_setInverse, action_resolve, action_reorder, NULL}},\r
+    /* 5: Visual RTL => Logical RTL */\r
+    {RTL, VISUAL, RTL, LOGICAL, SHAPE_LOGICAL, SHAPE_VISUAL, RTL,\r
+            {action_reverse, action_shapeArabic, action_setInverse, action_resolve, action_reorder, NULL}},\r
+    /* 6: Visual LTR => Logical LTR */\r
+    {LTR, VISUAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,\r
+            {action_setInverse, action_resolve, action_reorder, action_shapeArabic, NULL}},\r
+    /* 7: Visual RTL => Logical LTR */\r
+    {RTL, VISUAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,\r
+            {action_reverse, action_setInverse, action_resolve, action_reorder, action_shapeArabic, NULL}},\r
+    /* 8: Logical LTR => Logical RTL */\r
+    {LTR, LOGICAL, RTL, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,\r
+            {action_shapeArabic, action_resolve, action_mirror, action_setRunsOnly, action_resolve, action_reorder, NULL}},\r
+    /* 9: Logical RTL => Logical LTR */\r
+    {RTL, LOGICAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, RTL,\r
+            {action_resolve, action_mirror, action_setRunsOnly, action_resolve, action_reorder, action_shapeArabic, NULL}},\r
+    /* 10: Visual LTR => Visual RTL */\r
+    {LTR, VISUAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,\r
+            {action_shapeArabic, action_setInverse, action_resolve, action_mirror, action_reverse, NULL}},\r
+    /* 11: Visual RTL => Visual LTR */\r
+    {RTL, VISUAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,\r
+            {action_reverse, action_shapeArabic, action_setInverse, action_resolve, action_mirror, NULL}},\r
+    /* 12: Logical LTR => Logical LTR */\r
+    {LTR, LOGICAL, LTR, LOGICAL, SHAPE_LOGICAL, SHAPE_LOGICAL, LTR,\r
+            {action_resolve, action_mirror, action_shapeArabic, NULL}},\r
+    /* 13: Logical RTL => Logical RTL */\r
+    {RTL, LOGICAL, RTL, LOGICAL, SHAPE_VISUAL, SHAPE_LOGICAL, RTL,\r
+            {action_resolve, action_mirror, action_shapeArabic, NULL}},\r
+    /* 14: Visual LTR => Visual LTR */\r
+    {LTR, VISUAL, LTR, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,\r
+            {action_resolve, action_mirror, action_shapeArabic, NULL}},\r
+    /* 15: Visual RTL => Visual RTL */\r
+    {RTL, VISUAL, RTL, VISUAL, SHAPE_LOGICAL, SHAPE_VISUAL, LTR,\r
+            {action_reverse, action_resolve, action_mirror, action_shapeArabic, action_reverse, NULL}}\r
+};\r
+\r
+static const uint32_t nSchemes = sizeof(Schemes) / sizeof(*Schemes);\r
+\r
+/**\r
+ * When the direction option is <code>UBIDI_DEFAULT_LTR</code> or\r
+ * <code>UBIDI_DEFAULT_RTL</code>, resolve the base direction according to that\r
+ * of the first strong bidi character.\r
+ */\r
+static void\r
+resolveBaseDirection(const UChar *text, uint32_t length,\r
+        UBiDiLevel *pInLevel, UBiDiLevel *pOutLevel)\r
+{\r
+    switch (*pInLevel) {\r
+        case UBIDI_DEFAULT_LTR:\r
+        case UBIDI_DEFAULT_RTL: {\r
+            UBiDiLevel level = ubidi_getBaseDirection(text, length);\r
+            *pInLevel = level != UBIDI_NEUTRAL ? level\r
+                    : *pInLevel == UBIDI_DEFAULT_RTL ? RTL : LTR;\r
+            break;\r
+        }\r
+        default:\r
+            *pInLevel &= 1;\r
+            break;\r
+    }\r
+    switch (*pOutLevel) {\r
+        case UBIDI_DEFAULT_LTR:\r
+        case UBIDI_DEFAULT_RTL:\r
+            *pOutLevel = *pInLevel;\r
+            break;\r
+        default:\r
+            *pOutLevel &= 1;\r
+            break;\r
+    }\r
+}\r
+\r
+/**\r
+ * Finds a valid <code>ReorderingScheme</code> matching the\r
+ * caller-defined scheme.\r
+ * \r
+ * @return A valid <code>ReorderingScheme</code> object or NULL\r
+ */\r
+static const ReorderingScheme*\r
+findMatchingScheme(UBiDiLevel inLevel, UBiDiLevel outLevel,\r
+        UBiDiOrder inOrder, UBiDiOrder outOrder)\r
+{\r
+    uint32_t i;\r
+    for (i = 0; i < nSchemes; i++) {\r
+        const ReorderingScheme *pScheme = Schemes + i;\r
+        if (inLevel == pScheme->inLevel && outLevel == pScheme->outLevel\r
+                && inOrder == pScheme->inOrder && outOrder == pScheme->outOrder) {\r
+            return pScheme;\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
+\r
+U_DRAFT uint32_t U_EXPORT2\r
+ubiditransform_transform(UBiDiTransform *pBiDiTransform,\r
+            const UChar *src, int32_t srcLength,\r
+            UChar *dest, int32_t destSize,\r
+            UBiDiLevel inParaLevel, UBiDiOrder inOrder,\r
+            UBiDiLevel outParaLevel, UBiDiOrder outOrder,\r
+            UBiDiMirroring doMirroring, uint32_t shapingOptions,\r
+            UErrorCode *pErrorCode)\r
+{\r
+    uint32_t destLength = 0;\r
+    UBool textChanged = FALSE;\r
+    const UBiDiTransform *pOrigTransform = pBiDiTransform;\r
+    const UBiDiAction *action = NULL;\r
+\r
+    if (U_FAILURE(*pErrorCode)) {\r
+        return 0;\r
+    }\r
+    if (src == NULL || dest == NULL) {\r
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;\r
+        return 0;\r
+    }\r
+    CHECK_LEN(src, srcLength, pErrorCode);\r
+    CHECK_LEN(dest, destSize, pErrorCode);\r
+\r
+    if (pBiDiTransform == NULL) {\r
+        pBiDiTransform = ubiditransform_open(pErrorCode);\r
+        if (U_FAILURE(*pErrorCode)) {\r
+            return 0;\r
+        }\r
+    }\r
+    /* Current limitation: in multiple paragraphs will be resolved according\r
+       to the 1st paragraph */\r
+    resolveBaseDirection(src, srcLength, &inParaLevel, &outParaLevel);\r
+\r
+    pBiDiTransform->pActiveScheme = findMatchingScheme(inParaLevel, outParaLevel,\r
+            inOrder, outOrder);\r
+    if (pBiDiTransform->pActiveScheme == NULL || pBiDiTransform->pActiveScheme->actions == NULL) {\r
+        goto cleanup;\r
+    }\r
+    pBiDiTransform->reorderingOptions = doMirroring ? UBIDI_DO_MIRRORING\r
+            : UBIDI_REORDER_DEFAULT;\r
+\r
+    /* Ignore TEXT_DIRECTION_* flags, as we apply our own depending on the text\r
+       scheme at the time shaping is invoked. */\r
+    shapingOptions &= ~U_SHAPE_TEXT_DIRECTION_MASK;\r
+    pBiDiTransform->digits = shapingOptions & ~U_SHAPE_LETTERS_MASK;\r
+    pBiDiTransform->letters = shapingOptions & ~U_SHAPE_DIGITS_MASK;\r
+\r
+    updateSrc(pBiDiTransform, src, srcLength, destSize > srcLength ? destSize : srcLength, pErrorCode);\r
+    if (U_FAILURE(*pErrorCode)) {\r
+        goto cleanup;\r
+    }\r
+    if (pBiDiTransform->pBidi == NULL) {\r
+        pBiDiTransform->pBidi = ubidi_openSized(0, 0, pErrorCode);\r
+        if (U_FAILURE(*pErrorCode)) {\r
+            goto cleanup;\r
+        }\r
+    }\r
+    pBiDiTransform->dest = dest;\r
+    pBiDiTransform->destSize = destSize;\r
+    pBiDiTransform->pDestLength = &destLength;\r
+\r
+    /* Checking for U_SUCCESS() within the loop to bail out on first failure. */\r
+    for (action = pBiDiTransform->pActiveScheme->actions; *action && U_SUCCESS(*pErrorCode); action++) {\r
+        if ((*action)(pBiDiTransform, pErrorCode)) {\r
+            if (action + 1) {\r
+                updateSrc(pBiDiTransform, pBiDiTransform->dest, *pBiDiTransform->pDestLength,\r
+                        *pBiDiTransform->pDestLength, pErrorCode);\r
+            }\r
+            textChanged = TRUE;\r
+        }\r
+    }\r
+    ubidi_setInverse(pBiDiTransform->pBidi, FALSE);\r
+\r
+    if (!textChanged && U_SUCCESS(*pErrorCode)) {\r
+        /* Text was not changed - just copy src to dest */\r
+        if (destSize < srcLength) {\r
+            *pErrorCode = U_BUFFER_OVERFLOW_ERROR;\r
+        } else {\r
+            u_strncpy(dest, src, srcLength);\r
+            destLength = srcLength;\r
+        }\r
+    }\r
+cleanup:\r
+    if (pOrigTransform != pBiDiTransform) {\r
+        ubiditransform_close(pBiDiTransform);\r
+    } else {\r
+        pBiDiTransform->dest = NULL;\r
+        pBiDiTransform->pDestLength = NULL;\r
+        pBiDiTransform->srcLength = 0;\r
+        pBiDiTransform->destSize = 0;\r
+    }\r
+    return U_FAILURE(*pErrorCode) ? 0 : destLength;\r
+}\r
diff --git a/icu4c/source/common/unicode/ubiditransform.h b/icu4c/source/common/unicode/ubiditransform.h
new file mode 100644 (file)
index 0000000..d3fbe9c
--- /dev/null
@@ -0,0 +1,312 @@
+/*\r
+******************************************************************************\r
+*\r
+* Copyright (C) 2016 and later: Unicode, Inc. and others.\r
+* License & terms of use: http://www.unicode.org/copyright.html\r
+*\r
+******************************************************************************\r
+*   file name:  ubiditransform.h\r
+*   encoding:   US-ASCII\r
+*   tab size:   8 (not used)\r
+*   indentation:4\r
+*\r
+*   created on: 2016jul24\r
+*   created by: Lina Kemmel\r
+*\r
+*/\r
+\r
+#ifndef UBIDITRANSFORM_H\r
+#define UBIDITRANSFORM_H\r
+\r
+#include "unicode/uchar.h"\r
+#include "unicode/localpointer.h"\r
+\r
+/**\r
+ * <code>UBiDiOrder</code> indicates the order of text.<p>\r
+ * This bidi transformation engine supports all possible combinations (4 in\r
+ * total) of input and output text order:\r
+ * <ul>\r
+ * <li><logical input, visual output>: unless the output direction is RTL, this\r
+ * corresponds to a normal operation of the Bidi algorithm as described in the\r
+ * Unicode Technical Report and implemented by <code>UBiDi</code> when the\r
+ * reordering mode is set to <code>UBIDI_REORDER_DEFAULT</code>. Visual RTL\r
+ * mode is not supported by <code>UBiDi</code> and is accomplished through\r
+ * reversing a visual LTR string,</li>\r
+ * <li><visual input, logical output>: unless the input direction is RTL, this\r
+ * corresponds to an "inverse bidi algorithm" in <code>UBiDi</code> with the\r
+ * reordering mode set to <code>UBIDI_REORDER_INVERSE_LIKE_DIRECT</code>.\r
+ * Visual RTL mode is not not supported by <code>UBiDi</code> and is\r
+ * accomplished through reversing a visual LTR string,</li>\r
+ * <li><logical input, logical output>: if the input and output base directions\r
+ * mismatch, this corresponds to the <code>UBiDi</code> implementation with the\r
+ * reordering mode set to <code>UBIDI_REORDER_RUNS_ONLY</code>; and if the\r
+ * input and output base directions are identical, the transformation engine\r
+ * will only handle character mirroring and Arabic shaping operations without\r
+ * reordering,</li>\r
+ * <li><visual input, visual output>: this reordering mode is not supported by\r
+ * the <code>UBiDi</code> engine; it implies character mirroring, Arabic\r
+ * shaping, and - if the input/output base directions mismatch -  string\r
+ * reverse operations.</li>\r
+ * </ul>\r
+ * @see ubidi_setInverse\r
+ * @see ubidi_setReorderingMode\r
+ * @see UBIDI_REORDER_DEFAULT\r
+ * @see UBIDI_REORDER_INVERSE_LIKE_DIRECT\r
+ * @see UBIDI_REORDER_RUNS_ONLY\r
+ * @draft ICU 58\r
+ */\r
+typedef enum {\r
+    /** 0: Constant indicating a logical order.\r
+      * This is the default for input text.\r
+      * @draft ICU 58\r
+      */\r
+    UBIDI_LOGICAL = 0,\r
+    /** 1: Constant indicating a visual order.\r
+      * This is a default for output text.\r
+      * @draft ICU 58\r
+      */\r
+    UBIDI_VISUAL\r
+} UBiDiOrder;\r
+\r
+/**\r
+ * <code>UBiDiMirroring</code> indicates whether or not characters with the\r
+ * "mirrored" property in RTL runs should be replaced with their mirror-image\r
+ * counterparts.\r
+ * @see UBIDI_DO_MIRRORING\r
+ * @see ubidi_setReorderingOptions\r
+ * @see ubidi_writeReordered\r
+ * @see ubidi_writeReverse\r
+ * @draft ICU 58\r
+ */\r
+typedef enum {\r
+    /** 0: Constant indicating that character mirroring should not be\r
+      * performed.\r
+      * This is the default.\r
+      * @draft ICU 58\r
+      */\r
+    UBIDI_MIRRORING_OFF = 0,\r
+    /** 1: Constant indicating that character mirroring should be performed.\r
+      * This corresponds to calling <code>ubidi_writeReordered</code> or\r
+      * <code>ubidi_writeReverse</code> with the\r
+      * <code>UBIDI_DO_MIRRORING</code> option bit set.\r
+      * @draft ICU 58\r
+      */\r
+    UBIDI_MIRRORING_ON\r
+} UBiDiMirroring;\r
+\r
+/**\r
+ * Forward declaration of the <code>UBiDiTransform</code> structure that stores\r
+ * information used by the layout transformation engine.\r
+ * @draft ICU 58\r
+ */\r
+typedef struct UBiDiTransform UBiDiTransform;\r
+\r
+/**\r
+ * Performs transformation of text from the bidi layout defined by the input\r
+ * ordering scheme to the bidi layout defined by the output ordering scheme,\r
+ * and applies character mirroring and Arabic shaping operations.<p>\r
+ * In terms of <code>UBiDi</code>, such a transformation implies:\r
+ * <li>calling <code>ubidi_setReorderingMode</code> as needed (when the\r
+ * reordering mode is other than normal),</li>\r
+ * <li>calling <code>ubidi_setInverse</code> as needed (when text should be\r
+ * transformed from a visual to a logical form),</li>\r
+ * <li>resolving embedding levels of each character in the input text by\r
+ * calling <code>ubidi_setPara</code>,</li>\r
+ * <li>reordering the characters based on the computed embedding levels, also\r
+ * performing character mirroring as needed, and streaming the result to the\r
+ * output, by calling <code>ubidi_writeReordered</code>,</li>\r
+ * <li>performing Arabic digit and letter shaping on the output text by calling\r
+ * <code>u_shapeArabic</code>.</li>\r
+ * </ul>\r
+ * An "ordering scheme" encompasses the base direction and the order of text,\r
+ * and these characteristics must be defined by the caller for both input and\r
+ * output explicitly .<p>\r
+ * There are 36 possible combinations of <input, output> ordering schemes,\r
+ * which are partially supported by <code>UBiDi</code> already. Examples of the\r
+ * currently supported combinations:\r
+ * <ul>\r
+ * <li><Logical LTR, Visual LTR>: this is equivalent to calling\r
+ * <code>ubidi_setPara</code> with <code>paraLevel == UBIDI_LTR</code>,</li>\r
+ * <li><Logical RTL, Visual LTR>: this is equivalent to calling\r
+ * <code>ubidi_setPara</code> with <code>paraLevel == UBIDI_RTL</code>,</li>\r
+ * <li><Logical Default ("Auto") LTR, Visual LTR>: this is equivalent to\r
+ * calling <code>ubidi_setPara</code> with \r
+ * <code>paraLevel == UBIDI_DEFAULT_LTR</code>,</li>\r
+ * <li><Logical Default ("Auto") RTL, Visual LTR>: this is equivalent to\r
+ * calling <code>ubidi_setPara</code> with\r
+ * <code>paraLevel == UBIDI_DEFAULT_RTL</code>,</li>\r
+ * <li><Visual LTR, Logical LTR>: this is equivalent to\r
+ * calling <code>ubidi_setInverse(UBiDi*, TRUE)</code> and then\r
+ * <code>ubidi_setPara</code> with <code>paraLevel == UBIDI_LTR</code>,</li>\r
+ * <li><Visual LTR, Logical RTL>: this is equivalent to\r
+ * calling <code>ubidi_setInverse(UBiDi*, TRUE)</code> and then\r
+ * <code>ubidi_setPara</code> with <code>paraLevel == UBIDI_RTL</code>.</li>\r
+ * </ul>\r
+ * All combinations that involve the Visual RTL scheme are unsupported by\r
+ * <code>UBiDi</code>, for instance:\r
+ * <ul>\r
+ * <li><Logical LTR, Visual RTL>,</li>\r
+ * <li><Visual RTL, Logical RTL>.</li>\r
+ * </ul>\r
+ * <p>Example of usage of the transformation engine:<br>\r
+ * <pre>\r
+ * \code\r
+ * UChar text1[] = {'a', 'b', 'c', 0x0625, '1', 0};\r
+ * UChar text2[] = {'a', 'b', 'c', 0x0625, '1', 0};\r
+ * UErrorCode errorCode = U_ZERO_ERROR;\r
+ * // Run a transformation.\r
+ * ubiditransform_transform(pBidiTransform,\r
+ *          text1, -1, text2, -1,\r
+ *          UBIDI_LTR, UBIDI_VISUAL,\r
+ *          UBIDI_RTL, UBIDI_LOGICAL,\r
+ *          UBIDI_MIRRORING_OFF,\r
+ *          U_SHAPE_DIGITS_AN2EN | U_SHAPE_DIGIT_TYPE_AN_EXTENDED,\r
+ *          &errorCode);\r
+ * // Do something with text2.\r
+ *  text2[4] = '2';\r
+ * // Run a reverse transformation.\r
+ * ubiditransform_transform(pBidiTransform,\r
+ *          text2, -1, text1, -1,\r
+ *          UBIDI_RTL, UBIDI_LOGICAL,\r
+ *          UBIDI_LTR, UBIDI_VISUAL,\r
+ *          UBIDI_MIRRORING_OFF,\r
+ *          U_SHAPE_DIGITS_EN2AN | U_SHAPE_DIGIT_TYPE_AN_EXTENDED,\r
+ *          &errorCode);\r
+ *\endcode\r
+ * </pre>\r
+ * </p>\r
+ *\r
+ * @param pBiDiTransform A pointer to a <code>UBiDiTransform</code> object\r
+ *        allocated with <code>ubiditransform_open()</code> or\r
+ *        <code>NULL</code>.<p>\r
+ *        This object serves for one-time setup to amortize initialization\r
+ *        overheads. Use of this object is not thread-safe. All other threads\r
+ *        should allocate a new <code>UBiDiTransform</code> object by calling\r
+ *        <code>ubiditransform_open()</code> before using it. Alternatively,\r
+ *        a caller can set this parameter to <code>NULL</code>, in which case\r
+ *        the object will be allocated by the engine on the fly.</p>\r
+ * @param src A pointer to the text that the Bidi layout transformations will\r
+ *        be performed on.\r
+ *        <p><strong>Note:</strong> the text must be (at least)\r
+ *        <code>srcLength</code> long.</p>\r
+ * @param srcLength The length of the text, in number of UChars. If\r
+ *        <code>length == -1</code> then the text must be zero-terminated.\r
+ * @param dest A pointer to where the processed text is to be copied.\r
+ * @param destSize The size of the <code>dest</code> buffer, in number of\r
+ *        UChars. If the <code>U_SHAPE_LETTERS_UNSHAPE</code> option is set,\r
+ *        then the destination length could be as large as\r
+ *        <code>srcLength * 2</code>. Otherwise, the destination length will\r
+ *        not exceed <code>srcLength</code>. If the caller reserves the last\r
+ *        position for zero-termination, it should be excluded from\r
+ *        <code>destSize</code>.\r
+ *        <p><code>destSize == -1</code> is allowed and makes sense when\r
+ *        <code>dest</code> was holds some meaningful value, e.g. that of\r
+ *        <code>src</code>. In this case <code>dest</code> must be\r
+ *        zero-terminated.</p>\r
+ * @param inParaLevel A base embedding level of the input as defined in\r
+ *        <code>ubidi_setPara</code> documentation for the\r
+ *        <code>paraLevel</code> parameter.\r
+ * @param inOrder An order of the input, which can be one of the\r
+ *        <code>UBiDiOrder</code> values.\r
+ * @param outParaLevel A base embedding level of the output as defined in\r
+ *        <code>ubidi_setPara</code> documentation for the\r
+ *        <code>paraLevel</code> parameter.\r
+ * @param outOrder An order of the output, which can be one of the\r
+ *        <code>UBiDiOrder</code> values.\r
+ * @param doMirroring Indicates whether or not to perform character mirroring,\r
+ *        and can accept one of the <code>UBiDiMirroring</code> values.\r
+ * @param shapingOptions Arabic digit and letter shaping options defined in the\r
+ *        ushape.h documentation.\r
+ *        <p><strong>Note:</strong> Direction indicator options are computed by\r
+ *        the transformation engine based on the effective ordering schemes, so\r
+ *        user-defined direction indicators will be ignored.</p>\r
+ * @param pErrorCode A pointer to an error code value.\r
+ *\r
+ * @return The destination length, i.e. the number of UChars written to\r
+ *         <code>dest</code>. If the transformation fails, the return value\r
+ *         will be 0 (and the error code will be written to\r
+ *         <code>pErrorCode</code>).\r
+ *\r
+ * @see UBiDiLevel\r
+ * @see UBiDiOrder\r
+ * @see UBiDiMirroring\r
+ * @see ubidi_setPara\r
+ * @see u_shapeArabic\r
+ * @draft ICU 58\r
+ */\r
+U_DRAFT uint32_t U_EXPORT2\r
+ubiditransform_transform(UBiDiTransform *pBiDiTransform,\r
+            const UChar *src, int32_t srcLength,\r
+            UChar *dest, int32_t destSize,\r
+            UBiDiLevel inParaLevel, UBiDiOrder inOrder,\r
+            UBiDiLevel outParaLevel, UBiDiOrder outOrder,\r
+            UBiDiMirroring doMirroring, uint32_t shapingOptions,\r
+            UErrorCode *pErrorCode);\r
+\r
+/**\r
+ * Allocates a <code>UBiDiTransform</code> object. This object can be reused,\r
+ * e.g. with different ordering schemes, mirroring or shaping options.<p>\r
+ * <strong>Note:</strong>The object can only be reused in the same thread.\r
+ * All other threads should allocate a new <code>UBiDiTransform</code> object\r
+ * before using it.<p>\r
+ * Example of usage:<p>\r
+ * <pre>\r
+ * \code\r
+ * UErrorCode errorCode = U_ZERO_ERROR;\r
+ * // Open a new UBiDiTransform.\r
+ * UBiDiTransform* transform = ubiditransform_open(&errorCode);\r
+ * // Run a transformation.\r
+ * ubiditransform_transform(transform,\r
+ *          text1, -1, text2, -1,\r
+ *          UBIDI_RTL, UBIDI_LOGICAL,\r
+ *          UBIDI_LTR, UBIDI_VISUAL,\r
+ *          UBIDI_MIRRORING_ON,\r
+ *          U_SHAPE_DIGITS_EN2AN,\r
+ *          &errorCode);\r
+ * // Do something with the output text and invoke another transformation using\r
+ * //   that text as input.\r
+ * ubiditransform_transform(transform,\r
+ *          text2, -1, text3, -1,\r
+ *          UBIDI_LTR, UBIDI_VISUAL,\r
+ *          UBIDI_RTL, UBIDI_VISUAL,\r
+ *          UBIDI_MIRRORING_ON,\r
+ *          0, &errorCode);\r
+ *\endcode\r
+ * </pre>\r
+ * <p>\r
+ * The <code>UBiDiTransform</code> object must be deallocated by calling\r
+ * <code>ubiditransform_close()</code>.\r
+ *\r
+ * @return An empty <code>UBiDiTransform</code> object.\r
+ * @draft ICU 58\r
+ */\r
+U_DRAFT UBiDiTransform* U_EXPORT2\r
+ubiditransform_open(UErrorCode *pErrorCode);\r
+\r
+/**\r
+ * Deallocates the given <code>UBiDiTransform</code> object.\r
+ * @draft ICU 58\r
+ */\r
+U_DRAFT void U_EXPORT2\r
+ubiditransform_close(UBiDiTransform *pBidiTransform);\r
+\r
+#if U_SHOW_CPLUSPLUS_API\r
+\r
+U_NAMESPACE_BEGIN\r
+\r
+/**\r
+ * \class LocalUBiDiTransformPointer\r
+ * "Smart pointer" class, closes a UBiDiTransform via ubiditransform_close().\r
+ * For most methods see the LocalPointerBase base class.\r
+ *\r
+ * @see LocalPointerBase\r
+ * @see LocalPointer\r
+ * @draft ICU 58\r
+ */\r
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUBiDiTransformPointer, UBiDiTransform, ubiditransform_close);\r
+\r
+U_NAMESPACE_END\r
+\r
+#endif\r
+\r
+#endif\r
index 904b2bec22ace894d4a10fbcaa9e0a55b8d72b9d..f60bb66db83d30768259ceb8ee918de216d41d57 100644 (file)
@@ -53,6 +53,7 @@ uenumtst.o utmstest.o currtest.o \
 idnatest.o nfsprep.o spreptst.o sprpdata.o \
 hpmufn.o tracetst.o reapits.o uregiontest.o ulistfmttest.o\
 utexttst.o ucsdetst.o spooftest.o \
+cbiditransformtst.o \
 cgendtst.o
 
 DEPS = $(OBJECTS:.o=.d)
index c35aae1268a42b86334906391805207dbc217775..e759be8f6b7417d632ab269a359fc8727859db99 100644 (file)
@@ -25,6 +25,7 @@ void addFormatTest(TestNode** root);
 void addConvert(TestNode** root);
 void addCollTest(TestNode** root);
 void addComplexTest(TestNode** root);
+void addBidiTransformTest(TestNode** root);
 void addUDataTest(TestNode** root);
 void addUTF16Test(TestNode** root);
 void addUTF8Test(TestNode** root);
@@ -60,6 +61,7 @@ void addAllTests(TestNode** root)
     addStandardNamesTest(root);
     addUCsdetTest(root);
     addComplexTest(root);
+    addBidiTransformTest(root);
     addUSetTest(root);
 #if !UCONFIG_NO_IDNA
     addUStringPrepTest(root);
diff --git a/icu4c/source/test/cintltst/cbiditransformtst.c b/icu4c/source/test/cintltst/cbiditransformtst.c
new file mode 100644 (file)
index 0000000..0e18d1e
--- /dev/null
@@ -0,0 +1,430 @@
+/********************************************************************\r
+ * Copyright (C) 2016 and later: Unicode, Inc. and others.\r
+ * License & terms of use: http://www.unicode.org/copyright.html\r
+ ********************************************************************/\r
+/*   file name:  cbiditransformtst.c\r
+ *   encoding:   US-ASCII\r
+ *   tab size:   8 (not used)\r
+ *   indentation:4\r
+ *\r
+ *   created on: 2016aug21\r
+ *   created by: Lina Kemmel\r
+*/\r
+\r
+#include "cintltst.h"\r
+#include "unicode/ubidi.h"\r
+#include "unicode/ubiditransform.h"\r
+#include "unicode/ushape.h"\r
+#include "unicode/ustring.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define     LATN_ZERO           0x0030\r
+#define     ARAB_ZERO           0x0660\r
+#define     MIN_HEB_LETTER      0x05D0\r
+#define     MIN_ARAB_LETTER     0x0630\r
+#define     MIN_SHAPED_LETTER   0xFEAB\r
+\r
+#define     STR_CAPACITY        100\r
+\r
+typedef struct {\r
+    UBiDiLevel  inLevel;\r
+    UBiDiOrder  inOr;\r
+    UBiDiLevel  outLevel;\r
+    UBiDiOrder  outOr;\r
+    const char  *pReorderNoMirror;\r
+    const char  *pReorderAndMirror;\r
+    const char  *pContextShapes;\r
+    const char  *pMessage;\r
+} UBidiTestCases;\r
+\r
+UChar src[STR_CAPACITY] = { 0 };\r
+UChar dest[STR_CAPACITY] = { 0 };\r
+UChar expected[STR_CAPACITY] = { 0 };\r
+UChar temp[STR_CAPACITY * 2] = { 0 };\r
+char pseudo[STR_CAPACITY] = { 0 };\r
+\r
+void addBidiTransformTest(TestNode** root);\r
+\r
+static void testAutoDirection(void);\r
+\r
+static void testAllTransformOptions(void);\r
+\r
+static char* pseudoScript(const UChar *str);\r
+\r
+static void shapeDigits(UChar *str, uint32_t digits);\r
+\r
+static void logResultsForDir(const UChar *srcText, const UChar *destTxt,\r
+            const UChar *expectedTxt, UBiDiLevel inLevel, UBiDiLevel outLevel);\r
+\r
+static void verifyResultsForAllOpt(const UBidiTestCases *pTest, const UChar *srcTxt,\r
+            const UChar *destTxt, const char *expectedChars, uint32_t digits,\r
+            uint32_t letters);\r
+\r
+#if 0\r
+static void substituteByPseudoChar(const UChar *src, char *dest,\r
+            const UChar baseReal, const char basePseudo, const char max);\r
+\r
+\r
+/* TODO: This code assumes the codepage is ASCII based. */\r
+\r
+/*\r
+ * Using the following conventions:\r
+ * AL unshaped: A-E\r
+ * AL shaped: F-J\r
+ * R:  K-Z\r
+ * EN: 0-4\r
+ * AN: 5-9\r
+*/\r
+static void\r
+substituteByPseudoChar(const UChar *src, char *dest, const UChar baseReal,\r
+           const char basePseudo, const char max) {\r
+    *dest = basePseudo + (*src - baseReal); /* (range math won't work on EBCDIC) */\r
+    if (*dest > max) {\r
+        *dest = max;\r
+    }\r
+}\r
+\r
+static char*\r
+pseudoScript(const UChar *str) {\r
+    char *p;\r
+    if (!str) {\r
+        return "\0";\r
+    }\r
+    for (p = pseudo; *str; str++, p++) {\r
+        switch (u_charDirection(*str)) {\r
+            case U_RIGHT_TO_LEFT:\r
+                substituteByPseudoChar(str, p, MIN_HEB_LETTER, 'K', 'Z');\r
+                break;\r
+            case U_RIGHT_TO_LEFT_ARABIC:\r
+                if (*str > 0xFE00) {\r
+                    substituteByPseudoChar(str, p, MIN_SHAPED_LETTER, 'F', 'J');\r
+                } else {\r
+                    substituteByPseudoChar(str, p, MIN_ARAB_LETTER, 'A', 'E');\r
+                }\r
+                break;\r
+            case U_ARABIC_NUMBER:\r
+                substituteByPseudoChar(str, p, ARAB_ZERO, '5', '9');\r
+                break;\r
+            default:\r
+                *p = (char)*str;\r
+                break;\r
+        }\r
+    }\r
+    *p = '\0';\r
+    return pseudo;\r
+}\r
+#else\r
+static char*\r
+pseudoScript(const UChar *str) {\r
+    return aescstrdup(str, -1);\r
+}\r
+#endif\r
+\r
+static void\r
+logResultsForDir(const UChar *srcTxt, const UChar *destTxt, const UChar *expectedTxt,\r
+            UBiDiLevel inLevel, UBiDiLevel outLevel)\r
+{\r
+    if (u_strcmp(expectedTxt, destTxt)) {\r
+        log_err("Unexpected transform Dest: inLevel: 0x%02x; outLevel: 0x%02x;\ninText: %s; outText: %s; expected: %s\n",\r
+                inLevel, outLevel, pseudoScript(srcTxt), pseudoScript(destTxt), pseudoScript(expectedTxt));\r
+    }\r
+}\r
+\r
+/**\r
+ * Tests various combinations of base directions, with the input either\r
+ * <code>UBIDI_DEFAULT_LTR</code> or <code>UBIDI_DEFAULT_RTL</code>, and the\r
+ * output either <code>UBIDI_LTR</code> or <code>UBIDI_RTL</code>. Order is\r
+ * always <code>UBIDI_LOGICAL</code> for the input and <code>UBIDI_VISUAL</code>\r
+ * for the output.\r
+ */\r
+static void\r
+testAutoDirection(void)\r
+{\r
+    static const UBiDiLevel inLevels[] = {\r
+        UBIDI_DEFAULT_LTR, UBIDI_DEFAULT_RTL\r
+    };\r
+    static const UBiDiLevel outLevels[] = {\r
+        UBIDI_LTR, UBIDI_RTL\r
+    };\r
+    static const char *srcTexts[] = {\r
+        "abc \\u05d0\\u05d1\0",\r
+        "... abc \\u05d0\\u05d1\0",\r
+        "\\u05d0\\u05d1 abc\0",\r
+        "... \\u05d0\\u05d1 abc\0",\r
+        ".*:"\r
+    };\r
+    uint32_t nTexts = sizeof(srcTexts) / sizeof(srcTexts[0]);\r
+    uint32_t i, nInLevels = sizeof(inLevels) / sizeof(inLevels[0]);\r
+    uint32_t j, nOutLevels = sizeof(outLevels) / sizeof(outLevels[0]);\r
+\r
+    UBiDi *pBidi = ubidi_open();\r
+\r
+    UErrorCode errorCode = U_ZERO_ERROR;\r
+    UBiDiTransform *pTransform = ubiditransform_open(&errorCode);\r
+\r
+    while (nTexts-- > 0) {\r
+        uint32_t srcLen;\r
+        u_unescape(srcTexts[nTexts], src, STR_CAPACITY);\r
+        srcLen = u_strlen(src);\r
+        for (i = 0; i < nInLevels; i++) {\r
+            for (j = 0; j < nOutLevels; j++) {\r
+                ubiditransform_transform(pTransform, src, -1, dest, STR_CAPACITY - 1,\r
+                        inLevels[i], UBIDI_LOGICAL, outLevels[j], UBIDI_VISUAL,\r
+                        UBIDI_MIRRORING_OFF, 0, &errorCode);\r
+                /* Use UBiDi as a model we compare to */\r
+                ubidi_setPara(pBidi, src, srcLen, inLevels[i], NULL, &errorCode);\r
+                ubidi_writeReordered(pBidi, expected, STR_CAPACITY, UBIDI_REORDER_DEFAULT, &errorCode);\r
+                if (outLevels[j] == UBIDI_RTL) {\r
+                    ubidi_writeReverse(expected, u_strlen(expected), temp, STR_CAPACITY,\r
+                            UBIDI_OUTPUT_REVERSE, &errorCode);\r
+                    logResultsForDir(src, dest, temp, inLevels[i], outLevels[j]);\r
+                } else {\r
+                    logResultsForDir(src, dest, expected, inLevels[i], outLevels[j]);\r
+                }\r
+            }\r
+        }\r
+    }\r
+    ubidi_close(pBidi);\r
+    ubiditransform_close(pTransform);\r
+}\r
+\r
+static void\r
+shapeDigits(UChar *str, uint32_t digits)\r
+{\r
+    const UChar srcZero = (digits & U_SHAPE_DIGITS_EN2AN) ? LATN_ZERO : ARAB_ZERO;\r
+    const UChar extent = srcZero == ARAB_ZERO ? LATN_ZERO - ARAB_ZERO : ARAB_ZERO - LATN_ZERO;\r
+    UChar32 c = 0;\r
+    uint32_t i = 0, j, length = u_strlen(str);\r
+    while (i < length) {\r
+        j = i;\r
+        U16_NEXT(str, i, length, c); \r
+        if (c >= srcZero && c <= srcZero + 9) {\r
+            /* length of c here is always a single UChar16 */\r
+            str[j] = c + extent;\r
+        }\r
+    }\r
+}\r
+\r
+static void\r
+verifyResultsForAllOpt(const UBidiTestCases *pTest, const UChar *srcTxt,\r
+        const UChar *destTxt, const char *expectedChars, uint32_t digits, uint32_t letters)\r
+{\r
+    switch (digits) {\r
+        case U_SHAPE_DIGITS_EN2AN:\r
+        case U_SHAPE_DIGITS_AN2EN:\r
+            u_unescape(expectedChars, expected, STR_CAPACITY);\r
+            shapeDigits(expected, digits);\r
+            break;\r
+        case U_SHAPE_DIGITS_ALEN2AN_INIT_LR:\r
+            u_unescape(pTest->pContextShapes, expected, STR_CAPACITY);\r
+            break;\r
+        case U_SHAPE_DIGITS_NOOP:\r
+            u_unescape(expectedChars, expected, STR_CAPACITY);\r
+            break;\r
+    }\r
+    if (letters & U_SHAPE_LETTERS_SHAPE) {\r
+        uint32_t i = 0, j, length = u_strlen(expected);\r
+        UChar32 c = 0;\r
+        while (i < length) {\r
+            j = i;\r
+            U16_NEXT(expected, i, length, c); \r
+            /* below the length of old and new values is always a single\r
+               UChar16, so can just assign a new value to expected[j] */\r
+            if (c == 0x0630) {\r
+                expected[j] = 0xfeab;\r
+            } else if (c == 0x0631) {\r
+                expected[j] = 0xfead;\r
+            } else if (c == 0x0632) {\r
+                expected[j] = 0xfeaf;\r
+            }\r
+        }\r
+    }\r
+    if (u_strcmp(expected, dest)) {\r
+        log_err("Unexpected transform Dest: Test: %s; Digits: 0x%08x; Letters: 0x%08x\ninText: %s; outText: %s; expected: %s\n",\r
+                pTest->pMessage, digits, letters, pseudoScript(srcTxt), pseudoScript(destTxt), pseudoScript(expected));\r
+    }\r
+}\r
+\r
+/**\r
+ * This function covers:\r
+ * <ul>\r
+ * <li>all possible combinations of ordering schemes and <strong>explicit</strong>\r
+ * base directions, applied to both input and output,</li>\r
+ * <li>selected tests for auto direction (systematically, auto direction is\r
+ * covered in a dedicated test) applied on both input and output,</li>\r
+ * <li>all possible combinations of mirroring, digits and letters applied\r
+ * to output only.</li>\r
+ * </ul>\r
+ */\r
+static void\r
+testAllTransformOptions(void)\r
+{\r
+    static const char *inText =\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662\0";\r
+\r
+    static const UBidiTestCases testCases[] = {\r
+        { UBIDI_LTR, UBIDI_LOGICAL,\r
+            UBIDI_LTR, UBIDI_LOGICAL,\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662\0", // reordering no mirroring\r
+            "a[b]c \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662", // mirroring\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u0662\\u0663\\u0660 e\\u0631\\u0664 f \\u0632 \\u0661\\u0662", // context numeric shaping\r
+            "1: Logical LTR ==> Logical LTR" },\r
+        { UBIDI_LTR, UBIDI_LOGICAL, UBIDI_LTR, UBIDI_VISUAL,\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d \\u0662\\u0663\\u0660 \\u0630 e\\u0664\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "2: Logical LTR ==> Visual LTR" },\r
+        { UBIDI_LTR, UBIDI_LOGICAL, UBIDI_RTL, UBIDI_LOGICAL,\r
+            "\\u0632 \\u0661\\u0662 f \\u0631e4 \\u0630 23\\u0660 d \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 a[b]c",\r
+            "\\u0632 \\u0661\\u0662 f \\u0631e4 \\u0630 23\\u0660 d \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 a[b]c",\r
+            "\\u0632 \\u0661\\u0662 f \\u0631e\\u0664 \\u0630 \\u0662\\u0663\\u0660 d \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 a[b]c",\r
+            "3: Logical LTR ==> Logical RTL" },\r
+        { UBIDI_LTR, UBIDI_LOGICAL, UBIDI_RTL, UBIDI_VISUAL,\r
+            "\\u0632 \\u0662\\u0661 f \\u06314e \\u0630 \\u066032 d \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 c]b[a",\r
+            "\\u0632 \\u0662\\u0661 f \\u06314e \\u0630 \\u066032 d \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 c]b[a",\r
+            "\\u0632 \\u0662\\u0661 f \\u0631\\u0664e \\u0630 \\u0660\\u0663\\u0662 d \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 c]b[a",\r
+            "4: Logical LTR ==> Visual RTL" },\r
+        { UBIDI_RTL, UBIDI_LOGICAL, UBIDI_RTL, UBIDI_LOGICAL,\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662\0",\r
+            "a[b]c \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662", // mirroring\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662",\r
+            "5: Logical RTL ==> Logical RTL" },\r
+        { UBIDI_RTL, UBIDI_LOGICAL, UBIDI_RTL, UBIDI_VISUAL,\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "6: Logical RTL ==> Visual RTL" },\r
+        { UBIDI_RTL, UBIDI_LOGICAL, UBIDI_LTR, UBIDI_LOGICAL,\r
+            "\\u0632 \\u0661\\u0662 f 4\\u0631e 23\\u0630 \\u0660 d 1 \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 a[b]c",\r
+            "\\u0632 \\u0661\\u0662 f 4\\u0631e 23\\u0630 \\u0660 d 1 \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 a[b]c",\r
+            "\\u0632 \\u0661\\u0662 f 4\\u0631e 23\\u0630 \\u0660 d 1 \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 a[b]c",\r
+            "7: Logical RTL ==> Logical LTR" },\r
+        { UBIDI_RTL, UBIDI_LOGICAL, UBIDI_LTR, UBIDI_VISUAL,\r
+            "\\u0661\\u0662 \\u0632 f 4\\u0631e 23\\u0660 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 a[b]c",\r
+            "\\u0661\\u0662 \\u0632 f 4\\u0631e 23\\u0660 \\u0630 d 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 a[b]c",\r
+            "\\u0661\\u0662 \\u0632 f 4\\u0631e 23\\u0660 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 a[b]c",\r
+            "8: Logical RTL ==> Visual LTR" },\r
+        { UBIDI_LTR, UBIDI_VISUAL, UBIDI_LTR, UBIDI_VISUAL, \r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662\0",\r
+            "a[b]c \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662", // mirroring\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u0662\\u0663\\u0660 e\\u0631\\u0664 f \\u0632 \\u0661\\u0662",\r
+            "9: Visual LTR ==> Visual LTR" },\r
+        { UBIDI_LTR, UBIDI_VISUAL, UBIDI_LTR, UBIDI_LOGICAL,\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "10: Visual LTR ==> Logical LTR" },\r
+        { UBIDI_LTR, UBIDI_VISUAL, UBIDI_RTL, UBIDI_VISUAL,\r
+            "\\u0662\\u0661 \\u0632 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 c]b[a",\r
+            "\\u0662\\u0661 \\u0632 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 c]b[a",\r
+            "\\u0662\\u0661 \\u0632 f \\u0664\\u0631e \\u0660\\u0663\\u0662 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 c]b[a",\r
+            "11: Visual LTR ==> Visual RTL" },\r
+        { UBIDI_LTR, UBIDI_VISUAL, UBIDI_RTL, UBIDI_LOGICAL,\r
+            "\\u0661\\u0662 \\u0632 f 4\\u0631e 23\\u0660 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 a[b]c",\r
+            "\\u0661\\u0662 \\u0632 f 4\\u0631e 23\\u0660 \\u0630 d 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 a[b]c",\r
+            "\\u0661\\u0662 \\u0632 f \\u0664\\u0631e \\u0662\\u0663\\u0660 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 a[b]c",\r
+            "12: Visual LTR ==> Logical RTL" }, \r
+        { UBIDI_RTL, UBIDI_VISUAL, UBIDI_RTL, UBIDI_VISUAL,\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662\0",\r
+            "a[b]c \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662",\r
+            "a[b]c \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 23\\u0660 e\\u06314 f \\u0632 \\u0661\\u0662",\r
+            "13: Visual RTL ==> Visual RTL" },\r
+        { UBIDI_RTL, UBIDI_VISUAL, UBIDI_RTL, UBIDI_LOGICAL,\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "14: Visual RTL ==> Logical RTL" },\r
+        { UBIDI_RTL, UBIDI_VISUAL, UBIDI_LTR, UBIDI_VISUAL,\r
+            "\\u0662\\u0661 \\u0632 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 c]b[a",\r
+            "\\u0662\\u0661 \\u0632 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 c]b[a",\r
+            "\\u0662\\u0661 \\u0632 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 c]b[a",\r
+            "15: Visual RTL ==> Visual LTR" },\r
+        { UBIDI_RTL, UBIDI_VISUAL, UBIDI_LTR, UBIDI_LOGICAL,\r
+            "\\u0632 \\u0662\\u0661 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 c]b[a",\r
+            "\\u0632 \\u0662\\u0661 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 c]b[a",\r
+            "\\u0632 \\u0662\\u0661 f 4\\u0631e \\u066032 \\u0630 d 1 \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 c]b[a",\r
+            "16: Visual RTL ==> Logical LTR" },\r
+\r
+        { UBIDI_DEFAULT_RTL, UBIDI_LOGICAL, UBIDI_LTR, UBIDI_VISUAL,\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d \\u0662\\u0663\\u0660 \\u0630 e\\u0664\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "17: Logical DEFAULT_RTL ==> Visual LTR" },\r
+#if 0\r
+        { UBIDI_RTL, UBIDI_LOGICAL, UBIDI_DEFAULT_LTR, UBIDI_VISUAL,\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "18: Logical RTL ==> Visual DEFAULT_LTR" },\r
+#endif\r
+        { UBIDI_DEFAULT_LTR, UBIDI_LOGICAL, UBIDI_LTR, UBIDI_VISUAL,\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4(\\u05d3 \\u05d2\\u05d1)\\u05d0 d 23\\u0660 \\u0630 e4\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "a[b]c 1 \\u05d4)\\u05d3 \\u05d2\\u05d1(\\u05d0 d \\u0662\\u0663\\u0660 \\u0630 e\\u0664\\u0631 f \\u0661\\u0662 \\u0632",\r
+            "19: Logical DEFAULT_LTR ==> Visual LTR" },\r
+#if 0\r
+        { UBIDI_RTL, UBIDI_LOGICAL, UBIDI_DEFAULT_RTL, UBIDI_VISUAL,\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0)\\u05d1\\u05d2 \\u05d3(\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "c]b[a \\u05d0(\\u05d1\\u05d2 \\u05d3)\\u05d4 1 d \\u0630 \\u066032 e\\u06314 f \\u0632 \\u0662\\u0661",\r
+            "20: Logical RTL ==> Visual DEFAULT_RTL" }\r
+#endif\r
+    };\r
+    static const uint32_t digits[] = {\r
+        U_SHAPE_DIGITS_NOOP,\r
+        U_SHAPE_DIGITS_AN2EN,\r
+        U_SHAPE_DIGITS_EN2AN,\r
+        U_SHAPE_DIGITS_ALEN2AN_INIT_LR\r
+    };\r
+    static const uint32_t letters[] = {\r
+        U_SHAPE_LETTERS_UNSHAPE,\r
+        U_SHAPE_LETTERS_SHAPE\r
+    };\r
+    uint32_t i, nTestCases = sizeof(testCases) / sizeof(testCases[0]);\r
+    uint32_t j, nDigits = sizeof(digits) / sizeof(digits[0]);\r
+    uint32_t k, nLetters = sizeof(letters) / sizeof(letters[0]);\r
+    \r
+    UErrorCode errorCode = U_ZERO_ERROR;\r
+    UBiDiTransform *pTransform = ubiditransform_open(&errorCode);\r
+\r
+    u_unescape(inText, src, STR_CAPACITY);\r
+\r
+    // Test various combinations of para level, order, mirroring, digits and letters\r
+    for (i = 0; i < nTestCases; i++) {\r
+        ubiditransform_transform(pTransform, src, -1, dest, STR_CAPACITY,\r
+                testCases[i].inLevel, testCases[i].inOr,\r
+                testCases[i].outLevel, testCases[i].outOr,\r
+                UBIDI_MIRRORING_ON, 0, &errorCode);\r
+        verifyResultsForAllOpt(&testCases[i], src, dest,\r
+                testCases[i].pReorderAndMirror, U_SHAPE_DIGITS_NOOP,\r
+                U_SHAPE_LETTERS_NOOP);\r
+\r
+        for (j = 0; j < nDigits; j++) {\r
+            for (k = 0; k < nLetters; k++) {\r
+                /* Use here NULL for pTransform */\r
+                ubiditransform_transform(NULL, src, -1, dest, STR_CAPACITY,\r
+                        testCases[i].inLevel, testCases[i].inOr,\r
+                        testCases[i].outLevel, testCases[i].outOr,\r
+                        UBIDI_MIRRORING_OFF, digits[j] | letters[k],\r
+                        &errorCode);\r
+                verifyResultsForAllOpt(&testCases[i], src, dest,\r
+                        testCases[i].pReorderNoMirror, digits[j], letters[k]);\r
+            }\r
+        }\r
+    }\r
+    ubiditransform_close(pTransform);\r
+}\r
+\r
+void\r
+addBidiTransformTest(TestNode** root)\r
+{\r
+    addTest(root, testAutoDirection, "complex/bidi-transform/TestAutoDirection");\r
+    addTest(root, testAllTransformOptions, "complex/bidi-transform/TestAllTransformOptions");\r
+}\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
index 5f2b48e282bfd83e7bfe110595d6e905b705484a..81403f6c0ad27a5cac61b4d4142dedaddd816173 100644 (file)
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="cbididat.c" />
+    <ClCompile Include="cbiditransformtst.c" />
     <ClCompile Include="cbiditst.c" />
     <ClCompile Include="cbiapts.c" />
     <ClCompile Include="cbkittst.c" />
index b8a340e76c98e3dd87ee869869d774f96a1b8320..e51a98f964fe741a4dea13ae16a96896dfc9f003 100644 (file)
     <ClCompile Include="spooftest.c">
       <Filter>spoof</Filter>
     </ClCompile>
+    <ClCompile Include="cbiditransformtst.c">
+      <Filter>bidi</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="cbiditst.h">
       <Filter>sprep &amp; idna</Filter>
     </ClInclude>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file