UNPKG

dojox

Version:

Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.

1,422 lines (1,334 loc) 58.6 kB
define(["dojo/_base/lang", "dojo/_base/declare", "dojo/Stateful"], function(lang,declare,Stateful) { lang.getObject("string", true, dojox); var BidiEngine = declare("dojox.string.BidiEngine", Stateful, { // summary: // This class provides a bidi transformation engine, i.e. // functions for reordering and shaping bidi text. // description: // Bidi stands for support for languages with a bidirectional script. // // Usually Unicode Bidi Algorithm used by OS platform (and web browsers) is capable of properly // transforming Bidi text and as a result it is adequately displayed on the screen. // However, in some situations, Unicode Bidi Algorithm is not invoked or is not properly applied. // This may occur in situation in which software responsible for rendering the text is not leveraging // Unicode Bidi Algorithm implemented by OS (e.g. GFX renderers). // // Bidi engine provided in this class implements Unicode Bidi Algorithm as specified at // http://www.unicode.org/reports/tr9/. // // For more information on basic Bidi concepts please read // "Bidirectional script support - A primer" available from // http://www.ibm.com/developerworks/websphere/library/techarticles/bidi/bidigen.html. // // As of February 2011, Bidi engine has following limitations: // // 1. No support for following numeric shaping options: // - H - Hindi, // - C - Contextual, // - N - Nominal. // 2. No support for following shaping options: // - I - Initial shaping, // - M - Middle shaping, // - F - Final shaping, // - B - Isolated shaping. // 3. No support for LRE/RLE/LRO/RLO/PDF (they are handled like neutrals). // 4. No support for Windows compatibility. // 5. No support for insert/remove marks. // 6. No support for code pages. // // Input Bidi layout in which inputText is passed to the function. inputFormat: "ILYNN", // Output Bidi layout to which inputText should be transformed. outputFormat: "VLNNN", // Array, containing positions of each character from the source text in the resulting text. sourceToTarget: [], // Array, containing positions of each character from the resulting text in the source text. targetToSource: [], // Array, containing bidi level of each character from the source text levels: [], bidiTransform: function (/*String*/text, /*String*/formatIn, /*String*/formatOut) { // summary: // Central public API for Bidi engine. Transforms the text according to formatIn, formatOut // parameters. If formatIn or formatOut parametrs are not valid throws an exception. // inputText: // Input text subject to application of Bidi transformation. // formatIn: // Input Bidi layout in which inputText is passed to the function. // formatOut: // Output Bidi layout to which inputText should be transformed. // description: // Both formatIn and formatOut parameters are 5 letters long strings. // For example - "ILYNN". Each letter is associated with specific attribute of Bidi layout. // Possible and default values for each one of the letters are provided below: // // First letter: // // - Letter position/index: // 1 // - Letter meaning: // Ordering Schema. // - Possible values: // - I - Implicit (Logical). // - V - Visual. // - Default value: // I // // Second letter: // // - Letter position/index: // 2 // - Letter meaning: // Orientation. // - Possible values: // - L - Left To Right. // - R - Right To Left. // - C - Contextual Left to Right. // - D - Contextual Right to Left. // - Default value: // L // // Third letter: // // - Letter position/index: // 3 // - Letter meaning: // Symmetric Swapping. // - Possible values: // - Y - Symmetric swapping is on. // - N - Symmetric swapping is off. // - Default value: // Y // // Fourth letter: // // - Letter position/index: // 4 // - Letter meaning: // Shaping. // - Possible values: // - S - Text is shaped. // - N - Text is not shaped. // - Default value: // N // // Fifth letter: // // - Letter position/index: // 5 // - Letter meaning: // Numeric Shaping. // - Possible values: // - N - Nominal. // - Default value: // N // // The output of this function is original text (passed via first argument) transformed from // input Bidi layout (second argument) to output Bidi layout (last argument). // // Sample call: // | mytext = bidiTransform("HELLO WORLD", "ILYNN", "VLYNN"); // In this case, "HELLO WORLD" text is transformed from Logical - LTR to Visual - LTR Bidi layout // with default values for symmetric swapping (Yes), shaping (Not shaped) and numeric shaping // (Nominal). // returns: String // Original text transformed from input Bidi layout (second argument) // to output Bidi layout (last argument). // Throws an exception if the bidi layout strings are not valid. // tags: // public this.sourceToTarget = []; this.targetToSource = []; if (!text) { return ""; } initMaps(this.sourceToTarget, this.targetToSource, text.length); if (!this.checkParameters(formatIn, formatOut)) { return text; } formatIn = this.inputFormat; formatOut = this.outputFormat; var result = text; var bdx = BDX; var orientIn = getOrientation(formatIn.charAt(1)), orientOut = getOrientation(formatOut.charAt(1)), osIn = (formatIn.charAt(0) === "I") ? "L" : formatIn.charAt(0), osOut = (formatOut.charAt(0) === "I") ? "L" : formatOut.charAt(0), inFormat = osIn + orientIn, outFormat = osOut + orientOut, swap = formatIn.charAt(2) + formatOut.charAt(2); bdx.defInFormat = inFormat; bdx.defOutFormat = outFormat; bdx.defSwap = swap; var stage1Text = doBidiReorder(text, inFormat, outFormat, swap, bdx), isRtl = false; if (formatOut.charAt(1) === "R") { isRtl = true; } else if (formatOut.charAt(1) === "C" || formatOut.charAt(1) === "D") { isRtl = this.checkContextual(stage1Text); } this.sourceToTarget = stMap; this.targetToSource = reverseMap(this.sourceToTarget); tsMap = this.targetToSource; if (formatIn.charAt(3) === formatOut.charAt(3)) { result = stage1Text; } else if (formatOut.charAt(3) === "S") { result = shape(isRtl, stage1Text, true); } else { //formatOut.charAt(3) === "N" result = deshape(stage1Text, isRtl, true); } this.sourceToTarget = stMap; this.targetToSource = tsMap; this.levels = lvMap; return result; }, _inputFormatSetter: function (format) { if (!validFormat.test(format)) { throw new Error("dojox/string/BidiEngine: the bidi layout string is wrong!"); } this.inputFormat = format; }, _outputFormatSetter: function (format) { if (!validFormat.test(format)) { throw new Error("dojox/string/BidiEngine: the bidi layout string is wrong!"); } this.outputFormat = format; }, checkParameters: function (/*String*/formatIn, /*String*/formatOut) { // summary: // Checks layout parameters. // formatIn: // Input Bidi layout in which inputText is passed to the function. // formatOut: // Output Bidi layout to which inputText should be transformed. // description: // Checks, that layout parameters are different and contain allowed values. // Allowed values for format string are: // - 1st letter: I, V // - 2nd letter: L, R, C, D // - 3rd letter: Y, N // - 4th letter: S, N // - 5th letter: N // returns: /*Boolean*/ // true - if layout parameters are valid. // false - otherwise. // tags: // private if (!formatIn) { formatIn = this.inputFormat; } else { this.set("inputFormat", formatIn); } if (!formatOut) { formatOut = this.outputFormat; } else { this.set("outputFormat", formatOut); } if (formatIn === formatOut) { return false; } return true; }, checkContextual: function (/*String*/text) { // summary: // Determine the base direction of a bidi text according // to its first strong directional character. // text: // The text to check. // returns: /*String*/ // "ltr" or "rtl" according to the first strong character. // If there is no strong character, returns the value of the // document dir property. // tags: // public var dir = firstStrongDir(text); if (dir !== "ltr" && dir !== "rtl") { try { dir = document.dir.toLowerCase(); } catch (e) { } if (dir !== "ltr" && dir !== "rtl") { dir = "ltr"; } } return dir; }, hasBidiChar: function (/*String*/text) { // summary: // Return true if text contains RTL directed character. // text: // The source string. // description: // Searches for RTL directed character. // Returns true if found, else returns false. // returns: /*Boolean*/ // true - if text has a RTL directed character. // false - otherwise. // tags: // public return bidiChars.test(text); } }); function doBidiReorder(/*String*/text, /*String*/inFormat, /*String*/outFormat, /*String*/swap, /*Object*/bdx) { // summary: // Reorder the source text according to the bidi attributes // of source and result. // text: // The text to reorder. // inFormat: // Ordering scheme and base direction of the source text. // Can be "LLTR", "LRTL", "LCLR", "LCRL", "VLTR", "VRTL", // "VCLR", "VCRL". // The first letter is "L" for logical ordering scheme, // "V" for visual ordering scheme. // The other letters specify the base direction. // "CLR" means contextual direction defaulting to LTR if // there is no strong letter. // "CRL" means contextual direction defaulting to RTL if // there is no strong letter. // The initial value is "LLTR", if none, the initial value is used. // outFormat: // Required ordering scheme and base direction of the // result. Has the same format as inFormat. // If none, the initial value "VLTR" is used. // swap: // Symmetric swapping attributes of source and result. // The allowed values can be "YN", "NY", "YY" and "NN". // The first letter reflects the symmetric swapping attribute // of the source, the second letter that of the result. // bdx: Object // Used for intermediate data storage // returns: // Text reordered according to source and result attributes. var params = prepareReorderingParameters(text, {inFormat: inFormat, outFormat: outFormat, swap: swap}, bdx); if (params.inFormat === params.outFormat) { return text; } inFormat = params.inFormat; outFormat = params.outFormat; swap = params.swap; var inOrdering = inFormat.substring(0, 1), inOrientation = inFormat.substring(1, 4), outOrdering = outFormat.substring(0, 1), outOrientation = outFormat.substring(1, 4); bdx.inFormat = inFormat; bdx.outFormat = outFormat; bdx.swap = swap; if ((inOrdering === "L") && (outFormat === "VLTR")) { //core cases //cases: LLTR->VLTR, LRTL->VLTR if (inOrientation === "LTR") { bdx.dir = LTR; return doReorder(text, bdx); } if (inOrientation === "RTL") { bdx.dir = RTL; return doReorder(text, bdx); } } if ((inOrdering === "V") && (outOrdering === "V")) { //inOrientation != outOrientation //cases: VRTL->VLTR, VLTR->VRTL bdx.dir = inOrientation === "RTL"? RTL : LTR; return invertStr(text, bdx); } if ((inOrdering === "L") && (outFormat === "VRTL")) { //cases: LLTR->VRTL, LRTL->VRTL if (inOrientation === "LTR") { bdx.dir = LTR; text = doReorder(text, bdx); } else { //inOrientation == RTL bdx.dir = RTL; text = doReorder(text, bdx); } return invertStr(text); } if ((inFormat === "VLTR") && (outFormat === "LLTR")) { //case: VLTR->LLTR bdx.dir = LTR; return doReorder(text, bdx); } if ((inOrdering === "V") && (outOrdering === "L") && (inOrientation !== outOrientation)) { //cases: VLTR->LRTL, VRTL->LLTR text = invertStr(text); return (inOrientation === "RTL") ? doBidiReorder(text, "LLTR", "VLTR", swap, bdx) : doBidiReorder(text, "LRTL", "VRTL", swap, bdx); } if ((inFormat === "VRTL") && (outFormat === "LRTL")) { //case VRTL->LRTL return doBidiReorder(text, "LRTL", "VRTL", swap, bdx); } if ((inOrdering === "L") && (outOrdering === "L")) { //inOrientation != outOrientation //cases: LRTL->LLTR, LLTR->LRTL var saveSwap = bdx.swap; bdx.swap = saveSwap.substr(0, 1) + "N"; if (inOrientation === "RTL") { //LRTL->LLTR bdx.dir = RTL; text = doReorder(text, bdx); bdx.swap = "N" + saveSwap.substr(1, 2); bdx.dir = LTR; text = doReorder(text, bdx); } else { //LLTR->LRTL bdx.dir = LTR; text = doReorder(text, bdx); bdx.swap = "N" + saveSwap.substr(1, 2); text = doBidiReorder(text, "VLTR", "LRTL", bdx.swap, bdx); } return text; } } function prepareReorderingParameters(/*String*/text, /*Object*/params, /*Object*/bdx) { // summary: // Prepare reordering parameters // text: // The text to reorder. // params: // Object, containing reordering parameters: // - inFormat: Ordering scheme and base direction of the source text. // - outFormat: Required ordering scheme and base direction of the result. // - swap: Symmetric swapping attributes of source and result. // bdx: Object // Used for intermediate data storage // tags: // private if (params.inFormat === undefined) { params.inFormat = bdx.defInFormat; } if (params.outFormat === undefined) { params.outFormat = bdx.defOutFormat; } if (params.swap === undefined) { params.swap = bdx.defSwap; } if (params.inFormat === params.outFormat) { return params; } var dir, inOrdering = params.inFormat.substring(0, 1), inOrientation = params.inFormat.substring(1, 4), outOrdering = params.outFormat.substring(0, 1), outOrientation = params.outFormat.substring(1, 4); if (inOrientation.charAt(0) === "C") { dir = firstStrongDir(text); if (dir === "ltr" || dir === "rtl") { inOrientation = dir.toUpperCase(); } else { inOrientation = params.inFormat.charAt(2) === "L" ? "LTR" : "RTL"; } params.inFormat = inOrdering + inOrientation; } if (outOrientation.charAt(0) === "C") { dir = firstStrongDir(text); if (dir === "rtl") { outOrientation = "RTL"; } else if (dir === "ltr") { dir = lastStrongDir(text); outOrientation = dir.toUpperCase(); } else { outOrientation = params.outFormat.charAt(2) === "L" ? "LTR" : "RTL"; } params.outFormat = outOrdering + outOrientation; } return params; } function shape(/*boolean*/rtl, /*String*/text, /*boolean*/compress) { // summary: // Shape the source text. // rtl: // Flag indicating if the text is in RTL direction (logical // direction for Arabic words). // text: // The text to shape. // compress: // A flag indicates to insert extra space after the lam alef compression // to preserve the buffer size or not insert an extra space which will lead // to decrease the buffer size. This option can be: // // - true (default) to not insert extra space after compressing Lam+Alef into one character Lamalef // - false to insert an extra space after compressed Lamalef to preserve the buffer size // returns: // text shaped. // tags: // private. if (text.length === 0) { return; } if (rtl === undefined) { rtl = true; } if (compress === undefined) { compress = true; } text = String(text); var str06 = text.split(""), Ix = 0, step = +1, nIEnd = str06.length; if (!rtl) { Ix = str06.length - 1; step = -1; nIEnd = 1; } var compressArray = doShape(str06, Ix, step, nIEnd, compress); var outBuf = ""; for (var idx = 0; idx < str06.length; idx++) { if (!(compress && indexOf(compressArray, compressArray.length, idx) > -1)) { outBuf += str06[idx]; } else { updateMap(tsMap, idx, !rtl, -1); stMap.splice(idx, 1); } } return outBuf; } function doShape(str06, Ix, step, nIEnd, compress) { // summary: // Shape the source text. // str06: // Array containing source text // Ix: // Index of the first handled element // step: // direction of the process // nIEnd: // Index of the last handled element // compress: // A flag indicates to insert extra space after the lam alef compression // to preserve the buffer size or not insert an extra space which will lead // to decrease the buffer size. // returns: // Array, contained shaped text. // tags: // private. var previousCursive = 0, compressArray = [], compressArrayIndx = 0; for (var index = Ix; index * step < nIEnd; index = index + step) { if (isArabicAlefbet(str06[index]) || isArabicDiacritics(str06[index])) { // Arabic letter Lam if (str06[index] === "\u0644" && isNextAlef(str06, (index + step), step, nIEnd)) { str06[index] = (previousCursive === 0) ? getLamAlefFE(str06[index + step], LamAlefInialTableFE) : getLamAlefFE(str06[index + step], LamAlefMedialTableFE); index += step; setAlefToSpace(str06, index, step, nIEnd); if (compress) { compressArray[compressArrayIndx] = index; compressArrayIndx++; } previousCursive = 0; continue; } var currentChr = str06[index]; if (previousCursive === 1) { // if next is Arabic // Character is in medial form // else character is in final form str06[index] = (isNextArabic(str06, (index + step), step, nIEnd)) ? getMedialFormCharacterFE(str06[index]) : getFormCharacterFE(str06[index], FinalForm); } else { if (isNextArabic(str06, (index + step), step, nIEnd) === true) { //character is in Initial form str06[index] = getFormCharacterFE(str06[index], InitialForm); } else { str06[index] = getFormCharacterFE(str06[index], IsolatedForm); } } //exam if the current character is cursive if (!isArabicDiacritics(currentChr)) { previousCursive = 1; } if (isStandAlonCharacter(currentChr) === true) { previousCursive = 0; } } else { previousCursive = 0; } } return compressArray; } function firstStrongDir(/*String*/text) { // summary: // Return the first strong character direction // text: // The source string. // description: // Searches for first "strong" character. // Returns if strong character was found with the direction defined by this // character, if no strong character was found returns an empty string. // returns: String // "ltr" - if the first strong character is Latin. // "rtl" - if the first strong character is RTL directed character. // "" - if the strong character wasn't found. // tags: // private var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text); // if found return the direction that defined by the character return fdc ? (fdc[0] <= "z" ? "ltr" : "rtl") : ""; } function lastStrongDir(text) { // summary: // Return the last strong character direction // text: // The source string. // description: // Searches for first (from the end) "strong" character. // Returns if strong character was found with the direction defined by this // character, if no strong character was found returns an empty string. // tags: // private var chars = text.split(""); chars.reverse(); return firstStrongDir(chars.join("")); } function deshape(/*String*/text, /*boolean*/rtl, /*boolean*/consumeNextSpace) { // summary: // deshape the source text. // text: // the text to be deshape. // rtl: // flag indicating if the text is in RTL direction (logical // direction for Arabic words). // consumeNextSpace: // flag indicating whether to consume the space next to the // the lam alef if there is a space followed the Lamalef character to preserve the buffer size. // In case there is no space next to the lam alef the buffer size will be increased due to the // expansion of the lam alef one character into lam+alef two characters // returns: // text deshaped. if (text.length === 0) { return; } if (consumeNextSpace === undefined) { consumeNextSpace = true; } if (rtl === undefined) { rtl = true; } text = String(text); var outBuf = "", strFE = []; strFE = text.split(""); for (var i = 0; i < text.length; i++) { var increase = false; if (strFE[i] >= "\uFE70" && strFE[i] < "\uFEFF") { var chNum = text.charCodeAt(i); if (strFE[i] >= "\uFEF5" && strFE[i] <= "\uFEFC") { //expand the LamAlef if (rtl) { //Lam + Alef if (i > 0 && consumeNextSpace && strFE[i - 1] === " ") { outBuf = outBuf.substring(0, outBuf.length - 1) + "\u0644"; } else { outBuf += "\u0644"; increase = true; } outBuf += AlefTable[(chNum - 65269) / 2]; } else { outBuf += AlefTable[(chNum - 65269) / 2]; outBuf += "\u0644"; if (i + 1 < text.length && consumeNextSpace && strFE[i + 1] === " ") { i++; } else { increase = true; } } if (increase) { updateMap(tsMap, i, true, 1); stMap.splice(i, 0, stMap[i]); } } else { outBuf += FETo06Table[chNum - 65136]; } } else { outBuf += strFE[i]; } } return outBuf; } function doReorder(str, bdx) { // summary: // Helper to the doBidiReorder. Manages the UBA. // str: // the string to reorder. // bdx: Object // Used for intermediate data storage // returns: // text reordered according to source and result attributes. // tags: // private var chars = str.split(""), levels = []; computeLevels(chars, levels, bdx); swapChars(chars, levels, bdx); invertLevel(2, chars, levels, bdx); invertLevel(1, chars, levels, bdx); lvMap = levels; return chars.join(""); } function computeLevels(chars, levels, bdx) { var len = chars.length, impTab = bdx.dir ? impTabRtl : impTabLtr, prevState = null, newClass = null, newLevel = null, newState = 0, action = null, cond = null, condPos = -1, i = null, ix = null, types = [], classes = []; bdx.hiLevel = bdx.dir; bdx.lastArabic = false; bdx.hasUbatAl = false; bdx.hasUbatB = false; bdx.hasUbatS = false; for (i = 0; i < len; i++) { types[i] = getCharacterType(chars[i]); } for (ix = 0; ix < len; ix++) { prevState = newState; classes[ix] = newClass = getCharClass(chars, types, classes, ix, bdx); newState = impTab[prevState][newClass]; action = newState & 0xF0; newState &= 0x0F; levels[ix] = newLevel = impTab[newState][ITIL]; if (action > 0) { if (action === 0x10) { // set conditional run to level 1 for (i = condPos; i < ix; i++) { levels[i] = 1; } condPos = -1; } else { // 0x20 confirm the conditional run condPos = -1; } } cond = impTab[newState][ITCOND]; if (cond) { if (condPos === -1) { condPos = ix; } } else { // unconditional level if (condPos > -1) { for (i = condPos; i < ix; i++) { levels[i] = newLevel; } condPos = -1; } } if (types[ix] === UBAT_B) { levels[ix] = 0; } bdx.hiLevel |= newLevel; } if (bdx.hasUbatS) { handleUbatS(types, levels, len, bdx); } } function handleUbatS(types, levels, len, bdx) { for (var i = 0; i < len; i++) { if (types[i] === UBAT_S) { levels[i] = bdx.dir; for (var j = i - 1; j >= 0; j--) { if (types[j] === UBAT_WS) { levels[j] = bdx.dir; } else { break; } } } } } function swapChars(chars, levels, bdx) { // summary: // Swap characters with symmetrical mirroring as all kinds of parenthesis. // (When needed). // chars: // The source string as Array of characters. // levels: // An array (like hash) of flags for each character in the source string, // that defines if swapping should be applied on the following character. // bdx: Object // Used for intermediate data storage // tags: // private if (bdx.hiLevel === 0 || bdx.swap.substr(0, 1) === bdx.swap.substr(1, 2)) { return; } for (var i = 0; i < chars.length; i++) { if (levels[i] === 1) { chars[i] = getMirror(chars[i]); } } } function getCharacterType(ch) { // summary: // Return the type of the character. // ch: // The character to be checked. // description: // Check the type of the character according to MasterTable, // type = LTR, RTL, neutral,Arabic-Indic digit etc. // tags: // private var uc = ch.charCodeAt(0), hi = MasterTable[uc >> 8]; return (hi < TBBASE) ? hi : UnicodeTable[hi - TBBASE][uc & 0xFF]; } function invertStr(str, bdx) { // summary: // Return the reversed string. // str: // The string to be reversed. // description: // Reverse the string str. // tags: // private var chars = str.split(""); if (bdx) { var levels = []; computeLevels(chars, levels, bdx); lvMap = levels; } chars.reverse(); stMap.reverse(); return chars.join(""); } function indexOf(cArray, cLength, idx) { for (var i = 0; i < cLength; i++) { if (cArray[i] === idx) { return i; } } return -1; } function isArabicAlefbet(c) { for (var i = 0; i < ArabicAlefBetIntervalsBegine.length; i++) { if (c >= ArabicAlefBetIntervalsBegine[i] && c <= ArabicAlefBetIntervalsEnd[i]) { return true; } } return false; } function isNextArabic(str06, index, step, nIEnd) { while (((index) * step) < nIEnd && isArabicDiacritics(str06[index])) { index += step; } if (((index) * step) < nIEnd && isArabicAlefbet(str06[index])) { return true; } return false; } function isNextAlef(str06, index, step, nIEnd) { while (((index) * step) < nIEnd && isArabicDiacritics(str06[index])) { index += step; } var c = " "; if (((index) * step) < nIEnd) { c = str06[index]; } else { return false; } for (var i = 0; i < AlefTable.length; i++) { if (AlefTable[i] === c) { return true; } } return false; } function invertLevel(lev, chars, levels, bdx) { if (bdx.hiLevel < lev) { return; } if (lev === 1 && bdx.dir === RTL && !bdx.hasUbatB) { chars.reverse(); stMap.reverse(); return; } var len = chars.length, start = 0, end, lo, hi, tmp; while (start < len) { if (levels[start] >= lev) { end = start + 1; while (end < len && levels[end] >= lev) { end++; } for (lo = start, hi = end - 1 ; lo < hi; lo++, hi--) { tmp = chars[lo]; chars[lo] = chars[hi]; chars[hi] = tmp; tmp = stMap[lo]; stMap[lo] = stMap[hi]; stMap[hi] = tmp; } start = end; } start++; } } function getCharClass(chars, types, classes, ix, bdx) { // summary: // Return the class if ix character in chars. // chars: // The source string as Array of characters. // types: // Array of types, for each character in chars. // classes: // Array of classes that already been solved. // ix: // the index of checked character. // bdx: Object // Used for intermediate data storage // tags: // private var cType = types[ix], results = { UBAT_L : function () { bdx.lastArabic = false; return UBAT_L; }, UBAT_R : function () { bdx.lastArabic = false; return UBAT_R; }, UBAT_ON : function () { return UBAT_ON; }, UBAT_AN : function () { return UBAT_AN; }, UBAT_EN : function () { return bdx.lastArabic ? UBAT_AN : UBAT_EN; }, UBAT_AL : function () { bdx.lastArabic = true; bdx.hasUbatAl = true; return UBAT_R; }, UBAT_WS : function () { return UBAT_ON; }, UBAT_CS : function () { var wType, nType; if (ix < 1 || (ix + 1) >= types.length || ((wType = classes[ix - 1]) !== UBAT_EN && wType !== UBAT_AN) || ((nType = types[ix + 1]) !== UBAT_EN && nType !== UBAT_AN)) { return UBAT_ON; } if (bdx.lastArabic) { nType = UBAT_AN; } return nType === wType ? nType : UBAT_ON; }, UBAT_ES : function () { var wType = ix > 0 ? classes[ix - 1] : UBAT_B; if (wType === UBAT_EN && (ix + 1) < types.length && types[ix + 1] === UBAT_EN) { return UBAT_EN; } return UBAT_ON; }, UBAT_ET : function () { if (ix > 0 && classes[ix - 1] === UBAT_EN) { return UBAT_EN; } if (bdx.lastArabic) { return UBAT_ON; } var i = ix + 1, len = types.length; while (i < len && types[i] === UBAT_ET) { i++; } if (i < len && types[i] === UBAT_EN) { return UBAT_EN; } return UBAT_ON; }, UBAT_NSM : function () { if (bdx.inFormat === "VLTR") { // visual to implicit transformation var len = types.length, i = ix + 1; while (i < len && types[i] === UBAT_NSM) { i++; } if (i < len) { var c = chars[ix], rtlCandidate = (c >= 0x0591 && c <= 0x08FF) || c === 0xFB1E, wType = types[i]; if (rtlCandidate && (wType === UBAT_R || wType === UBAT_AL)) { return UBAT_R; } } } if (ix < 1 || types[ix - 1] === UBAT_B) { return UBAT_ON; } return classes[ix - 1]; }, UBAT_B : function () { bdx.lastArabic = true; bdx.hasUbatB = true; return bdx.dir; }, UBAT_S : function () { bdx.hasUbatS = true; return UBAT_ON; }, UBAT_LRE : function () { bdx.lastArabic = false; return UBAT_ON; }, UBAT_RLE : function () { bdx.lastArabic = false; return UBAT_ON; }, UBAT_LRO : function () { bdx.lastArabic = false; return UBAT_ON; }, UBAT_RLO : function () { bdx.lastArabic = false; return UBAT_ON; }, UBAT_PDF : function () { bdx.lastArabic = false; return UBAT_ON; }, UBAT_BN : function () { return UBAT_ON; } }; return results[TYPES_NAMES[cType]](); } function getMirror(c) { // summary: // Calculates the mirrored character of c // c: // The character to be mirrored. // tags: // private var mid, low = 0, high = SwapTable.length - 1; while (low <= high) { mid = Math.floor((low + high) / 2); if (c < SwapTable[mid][0]) { high = mid - 1; } else if (c > SwapTable[mid][0]) { low = mid + 1; } else { return SwapTable[mid][1]; } } return c; } function isStandAlonCharacter(c) { for (var i = 0; i < StandAlonForm.length; i++) { if (StandAlonForm[i] === c) { return true; } } return false; } function getMedialFormCharacterFE(c) { for (var i = 0; i < BaseForm.length; i++) { if (c === BaseForm[i]) { return MedialForm[i]; } } return c; } function getFormCharacterFE(/*char*/ c, /*char[]*/formArr) { for (var i = 0; i < BaseForm.length; i++) { if (c === BaseForm[i]) { return formArr[i]; } } return c; } function isArabicDiacritics(c) { return (c >= "\u064b" && c <= "\u0655") ? true : false; } function getOrientation(/*Char*/ oc) { if (oc === "L") { return "LTR"; } if (oc === "R") { return "RTL"; } if (oc === "C") { return "CLR"; } if (oc === "D") { return "CRL"; } } function setAlefToSpace(str06, index, step, nIEnd) { while (((index) * step) < nIEnd && isArabicDiacritics(str06[index])) { index += step; } if (((index) * step) < nIEnd) { str06[index] = " "; return true; } return false; } function getLamAlefFE(alef06, LamAlefForm) { for (var i = 0; i < AlefTable.length; i++) { if (alef06 === AlefTable[i]) { return LamAlefForm[i]; } } return alef06; } function initMaps(map1, map2, length) { stMap = []; lvMap = []; for (var i = 0; i < length; i++) { map1[i] = i; map2[i] = i; stMap[i] = i; } } function reverseMap(sourceMap) { var map = new Array(sourceMap.length); for (var i = 0; i < sourceMap.length; i++) { map[sourceMap[i]] = i; } return map; } function updateMap(map, value, isGreater, update) { for (var i = 0; i < map.length; i++) { if (map[i] > value || (!isGreater && map[i] === value)) { map[i] += update; } } } var stMap = []; var tsMap = []; var lvMap = []; var BDX = { dir: 0, defInFormat: "LLTR", defoutFormat: "VLTR", defSwap: "YN", inFormat: "LLTR", outFormat: "VLTR", swap: "YN", hiLevel: 0, lastArabic: false, hasUbatAl: false, hasBlockSep: false, hasSegSep: false }; var ITIL = 5; var ITCOND = 6; var LTR = 0; var RTL = 1; var validFormat = /^[(I|V)][(L|R|C|D)][(Y|N)][(S|N)][N]$/; var bidiChars = /[\u0591-\u06ff\ufb1d-\ufefc]/; /****************************************************************************/ /* Array in which directional characters are replaced by their symmetric. */ /****************************************************************************/ var SwapTable = [ [ "\u0028", "\u0029" ], /* Round brackets */ [ "\u0029", "\u0028" ], [ "\u003C", "\u003E" ], /* Less than/greater than */ [ "\u003E", "\u003C" ], [ "\u005B", "\u005D" ], /* Square brackets */ [ "\u005D", "\u005B" ], [ "\u007B", "\u007D" ], /* Curly brackets */ [ "\u007D", "\u007B" ], [ "\u00AB", "\u00BB" ], /* Double angle quotation marks */ [ "\u00BB", "\u00AB" ], [ "\u2039", "\u203A" ], /* single angle quotation mark */ [ "\u203A", "\u2039" ], [ "\u207D", "\u207E" ], /* Superscript parentheses */ [ "\u207E", "\u207D" ], [ "\u208D", "\u208E" ], /* Subscript parentheses */ [ "\u208E", "\u208D" ], [ "\u2264", "\u2265" ], /* Less/greater than or equal */ [ "\u2265", "\u2264" ], [ "\u2329", "\u232A" ], /* Angle brackets */ [ "\u232A", "\u2329" ], [ "\uFE59", "\uFE5A" ], /* Small round brackets */ [ "\uFE5A", "\uFE59" ], [ "\uFE5B", "\uFE5C" ], /* Small curly brackets */ [ "\uFE5C", "\uFE5B" ], [ "\uFE5D", "\uFE5E" ], /* Small tortoise shell brackets */ [ "\uFE5E", "\uFE5D" ], [ "\uFE64", "\uFE65" ], /* Small less than/greater than */ [ "\uFE65", "\uFE64" ] ]; var AlefTable = ["\u0622", "\u0623", "\u0625", "\u0627"]; var LamAlefInialTableFE = ["\ufef5", "\ufef7", "\ufef9", "\ufefb"]; var LamAlefMedialTableFE = ["\ufef6", "\ufef8", "\ufefa", "\ufefc"]; /** * Arabic Characters in the base form */ var BaseForm = ["\u0627", "\u0628", "\u062A", "\u062B", "\u062C", "\u062D", "\u062E", "\u062F", "\u0630", "\u0631", "\u0632", "\u0633", "\u0634", "\u0635", "\u0636", "\u0637", "\u0638", "\u0639", "\u063A", "\u0641", "\u0642", "\u0643", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", "\u064A", "\u0625", "\u0623", "\u0622", "\u0629", "\u0649", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", "\u064A", "\u0625", "\u0623", "\u0622", "\u0629", "\u0649", "\u06CC", "\u0626", "\u0624"]; /** * Arabic shaped characters in Isolated form */ var IsolatedForm = ["\uFE8D", "\uFE8F", "\uFE95", "\uFE99", "\uFE9D", "\uFEA1", "\uFEA5", "\uFEA9", "\uFEAB", "\uFEAD", "\uFEAF", "\uFEB1", "\uFEB5", "\uFEB9", "\uFEBD", "\uFEC1", "\uFEC5", "\uFEC9", "\uFECD", "\uFED1", "\uFED5", "\uFED9", "\uFEDD", "\uFEE1", "\uFEE5", "\uFEE9", "\uFEED", "\uFEF1", "\uFE87", "\uFE83", "\uFE81", "\uFE93", "\uFEEF", "\uFBFC", "\uFE89", "\uFE85", "\uFE70", "\uFE72", "\uFE74", "\uFE76", "\uFE78", "\uFE7A", "\uFE7C", "\uFE7E", "\uFE80", "\uFE89", "\uFE85"]; /** * Arabic shaped characters in Final form */ var FinalForm = ["\uFE8E", "\uFE90", "\uFE96", "\uFE9A", "\uFE9E", "\uFEA2", "\uFEA6", "\uFEAA", "\uFEAC", "\uFEAE", "\uFEB0", "\uFEB2", "\uFEB6", "\uFEBA", "\uFEBE", "\uFEC2", "\uFEC6", "\uFECA", "\uFECE", "\uFED2", "\uFED6", "\uFEDA", "\uFEDE", "\uFEE2", "\uFEE6", "\uFEEA", "\uFEEE", "\uFEF2", "\uFE88", "\uFE84", "\uFE82", "\uFE94", "\uFEF0", "\uFBFD", "\uFE8A", "\uFE86", "\uFE70", "\uFE72", "\uFE74", "\uFE76", "\uFE78", "\uFE7A", "\uFE7C", "\uFE7E", "\uFE80", "\uFE8A", "\uFE86"]; /** * Arabic shaped characters in Media form */ var MedialForm = ["\uFE8E", "\uFE92", "\uFE98", "\uFE9C", "\uFEA0", "\uFEA4", "\uFEA8", "\uFEAA", "\uFEAC", "\uFEAE", "\uFEB0", "\uFEB4", "\uFEB8", "\uFEBC", "\uFEC0", "\uFEC4", "\uFEC8", "\uFECC", "\uFED0", "\uFED4", "\uFED8", "\uFEDC", "\uFEE0", "\uFEE4", "\uFEE8", "\uFEEC", "\uFEEE", "\uFEF4", "\uFE88", "\uFE84", "\uFE82", "\uFE94", "\uFEF0", "\uFBFF", "\uFE8C", "\uFE86", "\uFE71", "\uFE72", "\uFE74", "\uFE77", "\uFE79", "\uFE7B", "\uFE7D", "\uFE7F", "\uFE80", "\uFE8C", "\uFE86"]; /** * Arabic shaped characters in Initial form */ var InitialForm = ["\uFE8D", "\uFE91", "\uFE97", "\uFE9B", "\uFE9F", "\uFEA3", "\uFEA7", "\uFEA9", "\uFEAB", "\uFEAD", "\uFEAF", "\uFEB3", "\uFEB7", "\uFEBB", "\uFEBF", "\uFEC3", "\uFEC7", "\uFECB", "\uFECF", "\uFED3", "\uFED7", "\uFEDB", "\uFEDF", "\uFEE3", "\uFEE7", "\uFEEB", "\uFEED", "\uFEF3", "\uFE87", "\uFE83", "\uFE81", "\uFE93", "\uFEEF", "\uFBFE", "\uFE8B", "\uFE85", "\uFE70", "\uFE72", "\uFE74", "\uFE76", "\uFE78", "\uFE7A", "\uFE7C", "\uFE7E", "\uFE80", "\uFE8B", "\uFE85"]; /** * Arabic characters that couldn't join to the next character */ var StandAlonForm = ["\u0621", "\u0622", "\u0623", "\u0624", "\u0625", "\u0627", "\u0629", "\u062F", "\u0630", "\u0631", "\u0632", "\u0648", "\u0649"]; var FETo06Table = ["\u064B", "\u064B", "\u064C", "\u061F", "\u064D", "\u061F", "\u064E", "\u064E", "\u064F", "\u064F", "\u0650", "\u0650", "\u0651", "\u0651", "\u0652", "\u0652", "\u0621", "\u0622", "\u0622", "\u0623", "\u0623", "\u0624", "\u0624", "\u0625", "\u0625", "\u0626", "\u0626", "\u0626", "\u0626", "\u0627", "\u0627", "\u0628", "\u0628", "\u0628", "\u0628", "\u0629", "\u0629", "\u062A", "\u062A", "\u062A", "\u062A", "\u062B", "\u062B", "\u062B", "\u062B", "\u062C", "\u062C", "\u062C", "\u062c", "\u062D", "\u062D", "\u062D", "\u062D", "\u062E", "\u062E", "\u062E", "\u062E", "\u062F", "\u062F", "\u0630", "\u0630", "\u0631", "\u0631", "\u0632", "\u0632", "\u0633", "\u0633", "\u0633", "\u0633", "\u0634", "\u0634", "\u0634", "\u0634", "\u0635", "\u0635", "\u0635", "\u0635", "\u0636", "\u0636", "\u0636", "\u0636", "\u0637", "\u0637", "\u0637", "\u0637", "\u0638", "\u0638", "\u0638", "\u0638", "\u0639", "\u0639", "\u0639", "\u0639", "\u063A", "\u063A", "\u063A", "\u063A", "\u0641", "\u0641", "\u0641", "\u0641", "\u0642", "\u0642", "\u0642", "\u0642", "\u0643", "\u0643", "\u0643", "\u0643", "\u0644", "\u0644", "\u0644", "\u0644", "\u0645", "\u0645", "\u0645", "\u0645", "\u0646", "\u0646", "\u0646", "\u0646", "\u0647", "\u0647", "\u0647", "\u0647", "\u0648", "\u0648", "\u0649", "\u0649", "\u064A", "\u064A", "\u064A", "\u064A", "\uFEF5", "\uFEF6", "\uFEF7", "\uFEF8", "\uFEF9", "\uFEFA", "\uFEFB", "\uFEFC", "\u061F", "\u061F", "\u061F"]; var ArabicAlefBetIntervalsBegine = ["\u0621", "\u0641"]; var ArabicAlefBetIntervalsEnd = ["\u063A", "\u064a"]; var impTabLtr = [ /* L, R, EN, AN, N, IL, Cond */ [ 0, 3, 0, 1, 0, 0, 0 ], /* 0 LTR text */ [ 0, 3, 0, 1, 2, 2, 0 ], /* 1 LTR+AN */ [ 0, 3, 0, 0x11, 2, 0, 1 ], /* 2 LTR+AN+N */ [ 0, 3, 5, 5, 4, 1, 0 ], /* 3 RTL text */ [ 0, 3, 0x15, 0x15, 4, 0, 1 ], /* 4 RTL cont */ [ 0, 3, 5, 5, 4, 2, 0 ] /* 5 RTL+EN/AN */ ]; var impTabRtl = [ /* L, R, EN, AN, N, IL, Cond */ [ 2, 0, 1, 1, 0, 1, 0 ], /* 0 RTL text */ [ 2, 0, 1, 1, 0, 2, 0 ], /* 1 RTL+EN/AN */ [ 2, 0, 2, 1, 3, 2, 0 ], /* 2 LTR text */ [ 2, 0, 2, 0x21, 3, 1, 1 ] /* 3 LTR+cont */ ]; var UBAT_L = 0; /* left to right */ var UBAT_R = 1; /* right to left */ var UBAT_EN = 2; /* European digit */ var UBAT_AN = 3; /* Arabic-Indic digit */ var UBAT_ON = 4; /* neutral */ var UBAT_B = 5; /* block separator */ var UBAT_S = 6; /* segment separator */ var UBAT_AL = 7; /* Arabic Letter */ var UBAT_WS = 8; /* white space */ var UBAT_CS = 9; /* common digit separator */ var UBAT_ES = 10; /* European digit separator */ var UBAT_ET = 11; /* European digit terminator */ var UBAT_NSM = 12; /* Non Spacing Mark */ var UBAT_LRE = 13; /* LRE */ var UBAT_RLE = 14; /* RLE */ var UBAT_PDF = 15; /* PDF */ var UBAT_LRO = 16; /* LRO */ var UBAT_RLO = 17; /* RLO */ var UBAT_BN = 18; /* Boundary Neutral */ var TYPES_NAMES = [ "UBAT_L", "UBAT_R", "UBAT_EN", "UBAT_AN", "UBAT_ON", "UBAT_B", "UBAT_S", "UBAT_AL", "UBAT_WS", "UBAT_CS", "UBAT_ES", "UBAT_ET", "UBAT_NSM", "UBAT_LRE", "UBAT_RLE", "UBAT_PDF", "UBAT_LRO", "UBAT_RLO", "UBAT_BN" ]; var TBBASE = 100; var TB00 = TBBASE + 0; var TB05 = TBBASE + 1; var TB06 = TBBASE + 2; var TB07 = TBBASE + 3; var TB20 = TBBASE + 4; var TBFB = TBBASE + 5; var TBFE = TBBASE + 6; var TBFF = TBBASE + 7; var L = UBAT_L; var R = UBAT_R; var EN = UBAT_EN; var AN = UBAT_AN; var ON = UBAT_ON; var B = UBAT_B; var S = UBAT_S; var AL = UBAT_AL; var WS = UBAT_WS; var CS = UBAT_CS; var ES = UBAT_ES; var ET = UBAT_ET; var NSM = UBAT_NSM; var LRE = UBAT_LRE; var RLE = UBAT_RLE; var PDF = UBAT_PDF; var LRO = UBAT_LRO; var RLO = UBAT_RLO; var BN = UBAT_BN; var MasterTable = [ /*******************************************************************************************************/ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /*******************************************************************************************************/ /*0-*/ TB00, L, L, L, L, TB05, TB06, TB07, R, L, L, L, L, L, L, L, /*1-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*2-*/ TB20, ON, ON, ON, L, ON, L, ON, L, ON, ON, ON, L, L, ON, ON, /*3-*/ L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*4-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, ON, /*5-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*6-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*7-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*8-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*9-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, /*A-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, /*B-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*C-*/ ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*D-*/ ON, ON, ON, ON, ON, ON, ON, L, L, ON, ON, L, L, ON, ON, L, /*E-*/ L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, /*F-*/ ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, TBFB, AL, AL, TBFE, TBFF ]; var UnicodeTable = [ [ /* Table 00: Unicode 00xx */ /****************************************************************************************/ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /****************************************************************************************/ /*0-*/ BN, BN, BN, BN, BN, BN, BN, BN, BN, S, B, S, WS, B, BN, BN, /*1-*/ BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, B, B, B, S, /*2-*/ WS, ON, ON, ET, ET, ET, ON, ON, ON, ON, ON, ES, CS, ES, CS, CS, /*3-*/ EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, CS, ON, ON, ON, ON, ON, /*4-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*5-*/ L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, /*6-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*7-*/ L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, BN, /*8-*/ BN, BN, BN, BN, BN, B, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, /*9-*/ BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, /*A-*/ CS, ON, ET, ET, ET, ET, ON, ON, ON, ON, L, ON, ON, BN, ON, ON, /*B-*/ ET, ET, EN, EN, ON, L, ON, ON, ON, EN, L, ON, ON, ON, ON, ON, /*C-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*D-*/ L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L, /*E-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*F-*/ L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L ], [ /* Table 01: Unicode 05xx */ /****************************************************************************************/ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /****************************************************************************************/ /*0-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*1-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*2-*/ L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, /*3-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*4-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*5-*/ L, L, L, L, L, L, L, ON, ON, L, L, L, L, L, L, L, /*6-*/ ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*7-*/ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, /*8-*/ L, L, L, L, L, L, L, L, ON, L, ON, ON, ON, ON, ON, ON, /*9-*/ ON, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, /*A-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, /*B-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, NSM, /*C-*/ R, NSM, NSM, R, NSM, NSM, R, NSM, ON, ON, ON, ON, ON, ON, ON, ON, /*D-*/ R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, /*E-*/ R, R, R, R, R, R, R, R, R, R, R, ON, ON, ON, ON, ON, /*F-*/ R, R, R, R, R, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON ], [ /* Table 02: Unicode 06xx */ /****************************************************************************************/ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /****************************************************************************************/ /*0-*/ AN, AN, AN, AN, ON, ON, ON, ON, AL, ET, ET, AL, CS, AL, ON, ON, /*1-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AL, ON, ON, AL, AL, /*2-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*3-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*4-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, /*5-*/ NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, /*6-*/ AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, ET, AN, AN, AL, AL, AL, /*7-*/ NSM, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*8-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*9-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*A-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*B-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*C-*/ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, /*D-*/ AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AN, ON, NSM, /*E-*/ NSM, NSM, NSM, NSM, NSM, AL, AL, NSM, NSM, ON, NSM, NSM, NSM, NSM, AL, AL, /*F-*/ EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, AL, AL, AL, AL, AL, AL ], [ /* Table 03: Unicode 07xx */ /****************************************************************************************/ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /*****************************************************