Converting Arabic Script to Presentation Forms-B in Java

posted on: Monday, 13th of August 2018

This Java utility class below converts Arabic Script to Presentation Forms-B. The transformation is done character-by-character. It doesn't require the text to be converted to a string beforehand. It supports Arabic, Farsi, as well as Urdu and Kurdish to some degree.

Arabic Script via Presentation Forms-B

The utility is suitable when the text is e.g. rendered via a Bitmap Font in OpenGL. Also, rather than String, it operates on CharSequence giving more flexibility.

// text to be rendered (e.g. a String)
CharSequence text = ...

// our text render loop
for (int i = 0, iMax = text.length(); i < iMax; i++) {
  // obtain the character to render & convert as needed
  char ch = text.charAt(i);
  if (ArabicScripture.isLetterARConvert(ch)) {
    ch = ArabicScripture.toCorrect(text, i);  // <-- conversion to Presentation Forms-B
  }

  // render the character to the screen
  render(ch);
}

References for Arabic Script:

Limitations: The text still has to be rendered from right-to-left (L2R). Also for best practices, it is advised to right-align the text.

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Utility class to convert Arabic script to Presentation Form B to e.g. render it via a
 * Bitmap Font in OpenGL.
 *
 * @author noblemaster
 */
public final class ArabicScripture {

  /** Arabic letter that needs presentation form change. */
  private static final char ARABIC_LETTER_START = 0x0621;
  /** Arabic letter that needs presentation form change. */
  private static final char ARABIC_LETTER_FINAL = 0x06D3;


  private TextScriptureArabic() {
    // to prevent instantiation
  }

  /** Returns true for Arabic letters. */
  public static boolean isLetterAR(char ch) {
    // check the range...
    if (ch < 0x0600) {
      return false;
    }
    else {
      return (                  (ch <= 0x06FF)) ||
             ((ch >= 0x0750) && (ch <= 0x077F)) ||
             ((ch >= 0x08A0) && (ch <= 0x08FF)) ||
             ((ch >= 0xFB50) && (ch <= 0xFDFF)) ||
             ((ch >= 0xFE70) && (ch <= 0xFEFF));
    }
  }

  /** Returns true if this is an arabic letter that needs presentation form fixing. */
  public static boolean isLetterARConvert(char ch) {
    return (ch >= ARABIC_LETTER_START) && (ch <= ARABIC_LETTER_FINAL);
  }

  // -------------------------------------------------------------------------------------------------------------------

  /** Returns the presentation char: check isLetterARConvert beforehand! */
  public static char toCorrect(CharSequence text, int index) {
    // possibly bad hack to get special stuff to work?
    char ch = text.charAt(index);
    if (TRANSPARENT.contains(ch)) {
      // "transparent" character that is rendered as is
      switch (ch) {
        case 0x0654: {
          // non-existing glyph in font: replace /w higher-up version (maybe too high)
          ch = 0x035B;
          break;
        }
        default:
          // unchanged...
      }
      return ch;
    }
    else {
      // arabic: determine previous & next
      int textCount = text.length();

      int prevTries = 4;  // <-- we try to go back 4 at max.!
      int prevIndex = index - 1;
      while ((prevTries > 0) && (prevIndex >= 0) && (TRANSPARENT.contains(text.charAt(prevIndex)))) {
        prevTries--;
        prevIndex--;
      }
      char prev = prevIndex >= 0 ? text.charAt(prevIndex) : 0x0000;

      int nextTries = 4;  // <-- we try to go back 4 at max.!
      int nextIndex = index + 1;
      while ((nextTries > 0) && (nextIndex < textCount) && (TRANSPARENT.contains(text.charAt(nextIndex)))) {
        nextTries--;
        nextIndex++;
      }
      char next = nextIndex < textCount ? text.charAt(nextIndex) : 0x0000;

      // covert Arabic letter
      boolean isLa  = isLamAlef(ch, next);
      boolean isApl = isAlefPrevLam(prev, ch);
      boolean isLapl = isLa | isApl;

      // determine character to return
      int col = ((((isLapl | isLetterARConvert(next)) & isLinkingType(ch)) ? 1 : 0) << 1) | (isLinkingType(prev) ? 1 : 0);
      int ref = (next * (isLa ? 1 : 0)) + (ch * (isLa ? 0 : 1));
      return (char)ARABIC_FORMS_B[ref - ARABIC_LETTER_START][isLapl ? 1 : 0][col];
    }
  }

