#define CHECK_LEN(STR, LEN, ERROR) UPRV_BLOCK_MACRO_BEGIN { \ if (LEN == 0) return 0; \ if (LEN < -1) { *(ERROR) = U_ILLEGAL_ARGUMENT_ERROR; return 0; } \ if (LEN == -1) LEN = u_strlen(STR); \
} UPRV_BLOCK_MACRO_END
#define MAX_ACTIONS 7
/** * Typedef for a pointer to a function, which performs some operation (such as * reordering, setting "inverse" mode, character mirroring, etc.). Return value * indicates whether the text was changed in the course of this operation or * not.
*/ typedef UBool (*UBiDiAction)(UBiDiTransform *, UErrorCode *);
/** * Structure that holds a predefined reordering scheme, including the following * information: * <ul> * <li>an input base direction,</li> * <li>an input order,</li> * <li>an output base direction,</li> * <li>an output order,</li> * <li>a digit shaping direction,</li> * <li>a letter shaping direction,</li> * <li>a base direction that should be applied when the reordering engine is * invoked (which can not always be derived from the caller-defined * options),</li> * <li>an array of pointers to functions that accomplish the bidi layout * transformation.</li> * </ul>
*/ typedefstruct {
UBiDiLevel inLevel; /* input level */
UBiDiOrder inOrder; /* input order */
UBiDiLevel outLevel; /* output level */
UBiDiOrder outOrder; /* output order */
uint32_t digitsDir; /* digit shaping direction */
uint32_t lettersDir; /* letter shaping direction */
UBiDiLevel baseLevel; /* paragraph level to be used with setPara */ const UBiDiAction actions[MAX_ACTIONS]; /* array of pointers to functions carrying out the transformation */
} ReorderingScheme;
struct UBiDiTransform {
UBiDi *pBidi; /* pointer to a UBiDi object */ const ReorderingScheme *pActiveScheme; /* effective reordering scheme */
char16_t *src; /* input text */
char16_t *dest; /* output text */
uint32_t srcLength; /* input text length - not really needed as we are zero-terminated and can u_strlen */
uint32_t srcSize; /* input text capacity excluding the trailing zero */
uint32_t destSize; /* output text capacity */
uint32_t *pDestLength; /* number of UChars written to dest */
uint32_t reorderingOptions; /* reordering options - currently only suppot DO_MIRRORING */
uint32_t digits; /* digit option for ArabicShaping */
uint32_t letters; /* letter option for ArabicShaping */
};
U_CAPI void U_EXPORT2
ubiditransform_close(UBiDiTransform *pBiDiTransform)
{ if (pBiDiTransform != nullptr) { if (pBiDiTransform->pBidi != nullptr) {
ubidi_close(pBiDiTransform->pBidi);
} if (pBiDiTransform->src != nullptr) {
uprv_free(pBiDiTransform->src);
}
uprv_free(pBiDiTransform);
}
}
/** * Performs Bidi resolution of text. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_resolve(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
ubidi_setPara(pTransform->pBidi, pTransform->src, pTransform->srcLength,
pTransform->pActiveScheme->baseLevel, nullptr, pErrorCode); returnfalse;
}
/** * Performs basic reordering of text (Logical -> Visual LTR). * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_reorder(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
ubidi_writeReordered(pTransform->pBidi, pTransform->dest, pTransform->destSize, static_cast<uint16_t>(pTransform->reorderingOptions), pErrorCode);
/** * Sets "inverse" mode on the <code>UBiDi</code> object. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_setInverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
(void)pErrorCode;
ubidi_setInverse(pTransform->pBidi, true);
ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT); returnfalse;
}
/** * Sets "runs only" reordering mode indicating a Logical LTR <-> Logical RTL * transformation. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_setRunsOnly(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
(void)pErrorCode;
ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_RUNS_ONLY); returnfalse;
}
/** * Performs string reverse. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_reverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
ubidi_writeReverse(pTransform->src, pTransform->srcLength,
pTransform->dest, pTransform->destSize,
UBIDI_REORDER_DEFAULT, pErrorCode);
*pTransform->pDestLength = pTransform->srcLength; returntrue;
}
/** * Applies a new value to the text that serves as input at the current * processing step. This value is identical to the original one when we begin * the processing, but usually changes as the transformation progresses. * * @param pTransform A pointer to the <code>UBiDiTransform</code> structure. * @param newSrc A pointer whose value is to be used as input text. * @param newLength A length of the new text in <code>char16_t</code>s. * @param newSize A new source capacity in <code>char16_t</code>s. * @param pErrorCode Pointer to the error code value.
*/ staticvoid
updateSrc(UBiDiTransform *pTransform, const char16_t *newSrc, uint32_t newLength,
uint32_t newSize, UErrorCode *pErrorCode)
{ if (newSize < newLength) {
*pErrorCode = U_BUFFER_OVERFLOW_ERROR; return;
} if (newSize > pTransform->srcSize) {
newSize += 50; // allocate slightly more than needed right now if (pTransform->src != nullptr) {
uprv_free(pTransform->src);
pTransform->src = nullptr;
}
pTransform->src = static_cast<char16_t*>(uprv_malloc(newSize * sizeof(char16_t))); if (pTransform->src == nullptr) {
*pErrorCode = U_MEMORY_ALLOCATION_ERROR; //pTransform->srcLength = pTransform->srcSize = 0; return;
}
pTransform->srcSize = newSize;
}
u_strncpy(pTransform->src, newSrc, newLength);
pTransform->srcLength = u_terminateUChars(pTransform->src,
pTransform->srcSize, newLength, pErrorCode);
}
/** * Calls a lower level shaping function. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param options Shaping options. * @param pErrorCode Pointer to the error code value.
*/ staticvoid
doShape(UBiDiTransform *pTransform, uint32_t options, UErrorCode *pErrorCode)
{
*pTransform->pDestLength = u_shapeArabic(pTransform->src,
pTransform->srcLength, pTransform->dest, pTransform->destSize,
options, pErrorCode);
}
/** * Performs digit and letter shaping. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_shapeArabic(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{ if ((pTransform->letters | pTransform->digits) == 0) { returnfalse;
} if (pTransform->pActiveScheme->lettersDir == pTransform->pActiveScheme->digitsDir) {
doShape(pTransform, pTransform->letters | pTransform->digits | pTransform->pActiveScheme->lettersDir,
pErrorCode);
} else {
doShape(pTransform, pTransform->digits | pTransform->pActiveScheme->digitsDir, pErrorCode); if (U_SUCCESS(*pErrorCode)) {
updateSrc(pTransform, pTransform->dest, *pTransform->pDestLength,
*pTransform->pDestLength, pErrorCode);
doShape(pTransform, pTransform->letters | pTransform->pActiveScheme->lettersDir,
pErrorCode);
}
} returntrue;
}
/** * Performs character mirroring. * * @param pTransform Pointer to the <code>UBiDiTransform</code> structure. * @param pErrorCode Pointer to the error code value. * * @return Whether or not this function modifies the text. Besides the return * value, the caller should also check <code>U_SUCCESS(*pErrorCode)</code>.
*/ static UBool
action_mirror(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
UChar32 c;
uint32_t i = 0, j = 0; if (0 == (pTransform->reorderingOptions & UBIDI_DO_MIRRORING)) { returnfalse;
} if (pTransform->destSize < pTransform->srcLength) {
*pErrorCode = U_BUFFER_OVERFLOW_ERROR; returnfalse;
} do {
UBool isOdd = ubidi_getLevelAt(pTransform->pBidi, i) & 1;
U16_NEXT(pTransform->src, i, pTransform->srcLength, c);
U16_APPEND_UNSAFE(pTransform->dest, j, isOdd ? u_charMirror(c) : c);
} while (i < pTransform->srcLength);
if (U_FAILURE(*pErrorCode)) { return 0;
} if (src == nullptr || dest == nullptr) {
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; return 0;
}
CHECK_LEN(src, srcLength, pErrorCode);
CHECK_LEN(dest, destSize, pErrorCode);
if (pBiDiTransform == nullptr) {
pBiDiTransform = ubiditransform_open(pErrorCode); if (U_FAILURE(*pErrorCode)) { return 0;
}
} /* Current limitation: in multiple paragraphs will be resolved according
to the 1st paragraph */
resolveBaseDirection(src, srcLength, &inParaLevel, &outParaLevel);
/* Ignore TEXT_DIRECTION_* flags, as we apply our own depending on the text
scheme at the time shaping is invoked. */
shapingOptions &= ~U_SHAPE_TEXT_DIRECTION_MASK;
pBiDiTransform->digits = shapingOptions & ~U_SHAPE_LETTERS_MASK;
pBiDiTransform->letters = shapingOptions & ~U_SHAPE_DIGITS_MASK;
/* Checking for U_SUCCESS() within the loop to bail out on first failure. */ for (action = pBiDiTransform->pActiveScheme->actions; *action && U_SUCCESS(*pErrorCode); action++) { if ((*action)(pBiDiTransform, pErrorCode)) { if (action[1] != nullptr) {
updateSrc(pBiDiTransform, pBiDiTransform->dest, *pBiDiTransform->pDestLength,
*pBiDiTransform->pDestLength, pErrorCode);
}
textChanged = true;
}
}
ubidi_setInverse(pBiDiTransform->pBidi, false);
if (!textChanged && U_SUCCESS(*pErrorCode)) { /* Text was not changed - just copy src to dest */ if (destSize < srcLength) {
*pErrorCode = U_BUFFER_OVERFLOW_ERROR;
} else {
u_strncpy(dest, src, srcLength);
destLength = srcLength;
}
}
cleanup: if (pOrigTransform != pBiDiTransform) {
ubiditransform_close(pBiDiTransform);
} else {
pBiDiTransform->dest = nullptr;
pBiDiTransform->pDestLength = nullptr;
pBiDiTransform->srcLength = 0;
pBiDiTransform->destSize = 0;
} return U_FAILURE(*pErrorCode) ? 0 : destLength;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.