PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/Zend/Text/Figlet.php

https://bitbucket.org/simukti/zf1
PHP | 1232 lines | 668 code | 171 blank | 393 comment | 247 complexity | aa60e7a4f22dd98d0037e6b2521c98e9 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Text_Figlet
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Figlet.php 24593 2012-01-05 20:35:02Z matthew $
  20. */
  21. /**
  22. * Zend_Text_Figlet is a PHP implementation of FIGlet
  23. *
  24. * @category Zend
  25. * @package Zend_Text_Figlet
  26. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  27. * @license http://framework.zend.com/license/new-bsd New BSD License
  28. */
  29. class Zend_Text_Figlet
  30. {
  31. /**
  32. * Smush2 layout modes
  33. */
  34. const SM_EQUAL = 0x01;
  35. const SM_LOWLINE = 0x02;
  36. const SM_HIERARCHY = 0x04;
  37. const SM_PAIR = 0x08;
  38. const SM_BIGX = 0x10;
  39. const SM_HARDBLANK = 0x20;
  40. const SM_KERN = 0x40;
  41. const SM_SMUSH = 0x80;
  42. /**
  43. * Smush mode override modes
  44. */
  45. const SMO_NO = 0;
  46. const SMO_YES = 1;
  47. const SMO_FORCE = 2;
  48. /**
  49. * Justifications
  50. */
  51. const JUSTIFICATION_LEFT = 0;
  52. const JUSTIFICATION_CENTER = 1;
  53. const JUSTIFICATION_RIGHT = 2;
  54. /**
  55. * Write directions
  56. */
  57. const DIRECTION_LEFT_TO_RIGHT = 0;
  58. const DIRECTION_RIGHT_TO_LEFT = 1;
  59. /**
  60. * Magic fontfile number
  61. */
  62. const FONTFILE_MAGIC_NUMBER = 'flf2';
  63. /**
  64. * Array containing all characters of the current font
  65. *
  66. * @var array
  67. */
  68. protected $_charList = array();
  69. /**
  70. * Indicates if a font was loaded yet
  71. *
  72. * @var boolean
  73. */
  74. protected $_fontLoaded = false;
  75. /**
  76. * Latin-1 codes for German letters, respectively:
  77. *
  78. * LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut
  79. * LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut
  80. * LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut
  81. * LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut
  82. * LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut
  83. * LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut
  84. * LATIN SMALL LETTER SHARP S = ess-zed
  85. *
  86. * @var array
  87. */
  88. protected $_germanChars = array(196, 214, 220, 228, 246, 252, 223);
  89. /**
  90. * Output width, defaults to 80.
  91. *
  92. * @var integer
  93. */
  94. protected $_outputWidth = 80;
  95. /**
  96. * Hard blank character
  97. *
  98. * @var string
  99. */
  100. protected $_hardBlank;
  101. /**
  102. * Height of the characters
  103. *
  104. * @var integer
  105. */
  106. protected $_charHeight;
  107. /**
  108. * Max length of any character
  109. *
  110. * @var integer
  111. */
  112. protected $_maxLength;
  113. /**
  114. * Smush mode
  115. *
  116. * @var integer
  117. */
  118. protected $_smushMode = 0;
  119. /**
  120. * Smush defined by the font
  121. *
  122. * @var integer
  123. */
  124. protected $_fontSmush = 0;
  125. /**
  126. * Smush defined by the user
  127. *
  128. * @var integer
  129. */
  130. protected $_userSmush = 0;
  131. /**
  132. * Wether to handle paragraphs || not
  133. *
  134. * @var boolean
  135. */
  136. protected $_handleParagraphs = false;
  137. /**
  138. * Justification for the text, according to $_outputWidth
  139. *
  140. * For using font default, this parameter should be null, else one of
  141. * the values of Zend_Text_Figlet::JUSTIFICATION_*
  142. *
  143. * @var integer
  144. */
  145. protected $_justification = null;
  146. /**
  147. * Direction of text-writing, namely right to left
  148. *
  149. * For using font default, this parameter should be null, else one of
  150. * the values of Zend_Text_Figlet::DIRECTION_*
  151. *
  152. * @var integer
  153. */
  154. protected $_rightToLeft = null;
  155. /**
  156. * Override font file smush layout
  157. *
  158. * @var integer
  159. */
  160. protected $_smushOverride = 0;
  161. /**
  162. * Options of the current font
  163. *
  164. * @var array
  165. */
  166. protected $_fontOptions = array();
  167. /**
  168. * Previous character width
  169. *
  170. * @var integer
  171. */
  172. protected $_previousCharWidth = 0;
  173. /**
  174. * Current character width
  175. *
  176. * @var integer
  177. */
  178. protected $_currentCharWidth = 0;
  179. /**
  180. * Current outline length
  181. *
  182. * @var integer
  183. */
  184. protected $_outlineLength = 0;
  185. /**
  186. * Maxmimum outline length
  187. *
  188. * @var integer
  189. */
  190. protected $_outlineLengthLimit = 0;
  191. /**
  192. * In character line
  193. *
  194. * @var string
  195. */
  196. protected $_inCharLine;
  197. /**
  198. * In character line length
  199. *
  200. * @var integer
  201. */
  202. protected $_inCharLineLength = 0;
  203. /**
  204. * Maximum in character line length
  205. *
  206. * @var integer
  207. */
  208. protected $_inCharLineLengthLimit = 0;
  209. /**
  210. * Current char
  211. *
  212. * @var array
  213. */
  214. protected $_currentChar = null;
  215. /**
  216. * Current output line
  217. *
  218. * @var array
  219. */
  220. protected $_outputLine;
  221. /**
  222. * Current output
  223. *
  224. * @var string
  225. */
  226. protected $_output;
  227. /**
  228. * Option keys to skip when calling setOptions()
  229. *
  230. * @var array
  231. */
  232. protected $_skipOptions = array(
  233. 'options',
  234. 'config',
  235. );
  236. /**
  237. * Instantiate the FIGlet with a specific font. If no font is given, the
  238. * standard font is used. You can also supply multiple options via
  239. * the $options variable, which can either be an array or an instance of
  240. * Zend_Config.
  241. *
  242. * @param array|Zend_Config $options Options for the output
  243. */
  244. public function __construct($options = null)
  245. {
  246. // Set options
  247. if (is_array($options)) {
  248. $this->setOptions($options);
  249. } else if ($options instanceof Zend_Config) {
  250. $this->setConfig($options);
  251. }
  252. // If no font was defined, load default font
  253. if (!$this->_fontLoaded) {
  254. $this->_loadFont(dirname(__FILE__) . '/Figlet/zend-framework.flf');
  255. }
  256. }
  257. /**
  258. * Set options from array
  259. *
  260. * @param array $options Configuration for Zend_Text_Figlet
  261. * @return Zend_Text_Figlet
  262. */
  263. public function setOptions(array $options)
  264. {
  265. foreach ($options as $key => $value) {
  266. if (in_array(strtolower($key), $this->_skipOptions)) {
  267. continue;
  268. }
  269. $method = 'set' . ucfirst($key);
  270. if (method_exists($this, $method)) {
  271. $this->$method($value);
  272. }
  273. }
  274. return $this;
  275. }
  276. /**
  277. * Set options from config object
  278. *
  279. * @param Zend_Config $config Configuration for Zend_Text_Figlet
  280. * @return Zend_Text_Figlet
  281. */
  282. public function setConfig(Zend_Config $config)
  283. {
  284. return $this->setOptions($config->toArray());
  285. }
  286. /**
  287. * Set a font to use
  288. *
  289. * @param string $font Path to the font
  290. * @return Zend_Text_Figlet
  291. */
  292. public function setFont($font)
  293. {
  294. $this->_loadFont($font);
  295. return $this;
  296. }
  297. /**
  298. * Set handling of paragraphs
  299. *
  300. * @param boolean $handleParagraphs Wether to handle paragraphs or not
  301. * @return Zend_Text_Figlet
  302. */
  303. public function setHandleParagraphs($handleParagraphs)
  304. {
  305. $this->_handleParagraphs = (bool) $handleParagraphs;
  306. return $this;
  307. }
  308. /**
  309. * Set the justification. 0 stands for left aligned, 1 for centered and 2
  310. * for right aligned.
  311. *
  312. * @param integer $justification Justification of the output text
  313. * @return Zend_Text_Figlet
  314. */
  315. public function setJustification($justification)
  316. {
  317. $this->_justification = min(3, max(0, (int) $justification));
  318. return $this;
  319. }
  320. /**
  321. * Set the output width
  322. *
  323. * @param integer $outputWidth Output with which should be used for word
  324. * wrapping and justification
  325. * @return Zend_Text_Figlet
  326. */
  327. public function setOutputWidth($outputWidth)
  328. {
  329. $this->_outputWidth = max(1, (int) $outputWidth);
  330. return $this;
  331. }
  332. /**
  333. * Set right to left mode. For writing from left to right, use
  334. * Zend_Text_Figlet::DIRECTION_LEFT_TO_RIGHT. For writing from right to left,
  335. * use Zend_Text_Figlet::DIRECTION_RIGHT_TO_LEFT.
  336. *
  337. * @param integer $rightToLeft Right-to-left mode
  338. * @return Zend_Text_Figlet
  339. */
  340. public function setRightToLeft($rightToLeft)
  341. {
  342. $this->_rightToLeft = min(1, max(0, (int) $rightToLeft));
  343. return $this;
  344. }
  345. /**
  346. * Set the smush mode.
  347. *
  348. * Use one of the constants of Zend_Text_Figlet::SM_*, you may combine them.
  349. *
  350. * @param integer $smushMode Smush mode to use for generating text
  351. * @return Zend_Text_Figlet
  352. */
  353. public function setSmushMode($smushMode)
  354. {
  355. $smushMode = (int) $smushMode;
  356. if ($smushMode < -1) {
  357. $this->_smushOverride = self::SMO_NO;
  358. } else {
  359. if ($smushMode === 0) {
  360. $this->_userSmush = self::SM_KERN;
  361. } else if ($smushMode === -1) {
  362. $this->_userSmush = 0;
  363. } else {
  364. $this->_userSmush = (($smushMode & 63) | self::SM_SMUSH);
  365. }
  366. $this->_smushOverride = self::SMO_YES;
  367. }
  368. $this->_setUsedSmush();
  369. return $this;
  370. }
  371. /**
  372. * Render a FIGlet text
  373. *
  374. * @param string $text Text to convert to a figlet text
  375. * @param string $encoding Encoding of the input string
  376. * @throws InvalidArgumentException When $text is not a string
  377. * @throws Zend_Text_Figlet_Exception When $text it not properly encoded
  378. * @return string
  379. */
  380. public function render($text, $encoding = 'UTF-8')
  381. {
  382. if (!is_string($text)) {
  383. throw new InvalidArgumentException('$text must be a string');
  384. }
  385. if ($encoding !== 'UTF-8') {
  386. $text = iconv($encoding, 'UTF-8', $text);
  387. }
  388. $this->_output = '';
  389. $this->_outputLine = array();
  390. $this->_clearLine();
  391. $this->_outlineLengthLimit = ($this->_outputWidth - 1);
  392. $this->_inCharLineLengthLimit = ($this->_outputWidth * 4 + 100);
  393. $wordBreakMode = 0;
  394. $lastCharWasEol = false;
  395. $textLength = @iconv_strlen($text, 'UTF-8');
  396. if ($textLength === false) {
  397. require_once 'Zend/Text/Figlet/Exception.php';
  398. throw new Zend_Text_Figlet_Exception('$text is not encoded with ' . $encoding);
  399. }
  400. for ($charNum = 0; $charNum < $textLength; $charNum++) {
  401. // Handle paragraphs
  402. $char = iconv_substr($text, $charNum, 1, 'UTF-8');
  403. if ($char === "\n" && $this->_handleParagraphs && !$lastCharWasEol) {
  404. $nextChar = iconv_substr($text, ($charNum + 1), 1, 'UTF-8');
  405. if (!$nextChar) {
  406. $nextChar = null;
  407. }
  408. $char = (ctype_space($nextChar)) ? "\n" : ' ';
  409. }
  410. $lastCharWasEol = (ctype_space($char) && $char !== "\t" && $char !== ' ');
  411. if (ctype_space($char)) {
  412. $char = ($char === "\t" || $char === ' ') ? ' ': "\n";
  413. }
  414. // Skip unprintable characters
  415. $ordChar = $this->_uniOrd($char);
  416. if (($ordChar > 0 && $ordChar < 32 && $char !== "\n") || $ordChar === 127) {
  417. continue;
  418. }
  419. // Build the character
  420. // Note: The following code is complex and thoroughly tested.
  421. // Be careful when modifying!
  422. do {
  423. $charNotAdded = false;
  424. if ($wordBreakMode === -1) {
  425. if ($char === ' ') {
  426. break;
  427. } else if ($char === "\n") {
  428. $wordBreakMode = 0;
  429. break;
  430. }
  431. $wordBreakMode = 0;
  432. }
  433. if ($char === "\n") {
  434. $this->_appendLine();
  435. $wordBreakMode = false;
  436. } else if ($this->_addChar($char)) {
  437. if ($char !== ' ') {
  438. $wordBreakMode = ($wordBreakMode >= 2) ? 3: 1;
  439. } else {
  440. $wordBreakMode = ($wordBreakMode > 0) ? 2: 0;
  441. }
  442. } else if ($this->_outlineLength === 0) {
  443. for ($i = 0; $i < $this->_charHeight; $i++) {
  444. if ($this->_rightToLeft === 1 && $this->_outputWidth > 1) {
  445. $offset = (strlen($this->_currentChar[$i]) - $this->_outlineLengthLimit);
  446. $this->_putString(substr($this->_currentChar[$i], $offset));
  447. } else {
  448. $this->_putString($this->_currentChar[$i]);
  449. }
  450. }
  451. $wordBreakMode = -1;
  452. } else if ($char === ' ') {
  453. if ($wordBreakMode === 2) {
  454. $this->_splitLine();
  455. } else {
  456. $this->_appendLine();
  457. }
  458. $wordBreakMode = -1;
  459. } else {
  460. if ($wordBreakMode >= 2) {
  461. $this->_splitLine();
  462. } else {
  463. $this->_appendLine();
  464. }
  465. $wordBreakMode = ($wordBreakMode === 3) ? 1 : 0;
  466. $charNotAdded = true;
  467. }
  468. } while ($charNotAdded);
  469. }
  470. if ($this->_outlineLength !== 0) {
  471. $this->_appendLine();
  472. }
  473. return $this->_output;
  474. }
  475. /**
  476. * Puts the given string, substituting blanks for hardblanks. If outputWidth
  477. * is 1, puts the entire string; otherwise puts at most outputWidth - 1
  478. * characters. Puts a newline at the end of the string. The string is left-
  479. * justified, centered or right-justified (taking outputWidth as the screen
  480. * width) if justification is 0, 1 or 2 respectively.
  481. *
  482. * @param string $string The string to add to the output
  483. * @return void
  484. */
  485. protected function _putString($string)
  486. {
  487. $length = strlen($string);
  488. if ($this->_outputWidth > 1) {
  489. if ($length > ($this->_outputWidth - 1)) {
  490. $length = ($this->_outputWidth - 1);
  491. }
  492. if ($this->_justification > 0) {
  493. for ($i = 1;
  494. ((3 - $this->_justification) * $i + $length + $this->_justification - 2) < $this->_outputWidth;
  495. $i++) {
  496. $this->_output .= ' ';
  497. }
  498. }
  499. }
  500. $this->_output .= str_replace($this->_hardBlank, ' ', $string) . "\n";
  501. }
  502. /**
  503. * Appends the current line to the output
  504. *
  505. * @return void
  506. */
  507. protected function _appendLine()
  508. {
  509. for ($i = 0; $i < $this->_charHeight; $i++) {
  510. $this->_putString($this->_outputLine[$i]);
  511. }
  512. $this->_clearLine();
  513. }
  514. /**
  515. * Splits inCharLine at the last word break (bunch of consecutive blanks).
  516. * Makes a new line out of the first part and appends it using appendLine().
  517. * Makes a new line out of the second part and returns.
  518. *
  519. * @return void
  520. */
  521. protected function _splitLine()
  522. {
  523. $gotSpace = false;
  524. for ($i = ($this->_inCharLineLength - 1); $i >= 0; $i--) {
  525. if (!$gotSpace && $this->_inCharLine[$i] === ' ') {
  526. $gotSpace = true;
  527. $lastSpace = $i;
  528. }
  529. if ($gotSpace && $this->_inCharLine[$i] !== ' ') {
  530. break;
  531. }
  532. }
  533. $firstLength = ($i + 1);
  534. $lastLength = ($this->_inCharLineLength - $lastSpace - 1);
  535. $firstPart = '';
  536. for ($i = 0; $i < $firstLength; $i++) {
  537. $firstPart[$i] = $this->_inCharLine[$i];
  538. }
  539. $lastPart = '';
  540. for ($i = 0; $i < $lastLength; $i++) {
  541. $lastPart[$i] = $this->_inCharLine[($lastSpace + 1 + $i)];
  542. }
  543. $this->_clearLine();
  544. for ($i = 0; $i < $firstLength; $i++) {
  545. $this->_addChar($firstPart[$i]);
  546. }
  547. $this->_appendLine();
  548. for ($i = 0; $i < $lastLength; $i++) {
  549. $this->_addChar($lastPart[$i]);
  550. }
  551. }
  552. /**
  553. * Clears the current line
  554. *
  555. * @return void
  556. */
  557. protected function _clearLine()
  558. {
  559. for ($i = 0; $i < $this->_charHeight; $i++) {
  560. $this->_outputLine[$i] = '';
  561. }
  562. $this->_outlineLength = 0;
  563. $this->_inCharLineLength = 0;
  564. }
  565. /**
  566. * Attempts to add the given character onto the end of the current line.
  567. * Returns true if this can be done, false otherwise.
  568. *
  569. * @param string $char Character which to add to the output
  570. * @return boolean
  571. */
  572. protected function _addChar($char)
  573. {
  574. $this->_getLetter($char);
  575. if ($this->_currentChar === null) {
  576. return true;
  577. }
  578. $smushAmount = $this->_smushAmount();
  579. if (($this->_outlineLength + $this->_currentCharWidth - $smushAmount) > $this->_outlineLengthLimit
  580. || ($this->_inCharLineLength + 1) > $this->_inCharLineLengthLimit) {
  581. return false;
  582. }
  583. $tempLine = '';
  584. for ($row = 0; $row < $this->_charHeight; $row++) {
  585. if ($this->_rightToLeft === 1) {
  586. $tempLine = $this->_currentChar[$row];
  587. for ($k = 0; $k < $smushAmount; $k++) {
  588. $position = ($this->_currentCharWidth - $smushAmount + $k);
  589. $tempLine[$position] = $this->_smushem($tempLine[$position], $this->_outputLine[$row][$k]);
  590. }
  591. $this->_outputLine[$row] = $tempLine . substr($this->_outputLine[$row], $smushAmount);
  592. } else {
  593. for ($k = 0; $k < $smushAmount; $k++) {
  594. if (($this->_outlineLength - $smushAmount + $k) < 0) {
  595. continue;
  596. }
  597. $position = ($this->_outlineLength - $smushAmount + $k);
  598. if (isset($this->_outputLine[$row][$position])) {
  599. $leftChar = $this->_outputLine[$row][$position];
  600. } else {
  601. $leftChar = null;
  602. }
  603. $this->_outputLine[$row][$position] = $this->_smushem($leftChar, $this->_currentChar[$row][$k]);
  604. }
  605. $this->_outputLine[$row] .= substr($this->_currentChar[$row], $smushAmount);
  606. }
  607. }
  608. $this->_outlineLength = strlen($this->_outputLine[0]);
  609. $this->_inCharLine[$this->_inCharLineLength++] = $char;
  610. return true;
  611. }
  612. /**
  613. * Gets the requested character and sets current and previous char width.
  614. *
  615. * @param string $char The character from which to get the letter of
  616. * @return void
  617. */
  618. protected function _getLetter($char)
  619. {
  620. if (array_key_exists($this->_uniOrd($char), $this->_charList)) {
  621. $this->_currentChar = $this->_charList[$this->_uniOrd($char)];
  622. $this->_previousCharWidth = $this->_currentCharWidth;
  623. $this->_currentCharWidth = strlen($this->_currentChar[0]);
  624. } else {
  625. $this->_currentChar = null;
  626. }
  627. }
  628. /**
  629. * Returns the maximum amount that the current character can be smushed into
  630. * the current line.
  631. *
  632. * @return integer
  633. */
  634. protected function _smushAmount()
  635. {
  636. if (($this->_smushMode & (self::SM_SMUSH | self::SM_KERN)) === 0) {
  637. return 0;
  638. }
  639. $maxSmush = $this->_currentCharWidth;
  640. $amount = $maxSmush;
  641. for ($row = 0; $row < $this->_charHeight; $row++) {
  642. if ($this->_rightToLeft === 1) {
  643. $charbd = strlen($this->_currentChar[$row]);
  644. while (true) {
  645. if (!isset($this->_currentChar[$row][$charbd])) {
  646. $leftChar = null;
  647. } else {
  648. $leftChar = $this->_currentChar[$row][$charbd];
  649. }
  650. if ($charbd > 0 && ($leftChar === null || $leftChar == ' ')) {
  651. $charbd--;
  652. } else {
  653. break;
  654. }
  655. }
  656. $linebd = 0;
  657. while (true) {
  658. if (!isset($this->_outputLine[$row][$linebd])) {
  659. $rightChar = null;
  660. } else {
  661. $rightChar = $this->_outputLine[$row][$linebd];
  662. }
  663. if ($rightChar === ' ') {
  664. $linebd++;
  665. } else {
  666. break;
  667. }
  668. }
  669. $amount = ($linebd + $this->_currentCharWidth - 1 - $charbd);
  670. } else {
  671. $linebd = strlen($this->_outputLine[$row]);
  672. while (true) {
  673. if (!isset($this->_outputLine[$row][$linebd])) {
  674. $leftChar = null;
  675. } else {
  676. $leftChar = $this->_outputLine[$row][$linebd];
  677. }
  678. if ($linebd > 0 && ($leftChar === null || $leftChar == ' ')) {
  679. $linebd--;
  680. } else {
  681. break;
  682. }
  683. }
  684. $charbd = 0;
  685. while (true) {
  686. if (!isset($this->_currentChar[$row][$charbd])) {
  687. $rightChar = null;
  688. } else {
  689. $rightChar = $this->_currentChar[$row][$charbd];
  690. }
  691. if ($rightChar === ' ') {
  692. $charbd++;
  693. } else {
  694. break;
  695. }
  696. }
  697. $amount = ($charbd + $this->_outlineLength - 1 - $linebd);
  698. }
  699. if (empty($leftChar) || $leftChar === ' ') {
  700. $amount++;
  701. } else if (!empty($rightChar)) {
  702. if ($this->_smushem($leftChar, $rightChar) !== null) {
  703. $amount++;
  704. }
  705. }
  706. $maxSmush = min($amount, $maxSmush);
  707. }
  708. return $maxSmush;
  709. }
  710. /**
  711. * Given two characters, attempts to smush them into one, according to the
  712. * current smushmode. Returns smushed character or false if no smushing can
  713. * be done.
  714. *
  715. * Smushmode values are sum of following (all values smush blanks):
  716. *
  717. * 1: Smush equal chars (not hardblanks)
  718. * 2: Smush '_' with any char in hierarchy below
  719. * 4: hierarchy: "|", "/\", "[]", "{}", "()", "<>"
  720. * Each class in hier. can be replaced by later class.
  721. * 8: [ + ] -> |, { + } -> |, ( + ) -> |
  722. * 16: / + \ -> X, > + < -> X (only in that order)
  723. * 32: hardblank + hardblank -> hardblank
  724. *
  725. * @param string $leftChar Left character to smush
  726. * @param string $rightChar Right character to smush
  727. * @return string
  728. */
  729. protected function _smushem($leftChar, $rightChar)
  730. {
  731. if ($leftChar === ' ') {
  732. return $rightChar;
  733. }
  734. if ($rightChar === ' ') {
  735. return $leftChar;
  736. }
  737. if ($this->_previousCharWidth < 2 || $this->_currentCharWidth < 2) {
  738. // Disallows overlapping if the previous character or the current
  739. // character has a width of one or zero.
  740. return null;
  741. }
  742. if (($this->_smushMode & self::SM_SMUSH) === 0) {
  743. // Kerning
  744. return null;
  745. }
  746. if (($this->_smushMode & 63) === 0) {
  747. // This is smushing by universal overlapping
  748. if ($leftChar === ' ') {
  749. return $rightChar;
  750. } else if ($rightChar === ' ') {
  751. return $leftChar;
  752. } else if ($leftChar === $this->_hardBlank) {
  753. return $rightChar;
  754. } else if ($rightChar === $this->_hardBlank) {
  755. return $rightChar;
  756. } else if ($this->_rightToLeft === 1) {
  757. return $leftChar;
  758. } else {
  759. // Occurs in the absence of above exceptions
  760. return $rightChar;
  761. }
  762. }
  763. if (($this->_smushMode & self::SM_HARDBLANK) > 0) {
  764. if ($leftChar === $this->_hardBlank && $rightChar === $this->_hardBlank) {
  765. return $leftChar;
  766. }
  767. }
  768. if ($leftChar === $this->_hardBlank && $rightChar === $this->_hardBlank) {
  769. return null;
  770. }
  771. if (($this->_smushMode & self::SM_EQUAL) > 0) {
  772. if ($leftChar === $rightChar) {
  773. return $leftChar;
  774. }
  775. }
  776. if (($this->_smushMode & self::SM_LOWLINE) > 0) {
  777. if ($leftChar === '_' && strchr('|/\\[]{}()<>', $rightChar) !== false) {
  778. return $rightChar;
  779. } else if ($rightChar === '_' && strchr('|/\\[]{}()<>', $leftChar) !== false) {
  780. return $leftChar;
  781. }
  782. }
  783. if (($this->_smushMode & self::SM_HIERARCHY) > 0) {
  784. if ($leftChar === '|' && strchr('/\\[]{}()<>', $rightChar) !== false) {
  785. return $rightChar;
  786. } else if ($rightChar === '|' && strchr('/\\[]{}()<>', $leftChar) !== false) {
  787. return $leftChar;
  788. } else if (strchr('/\\', $leftChar) && strchr('[]{}()<>', $rightChar) !== false) {
  789. return $rightChar;
  790. } else if (strchr('/\\', $rightChar) && strchr('[]{}()<>', $leftChar) !== false) {
  791. return $leftChar;
  792. } else if (strchr('[]', $leftChar) && strchr('{}()<>', $rightChar) !== false) {
  793. return $rightChar;
  794. } else if (strchr('[]', $rightChar) && strchr('{}()<>', $leftChar) !== false) {
  795. return $leftChar;
  796. } else if (strchr('{}', $leftChar) && strchr('()<>', $rightChar) !== false) {
  797. return $rightChar;
  798. } else if (strchr('{}', $rightChar) && strchr('()<>', $leftChar) !== false) {
  799. return $leftChar;
  800. } else if (strchr('()', $leftChar) && strchr('<>', $rightChar) !== false) {
  801. return $rightChar;
  802. } else if (strchr('()', $rightChar) && strchr('<>', $leftChar) !== false) {
  803. return $leftChar;
  804. }
  805. }
  806. if (($this->_smushMode & self::SM_PAIR) > 0) {
  807. if ($leftChar === '[' && $rightChar === ']') {
  808. return '|';
  809. } else if ($rightChar === '[' && $leftChar === ']') {
  810. return '|';
  811. } else if ($leftChar === '{' && $rightChar === '}') {
  812. return '|';
  813. } else if ($rightChar === '{' && $leftChar === '}') {
  814. return '|';
  815. } else if ($leftChar === '(' && $rightChar === ')') {
  816. return '|';
  817. } else if ($rightChar === '(' && $leftChar === ')') {
  818. return '|';
  819. }
  820. }
  821. if (($this->_smushMode & self::SM_BIGX) > 0) {
  822. if ($leftChar === '/' && $rightChar === '\\') {
  823. return '|';
  824. } else if ($rightChar === '/' && $leftChar === '\\') {
  825. return 'Y';
  826. } else if ($leftChar === '>' && $rightChar === '<') {
  827. return 'X';
  828. }
  829. }
  830. return null;
  831. }
  832. /**
  833. * Load the specified font
  834. *
  835. * @param string $fontFile Font file to load
  836. * @throws Zend_Text_Figlet_Exception When font file was not found
  837. * @throws Zend_Text_Figlet_Exception When GZIP library is required but not found
  838. * @throws Zend_Text_Figlet_Exception When font file is not readable
  839. * @return void
  840. */
  841. protected function _loadFont($fontFile)
  842. {
  843. // Check if the font file exists
  844. if (!file_exists($fontFile)) {
  845. require_once 'Zend/Text/Figlet/Exception.php';
  846. throw new Zend_Text_Figlet_Exception($fontFile . ': Font file not found');
  847. }
  848. // Check if gzip support is required
  849. if (substr($fontFile, -3) === '.gz') {
  850. if (!function_exists('gzcompress')) {
  851. require_once 'Zend/Text/Figlet/Exception.php';
  852. throw new Zend_Text_Figlet_Exception('GZIP library is required for '
  853. . 'gzip compressed font files');
  854. }
  855. $fontFile = 'compress.zlib://' . $fontFile;
  856. $compressed = true;
  857. } else {
  858. $compressed = false;
  859. }
  860. // Try to open the file
  861. $fp = fopen($fontFile, 'rb');
  862. if ($fp === false) {
  863. require_once 'Zend/Text/Figlet/Exception.php';
  864. throw new Zend_Text_Figlet_Exception($fontFile . ': Could not open file');
  865. }
  866. // If the file is not compressed, lock the stream
  867. if (!$compressed) {
  868. flock($fp, LOCK_SH);
  869. }
  870. // Get magic
  871. $magic = $this->_readMagic($fp);
  872. // Get the header
  873. $numsRead = sscanf(fgets($fp, 1000),
  874. '%*c%c %d %*d %d %d %d %d %d',
  875. $this->_hardBlank,
  876. $this->_charHeight,
  877. $this->_maxLength,
  878. $smush,
  879. $cmtLines,
  880. $rightToLeft,
  881. $this->_fontSmush);
  882. if ($magic !== self::FONTFILE_MAGIC_NUMBER || $numsRead < 5) {
  883. require_once 'Zend/Text/Figlet/Exception.php';
  884. throw new Zend_Text_Figlet_Exception($fontFile . ': Not a FIGlet 2 font file');
  885. }
  886. // Set default right to left
  887. if ($numsRead < 6) {
  888. $rightToLeft = 0;
  889. }
  890. // If no smush2, decode smush into smush2
  891. if ($numsRead < 7) {
  892. if ($smush === 2) {
  893. $this->_fontSmush = self::SM_KERN;
  894. } else if ($smush < 0) {
  895. $this->_fontSmush = 0;
  896. } else {
  897. $this->_fontSmush = (($smush & 31) | self::SM_SMUSH);
  898. }
  899. }
  900. // Correct char height && maxlength
  901. $this->_charHeight = max(1, $this->_charHeight);
  902. $this->_maxLength = max(1, $this->_maxLength);
  903. // Give ourselves some extra room
  904. $this->_maxLength += 100;
  905. // See if we have to override smush settings
  906. $this->_setUsedSmush();
  907. // Get left to right value
  908. if ($this->_rightToLeft === null) {
  909. $this->_rightToLeft = $rightToLeft;
  910. }
  911. // Get justification value
  912. if ($this->_justification === null) {
  913. $this->_justification = (2 * $this->_rightToLeft);
  914. }
  915. // Skip all comment lines
  916. for ($line = 1; $line <= $cmtLines; $line++) {
  917. $this->_skipToEol($fp);
  918. }
  919. // Fetch all ASCII characters
  920. for ($asciiCode = 32; $asciiCode < 127; $asciiCode++) {
  921. $this->_charList[$asciiCode] = $this->_loadChar($fp);
  922. }
  923. // Fetch all german characters
  924. foreach ($this->_germanChars as $uniCode) {
  925. $char = $this->_loadChar($fp);
  926. if ($char === false) {
  927. fclose($fp);
  928. return;
  929. }
  930. if (trim(implode('', $char)) !== '') {
  931. $this->_charList[$uniCode] = $char;
  932. }
  933. }
  934. // At the end fetch all extended characters
  935. while (!feof($fp)) {
  936. // Get the Unicode
  937. list($uniCode) = explode(' ', fgets($fp, 2048));
  938. if (empty($uniCode)) {
  939. continue;
  940. }
  941. // Convert it if required
  942. if (substr($uniCode, 0, 2) === '0x') {
  943. $uniCode = hexdec(substr($uniCode, 2));
  944. } else if (substr($uniCode, 0, 1) === '0' and
  945. $uniCode !== '0' or
  946. substr($uniCode, 0, 2) === '-0') {
  947. $uniCode = octdec($uniCode);
  948. } else {
  949. $uniCode = (int) $uniCode;
  950. }
  951. // Now fetch the character
  952. $char = $this->_loadChar($fp);
  953. if ($char === false) {
  954. fclose($fp);
  955. return;
  956. }
  957. $this->_charList[$uniCode] = $char;
  958. }
  959. fclose($fp);
  960. $this->_fontLoaded = true;
  961. }
  962. /**
  963. * Set the used smush mode, according to smush override, user smsush and
  964. * font smush.
  965. *
  966. * @return void
  967. */
  968. protected function _setUsedSmush()
  969. {
  970. if ($this->_smushOverride === self::SMO_NO) {
  971. $this->_smushMode = $this->_fontSmush;
  972. } else if ($this->_smushOverride === self::SMO_YES) {
  973. $this->_smushMode = $this->_userSmush;
  974. } else if ($this->_smushOverride === self::SMO_FORCE) {
  975. $this->_smushMode = ($this->_fontSmush | $this->_userSmush);
  976. }
  977. }
  978. /**
  979. * Reads a four-character magic string from a stream
  980. *
  981. * @param resource $fp File pointer to the font file
  982. * @return string
  983. */
  984. protected function _readMagic($fp)
  985. {
  986. $magic = '';
  987. for ($i = 0; $i < 4; $i++) {
  988. $magic .= fgetc($fp);
  989. }
  990. return $magic;
  991. }
  992. /**
  993. * Skip a stream to the end of line
  994. *
  995. * @param resource $fp File pointer to the font file
  996. * @return void
  997. */
  998. protected function _skipToEol($fp)
  999. {
  1000. $dummy = fgetc($fp);
  1001. while ($dummy !== false && !feof($fp)) {
  1002. if ($dummy === "\n") {
  1003. return;
  1004. }
  1005. if ($dummy === "\r") {
  1006. $dummy = fgetc($fp);
  1007. if (!feof($fp) && $dummy !== "\n") {
  1008. fseek($fp, -1, SEEK_SET);
  1009. }
  1010. return;
  1011. }
  1012. $dummy = fgetc($fp);
  1013. }
  1014. }
  1015. /**
  1016. * Load a single character from the font file
  1017. *
  1018. * @param resource $fp File pointer to the font file
  1019. * @return array
  1020. */
  1021. protected function _loadChar($fp)
  1022. {
  1023. $char = array();
  1024. for ($i = 0; $i < $this->_charHeight; $i++) {
  1025. if (feof($fp)) {
  1026. return false;
  1027. }
  1028. $line = rtrim(fgets($fp, 2048), "\r\n");
  1029. if (preg_match('#(.)\\1?$#', $line, $result) === 1) {
  1030. $line = str_replace($result[1], '', $line);
  1031. }
  1032. $char[] = $line;
  1033. }
  1034. return $char;
  1035. }
  1036. /**
  1037. * Unicode compatible ord() method
  1038. *
  1039. * @param string $c The char to get the value from
  1040. * @return integer
  1041. */
  1042. protected function _uniOrd($c)
  1043. {
  1044. $h = ord($c[0]);
  1045. if ($h <= 0x7F) {
  1046. $ord = $h;
  1047. } else if ($h < 0xC2) {
  1048. $ord = 0;
  1049. } else if ($h <= 0xDF) {
  1050. $ord = (($h & 0x1F) << 6 | (ord($c[1]) & 0x3F));
  1051. } else if ($h <= 0xEF) {
  1052. $ord = (($h & 0x0F) << 12 | (ord($c[1]) & 0x3F) << 6 | (ord($c[2]) & 0x3F));
  1053. } else if ($h <= 0xF4) {
  1054. $ord = (($h & 0x0F) << 18 | (ord($c[1]) & 0x3F) << 12 |
  1055. (ord($c[2]) & 0x3F) << 6 | (ord($c[3]) & 0x3F));
  1056. } else {
  1057. $ord = 0;
  1058. }
  1059. return $ord;
  1060. }
  1061. }