  // -------------------------------------------------------------------------------------------------------------------

  private static final int UNICODE_LAM = 0x644;

  private static boolean isLamAlef(char cp, char next)  {
    return (cp == UNICODE_LAM) && (isLetterARConvert(next)) && (ARABIC_FORMS_B[next - ARABIC_LETTER_START][1][INITIAL] != 0);
  }

  private static boolean isAlefPrevLam(char prev, char cp)  {
    return (prev == UNICODE_LAM) && (isLetterARConvert(cp)) && (ARABIC_FORMS_B[cp - ARABIC_LETTER_START][1][INITIAL] != 0);
  }

  private static boolean isLinkingType(char cp) {
    return (isLetterARConvert(cp)) && (ARABIC_FORMS_B[cp - ARABIC_LETTER_START][0][MEDIAL] != 0);
  }

  // TABLE COLUMNS:
  //   0: isolated form
  //   1: ending form
  //   2: beginning form (if 0, it's a cutting type)
  //   3: middle form
  private static final int ISOLATED = 0;
  private static final int ENDING   = 1;
  private static final int INITIAL  = 2;
  private static final int MEDIAL   = 3;

  /** Transparent characters that are rendered as is and not used for combining. */
  private static final ArrayList<Integer> TRANSPARENT = new ArrayList<Integer>(Arrays.asList(
      0x0610, // ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM
      0x0612, // ARABIC SIGN ALAYHE ASSALLAM
      0x0613, // ARABIC SIGN RADI ALLAHOU ANHU
      0x0614, // ARABIC SIGN TAKHALLUS
      0x0615, // ARABIC SMALL HIGH TAH
      0x064B, // ARABIC FATHATAN
      0x064C, // ARABIC DAMMATAN
      0x064D, // ARABIC KASRATAN
      0x064E, // ARABIC FATHA
      0x064F, // ARABIC DAMMA
      0x0650, // ARABIC KASRA
      0x0651, // ARABIC SHADDA
      0x0652, // ARABIC SUKUN
      0x0653, // ARABIC MADDAH ABOVE
      0x0654, // ARABIC HAMZA ABOVE
      0x0655, // ARABIC HAMZA BELOW
      0x0656, // ARABIC SUBSCRIPT ALEF
      0x0657, // ARABIC INVERTED DAMMA
      0x0658, // ARABIC MARK NOON GHUNNA
      0x0660, // Arabic #0
      0x0661, // Arabic #1
      0x0662, // Arabic #2
      0x0663, // Arabic #3
      0x0664, // Arabic #4
      0x0665, // Arabic #5
      0x0666, // Arabic #6
      0x0667, // Arabic #7
      0x0668, // Arabic #8
      0x0669, // Arabic #9
      0x0670, // ARABIC LETTER SUPERSCRIPT ALEF
      0x06D6, // ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA
      0x06D7, // ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA
      0x06D8, // ARABIC SMALL HIGH MEEM INITIAL FORM
      0x06D9, // ARABIC SMALL HIGH LAM ALEF
      0x06DA, // ARABIC SMALL HIGH JEEM
      0x06DB, // ARABIC SMALL HIGH THREE DOTS
      0x06DC, // ARABIC SMALL HIGH SEEN
      0x06DF, // ARABIC SMALL HIGH ROUNDED ZERO
      0x06E0, // ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO
      0x06E1, // ARABIC SMALL HIGH DOTLESS HEAD OF KHAH
      0x06E2, // ARABIC SMALL HIGH MEEM ISOLATED FORM
      0x06E3, // ARABIC SMALL LOW SEEN
      0x06E4, // ARABIC SMALL HIGH MADDA
      0x06E7, // ARABIC SMALL HIGH YEH
      0x06E8, // ARABIC SMALL HIGH NOON
      0x06EA, // ARABIC EMPTY CENTRE LOW STOP
      0x06EB, // ARABIC EMPTY CENTRE HIGH STOP
      0x06EC, // ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE
      0x06ED  // ARABIC SMALL LOW MEEM
  ));

