} else {
     if (strtolower(substr($f, -4, 4)) == '.ttf' || strtolower(substr($f, -4, 4)) == '.otf') {
         $ret[] = $ttf->extractCoreInfo($ttfdir . $f);
     }
 }
 for ($i = 0; $i < count($ret); $i++) {
     if (!is_array($ret[$i])) {
         if (!$pdf) {
             echo $ret[$i] . '<br />';
         }
     } else {
         $tfname = $ret[$i][0];
         $bold = $ret[$i][1];
         $italic = $ret[$i][2];
         $fname = strtolower($tfname);
         $fname = preg_replace_callback_callback('/[ ()]/', '', $fname);
         $tempfonttrans[$tfname] = $fname;
         $style = '';
         if ($bold) {
             $style .= 'B';
         }
         if ($italic) {
             $style .= 'I';
         }
         if (!$style) {
             $style = 'R';
         }
         $tempfontdata[$fname][$style] = $f;
         if ($isTTC) {
             $tempfontdata[$fname]['TTCfontID'][$style] = $ret[$i][4];
         }
 function substituteIndic($earr, $lang, $font)
 {
     global $voltdata;
     if (!isset($voltdata[$font])) {
         include_once _MPDF_PATH . 'includes/' . $font . '.volt.php';
         $voltdata[$font] = $volt;
     }
     foreach ($earr as $eid => $char) {
         $earr[$eid] = sprintf("%04s", strtoupper(dechex($char)));
     }
     $vstr = "0020 " . implode(" ", $earr) . " 0020";
     //============================
     // Common Indic Punctuation marks
     // If NOT devanagari
     if ($lang != 'hi') {
         $vstr = str_replace('0964', '007C', $vstr);
         // U+0964 replace with "|"
         $vstr = str_replace('0965', '007C 007C', $vstr);
         // U+0964 replace with "|"
     }
     //============================
     // Tamil numeral for Zero missing Added mPDF 4.2
     if ($lang == 'ta') {
         $vstr = str_replace('0BE6', '0030', $vstr);
         // U+0BEB replace with "0"
     }
     //============================
     // Re-order vowels
     // DEVANAGARI vowel sign matraI[093F] before consonant
     if ($lang == 'hi') {
         $prebasedvowels = "(093F)";
         $nukta = "093C";
         $halant = "094D";
         $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr);
         // vowel sign pre-based shift left
         $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr);
         // before NUKTA
         $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
         // before CHAR HALANT  ==  VIRAMA
     } else {
         if ($lang == 'bn') {
             // Khanda Ta 09CE not in font -> replace with 09A4|09CD
             $vstr = preg_replace_callback_callback('/09CE/', '09A4 09CD 200D', $vstr);
             // mPDF 5.3.09
             // BENGALI double-part vowels [09CB 09C7 09BE][09CC 09C7 09D7]
             $vstr = str_replace('09CB', '09C7 09BE', $vstr);
             // convert to 2 parts
             $vstr = str_replace('09CC', '09C7 09D7', $vstr);
             // 09C7 pre-based is then shifted below
             $prebasedvowels = "(09BF|09C7|09C8)";
             $nukta = "09BC";
             $halant = "09CD";
             // mPDF 5.0.044
             $bnfullcons = "0995|0996|0997|0998|0999|099A|099B|099C|099D|099F|09A0|09A1|09A2|09A3|09A4|09A5|09A6|09A7|09A8|09AA|09AB|09AC|09AD|09AE|09AF|09B0|09B2|09B6|09B7|09B8|09B9|09DC|09DD|09DF";
             $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr);
             // vowel sign pre-based shift left
             $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr);
             // before NUKTA
             $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
             // before CHAR HALANT
             // mPDF 5.0.044
             // .. and shifting left-based vowel further to the left in case 3 consonants together.
             $vstr = preg_replace_callback_callback('/(' . $bnfullcons . ') ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
             // mPDF 5.0.044
             // If left-based vowel has now been shifted to left of RA/Halant (09B0/09CD)
             // Convert here to above-line form (E068) as it would get missed later
             // e.g. 09B0 09CD 09AD 09C7 would be changed above =>
             // e.g. 09C7 09B0 09CD 09AD. The 09B0 09CD should => E068
             // ??? need to add 09BF as well (09BF|09C7|09C8)
             $vstr = preg_replace_callback_callback('/(09C7|09C8) 09B0 09CD/', '\\1 E068', $vstr);
         } else {
             if ($lang == 'gu') {
                 $prebasedvowels = "(0ABF)";
                 $nukta = "0ABC";
                 $halant = "0ACD";
                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr);
                 // vowel sign pre-based shift left
                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr);
                 // before NUKTA
                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
                 // before CHAR HALANT
             } else {
                 if ($lang == 'pa') {
                     $prebasedvowels = "(0A3F)";
                     $nukta = "0A3C";
                     $halant = "0A4D";
                     $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr);
                     // vowel sign pre-based shift left
                     $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr);
                     // before NUKTA
                     $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
                     // before CHAR HALANT
                 } else {
                     if ($lang == 'ta') {
                         // Shrii (Shree)
                         $vstr = preg_replace_callback_callback('/0BB6 0BCD 0BB0 0BC0/', 'E04B', $vstr);
                         // TAMIL double-part vowels [0BCA 0BC6 0BBE][0BCB 0BC7 0BBE][0BCC 0BC6 0BD7]
                         $vstr = preg_replace_callback_callback('/0BCA/', '0BC6 0BBE', $vstr);
                         // convert to 2 parts
                         $vstr = preg_replace_callback_callback('/0BCB/', '0BC7 0BBE', $vstr);
                         // pre-based is then shifted below
                         $vstr = preg_replace_callback_callback('/0BCC/', '0BC6 0BD7', $vstr);
                         $prebasedvowels = "(0BC6|0BC7|0BC8)";
                         // No nukta
                         $halant = "0BCD";
                         // Doesn't seem to move most in front of halanted consonants
                         $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr);
                         // vowel sign pre-based shift left
                         // ? Only for special case KSS (already moved to left of 0BB7)
                         $vstr = preg_replace_callback_callback('/0B95 ' . $halant . ' ' . $prebasedvowels . ' 0BB7/', '\\1 0B95 ' . $halant . ' 0BB7', $vstr);
                     } else {
                         if ($lang == 'or') {
                             // ORIYA double-part vowels []
                             $vstr = str_replace('0B48', '0B47 0B56', $vstr);
                             // 2-part Vowel
                             $vstr = str_replace('0B4B', '0B47 0B3E', $vstr);
                             // 2-part Vowel
                             $vstr = str_replace('0B4C', '0B47 0B57', $vstr);
                             // 2-part Vowel
                             $orprebasedvowels = "(0B47)";
                             // No nukta
                             $halant = "0B4D";
                             $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $orprebasedvowels . '/', '\\2 \\1', $vstr);
                             // vowel sign pre-based shift left
                             $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $orprebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
                             // before CHAR HALANT
                             $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $orprebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
                             // before CHAR HALANT
                         } else {
                             if ($lang == 'ml') {
                                 // Chillus - old forms - remove ZWNJ after
                                 // This font Volt rules recognises e.g. "Na Halant(Virama)" as ChilluN
                                 $vstr = preg_replace_callback_callback('/(0D23 0D4D|0D28 0D4D|0D30 0D4D|0D32 0D4D|0D33 0D4D) 200D/', '\\1', $vstr);
                                 // See Chillus in Unicode [http://en.wikipedia.org/wiki/Malayalam_script]
                                 $vstr = str_replace('0D7A', '0D23 0D4D', $vstr);
                                 // [mlymChilluNn]
                                 $vstr = str_replace('0D7B', '0D28 0D4D', $vstr);
                                 // [mlymChilluN]
                                 $vstr = str_replace('0D7C', '0D30 0D4D', $vstr);
                                 // [mlymChilluR]
                                 $vstr = str_replace('0D7D', '0D32 0D4D', $vstr);
                                 // [mlymChilluL]
                                 $vstr = str_replace('0D7E', '0D33 0D4D', $vstr);
                                 // [mlymChilluLl]
                                 /*
                                 		// Chillus - 0D7A-0D7E not in font directly, but as E005-E009
                                 		$vstr = preg_replace_callback_callback('/0D23 0D4D 200D/','0D7A', $vstr);
                                 		$vstr = preg_replace_callback_callback('/0D28 0D4D 200D/','0D7B', $vstr);
                                 		$vstr = preg_replace_callback_callback('/0D30 0D4D 200D/','0D7C', $vstr);
                                 		$vstr = preg_replace_callback_callback('/0D32 0D4D 200D/','0D7D', $vstr);
                                 		$vstr = preg_replace_callback_callback('/0D33 0D4D 200D/','0D7E', $vstr);
                                 
                                 		$vstr = preg_replace_callback_callback('/0D7F/','E004', $vstr);	// [mlymChilluK] 
                                 		$vstr = preg_replace_callback_callback('/0D7A/','E005', $vstr);	// [mlymChilluNn] 
                                 		$vstr = preg_replace_callback_callback('/0D7B/','E006', $vstr);	// [mlymChilluN] 
                                 		$vstr = preg_replace_callback_callback('/0D7C/','E007', $vstr);	// [mlymChilluR] 
                                 		$vstr = preg_replace_callback_callback('/0D7D/','E008', $vstr);	// [mlymChilluL] 
                                 		$vstr = preg_replace_callback_callback('/0D7E/','E009', $vstr);	// [mlymChilluLl] 
                                 */
                                 // MALAYALAM double-part vowels []
                                 $vstr = str_replace('0D4A', '0D46 0D3E', $vstr);
                                 // 2-part Vowel
                                 $vstr = str_replace('0D4B', '0D47 0D3E', $vstr);
                                 // 2-part Vowel
                                 $vstr = str_replace('0D4C', '0D46 0D57', $vstr);
                                 // 2-part Vowel
                                 $mlprebasedvowels = "(0D46|0D47|0D48)";
                                 // No nukta
                                 $halant = "0D4D";
                                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $mlprebasedvowels . '/', '\\2 \\1', $vstr);
                                 // vowel sign pre-based shift left
                                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $mlprebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr);
                                 // before CHAR HALANT
                             } else {
                                 if ($lang == 'te') {
                                     // TELUGU double-part vowels [0C48 -> 0C46 0C56]
                                     $vstr = str_replace('0C48', '0C46 0C56', $vstr);
                                     // 2-part Vowel
                                     $prebasedvowels = "(0C46)";
                                     $abvvowels = "(0C3E|0C3F|0C40|0C46|0C47|0C4A|0C4B|0C4C|0C55)";
                                     // No nukta
                                     $halant = "0C4D";
                                     $tefullforms = "0C15|0C17|0C18|0C1A|0C1B|0C1C|0C1D|0C20|0C21|0C22|0C24|0C25|0C26|0C27|0C28|0C2A|0C2B|0C2D|0C2E|0C2F|0C30|0C33|0C35|0C36|0C37|0C38|0C39|E028|E029|E02A|E02B|E078|E07A|E07B";
                                     $vstr = preg_replace_callback_callback('/(' . $tefullforms . ') ' . $halant . ' (' . $tefullforms . ') ' . $abvvowels . '/', '\\1 \\3 ' . $halant . ' \\2', $vstr);
                                     // before HALANT
                                 } else {
                                     if ($lang == 'kn') {
                                         // KANNADA double-part vowels [0CC8 -> 0CC6 0CD6]
                                         $vstr = str_replace('0CC0', '0CBF 0CD5', $vstr);
                                         // 2-part Vowel
                                         $vstr = str_replace('0CC7', '0CC6 0CD5', $vstr);
                                         // 2-part Vowel
                                         $vstr = str_replace('0CC8', '0CC6 0CD6', $vstr);
                                         // 2-part Vowel AI - no glyph for single
                                         $vstr = str_replace('0CCA', '0CC6 0CC2', $vstr);
                                         // 2-part Vowel
                                         $vstr = str_replace('0CCB', '0CC6 0CC2 0CD5', $vstr);
                                         // 2-part Vowel
                                         $prebasedvowels = "(0CBF|0CC6)";
                                         $halant = "0CCD";
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     //============================
     // SPECIALS
     // DEVANAGARI Ra Halant Ra
     if ($lang == 'hi') {
         $vstr = str_replace('0930 094D 0930', 'E05D 0930', $vstr);
         // Ra Halant Ra => halfRa FullRa
     }
     // GUJARATI
     if ($lang == 'gu') {
         $vstr = str_replace('0AB0 0AC2', 'E02E', $vstr);
         // Ra VowelUu => SpecialForm RaUu
     }
     // TELUGU Ra Halant <Consonant> Halant => halfRa Halant<Consonant> Halant
     if ($lang == 'te') {
         $vstr = preg_replace_callback_callback('/0C30 0C4D ([A-F0-9]{4}) 0C4D/', 'E021 0C4D \\1 0C4D', $vstr);
     }
     // KANNADA
     // Reph at end of word becomes E0CC instead of E00B
     if ($lang == 'kn') {
         $vstr = str_replace('0CB0 0CCD 0020', 'E0CC 0020', $vstr);
         // mPDF 5.3.87
     }
     //============================
     // MAIN BIT FROM VOLT RULES
     foreach ($voltdata[$font] as $rid => $reps) {
         //echo $rid . ':  ' . $vstr.'<br />';
         $vstr = preg_replace_callback_callback('/' . $reps['match'] . '/', $reps['replace'], $vstr);
     }
     //echo $vstr.'<br />'; exit;
     //============================
     // SPECIALS
     // KANNADA
     // <Base> <BelowBase1> [<BelowBase2> ] MatraI -> <Base/MatraI ligature> <Belowbase1> etc
     if ($lang == 'kn') {
         $matraI = "0CBF";
         $knbase = preg_split('/\\|/', "0C95|0C96|0C97|0C98|0C9A|0C9B|0C9C|0C9D|0CA0|0CA1|0CA2|0CA3|0CA4|0CA5|0CA6|0CA7|0CA8|0CAA|0CAB|0CAC|0CAD|0CAE|0CAF|0CB0|0CB2|0CB3|0CB5|0CB6|0CB7|0CB8|0CB9|E0A3|E07D|E07E");
         $knmatraIligature = preg_split('/\\|/', "E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A4|E0A1|E0A2");
         $belowbase1 = "E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E081";
         $belowbase2 = "E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E081";
         for ($i = 0; $i < count($knbase); $i++) {
             $vstr = preg_replace_callback_callback('/' . $knbase[$i] . ' (' . $belowbase1 . ') (' . $belowbase2 . ') ' . $matraI . '/', $knmatraIligature[$i] . ' \\1 \\2', $vstr);
             $vstr = preg_replace_callback_callback('/' . $knbase[$i] . ' (' . $belowbase1 . ') ' . $matraI . '/', $knmatraIligature[$i] . ' \\1', $vstr);
         }
     }
     // KANNADA
     // [KanTtaFull] [matraI] => [KanTtaPartial] [matraI]
     if ($lang == 'kn') {
         $vstr = preg_replace_callback_callback('/0C9F ' . $matraI . '/', 'E015 ' . $matraI, $vstr);
     }
     // ORIYA
     if ($lang == 'or') {
         // SpecialCase Ra[0B30] Halant still left before [oryaFullNnNna] => E00F
         $vstr = preg_replace_callback_callback('/0B30 ' . $halant . ' E00F/', 'E00F E069', $vstr);
         // convert to Reph
     }
     //============================
     // SHIFT REPH
     // DEVANAGARI Shift Reph [E015]
     if ($lang == 'hi') {
         // FIRSTLY - halfRa = E05D - Change this to Reph [E015]
         $himatchhalfforms = "E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5|E0F6|E0F7|E0F8|E0F9|E0FA|E0FB|E0FC|E0FD|E0FE|E0FF|E100|E101|E102|E103|E104|E105|E106|E107|E108|E109|E10A|E10B|E10C|E10D|E10E|E10F|E110|E111|E112|E113|E114|E115|E116|E117|E118|E119|E11A|E13D|E13E|E13F|E140|E141|E142|E143|E144|E145";
         $himatchfullforms = "0915|0916|0917|0918|0919|091A|091B|091C|091D|091E|091F|0920|0921|0922|0923|0924|0925|0926|0927|0928|092A|092B|092C|092D|092E|092F|0930|0932|0933|0935|0936|0937|0938|0939|E028|E029|0958|0959|095A|E02A|E02B|E02C|E02D|095B|E02E|E02F|E030|E031|095C|095D|E032|E033|E034|E035|E036|0929|E037|095E|E038|E039|E03A|095F|0931|E03B|0934|E03C|E03D|E03E|E03F|E040|E041|E042|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E11E|E11F|E120|E121|E122|E123|E124|E125|E126|E127|E128|E129|E12A|E12B|E12C|E12D|E12E|E12F|E130|E131|E132|E133";
         $vstr = preg_replace_callback_callback('/E05D (' . $himatchhalfforms . '|' . $himatchfullforms . ')/', 'E015 \\1', $vstr);
         // Reph = E015 - Shift Right to just after end of syllable
         // FullAllForms + HalfAllForms + 093E matraA
         while (preg_match('/E015 (' . $himatchhalfforms . ')/', $vstr)) {
             $vstr = preg_replace_callback_callback('/E015 (' . $himatchhalfforms . ')/', '\\1 E015', $vstr);
         }
         $vstr = preg_replace_callback_callback('/E015 (' . $himatchfullforms . ')/', '\\1 E015', $vstr);
         // Now shift it beyond post-based vowels  // ??? Need to add others e.g. 0949,094A,094B,094C + presentation forms like E198
         $vstr = str_replace('E015 093E', '093E E015', $vstr);
         $vstr = preg_replace_callback_callback('/E015 (0940|E194|E195|E196|E197|E198)/', '\\1 E014', $vstr);
         // (Small) reph [E014] to Right of matraI
         $vstr = str_replace('E015 0947', '0947 E014', $vstr);
         // (Small) reph [E014] to Right of matraI
     } else {
         if ($lang == 'bn') {
             $bnfullconjuncts = "E002|E003|E004|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5|E0F6|E0F7|E0F8|E0F9|E0FA|E0FB|E0FC|E0FD|E0FE|E0FF|E100|E101|E102|E103|E104|E105|E106|E107|E108|E109|E10A|E10B|E10C|E10D|E10E|E10F|E110|E111|E112|E113|E114|E115|E116|E117|E118|E119|E11A|E11B|E11C|E11D|E11E|E11F|E120|E121|E122|E123|E124|E125|E126|E127|E128|E129|E12A|E12B|E12C|E12D|E12E|E12F|E130|E131|E132|E133|E134|E135|E136|E137|E138|E139|E13A|E13B|E13C|E13D|E13E|E13F|E140|E141|E142|E143|E144|E145|E146|E147|E148|E149|E14A|E14B|E14C|E14D|E14E|E14F|E150|E151|E152|E153|E154|E155|E156|E157|E158|E159|E15A|E15B|E15C|E15D|E15E|E15F|E160|E161|E162|E163|E164|E165|E166|E167|E168|E169|E16A|E16B|E16C|E16D|E16E|E16F|E170|E171|E172|E173|E174|E175|E176|E177|E178|E179|E17A|E17B|E17C|E17D|E17E|E17F|E180|E181|E182|E183|E184|E185|E186|E187|E188|E189|E18A|E18B|E18C|E18D|E18E|E18F|E190|E191|E192|E193|E194|E195|E196|E197|E198|E199|E19A";
             // $bnfullcons - set above;
             $vstr = preg_replace_callback_callback('/E068 (' . $bnfullconjuncts . '|' . $bnfullcons . ')/', '\\1 E068', $vstr);
             // ? Need to shift it beyond post-base vowels 09BE, 09C0, 09D7  haven't found so can't test??
             $vstr = preg_replace_callback_callback('/E068 (09BE|09C0|09D7)/', '\\1 E068', $vstr);
         } else {
             if ($lang == 'gu') {
                 $gufullforms = "0A95|0A96|0A97|0A98|0A99|0A9A|0A9B|0A9C|0A9D|0A9E|0A9F|0AA0|0AA1|0AA2|0AA3|0AA4|0AA5|0AA6|0AA7|0AA8|0AAA|0AAB|0AAC|0AAD|0AAE|0AAF|0AB0|0AB2|0AB3|0AB5|0AB6|0AB7|0AB8|0AB9|E002|E003|E004|E005|E006|E007|E008|E009|E00A|E00B|E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5";
                 $vstr = preg_replace_callback_callback('/E032 (' . $gufullforms . ')/', '\\1 E032', $vstr);
                 // Now shift it beyond post-based vowels  // ??? Need to add others e.g. 0949,094A,094B,094C + presentation forms like E198
                 // ? Need to shift it beyond post-base vowels 0ABE, 0AC0 haven't found so can't test??
                 $vstr = preg_replace_callback_callback('/E032 (0ABE|0AC0)/', '\\1 E032', $vstr);
             } else {
                 if ($lang == 'te') {
                     // tefullforms defined earlier
                     $tepartialforms = "E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E07C|E07D|E07E";
                     $matraligs = "E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF";
                     $tevowels = "0C3E|0C3F|0C40|0C46|0C47|0C56|0C4A|0C4B|0C4C" . "|0C41|0C42|0C43|0C44";
                     // post matras
                     $vstr = preg_replace_callback_callback('/(' . $tevowels . ') (E046|E069|E077)/', '\\2 \\1', $vstr);
                     while (preg_match('/(' . $tepartialforms . ') (E046|E069|E077)/', $vstr)) {
                         $vstr = preg_replace_callback_callback('/(' . $tepartialforms . ') (E046|E069|E077)/', '\\2 \\1', $vstr);
                     }
                     $vstr = preg_replace_callback_callback('/(' . $tefullforms . '|' . $matraligs . ') (E046|E069|E077)/', '\\2 \\1', $vstr);
                 } else {
                     if ($lang == 'kn') {
                         $knfullforms = "0C95|0C96|0C97|0C98|0C99|0C9A|0C9B|0C9C|0C9D|0C9E|0C9F|0CA0|0CA1|0CA2|0CA3|0CA4|0CA5|0CA6|0CA7|0CA8|0CAA|0CAB|0CAC|0CAD|0CAE|0CAF|0CB0|0CB1|0CB2|0CB3|0CB5|0CB6|0CB7|0CB8|0CB9|E07D|E07E|E0A3";
                         $knpartialforms = "E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|0C9E|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E07F";
                         while (preg_match('/E00B (' . $knpartialforms . ')/', $vstr)) {
                             $vstr = preg_replace_callback_callback('/E00B (' . $knpartialforms . ')/', '\\1 E00B', $vstr);
                         }
                         // mPDF 5.3.47  Also move Reph to right of matraIligatures
                         $knfullforms .= "|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A4|E0A1|E0A2";
                         $vstr = preg_replace_callback_callback('/E00B (' . $knfullforms . ')/', '\\1 E00B', $vstr);
                         // ? Need to shift it beyond base or below-base forms - haven't found so can't test??
                         // mPDF 5.3.87
                         // E004 added to list (which is a transformed version of 0CBE)
                         $knvowels = "0CBE|0CC0|0CC1|0CC2|0CC3|0CC4|0CC7|0CC8|0CCA|0CCB|0CD5|0CD6|E004";
                         $vstr = preg_replace_callback_callback('/E00B (' . $knvowels . ')/', '\\1 E00B', $vstr);
                     } else {
                         if ($lang == 'or') {
                             $orrephs = "E069|E06A|E06B|E06C";
                             $orfullforms = "0B15|0B16|0B17|0B18|0B19|0B1A|0B1B|0B1C|0B1D|0B1E|0B1F|0B20|0B21|0B22|0B23|0B24|0B25|0B26|0B27|0B28|0B29|0B2A|0B2B|0B2C|0B2D|0B2E|0B2F|0B30|0B31|0B32|0B33|0B34|0B35|0B36|0B37|0B38|E003|E004|E005|E006|E007|E008|E009|E00A|E00B|E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037";
                             // E123 - E147  FullHalant forms ? add to FullForms
                             $orpartialforms = "E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5";
                             // Combined MatraIReph[E06D] split [0B3F & E069] to allow reph to be shifted forwards
                             $vstr = preg_replace_callback_callback('/(' . $orfullforms . ') E06D (' . $orfullforms . ') 0B3E/', '\\1 0B3F E069 \\2 0B3E', $vstr);
                             while (preg_match('/(' . $orrephs . ') (' . $orpartialforms . ')/', $vstr)) {
                                 $vstr = preg_replace_callback_callback('/(' . $orrephs . ') (' . $orpartialforms . ')/', '\\2 \\1', $vstr);
                             }
                             $vstr = preg_replace_callback_callback('/(' . $orrephs . ') (' . $orfullforms . ')/', '\\2 \\1', $vstr);
                             // Combine Reph and MatraI
                             $vstr = str_replace('E069 0B3F', 'E06D', $vstr);
                             // Reph and MatraI -> MatraIReph
                             $vstr = str_replace('E06A 0B3F', 'E06E', $vstr);
                             // Reph and MatraI -> MatraIReph
                             $vstr = str_replace('E06B 0B3F', 'E06F', $vstr);
                             // Reph and MatraI -> MatraIReph
                         } else {
                             if ($lang == 'ml') {
                                 $halant = "0D4D";
                                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' 0D30/', 'E00E \\1', $vstr);
                                 // 0D30 = Ra
                                 $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $mlprebasedvowels . ' 0D30/', '\\2 E00E \\1', $vstr);
                                 // 0D30 = Ra
                                 $mlfullforms = "0D15|0D16|0D17|0D18|0D19|0D1A|0D1B|0D1C|0D1D|0D1E|0D1F|0D20|0D21|0D22|0D23|0D24|0D25|0D26|0D27|0D28|0D2A|0D2B|0D2C|0D2D|0D2E|0D2F|0D30|0D31|0D32|0D33|0D34|0D35|0D36|0D37|0D38|0D39" . "|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D";
                                 // = FullConsonants + FullConjuncts
                                 // = Add Chillu characters	// mPDF 5.0.024
                                 $mlfullforms .= "|E004|E005|E006|E007|E008|E009";
                                 while (preg_match('/(' . $mlfullforms . ') E00E/', $vstr)) {
                                     $vstr = preg_replace_callback_callback('/(' . $mlfullforms . ') E00E/', 'E00E \\1', $vstr);
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     //============================
     // SHIFT post-based vowels to Left of SmallForms (NOT to left of full forms)
     // TELUGU Shift
     if ($lang == 'te') {
         // NB $tevowels defined above
         // NB $tefullforms defined above
         $tebelowbase1 = "E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E";
         //'Small1KaToHa'
         $tebelowbase2 = "E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071";
         // 'Small2KaToHa'
         $vstr = preg_replace_callback_callback('/(' . $tebelowbase2 . ') (' . $tevowels . ')/', '\\2 \\1', $vstr);
         $vstr = preg_replace_callback_callback('/(' . $tebelowbase1 . ') (' . $tevowels . ')/', '\\2 \\1', $vstr);
     } else {
         if ($lang == 'kn') {
             $knvowels = "0CBE|0CC0|0CC1|0CC2|0CC3|0CC4|0CC7|0CC8|0CCA|0CCB|0CD5|0CD6" . "|E004|E007|E008|E009|E00A";
             // NB $knvowels defined above
             // NB $fullforms defined above
             // $belowbase1/2 defined above
             $vstr = preg_replace_callback_callback('/(' . $belowbase2 . ') (' . $knvowels . ')/', '\\2 \\1', $vstr);
             // mPDF 5.3.87
             $vstr = preg_replace_callback_callback('/(' . $belowbase1 . ') (' . $knvowels . ')/', '\\2 \\1', $vstr);
             //$vstr = preg_replace_callback_callback('/('.$fullforms.') ('.$knvowels.')/', '\\2 \\1', $vstr);
         }
     }
     //============================
     // Clear unwanted ZWJ, ZWNJ
     // MALAYALAM
     if ($lang == 'ml') {
         $vstr = preg_replace_callback_callback('/(200C|200D) /', '', $vstr);
     }
     //============================
     // END & PUT IT BACK TOGETHER
     $vstr = preg_replace_callback_callback('/^0020 (.*) 0020$/', '\\1', $vstr);
     $varr = explode(" ", $vstr);
     $e = '';
     foreach ($varr as $v) {
         $e .= code2utf(hexdec($v));
     }
     //============================
     return $e;
 }
if ($_REQUEST['filename']) {
    $filename = $_REQUEST['filename'];
} else {
    die("No file specified");
}
include "../mpdf.php";
$mpdf = new mPDF('utf-8-s');
$mpdf->debug = true;
$mpdf->tabSpaces = 6;
$mpdf->allow_charset_conversion = true;
$mpdf->charset_in = 'windows-1252';
//==============================================================
preg_match('/example[0]{0,1}(\\d+)_(.*?)\\.php/', $filename, $m);
$num = intval($m[1]);
$title = ucfirst(preg_replace_callback_callback('/_/', ' ', $m[2]));
if (!$num || !$title) {
    die("Invalid file");
}
if (preg_match('/\\//', $filename) || !preg_match('/\\.php$/', $filename)) {
    die("Hacking attempt");
}
$html = '
<h1>mPDF</h1>
<h2>Example ' . $num . '. ' . $title . '</h2>
<div style="border:1px solid #555555; background-color: #DDDDDD; padding: 1em; font-size:8pt; font-family: lucidaconsole, mono;">
';
$lines = file($filename);
$html .= '<pre>';
foreach ($lines as $line) {
    $html .= htmlspecialchars($line);
 function extractCoreInfo($file, $TTCfontID = 0)
 {
     $this->filename = $file;
     $this->fh = fopen($file, 'rb');
     if (!$this->fh) {
         return 'ERROR - Can\'t open file ' . $file;
     }
     $this->_pos = 0;
     $this->charWidths = '';
     $this->glyphPos = array();
     $this->charToGlyph = array();
     $this->tables = array();
     $this->otables = array();
     $this->ascent = 0;
     $this->descent = 0;
     $this->numTTCFonts = 0;
     $this->TTCFonts = array();
     $this->version = $version = $this->read_ulong();
     $this->panose = array();
     // mPDF 5.0
     if ($version == 0x4f54544f) {
         return "ERROR - NOT ADDED as Postscript outlines are not supported - " . $file;
     }
     if ($version == 0x74746366) {
         if ($TTCfontID > 0) {
             $this->version = $version = $this->read_ulong();
             // TTC Header version now
             if (!in_array($version, array(0x10000, 0x20000))) {
                 return "ERROR - NOT ADDED as Error parsing TrueType Collection: version=" . $version . " - " . $file;
             }
         } else {
             return "ERROR - Error parsing TrueType Collection - " . $file;
         }
         $this->numTTCFonts = $this->read_ulong();
         for ($i = 1; $i <= $this->numTTCFonts; $i++) {
             $this->TTCFonts[$i]['offset'] = $this->read_ulong();
         }
         $this->seek($this->TTCFonts[$TTCfontID]['offset']);
         $this->version = $version = $this->read_ulong();
         // TTFont version again now
         $this->readTableDirectory(false);
     } else {
         if (!in_array($version, array(0x10000, 0x74727565))) {
             return "ERROR - NOT ADDED as Not a TrueType font: version=" . $version . " - " . $file;
         }
         $this->readTableDirectory(false);
     }
     /* Included for testing...
     		$cmap_offset = $this->seek_table("cmap");
     		$this->skip(2);
     		$cmapTableCount = $this->read_ushort();
     		$unicode_cmap_offset = 0;
     		for ($i=0;$i<$cmapTableCount;$i++) {
     			$x[$i]['platformId'] = $this->read_ushort();
     			$x[$i]['encodingId'] = $this->read_ushort();
     			$x[$i]['offset'] = $this->read_ulong();
     			$save_pos = $this->_pos;
     			$x[$i]['format'] = $this->get_ushort($cmap_offset + $x[$i]['offset'] );
     			$this->seek($save_pos );
     		}
     		print_r($x); exit;
     */
     ///////////////////////////////////
     // name - Naming table
     ///////////////////////////////////
     /* Test purposes - displays table of names 
     			$name_offset = $this->seek_table("name");
     			$format = $this->read_ushort();
     			if ($format != 0 && $format != 1)	// mPDF 5.3.73
     				die("Unknown name table format ".$format);
     			$numRecords = $this->read_ushort();
     			$string_data_offset = $name_offset + $this->read_ushort();
     			for ($i=0;$i<$numRecords; $i++) {
     				$x[$i]['platformId'] = $this->read_ushort();
     				$x[$i]['encodingId'] = $this->read_ushort();
     				$x[$i]['languageId'] = $this->read_ushort();
     				$x[$i]['nameId'] = $this->read_ushort();
     				$x[$i]['length'] = $this->read_ushort();
     				$x[$i]['offset'] = $this->read_ushort();
     
     				$N = '';
     				if ($x[$i]['platformId'] == 1 && $x[$i]['encodingId'] == 0 && $x[$i]['languageId'] == 0) { // Roman
     					$opos = $this->_pos;
     					$N = $this->get_chunk($string_data_offset + $x[$i]['offset'] , $x[$i]['length'] );
     					$this->_pos = $opos;
     					$this->seek($opos);
     				}
     				else { 	// Unicode
     					$opos = $this->_pos;
     					$this->seek($string_data_offset + $x[$i]['offset'] );
     					$length = $x[$i]['length'] ;
     					if ($length % 2 != 0)
     						$length -= 1;
     				//		die("PostScript name is UTF-16BE string of odd length");
     					$length /= 2;
     					$N = '';
     					while ($length > 0) {
     						$char = $this->read_ushort();
     						$N .= (chr($char));
     						$length -= 1;
     					}
     					$this->_pos = $opos;
     					$this->seek($opos);
     				}
     				$x[$i]['names'][$nameId] = $N;
     			}
     			print_r($x); exit;
     */
     $name_offset = $this->seek_table("name");
     $format = $this->read_ushort();
     if ($format != 0 && $format != 1) {
         // mPDF 5.3.73
         return "ERROR - NOT ADDED as Unknown name table format " . $format . " - " . $file;
     }
     $numRecords = $this->read_ushort();
     $string_data_offset = $name_offset + $this->read_ushort();
     $names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => '');
     $K = array_keys($names);
     $nameCount = count($names);
     for ($i = 0; $i < $numRecords; $i++) {
         $platformId = $this->read_ushort();
         $encodingId = $this->read_ushort();
         $languageId = $this->read_ushort();
         $nameId = $this->read_ushort();
         $length = $this->read_ushort();
         $offset = $this->read_ushort();
         if (!in_array($nameId, $K)) {
             continue;
         }
         $N = '';
         if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) {
             // Microsoft, Unicode, US English, PS Name
             $opos = $this->_pos;
             $this->seek($string_data_offset + $offset);
             if ($length % 2 != 0) {
                 $length += 1;
             }
             $length /= 2;
             $N = '';
             while ($length > 0) {
                 $char = $this->read_ushort();
                 $N .= chr($char);
                 $length -= 1;
             }
             $this->_pos = $opos;
             $this->seek($opos);
         } else {
             if ($platformId == 1 && $encodingId == 0 && $languageId == 0) {
                 // Macintosh, Roman, English, PS Name
                 $opos = $this->_pos;
                 $N = $this->get_chunk($string_data_offset + $offset, $length);
                 $this->_pos = $opos;
                 $this->seek($opos);
             }
         }
         if ($N && $names[$nameId] == '') {
             $names[$nameId] = $N;
             $nameCount -= 1;
             if ($nameCount == 0) {
                 break;
             }
         }
     }
     if ($names[6]) {
         $psName = preg_replace_callback_callback('/ /', '-', $names[6]);
     } else {
         if ($names[4]) {
             $psName = preg_replace_callback_callback('/ /', '-', $names[4]);
         } else {
             if ($names[1]) {
                 $psName = preg_replace_callback_callback('/ /', '-', $names[1]);
             } else {
                 $psName = '';
             }
         }
     }
     if (!$names[1] && !$psName) {
         return "ERROR - NOT ADDED as Could not find valid font name - " . $file;
     }
     $this->name = $psName;
     if ($names[1]) {
         $this->familyName = $names[1];
     } else {
         $this->familyName = $psName;
     }
     if ($names[2]) {
         $this->styleName = $names[2];
     } else {
         $this->styleName = 'Regular';
     }
     ///////////////////////////////////
     // head - Font header table
     ///////////////////////////////////
     $this->seek_table("head");
     $ver_maj = $this->read_ushort();
     $ver_min = $this->read_ushort();
     if ($ver_maj != 1) {
         return 'ERROR - NOT ADDED as Unknown head table version ' . $ver_maj . '.' . $ver_min . " - " . $file;
     }
     $this->fontRevision = $this->read_ushort() . $this->read_ushort();
     $this->skip(4);
     $magic = $this->read_ulong();
     if ($magic != 0x5f0f3cf5) {
         return 'ERROR - NOT ADDED as Invalid head table magic ' . $magic . " - " . $file;
     }
     $this->skip(2);
     $this->unitsPerEm = $unitsPerEm = $this->read_ushort();
     $scale = 1000 / $unitsPerEm;
     $this->skip(24);
     $macStyle = $this->read_short();
     $this->skip(4);
     $indexLocFormat = $this->read_short();
     ///////////////////////////////////
     // OS/2 - OS/2 and Windows metrics table
     ///////////////////////////////////
     $sFamily = '';
     $panose = '';
     $fsSelection = '';
     if (isset($this->tables["OS/2"])) {
         $this->seek_table("OS/2");
         $this->skip(30);
         $sF = $this->read_short();
         $sFamily = $sF >> 8;
         $this->_pos += 10;
         //PANOSE = 10 byte length
         $panose = fread($this->fh, 10);
         $this->panose = array();
         for ($p = 0; $p < strlen($panose); $p++) {
             $this->panose[] = ord($panose[$p]);
         }
         $this->skip(20);
         $fsSelection = $this->read_short();
     }
     ///////////////////////////////////
     // post - PostScript table
     ///////////////////////////////////
     $this->seek_table("post");
     $this->skip(4);
     $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0;
     $this->skip(4);
     $isFixedPitch = $this->read_ulong();
     ///////////////////////////////////
     // cmap - Character to glyph index mapping table
     ///////////////////////////////////
     $cmap_offset = $this->seek_table("cmap");
     $this->skip(2);
     $cmapTableCount = $this->read_ushort();
     $unicode_cmap_offset = 0;
     for ($i = 0; $i < $cmapTableCount; $i++) {
         $platformID = $this->read_ushort();
         $encodingID = $this->read_ushort();
         $offset = $this->read_ulong();
         $save_pos = $this->_pos;
         if ($platformID == 3 && $encodingID == 1 || $platformID == 0) {
             // Microsoft, Unicode
             $format = $this->get_ushort($cmap_offset + $offset);
             if ($format == 4) {
                 if (!$unicode_cmap_offset) {
                     $unicode_cmap_offset = $cmap_offset + $offset;
                 }
             }
         } else {
             if ($platformID == 3 && $encodingID == 10 || $platformID == 0) {
                 // Microsoft, Unicode Format 12 table HKCS
                 $format = $this->get_ushort($cmap_offset + $offset);
                 if ($format == 12) {
                     $unicode_cmap_offset = $cmap_offset + $offset;
                     break;
                 }
             }
         }
         $this->seek($save_pos);
     }
     if (!$unicode_cmap_offset) {
         return 'ERROR - Font (' . $this->filename . ') NOT ADDED as it is not Unicode encoded, and cannot be used by mPDF';
     }
     $rtl = false;
     $indic = false;
     $cjk = false;
     $sip = false;
     $smp = false;
     $pua = false;
     $puaag = false;
     $glyphToChar = array();
     $unAGlyphs = '';
     // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above
     if ($format == 12) {
         $this->seek($unicode_cmap_offset + 4);
         $length = $this->read_ulong();
         $limit = $unicode_cmap_offset + $length;
         $this->skip(4);
         $nGroups = $this->read_ulong();
         for ($i = 0; $i < $nGroups; $i++) {
             $startCharCode = $this->read_ulong();
             $endCharCode = $this->read_ulong();
             $startGlyphCode = $this->read_ulong();
             if ($endCharCode > 0x20000 && $endCharCode < 0x2a6df || $endCharCode > 0x2f800 && $endCharCode < 0x2fa1f) {
                 $sip = true;
             }
             if ($endCharCode > 0x10000 && $endCharCode < 0x1ffff) {
                 $smp = true;
             }
             if ($endCharCode > 0x590 && $endCharCode < 0x77f || $endCharCode > 0xfe70 && $endCharCode < 0xfeff || $endCharCode > 0xfb50 && $endCharCode < 0xfdff) {
                 $rtl = true;
             }
             if ($endCharCode > 0x900 && $endCharCode < 0xdff) {
                 $indic = true;
             }
             if ($endCharCode > 0xe000 && $endCharCode < 0xf8ff) {
                 $pua = true;
                 if ($endCharCode > 0xf500 && $endCharCode < 0xf7ff) {
                     $puaag = true;
                 }
             }
             if ($endCharCode > 0x2e80 && $endCharCode < 0x4dc0 || $endCharCode > 0x4e00 && $endCharCode < 0xa4cf || $endCharCode > 0xac00 && $endCharCode < 0xd7af || $endCharCode > 0xf900 && $endCharCode < 0xfaff || $endCharCode > 0xfe30 && $endCharCode < 0xfe4f) {
                 $cjk = true;
             }
             $offset = 0;
             // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
             if (isset($this->tables['post'])) {
                 for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) {
                     $glyph = $startGlyphCode + $offset;
                     $offset++;
                     $glyphToChar[$glyph][] = $unichar;
                 }
             }
         }
     } else {
         // Format 4 CMap
         $this->seek($unicode_cmap_offset + 2);
         $length = $this->read_ushort();
         $limit = $unicode_cmap_offset + $length;
         $this->skip(2);
         $segCount = $this->read_ushort() / 2;
         $this->skip(6);
         $endCount = array();
         for ($i = 0; $i < $segCount; $i++) {
             $endCount[] = $this->read_ushort();
         }
         $this->skip(2);
         $startCount = array();
         for ($i = 0; $i < $segCount; $i++) {
             $startCount[] = $this->read_ushort();
         }
         $idDelta = array();
         for ($i = 0; $i < $segCount; $i++) {
             $idDelta[] = $this->read_short();
         }
         $idRangeOffset_start = $this->_pos;
         $idRangeOffset = array();
         for ($i = 0; $i < $segCount; $i++) {
             $idRangeOffset[] = $this->read_ushort();
         }
         for ($n = 0; $n < $segCount; $n++) {
             if ($endCount[$n] > 0x590 && $endCount[$n] < 0x77f || $endCount[$n] > 0xfe70 && $endCount[$n] < 0xfeff || $endCount[$n] > 0xfb50 && $endCount[$n] < 0xfdff) {
                 $rtl = true;
             }
             if ($endCount[$n] > 0x900 && $endCount[$n] < 0xdff) {
                 $indic = true;
             }
             if ($endCount[$n] > 0x2e80 && $endCount[$n] < 0x4dc0 || $endCount[$n] > 0x4e00 && $endCount[$n] < 0xa4cf || $endCount[$n] > 0xac00 && $endCount[$n] < 0xd7af || $endCount[$n] > 0xf900 && $endCount[$n] < 0xfaff || $endCount[$n] > 0xfe30 && $endCount[$n] < 0xfe4f) {
                 $cjk = true;
             }
             if ($endCount[$n] > 0xe000 && $endCount[$n] < 0xf8ff) {
                 $pua = true;
                 if ($endCount[$n] > 0xf500 && $endCount[$n] < 0xf7ff) {
                     $puaag = true;
                 }
             }
             // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
             if (isset($this->tables['post'])) {
                 $endpoint = $endCount[$n] + 1;
                 for ($unichar = $startCount[$n]; $unichar < $endpoint; $unichar++) {
                     if ($idRangeOffset[$n] == 0) {
                         $glyph = $unichar + $idDelta[$n] & 0xffff;
                     } else {
                         $offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n];
                         $offset = $idRangeOffset_start + 2 * $n + $offset;
                         if ($offset >= $limit) {
                             $glyph = 0;
                         } else {
                             $glyph = $this->get_ushort($offset);
                             if ($glyph != 0) {
                                 $glyph = $glyph + $idDelta[$n] & 0xffff;
                             }
                         }
                     }
                     $glyphToChar[$glyph][] = $unichar;
                 }
             }
         }
     }
     // 'POST' table for un-mapped arabic glyphs
     if (isset($this->tables['post'])) {
         $this->seek_table("post");
         // Only works on Format 2.0
         $formata = $this->read_ushort();
         $formatb = $this->read_ushort();
         if ($formata == 2 && $formatb == 0) {
             $this->skip(28);
             $nGlyfs = $this->read_ushort();
             $glyphNameIndex = array();
             for ($i = 0; $i < $nGlyfs; $i++) {
                 $glyphNameIndex[$this->read_ushort()] = $i;
             }
             $opost = $this->get_table('post');
             $ptr = 34 + $nGlyfs * 2;
             for ($i = 0; $i < $nGlyfs; $i++) {
                 $len = ord(substr($opost, $ptr, 1));
                 $ptr++;
                 $name = substr($opost, $ptr, $len);
                 $gid = $glyphNameIndex[$i + 258];
                 // Select uni0600.xxx(x) - uni06FF.xxx(x)
                 if (preg_match('/^uni(06[0-9a-f]{2})\\.(fina|medi|init|fin|med|ini)$/i', $name, $m)) {
                     if (!isset($glyphToChar[$gid]) || isset($glyphToChar[$gid]) && is_array($glyphToChar[$gid]) && count($glyphToChar[$gid]) == 1 && $glyphToChar[$gid][0] > 57343 && $glyphToChar[$gid][0] < 63489) {
                         // if set in PUA private use area E000-F8FF, or NOT Unicode mapped
                         $uni = hexdec($m[1]);
                         $form = strtoupper(substr($m[2], 0, 1));
                         // Assign new PUA Unicode between F500 - F7FF
                         $bit = $uni & 0xff;
                         if ($form == 'I') {
                             $bit += 0xf600;
                         } else {
                             if ($form == 'M') {
                                 $bit += 0xf700;
                             } else {
                                 $bit += 0xf500;
                             }
                         }
                         $unAGlyphs .= $gid;
                         $name = 'uni' . strtoupper($m[1]) . '.' . strtolower($m[2]);
                         $unAGlyphs .= ' : ' . $name;
                         $unihexstr = $m[1];
                         $unAGlyphs .= ' : ' . $unihexstr;
                         $unAGlyphs .= ' : ' . $uni;
                         $unAGlyphs .= ' : ' . $form;
                         // if already set in PUA private use area E000-F8FF
                         if (isset($glyphToChar[$gid]) && $glyphToChar[$gid][0] > 57343 && $glyphToChar[$gid][0] < 63489) {
                             $unAGlyphs .= ' : ' . $glyphToChar[$gid][0] . ' {' . dechex($glyphToChar[$gid][0]) . '}';
                         }
                         //else $unAGlyphs .= ':';
                         $unAGlyphs .= ' : ' . strtoupper(dechex($bit));
                         $unAGlyphs .= '<br />';
                     }
                 }
                 $ptr += $len;
             }
             if ($unAGlyphs) {
                 $unAGlyphs = 'GID:Name:Unicode base Hex:Dec:Form:PUA Unicode<br />' . $unAGlyphs;
             }
         }
     }
     $bold = false;
     $italic = false;
     $ftype = '';
     if ($macStyle & 1 << 0) {
         $bold = true;
     } else {
         if ($fsSelection & 1 << 5) {
             $bold = true;
         }
     }
     // 5 	BOLD 	Characters are emboldened
     if ($macStyle & 1 << 1) {
         $italic = true;
     } else {
         if ($fsSelection & 1 << 0) {
             $italic = true;
         } else {
             if ($this->italicAngle != 0) {
                 $italic = true;
             }
         }
     }
     if ($isFixedPitch) {
         $ftype = 'mono';
     } else {
         if ($sFamily > 0 && $sFamily < 8) {
             $ftype = 'serif';
         } else {
             if ($sFamily == 8) {
                 $ftype = 'sans';
             } else {
                 if ($sFamily == 10) {
                     $ftype = 'cursive';
                 }
             }
         }
     }
     // Use PANOSE
     if ($panose) {
         $bFamilyType = ord($panose[0]);
         if ($bFamilyType == 2) {
             $bSerifStyle = ord($panose[1]);
             if (!$ftype) {
                 if ($bSerifStyle > 1 && $bSerifStyle < 11) {
                     $ftype = 'serif';
                 } else {
                     if ($bSerifStyle > 10) {
                         $ftype = 'sans';
                     }
                 }
             }
             $bProportion = ord($panose[3]);
             if ($bProportion == 9 || $bProportion == 1) {
                 $ftype = 'mono';
             }
             // ==1 i.e. No Fit needed for OCR-a and -b
         } else {
             if ($bFamilyType == 3) {
                 $ftype = 'cursive';
             }
         }
     }
     fclose($this->fh);
     return array($this->familyName, $bold, $italic, $ftype, $TTCfontID, $rtl, $indic, $cjk, $sip, $smp, $puaag, $pua, $unAGlyphs);
 }
 function extractInfo($debug = false, $BMPonly = false, $kerninfo = false)
 {
     $this->panose = array();
     $this->sFamilyClass = 0;
     $this->sFamilySubClass = 0;
     ///////////////////////////////////
     // name - Naming table
     ///////////////////////////////////
     $name_offset = $this->seek_table("name");
     $format = $this->read_ushort();
     if ($format != 0 && $format != 1) {
         die("Unknown name table format " . $format);
     }
     $numRecords = $this->read_ushort();
     $string_data_offset = $name_offset + $this->read_ushort();
     $names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => '');
     $K = array_keys($names);
     $nameCount = count($names);
     for ($i = 0; $i < $numRecords; $i++) {
         $platformId = $this->read_ushort();
         $encodingId = $this->read_ushort();
         $languageId = $this->read_ushort();
         $nameId = $this->read_ushort();
         $length = $this->read_ushort();
         $offset = $this->read_ushort();
         if (!in_array($nameId, $K)) {
             continue;
         }
         $N = '';
         if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) {
             // Microsoft, Unicode, US English, PS Name
             $opos = $this->_pos;
             $this->seek($string_data_offset + $offset);
             if ($length % 2 != 0) {
                 die("PostScript name is UTF-16BE string of odd length");
             }
             $length /= 2;
             $N = '';
             while ($length > 0) {
                 $char = $this->read_ushort();
                 $N .= chr($char);
                 $length -= 1;
             }
             $this->_pos = $opos;
             $this->seek($opos);
         } else {
             if ($platformId == 1 && $encodingId == 0 && $languageId == 0) {
                 // Macintosh, Roman, English, PS Name
                 $opos = $this->_pos;
                 $N = $this->get_chunk($string_data_offset + $offset, $length);
                 $this->_pos = $opos;
                 $this->seek($opos);
             }
         }
         if ($N && $names[$nameId] == '') {
             $names[$nameId] = $N;
             $nameCount -= 1;
             if ($nameCount == 0) {
                 break;
             }
         }
     }
     if ($names[6]) {
         $psName = $names[6];
     } else {
         if ($names[4]) {
             $psName = preg_replace_callback_callback('/ /', '-', $names[4]);
         } else {
             if ($names[1]) {
                 $psName = preg_replace_callback_callback('/ /', '-', $names[1]);
             } else {
                 $psName = '';
             }
         }
     }
     if (!$psName) {
         die("Could not find PostScript font name: " . $this->filename);
     }
     if ($debug) {
         for ($i = 0; $i < count($psName); $i++) {
             $c = $psName[$i];
             $oc = ord($c);
             if ($oc > 126 || strpos(' [](){}<>/%', $c) !== false) {
                 die("psName=" . $psName . " contains invalid character " . $c . " ie U+" . ord(c));
             }
         }
     }
     $this->name = $psName;
     if ($names[1]) {
         $this->familyName = $names[1];
     } else {
         $this->familyName = $psName;
     }
     if ($names[2]) {
         $this->styleName = $names[2];
     } else {
         $this->styleName = 'Regular';
     }
     if ($names[4]) {
         $this->fullName = $names[4];
     } else {
         $this->fullName = $psName;
     }
     if ($names[3]) {
         $this->uniqueFontID = $names[3];
     } else {
         $this->uniqueFontID = $psName;
     }
     if ($names[6]) {
         $this->fullName = $names[6];
     }
     ///////////////////////////////////
     // head - Font header table
     ///////////////////////////////////
     $this->seek_table("head");
     if ($debug) {
         $ver_maj = $this->read_ushort();
         $ver_min = $this->read_ushort();
         if ($ver_maj != 1) {
             die('Unknown head table version ' . $ver_maj . '.' . $ver_min);
         }
         $this->fontRevision = $this->read_ushort() . $this->read_ushort();
         $this->skip(4);
         $magic = $this->read_ulong();
         if ($magic != 0x5f0f3cf5) {
             die('Invalid head table magic ' . $magic);
         }
         $this->skip(2);
     } else {
         $this->skip(18);
     }
     $this->unitsPerEm = $unitsPerEm = $this->read_ushort();
     $scale = 1000 / $unitsPerEm;
     $this->skip(16);
     $xMin = $this->read_short();
     $yMin = $this->read_short();
     $xMax = $this->read_short();
     $yMax = $this->read_short();
     $this->bbox = array($xMin * $scale, $yMin * $scale, $xMax * $scale, $yMax * $scale);
     $this->skip(3 * 2);
     $indexToLocFormat = $this->read_ushort();
     $glyphDataFormat = $this->read_ushort();
     if ($glyphDataFormat != 0) {
         die('Unknown glyph data format ' . $glyphDataFormat);
     }
     ///////////////////////////////////
     // hhea metrics table
     ///////////////////////////////////
     // ttf2t1 seems to use this value rather than the one in OS/2 - so put in for compatibility
     if (isset($this->tables["hhea"])) {
         $this->seek_table("hhea");
         $this->skip(4);
         $hheaAscender = $this->read_short();
         $hheaDescender = $this->read_short();
         $this->ascent = $hheaAscender * $scale;
         $this->descent = $hheaDescender * $scale;
     }
     ///////////////////////////////////
     // OS/2 - OS/2 and Windows metrics table
     ///////////////////////////////////
     if (isset($this->tables["OS/2"])) {
         $this->seek_table("OS/2");
         $version = $this->read_ushort();
         $this->skip(2);
         $usWeightClass = $this->read_ushort();
         $this->skip(2);
         $fsType = $this->read_ushort();
         if ($fsType == 0x2 || ($fsType & 0x300) != 0) {
             global $overrideTTFFontRestriction;
             if (!$overrideTTFFontRestriction) {
                 die('ERROR - Font file ' . $this->filename . ' cannot be embedded due to copyright restrictions.');
             }
             $this->restrictedUse = true;
         }
         $this->skip(20);
         $sF = $this->read_short();
         $this->sFamilyClass = $sF >> 8;
         $this->sFamilySubClass = $sF & 0xff;
         $this->_pos += 10;
         //PANOSE = 10 byte length
         $panose = fread($this->fh, 10);
         $this->panose = array();
         for ($p = 0; $p < strlen($panose); $p++) {
             $this->panose[] = ord($panose[$p]);
         }
         $this->skip(26);
         $sTypoAscender = $this->read_short();
         $sTypoDescender = $this->read_short();
         if (!$this->ascent) {
             $this->ascent = $sTypoAscender * $scale;
         }
         if (!$this->descent) {
             $this->descent = $sTypoDescender * $scale;
         }
         if ($version > 1) {
             $this->skip(16);
             $sCapHeight = $this->read_short();
             $this->capHeight = $sCapHeight * $scale;
         } else {
             $this->capHeight = $this->ascent;
         }
     } else {
         $usWeightClass = 500;
         if (!$this->ascent) {
             $this->ascent = $yMax * $scale;
         }
         if (!$this->descent) {
             $this->descent = $yMin * $scale;
         }
         $this->capHeight = $this->ascent;
     }
     $this->stemV = 50 + intval(pow($usWeightClass / 65.0, 2));
     ///////////////////////////////////
     // post - PostScript table
     ///////////////////////////////////
     $this->seek_table("post");
     if ($debug) {
         $ver_maj = $this->read_ushort();
         $ver_min = $this->read_ushort();
         if ($ver_maj < 1 || $ver_maj > 4) {
             die('Unknown post table version ' . $ver_maj);
         }
     } else {
         $this->skip(4);
     }
     $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0;
     $this->underlinePosition = $this->read_short() * $scale;
     $this->underlineThickness = $this->read_short() * $scale;
     $isFixedPitch = $this->read_ulong();
     $this->flags = 4;
     if ($this->italicAngle != 0) {
         $this->flags = $this->flags | 64;
     }
     if ($usWeightClass >= 600) {
         $this->flags = $this->flags | 262144;
     }
     if ($isFixedPitch) {
         $this->flags = $this->flags | 1;
     }
     ///////////////////////////////////
     // hhea - Horizontal header table
     ///////////////////////////////////
     $this->seek_table("hhea");
     if ($debug) {
         $ver_maj = $this->read_ushort();
         $ver_min = $this->read_ushort();
         if ($ver_maj != 1) {
             die('Unknown hhea table version ' . $ver_maj);
         }
         $this->skip(28);
     } else {
         $this->skip(32);
     }
     $metricDataFormat = $this->read_ushort();
     if ($metricDataFormat != 0) {
         die('Unknown horizontal metric data format ' . $metricDataFormat);
     }
     $numberOfHMetrics = $this->read_ushort();
     if ($numberOfHMetrics == 0) {
         die('Number of horizontal metrics is 0');
     }
     ///////////////////////////////////
     // maxp - Maximum profile table
     ///////////////////////////////////
     $this->seek_table("maxp");
     if ($debug) {
         $ver_maj = $this->read_ushort();
         $ver_min = $this->read_ushort();
         if ($ver_maj != 1) {
             die('Unknown maxp table version ' . $ver_maj);
         }
     } else {
         $this->skip(4);
     }
     $numGlyphs = $this->read_ushort();
     ///////////////////////////////////
     // cmap - Character to glyph index mapping table
     ///////////////////////////////////
     $cmap_offset = $this->seek_table("cmap");
     $this->skip(2);
     $cmapTableCount = $this->read_ushort();
     $unicode_cmap_offset = 0;
     for ($i = 0; $i < $cmapTableCount; $i++) {
         $platformID = $this->read_ushort();
         $encodingID = $this->read_ushort();
         $offset = $this->read_ulong();
         $save_pos = $this->_pos;
         if ($platformID == 3 && $encodingID == 1 || $platformID == 0) {
             // Microsoft, Unicode
             $format = $this->get_ushort($cmap_offset + $offset);
             if ($format == 4) {
                 if (!$unicode_cmap_offset) {
                     $unicode_cmap_offset = $cmap_offset + $offset;
                 }
                 if ($BMPonly) {
                     break;
                 }
             }
         } else {
             if (($platformID == 3 && $encodingID == 10 || $platformID == 0) && !$BMPonly) {
                 $format = $this->get_ushort($cmap_offset + $offset);
                 if ($format == 12) {
                     $unicode_cmap_offset = $cmap_offset + $offset;
                     break;
                 }
             }
         }
         $this->seek($save_pos);
     }
     if (!$unicode_cmap_offset) {
         die('Font (' . $this->filename . ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)');
     }
     $sipset = false;
     $smpset = false;
     // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above
     if ($format == 12 && !$BMPonly) {
         $this->maxUniChar = 0;
         $this->seek($unicode_cmap_offset + 4);
         $length = $this->read_ulong();
         $limit = $unicode_cmap_offset + $length;
         $this->skip(4);
         $nGroups = $this->read_ulong();
         $glyphToChar = array();
         $charToGlyph = array();
         for ($i = 0; $i < $nGroups; $i++) {
             $startCharCode = $this->read_ulong();
             $endCharCode = $this->read_ulong();
             $startGlyphCode = $this->read_ulong();
             if ($endCharCode > 0x20000 && $endCharCode < 0x2a6df || $endCharCode > 0x2f800 && $endCharCode < 0x2fa1f) {
                 $sipset = true;
             } else {
                 if ($endCharCode > 0x10000 && $endCharCode < 0x1ffff) {
                     $smpset = true;
                 }
             }
             $offset = 0;
             for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) {
                 $glyph = $startGlyphCode + $offset;
                 $offset++;
                 $charToGlyph[$unichar] = $glyph;
                 if ($unichar < 196608) {
                     $this->maxUniChar = max($unichar, $this->maxUniChar);
                 }
                 $glyphToChar[$glyph][] = $unichar;
             }
         }
     } else {
         $glyphToChar = array();
         $charToGlyph = array();
         $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph);
     }
     $this->sipset = $sipset;
     $this->smpset = $smpset;
     ///////////////////////////////////
     // hmtx - Horizontal metrics table
     ///////////////////////////////////
     $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale);
     ///////////////////////////////////
     // kern - Kerning pair table
     ///////////////////////////////////
     if ($kerninfo) {
         // Recognises old form of Kerning table - as required by Windows - Format 0 only
         $kern_offset = $this->seek_table("kern");
         $version = $this->read_ushort();
         $nTables = $this->read_ushort();
         // subtable header
         $sversion = $this->read_ushort();
         $slength = $this->read_ushort();
         $scoverage = $this->read_ushort();
         $format = $scoverage >> 8;
         if ($kern_offset && $version == 0 && $format == 0) {
             // Format 0
             $nPairs = $this->read_ushort();
             $this->skip(6);
             for ($i = 0; $i < $nPairs; $i++) {
                 $left = $this->read_ushort();
                 $right = $this->read_ushort();
                 $val = $this->read_short();
                 if (count($glyphToChar[$left]) == 1 && count($glyphToChar[$right]) == 1) {
                     if ($left != 32 && $right != 32) {
                         $this->kerninfo[$glyphToChar[$left][0]][$glyphToChar[$right][0]] = intval($val * $scale);
                     }
                 }
             }
         }
     }
 }
 function parseMozGradient($bg)
 {
     //	background[-image]: -moz-linear-gradient(left, #c7Fdde 20%, #FF0000 );
     //	background[-image]: linear-gradient(left, #c7Fdde 20%, #FF0000 ); // CSS3
     if (preg_match('/repeating-/', $bg)) {
         $repeat = true;
     } else {
         $repeat = false;
     }
     if (preg_match('/linear-gradient\\((.*)\\)/', $bg, $m)) {
         $g = array();
         $g['type'] = 2;
         $g['colorspace'] = 'RGB';
         $g['extend'] = array('true', 'true');
         $v = trim($m[1]);
         // Change commas inside e.g. rgb(x,x,x)
         while (preg_match('/(\\([^\\)]*?),/', $v)) {
             $v = preg_replace_callback_callback('/(\\([^\\)]*?),/', '\\1@', $v);
         }
         // Remove spaces inside e.g. rgb(x, x, x)
         while (preg_match('/(\\([^\\)]*?)[ ]/', $v)) {
             $v = preg_replace_callback_callback('/(\\([^\\)]*?)[ ]/', '\\1', $v);
         }
         $bgr = preg_split('/\\s*,\\s*/', $v);
         for ($i = 0; $i < count($bgr); $i++) {
             $bgr[$i] = preg_replace_callback_callback('/@/', ',', $bgr[$i]);
         }
         // Is first part $bgr[0] a valid point/angle?
         $first = preg_split('/\\s+/', trim($bgr[0]));
         if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) {
             $startStops = 1;
         } else {
             if (trim($first[count($first) - 1]) === "0") {
                 $startStops = 1;
             } else {
                 $check = $this->mpdf->ConvertColor($first[0]);
                 if ($check) {
                     $startStops = 0;
                 } else {
                     $startStops = 1;
                 }
             }
         }
         // first part a valid point/angle?
         if ($startStops == 1) {
             // default values
             // [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,]
             if (preg_match('/([\\-]*[0-9\\.]+)(deg|grad|rad)/i', $bgr[0], $m)) {
                 $angle = $m[1] + 0;
                 if (strtolower($m[2]) == 'deg') {
                     $angle = $angle;
                 } else {
                     if (strtolower($m[2]) == 'grad') {
                         $angle *= 360 / 400;
                     } else {
                         if (strtolower($m[2]) == 'rad') {
                             $angle = rad2deg($angle);
                         }
                     }
                 }
                 while ($angle < 0) {
                     $angle += 360;
                 }
                 $angle = $angle % 360;
             } else {
                 if (trim($first[count($first) - 1]) === "0") {
                     $angle = 0;
                 }
             }
             if (preg_match('/left/i', $bgr[0])) {
                 $startx = 0;
             } else {
                 if (preg_match('/right/i', $bgr[0])) {
                     $startx = 1;
                 }
             }
             if (preg_match('/top/i', $bgr[0])) {
                 $starty = 1;
             } else {
                 if (preg_match('/bottom/i', $bgr[0])) {
                     $starty = 0;
                 }
             }
             // Check for %? ?% or %%
             if (preg_match('/(\\d+)[%]/i', $first[0], $m)) {
                 $startx = $m[1] / 100;
             } else {
                 if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) {
                     $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
                     if ($tmp) {
                         $startx = $m[1];
                     }
                 }
             }
             if (isset($first[1]) && preg_match('/(\\d+)[%]/i', $first[1], $m)) {
                 $starty = 1 - $m[1] / 100;
             } else {
                 if (!isset($starty) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) {
                     $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
                     if ($tmp) {
                         $starty = $m[1];
                     }
                 }
             }
             if (isset($startx) && !isset($starty)) {
                 $starty = 0.5;
             }
             if (!isset($startx) && isset($starty)) {
                 $startx = 0.5;
             }
         } else {
             // default values T2B
             $starty = 1;
             $startx = 0.5;
             $endy = 0;
             $endx = 0.5;
         }
         $coords = array();
         if (!isset($startx)) {
             $startx = false;
         }
         if (!isset($starty)) {
             $starty = false;
         }
         if (!isset($endx)) {
             $endx = false;
         }
         if (!isset($endy)) {
             $endy = false;
         }
         if (!isset($angle)) {
             $angle = false;
         }
         $g['coords'] = array($startx, $starty, $endx, $endy, $angle, $repeat);
         $g['stops'] = array();
         for ($i = $startStops; $i < count($bgr); $i++) {
             $stop = array();
             // parse stops
             $el = preg_split('/\\s+/', trim($bgr[$i]));
             // mPDF 5.3.74
             $col = $this->mpdf->ConvertColor($el[0]);
             if ($col) {
                 $stop['col'] = $col;
             } else {
                 $stop['col'] = $col = $this->mpdf->ConvertColor(255);
             }
             if ($col[0] == 1) {
                 $g['colorspace'] = 'Gray';
             } else {
                 if ($col[0] == 4 || $col[0] == 6) {
                     $g['colorspace'] = 'CMYK';
                 }
             }
             if ($col[0] == 5) {
                 $stop['opacity'] = ord($col[4]) / 100;
             } else {
                 if ($col[0] == 6) {
                     $stop['opacity'] = ord($col[5]) / 100;
                 } else {
                     if ($col[0] == 1 && $col[2] == 1) {
                         $stop['opacity'] = ord($col[3]) / 100;
                     }
                 }
             }
             // transparency converted from rgba or cmyka()
             if (isset($el[1]) && preg_match('/(\\d+)[%]/', $el[1], $m)) {
                 $stop['offset'] = $m[1] / 100;
                 if ($stop['offset'] > 1) {
                     unset($stop['offset']);
                 }
             } else {
                 if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) {
                     $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
                     if ($tmp) {
                         $stop['offset'] = $m[1];
                     }
                 }
             }
             $g['stops'][] = $stop;
         }
         if (count($g['stops'])) {
             return $g;
         }
     } else {
         if (preg_match('/radial-gradient\\((.*)\\)/', $bg, $m)) {
             $g = array();
             $g['type'] = 3;
             $g['colorspace'] = 'RGB';
             $g['extend'] = array('true', 'true');
             $v = trim($m[1]);
             // Change commas inside e.g. rgb(x,x,x)
             while (preg_match('/(\\([^\\)]*?),/', $v)) {
                 $v = preg_replace_callback_callback('/(\\([^\\)]*?),/', '\\1@', $v);
             }
             // Remove spaces inside e.g. rgb(x, x, x)
             while (preg_match('/(\\([^\\)]*?)[ ]/', $v)) {
                 $v = preg_replace_callback_callback('/(\\([^\\)]*?)[ ]/', '\\1', $v);
             }
             $bgr = preg_split('/\\s*,\\s*/', $v);
             for ($i = 0; $i < count($bgr); $i++) {
                 $bgr[$i] = preg_replace_callback_callback('/@/', ',', $bgr[$i]);
             }
             // Is first part $bgr[0] a valid point/angle?
             $startStops = 0;
             $pos_angle = false;
             $shape_size = false;
             $first = preg_split('/\\s+/', trim($bgr[0]));
             $checkCol = $this->mpdf->ConvertColor($first[0]);
             if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) {
                 $startStops = 1;
                 $pos_angle = $bgr[0];
             } else {
                 if (trim($first[count($first) - 1]) === "0") {
                     $startStops = 1;
                     $pos_angle = $bgr[0];
                 } else {
                     if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[0])) {
                         $startStops = 1;
                         $shape_size = $bgr[0];
                     } else {
                         if (!$checkCol) {
                             $startStops = 1;
                             $pos_angle = $bgr[0];
                         }
                     }
                 }
             }
             if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[1])) {
                 $startStops = 2;
                 $shape_size = $bgr[1];
             }
             // If valid point/angle?
             if ($pos_angle) {
                 // default values
                 // [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,]
                 if (preg_match('/left/i', $pos_angle)) {
                     $startx = 0;
                 } else {
                     if (preg_match('/right/i', $pos_angle)) {
                         $startx = 1;
                     }
                 }
                 if (preg_match('/top/i', $pos_angle)) {
                     $starty = 1;
                 } else {
                     if (preg_match('/bottom/i', $pos_angle)) {
                         $starty = 0;
                     }
                 }
                 // Check for %? ?% or %%
                 if (preg_match('/(\\d+)[%]/i', $first[0], $m)) {
                     $startx = $m[1] / 100;
                 } else {
                     if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) {
                         $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
                         if ($tmp) {
                             $startx = $m[1];
                         }
                     }
                 }
                 if (isset($first[1]) && preg_match('/(\\d+)[%]/i', $first[1], $m)) {
                     $starty = 1 - $m[1] / 100;
                 } else {
                     if (!isset($starty) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) {
                         $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
                         if ($tmp) {
                             $starty = $m[1];
                         }
                     }
                 }
                 /*
                 		// ?? Angle has no effect in radial gradient (does not exist in CSS3 spec.)
                 		if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$pos_angle,$m)) {
                 			$angle = $m[1] + 0;
                 			if (strtolower($m[2])=='deg') { $angle = $angle; }
                 			else if (strtolower($m[2])=='grad') { $angle *= (360/400); }
                 			else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); }
                 			while($angle < 0) { $angle += 360; }
                 			$angle = ($angle % 360);
                 		}
                 */
                 if (!isset($starty)) {
                     $starty = 0.5;
                 }
                 if (!isset($startx)) {
                     $startx = 0.5;
                 }
             } else {
                 // default values Center
                 $starty = 0.5;
                 $startx = 0.5;
                 $endy = 0.5;
                 $endx = 0.5;
             }
             // If valid shape/size?
             $shape = 'ellipse';
             // default
             $size = 'farthest-corner';
             // default
             if ($shape_size) {
                 // default values
                 if (preg_match('/(circle|ellipse)/i', $shape_size, $m)) {
                     $shape = $m[1];
                 }
                 if (preg_match('/(closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $shape_size, $m)) {
                     $size = $m[1];
                     if ($size == 'contain') {
                         $size = 'closest-side';
                     } else {
                         if ($size == 'cover') {
                             $size = 'farthest-corner';
                         }
                     }
                 }
             }
             $coords = array();
             if (!isset($startx)) {
                 $startx = false;
             }
             if (!isset($starty)) {
                 $starty = false;
             }
             if (!isset($endx)) {
                 $endx = false;
             }
             if (!isset($endy)) {
                 $endy = false;
             }
             if (!isset($radius)) {
                 $radius = false;
             }
             if (!isset($angle)) {
                 $angle = 0;
             }
             $g['coords'] = array($startx, $starty, $endx, $endy, $radius, $angle, $shape, $size, $repeat);
             $g['stops'] = array();
             for ($i = $startStops; $i < count($bgr); $i++) {
                 $stop = array();
                 // parse stops
                 $el = preg_split('/\\s+/', trim($bgr[$i]));
                 // mPDF 5.3.74
                 $col = $this->mpdf->ConvertColor($el[0]);
                 if ($col) {
                     $stop['col'] = $col;
                 } else {
                     $stop['col'] = $col = $this->mpdf->ConvertColor(255);
                 }
                 if ($col[0] == 1) {
                     $g['colorspace'] = 'Gray';
                 } else {
                     if ($col[0] == 4 || $col[0] == 6) {
                         $g['colorspace'] = 'CMYK';
                     }
                 }
                 if ($col[0] == 5) {
                     $stop['opacity'] = ord($col[4]) / 100;
                 } else {
                     if ($col[0] == 6) {
                         $stop['opacity'] = ord($col[5]) / 100;
                     } else {
                         if ($col[0] == 1 && $col[2] == 1) {
                             $stop['opacity'] = ord($col[3]) / 100;
                         }
                     }
                 }
                 // transparency converted from rgba or cmyka()
                 if (isset($el[1]) && preg_match('/(\\d+)[%]/', $el[1], $m)) {
                     $stop['offset'] = $m[1] / 100;
                     if ($stop['offset'] > 1) {
                         unset($stop['offset']);
                     }
                 } else {
                     if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) {
                         $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
                         $stop['offset'] = $el[1];
                     }
                 }
                 $g['stops'][] = $stop;
             }
             if (count($g['stops'])) {
                 return $g;
             }
         }
     }
     return array();
 }
<?php

$ff = scandir('./');
sort($ff);
$files = array();
foreach ($ff as $f) {
    if (preg_match('/example[0]{0,1}(\\d+)_(.*?)\\.php/', $f, $m)) {
        $num = intval($m[1]);
        $files[$num] = array(ucfirst(preg_replace_callback_callback('/_/', ' ', $m[2])), $m[0]);
    }
}
echo '<html><body><h3>mPDF Example Files</h3>';
foreach ($files as $n => $f) {
    echo '<p>' . $n . ') ' . $f[0] . ' &nbsp; <a href="' . $f[1] . '">PDF</a> &nbsp;  <small><a href="show_code.php?filename=' . $f[1] . '">PHP</a></small></p>';
}
echo '</body></html>';
exit;
// For PHP4 compatability
if (!function_exists('scandir')) {
    function scandir($dir = './', $sort = 0)
    {
        $dir_open = @opendir($dir);
        if (!$dir_open) {
            return false;
            while (($dir_content = readdir($dir_open)) !== false) {
                $files[] = $dir_content;
            }
        }
        if ($sort == 1) {
            rsort($files, SORT_STRING);
        } else {