Skip to content

Commit

Permalink
Use PEAR Text_Figlet to render figlet fonts
Browse files Browse the repository at this point in the history
Summary:
Ref T7785. Makes Figlet available without installing the `figlet` package.

The PEAR Text_Figlet code is really sketchy and includes this API, which is quite marvelous:

```
    function loadFont($filename, $loadgerman = true)
```

At some point, this should probably be rewritten into a modern style, but it's not trivial since the figlet file format and rendering engine are somewhat complicated. I made some adjustments:

  - Broke the dependency on the PEAR core.
  - Prevented it from doing any wrong HTML escaping.
  - Looked through it for any glaring security or correctness problems.

This code isn't very pretty or modern, but as far as I can tell it's safe and does render Figlet fonts in a reasonable way.

Test Plan: {F803268}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9408, T7785

Differential Revision: https://secure.phabricator.com/D14102
  • Loading branch information
epriestley committed Sep 13, 2015
1 parent 935ced1 commit 6bd8ee8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 48 deletions.
44 changes: 17 additions & 27 deletions externals/pear-figlet/Text/Figlet.php
Expand Up @@ -15,7 +15,6 @@
* @version CVS: $Id$
* @link http://pear.php.net/package/Text_Figlet
*/
require_once 'PEAR.php';

/**
* ASCII art text creation
Expand Down Expand Up @@ -113,22 +112,9 @@ function loadFont($filename, $loadgerman = true)
{
$this->font = array();
if (!file_exists($filename)) {
//if it does not exist, try the Text_Figlet data directory
include_once 'PEAR/Config.php';

$config = PEAR_Config::singleton();
$fontdir = $config->get('data_dir') . '/Text_Figlet/fonts/';

//only for filenames without path separators
if (strpos($filename, '/') === false
&& file_exists($fontdir . $filename)
) {
$filename = $fontdir . $filename;
} else {
return PEAR::raiseError('Figlet font file "'
. $filename
. '" cannot be found', 1);
}
return self::raiseError('Figlet font file "'
. $filename
. '" cannot be found', 1);
}

$this->font_comment = '';
Expand All @@ -139,7 +125,7 @@ function loadFont($filename, $loadgerman = true)
$compressed = true;

if (!function_exists('gzcompress')) {
return PEAR::raiseError('Cannot load gzip compressed fonts since'
return self::raiseError('Cannot load gzip compressed fonts since'
. ' gzcompress() is not available.',
3);
}
Expand All @@ -148,29 +134,29 @@ function loadFont($filename, $loadgerman = true)
}

if (!($fp = fopen($filename, 'rb'))) {
return PEAR::raiseError('Cannot open figlet font file ' . $filename, 2);
return self::raiseError('Cannot open figlet font file ' . $filename, 2);
}

if (!$compressed) {
/* ZIPed font */
if (fread($fp, 2) == 'PK') {
if (!function_exists('zip_open')) {
return PEAR::raiseError('Cannot load ZIP compressed fonts since'
return self::raiseError('Cannot load ZIP compressed fonts since'
. ' ZIP PHP extension is not available.',
5);
}

fclose($fp);

if (!($fp = zip_open($filename))) {
return PEAR::raiseError('Cannot open figlet font file ' . $filename, 2);
return self::raiseError('Cannot open figlet font file ' . $filename, 2);
}

$name = zip_entry_name(zip_read($fp));
zip_close($fp);

if (!($fp = fopen('zip://' . realpath($filename) . '#' . $name, 'rb'))) {
return PEAR::raiseError('Cannot open figlet font file ' . $filename, 2);
return self::raiseError('Cannot open figlet font file ' . $filename, 2);
}

$compressed = true;
Expand All @@ -193,7 +179,7 @@ function loadFont($filename, $loadgerman = true)
$header = explode(' ', fgets($fp, 2048));

if (substr($header[0], 0, 5) <> 'flf2a') {
return PEAR::raiseError('Unknown FIGlet font format.', 4);
return self::raiseError('Unknown FIGlet font format.', 4);
}

@list ($this->hardblank, $this->height,,,
Expand Down Expand Up @@ -381,9 +367,9 @@ function lineEcho($str, $inhtml = false)
$str = strtr(implode("\n", $out), $trans);

if ($inhtml) {
return '<nobr>'.
nl2br(str_replace(' ', '&nbsp;', htmlspecialchars($str))).
'</nobr>';
self::raiseError(
'Do not use the HTML escaping provided by this class in '.
'a Phabricator context.');
}

return $str;
Expand Down Expand Up @@ -506,5 +492,9 @@ function _skip(&$fp)

return true;
}


private static function raiseError($message, $code = 1) {
throw new Exception($message);
}
}
?>
Expand Up @@ -7,41 +7,59 @@ public function getInterpreterName() {
return 'figlet';
}

/**
* @phutil-external-symbol class Text_Figlet
*/
public function markupContent($content, array $argv) {
if (!Filesystem::binaryExists('figlet')) {
return $this->markupError(
pht(
'Unable to locate the `%s` binary. Install figlet.',
'figlet'));
}
$map = self::getFigletMap();

$font = idx($argv, 'font', 'standard');
$safe_font = preg_replace('/[^0-9a-zA-Z-_.]/', '', $font);
$future = id(new ExecFuture('figlet -f %s', $safe_font))
->setTimeout(15)
->write(trim($content, "\n"));
$font = idx($argv, 'font');
$font = phutil_utf8_strtolower($font);
if (empty($map[$font])) {
$font = 'standard';
}

list($err, $stdout, $stderr) = $future->resolve();
$root = dirname(phutil_get_library_root('phabricator'));
require_once $root.'/externals/pear-figlet/Text/Figlet.php';

if ($err) {
return $this->markupError(
pht(
'Execution of `%s` failed: %s',
'figlet',
$stderr));
}
$figlet = new Text_Figlet();
$figlet->loadFont($map[$font]);

$result = $figlet->lineEcho($content);

if ($this->getEngine()->isTextMode()) {
return $stdout;
return $result;
}

return phutil_tag(
'div',
array(
'class' => 'PhabricatorMonospaced remarkup-figlet',
),
$stdout);
$result);
}

private static function getFigletMap() {
$root = dirname(phutil_get_library_root('phabricator'));

$dirs = array(
$root.'/externals/figlet/fonts/',
$root.'/externals/pear-figlet/fonts/',
$root.'/resources/figlet/custom/',
);

$map = array();
foreach ($dirs as $dir) {
foreach (Filesystem::listDirectory($dir, false) as $file) {
if (preg_match('/\.flf\z/', $file)) {
$name = phutil_utf8_strtolower($file);
$name = preg_replace('/\.flf\z/', '', $name);
$map[$name] = $dir.$file;
}
}
}

return $map;
}

}

0 comments on commit 6bd8ee8

Please sign in to comment.