  /** Table to convert to Arabic presentation form B. */
  private static final int[][][] ARABIC_FORMS_B = {
      { {0xFE80, 0xFE80,      0,      0}, {-1, -1, 0, 0} },            // 0x0621 | Arabic: hamza
      { {0xFE81, 0xFE82,      0,      0}, {-1, -1, 0xFEF5, 0xFEF6} },  // 0x0622 | Arabic: 2alif madda
      { {0xFE83, 0xFE84,      0,      0}, {-1, -1, 0xFEF7, 0xFEF8} },  // 0x0623 | Arabic: 2alif hamza
      { {0xFE85, 0xFE86,      0,      0}, {-1, -1, 0, 0} },            // 0x0624 | Arabic: waw hamza
      { {0xFE87, 0xFE88,      0,      0}, {-1, -1, 0xFEF9, 0xFEFA} },  // 0x0625 | Arabic: 2alif hamza maksoura
      { {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}, {-1, -1, 0, 0} },            // 0x0626 | Arabic: 2alif maqsoura hamza
      { {0xFE8D, 0xFE8E,      0,      0}, {-1, -1, 0xFEFB, 0xFEFC} },  // 0x0627 | Arabic: 2alif
      { {0xFE8F, 0xFE90, 0xFE91, 0xFE92}, {-1, -1, 0, 0} },            // 0x0628 | Arabic: ba2
      { {0xFE93, 0xFE94,      0,      0}, {-1, -1, 0, 0} },            // 0x0629 | Arabic: ta2 marbouta
      { {0xFE95, 0xFE96, 0xFE97, 0xFE98}, {-1, -1, 0, 0} },            // 0x062a | Arabic: ta2
      { {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}, {-1, -1, 0, 0} },            // 0x062b | Arabic: tha2
      { {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}, {-1, -1, 0, 0} },            // 0x062c | Arabic: jim
      { {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}, {-1, -1, 0, 0} },            // 0x062d | Arabic: 7a2
      { {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}, {-1, -1, 0, 0} },            // 0x062e | Arabic: kha2
      { {0xFEA9, 0xFEAA,      0,      0}, {-1, -1, 0, 0} },            // 0x062f | Arabic: dal
      { {0xFEAB, 0xFEAC,      0,      0}, {-1, -1, 0, 0} },            // 0x0630 | Arabic: dhal
      { {0xFEAD, 0xFEAE,      0,      0}, {-1, -1, 0, 0} },            // 0x0631 | Arabic: ra2
      { {0xFEAF, 0xFEB0,      0,      0}, {-1, -1, 0, 0} },            // 0x0632 | Arabic: zayn
      { {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}, {-1, -1, 0, 0} },            // 0x0633 | Arabic: syn
      { {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}, {-1, -1, 0, 0} },            // 0x0634 | Arabic: shin
      { {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}, {-1, -1, 0, 0} },            // 0x0635 | Arabic: sad
      { {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}, {-1, -1, 0, 0} },            // 0x0636 | Arabic: dad
      { {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}, {-1, -1, 0, 0} },            // 0x0637 | Arabic: tah
      { {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}, {-1, -1, 0, 0} },            // 0x0638 | Arabic: thah
      { {0xFEC9, 0xFECA, 0xFECB, 0xFECC}, {-1, -1, 0, 0} },            // 0x0639 | Arabic: 3ayn
      { {0xFECD, 0xFECE, 0xFECF, 0xFED0}, {-1, -1, 0, 0} },            // 0x063a | Arabic: ghayn
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x063b -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x063c -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x063d -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x063e -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x063f -
      { {0x0640, 0x0640, 0x0640, 0x0640}, {-1, -1, 0, 0} },            // 0x0640 | Arabic: wasla
      { {0xFED1, 0xFED2, 0xFED3, 0xFED4}, {-1, -1, 0, 0} },            // 0x0641 | Arabic: fa2
      { {0xFED5, 0xFED6, 0xFED7, 0xFED8}, {-1, -1, 0, 0} },            // 0x0642 | Arabic: qaf
      { {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}, {-1, -1, 0, 0} },            // 0x0643 | Arabic: kaf
      { {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}, {-1, -1, 0, 0} },            // 0x0644 | Arabic: lam
      { {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}, {-1, -1, 0, 0} },            // 0x0645 | Arabic: mim
      { {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}, {-1, -1, 0, 0} },            // 0x0646 | Arabic: noon
      { {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}, {-1, -1, 0, 0} },            // 0x0647 | Arabic: ha2
      { {0xFEED, 0xFEEE,      0,      0}, {-1, -1, 0, 0} },            // 0x0648 | Arabic: waw
      { {0xFEEF, 0xFEF0,      0,      0}, {-1, -1, 0, 0} },            // 0x0649 | Arabic: 2alif maksoura
      { {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}, {-1, -1, 0, 0} },            // 0x064a | Arabic: ya2
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x064b -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x064c -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x064d -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x064e -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x064f -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0650 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0651 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0652 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0653 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0654 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0655 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0656 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0657 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0658 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0659 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x065a -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x065b -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x065c -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x065d -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x065e -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x065f -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0660 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0661 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0662 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0663 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0664 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0665 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0666 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0667 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0668 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0669 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x066a -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x066b -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x066c -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x066d -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x066e -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x066f -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0670 -
      { {0xFB50, 0xFB51,      0,      0}, {-1, -1, 0, 0} },            // 0x0671 | ALEF WASLA
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0672 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0673 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0674 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0675 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0676 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0677 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0678 -
      { {0xFB66, 0xFB67, 0xFB68, 0xFB69}, {-1, -1, 0, 0} },            // 0x0679 | TTEH
      { {0xFB5E, 0xFB5F, 0xFB60, 0xFB61}, {-1, -1, 0, 0} },            // 0x067a | TTEHEH
      { {0xFB52, 0xFB53, 0xFB54, 0xFB55}, {-1, -1, 0, 0} },            // 0x067b | BEEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x067c -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x067d -
      { {0xFB56, 0xFB57, 0xFB58, 0xFB59}, {-1, -1, 0, 0} },            // 0x067e | PEH
      { {0xFB62, 0xFB63, 0xFB64, 0xFB65}, {-1, -1, 0, 0} },            // 0x067f | TEHEH
      { {0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}, {-1, -1, 0, 0} },            // 0x0680 | BEHEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0681 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0682 -
      { {0xFB76, 0xFB77, 0xFB78, 0xFB79}, {-1, -1, 0, 0} },            // 0x0683 | NYEH
      { {0xFB72, 0xFB73, 0xFB74, 0xFB75}, {-1, -1, 0, 0} },            // 0x0684 | DYEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0685 -
      { {0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}, {-1, -1, 0, 0} },            // 0x0686 | TCHEH
      { {0xFB7E, 0xFB7F, 0xFB80, 0xFB81}, {-1, -1, 0, 0} },            // 0x0687 | TCHEHEH
      { {0xFB88, 0xFB89,      0,      0}, {-1, -1, 0, 0} },            // 0x0688 | DDAL
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0689 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x068a -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x068b -
      { {0xFB84, 0xFB85,      0,      0}, {-1, -1, 0, 0} },            // 0x068c | DAHAL
      { {0xFB82, 0xFB83,      0,      0}, {-1, -1, 0, 0} },            // 0x068d | DDAHAL
      { {0xFB86, 0xFB87,      0,      0}, {-1, -1, 0, 0} },            // 0x068e | DUL
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x068f -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0690 -
      { {0xFB8C, 0xFB8D,      0,      0}, {-1, -1, 0, 0} },            // 0x0691 | RREH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0692 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0693 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0694 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0695 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0696 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0697 -
      { {0xFB8A, 0xFB8B,      0,      0}, {-1, -1, 0, 0} },            // 0x0698 | JEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x0699 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x069a -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x069b -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x069c -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x069d -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x069e -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x069f -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a0 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a1 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a2 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a3 -
      { {0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}, {-1, -1, 0, 0} },            // 0x06a4 | VEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a5 -
      { {0xFB6E, 0xFB6F, 0xFB70, 0xFB71}, {-1, -1, 0, 0} },            // 0x06a6 | PEHEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a7 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06a8 -
      { {0xFB8E, 0xFB8F, 0xFB90, 0xFB91}, {-1, -1, 0, 0} },            // 0x06a9 | KEHEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06aa -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06ab -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06ac -
      { {0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6}, {-1, -1, 0, 0} },            // 0x06ad | NG
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06ae -
      { {0xFB92, 0xFB93, 0xFB94, 0xFB95}, {-1, -1, 0, 0} },            // 0x06af | GAF
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b0 -
      { {0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D}, {-1, -1, 0, 0} },            // 0x06b1 | NGOEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b2 -
      { {0xFB96, 0xFB97, 0xFB98, 0xFB99}, {-1, -1, 0, 0} },            // 0x06b3 | GUEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b4 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b5 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b6 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b7 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b8 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06b9 -
      { {0xFB9E, 0xFB9F,      0,      0}, {-1, -1, 0, 0} },            // 0x06ba | NOON GHUNNA
      { {0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3}, {-1, -1, 0, 0} },            // 0x06bb | RNOON
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06bc -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06bd -
      { {0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}, {-1, -1, 0, 0} },            // 0x06be | HEH DOACHASHMEE
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06bf -
      { {0xFBA4, 0xFBA5,      0,      0}, {-1, -1, 0, 0} },            // 0x06c0 | HEH WITH YEH ABOVE
      { {0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9}, {-1, -1, 0, 0} },            // 0x06c1 | HEH GOAL
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06c2 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06c3 -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06c4 -
      { {0xFBE0, 0xFBE1,      0,      0}, {-1, -1, 0, 0} },            // 0x06c5 | KIRGHIZ OE
      { {0xFBD9, 0xFBDA,      0,      0}, {-1, -1, 0, 0} },            // 0x06c6 | OE
      { {0xFBD7, 0xFBD8,      0,      0}, {-1, -1, 0, 0} },            // 0x06c7 | U
      { {0xFBDB, 0xFBDC,      0,      0}, {-1, -1, 0, 0} },            // 0x06c8 | YU
      { {0xFBE2, 0xFBE3,      0,      0}, {-1, -1, 0, 0} },            // 0x06c9 | KIRGHIZ YU
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06ca -
      { {0xFBDE, 0xFBDF,      0,      0}, {-1, -1, 0, 0} },            // 0x06cb | VE
      { {0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}, {-1, -1, 0, 0} },            // 0x06cc | FARSI YEH
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06cd -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06ce -
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06cf -
      { {0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}, {-1, -1, 0, 0} },            // 0x06d0 | E
      { {     0,      0,      0,      0}, {-1, -1, 0, 0} },            // 0x06d1 -
      { {0xFBAE, 0xFBAF,      0,      0}, {-1, -1, 0, 0} },            // 0x06d2 | YEH BARREE
      { {0xFBB0, 0xFBB1,      0,      0}, {-1, -1, 0, 0} },            // 0x06d3 | YEH BARREE WITH HAMZA ABOVE
  };
}