SheenBidi ========= [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Travis-CI Build Status](https://api.travis-ci.org/Tehreer/SheenBidi.svg?branch=master)](https://travis-ci.org/Tehreer/SheenBidi) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/k2vvegcdqsb9ld5a?svg=true)](https://ci.appveyor.com/project/mta452/sheenbidi) [![Coverage Status](https://coveralls.io/repos/github/Tehreer/SheenBidi/badge.svg?branch=master)](https://coveralls.io/github/Tehreer/SheenBidi) SheenBidi implements Unicode Bidirectional Algorithm available at http://www.unicode.org/reports/tr9. 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. ## API The above screenshot depicts a visual representation of the API on a sample text. ### SBCodepointSequence It works as a code point decoder by accepting a string buffer in specified encoding. ### SBAlgorithm It provides bidirectional type of each code unit in source string. Paragraph boundaries can be quried from it as determined by rule [P1](https://www.unicode.org/reports/tr9/#P1). Individual paragraph objects can be created from it by explicitly specifying the base level or deriving it from rules [P2](https://www.unicode.org/reports/tr9/#P2)-[P3](https://www.unicode.org/reports/tr9/#P3). ### SBParagraph It represents a single paragraph of text processed with rules [X1](https://www.unicode.org/reports/tr9/#X1)-[I2](https://www.unicode.org/reports/tr9/#I2). It provides resolved embedding levels of all the code units of a paragraph. ### SBLine It represents a single line of text processed with rules [L1](https://www.unicode.org/reports/tr9/#L1)-[L2](https://www.unicode.org/reports/tr9/#L2). However, it provides reordered level runs instead of reordered characters. ### SBRun 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. ### SBMirrorLocator It provides the facility to find out the mirrored characters in a line as determined by rule [L4](https://www.unicode.org/reports/tr9/#L4). ### SBScriptLocator 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](https://www.unicode.org/reports/tr24/). ## Dependency SheenBidi does not depend on any external library. It only uses standard C library headers ```stddef.h```, ```stdint.h``` and ```stdlib.h```. ## Configuration 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. ## Compiling 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. ## Example Here is a simple example written in C11. ```c #include #include #include #include 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. */ SBMirrorLocatorRelease(mirrorLocator); SBLineRelease(paragraphLine); SBParagraphRelease(firstParagraph); SBAlgorithmRelease(bidiAlgorithm); return 0; } ```