You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Franzo 46094c9110 initial commit 1 year ago
Headers initial commit 1 year ago
Source initial commit 1 year ago
CMakeLists.txt initial commit 1 year ago
LICENSE initial commit 1 year ago initial commit 1 year ago


License Travis-CI Build Status AppVeyor Build Status Coverage Status

SheenBidi implements Unicode Bidirectional Algorithm available at It is a sophisticated implementaion which provides the developers an easy way to use UBA in their applications.

Here are some of the advantages of SheenBidi.

  • Object based.
  • Optimized to the core.
  • Designed to be thread safe.
  • Lightweight API for interaction.
  • Supports UTF-8, UTF-16 and UTF-32 encodings.


The above screenshot depicts a visual representation of the API on a sample text.


It works as a code point decoder by accepting a string buffer in specified encoding.


It provides bidirectional type of each code unit in source string. Paragraph boundaries can be quried from it as determined by rule P1. Individual paragraph objects can be created from it by explicitly specifying the base level or deriving it from rules P2-P3.


It represents a single paragraph of text processed with rules X1-I2. It provides resolved embedding levels of all the code units of a paragraph.


It represents a single line of text processed with rules L1-L2. However, it provides reordered level runs instead of reordered characters.


It represents a sequence of characters which have the same embedding level. The direction of a run would be right-to-left, if its embedding level is odd.


It provides the facility to find out the mirrored characters in a line as determined by rule L4.


Not directly related to UBA but can be useful for text shaping. It provides the facility to find out the script runs as specified in UAX #24.


SheenBidi does not depend on any external library. It only uses standard C library headers stddef.h, stdint.h and stdlib.h.


The configuration options are available in Headers/SBConfig.h.

  • SB_CONFIG_LOG logs every activity performed in order to apply bidirectional algorithm.
  • SB_CONFIG_UNITY builds the library as a single module and lets the compiler make decisions to inline functions.


SheenBidi can be compiled with any C compiler. The best way for compiling is to add all the files in an IDE and hit build. The only thing to consider however is that if SB_CONFIG_UNITY is enabled then only Source/SheenBidi.c should be compiled.


Here is a simple example written in C11.

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <SheenBidi.h>

int main(int argc, const char * argv[]) {
    /* Create code point sequence for a sample bidirectional text. */
    const char *bidiText = "یہ ایک )car( ہے۔";
    SBCodepointSequence codepointSequence = { SBStringEncodingUTF8, (void *)bidiText, strlen(bidiText) };

    /* Extract the first bidirectional paragraph. */
    SBAlgorithmRef bidiAlgorithm = SBAlgorithmCreate(&codepointSequence);
    SBParagraphRef firstParagraph = SBAlgorithmCreateParagraph(bidiAlgorithm, 0, INT32_MAX, SBLevelDefaultLTR);
    SBUInteger paragraphLength = SBParagraphGetLength(firstParagraph);

    /* Create a line consisting of whole paragraph and get its runs. */
    SBLineRef paragraphLine = SBParagraphCreateLine(firstParagraph, 0, paragraphLength);
    SBUInteger runCount = SBLineGetRunCount(paragraphLine);
    const SBRun *runArray = SBLineGetRunsPtr(paragraphLine);

    /* Log the details of each run in the line. */
    for (SBUInteger i = 0; i < runCount; i++) {
        printf("Run Offset: %ld\n", (long)runArray[i].offset);
        printf("Run Length: %ld\n", (long)runArray[i].length);
        printf("Run Level: %ld\n\n", (long)runArray[i].level);

    /* Create a mirror locator and load the line in it. */
    SBMirrorLocatorRef mirrorLocator = SBMirrorLocatorCreate();
    SBMirrorLocatorLoadLine(mirrorLocator, paragraphLine, (void *)bidiText);
    const SBMirrorAgent *mirrorAgent = SBMirrorLocatorGetAgent(mirrorLocator);

    /* Log the details of each mirror in the line. */
    while (SBMirrorLocatorMoveNext(mirrorLocator)) {
        printf("Mirror Index: %ld\n", (long)mirrorAgent->index);
        printf("Actual Code Point: %ld\n", (long)mirrorAgent->codepoint);
        printf("Mirrored Code Point: %ld\n\n", (long)mirrorAgent->mirror);

    /* Release all objects. */

    return 0;