Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/externals/pear-figlet/Text/Figlet.php
13450 views
1
<?php
2
/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
3
/**
4
* ASCII art text creation
5
*
6
* Project home page (Russian): http://bolknote.ru/files/figlet/
7
*
8
* PHP Version 4
9
*
10
* @category Text
11
* @package Text_Figlet
12
* @author Evgeny Stepanischev <[email protected]>
13
* @author Christian Weiske <[email protected]>
14
* @license http://www.php.net/license PHP License
15
* @version CVS: $Id$
16
* @link http://pear.php.net/package/Text_Figlet
17
*/
18
19
/**
20
* ASCII art text creation
21
*
22
* Project home page (Russian): http://bolknote.ru/files/figlet/
23
*
24
* PHP Version 4
25
*
26
* @category Text
27
* @package Text_Figlet
28
* @author Evgeny Stepanischev <[email protected]>
29
* @author Christian Weiske <[email protected]>
30
* @license http://www.php.net/license PHP License
31
* @link http://pear.php.net/package/Text_Figlet
32
*/
33
class Text_Figlet
34
{
35
/**
36
* Height of a letter
37
*
38
* @var integer
39
*
40
* @access protected
41
*/
42
var $height;
43
44
/**
45
* Letter baseline
46
*
47
* @var integer
48
*
49
* @access protected
50
*/
51
var $oldlayout;
52
53
/**
54
* Flag - RTL (right to left) or LTR (left to right) text direction
55
*
56
* @var integer
57
*
58
* @access protected
59
*/
60
var $rtol;
61
62
/**
63
* Information about special 'hardblank' character
64
*
65
* @var integer
66
*
67
* @access protected
68
*/
69
var $hardblank;
70
71
/**
72
* Is used for keeping font
73
*
74
* @var array
75
*
76
* @access protected
77
*/
78
var $font;
79
80
/**
81
* Flag is true if smushing occured in letters printing cycle
82
*
83
* @var integer
84
*
85
* @access protected
86
*/
87
var $smush_flag;
88
89
/**
90
* Comment lines buffer
91
*
92
* @var string
93
*
94
* @access public
95
*/
96
97
var $font_comment;
98
99
100
/**
101
* Load user font. Must be invoked first.
102
* Automatically tries the Text_Figlet font data directory
103
* as long as no path separator is in the filename.
104
*
105
* @param string $filename font file name
106
* @param bool $loadgerman (optional) load German character set or not
107
*
108
* @access public
109
* @return mixed PEAR_Error or true for success
110
*/
111
function loadFont($filename, $loadgerman = true)
112
{
113
$this->font = array();
114
if (!file_exists($filename)) {
115
return self::raiseError('Figlet font file "'
116
. $filename
117
. '" cannot be found', 1);
118
}
119
120
$this->font_comment = '';
121
122
// If Gzip compressed font
123
if (substr($filename, -3, 3) == '.gz') {
124
$filename = 'compress.zlib://' . $filename;
125
$compressed = true;
126
127
if (!function_exists('gzcompress')) {
128
return self::raiseError('Cannot load gzip compressed fonts since'
129
. ' gzcompress() is not available.',
130
3);
131
}
132
} else {
133
$compressed = false;
134
}
135
136
if (!($fp = fopen($filename, 'rb'))) {
137
return self::raiseError('Cannot open figlet font file ' . $filename, 2);
138
}
139
140
if (!$compressed) {
141
/* ZIPed font */
142
if (fread($fp, 2) == 'PK') {
143
fclose($fp);
144
145
$zip = new ZipArchive();
146
$open_flag = 0;
147
// The RDONLY flag was only introduced in 7.4.3.
148
if (defined('ZipArchive::RDONLY')) {
149
$open_flag = ZipArchive::RDONLY;
150
}
151
$open_result = $zip->open($filename, $open_flag);
152
if ($open_result !== true) {
153
return self::raiseError('Cannot open figlet font file ' .
154
$filename . ', got error: ' . $open_result, 2);
155
}
156
157
$name = $zip->getNameIndex(0);
158
$zip->close();
159
160
if (!($fp = fopen('zip://' . realpath($filename) . '#' . $name, 'rb'))) {
161
return self::raiseError('Cannot open figlet font file ' . $filename, 2);
162
}
163
164
$compressed = true;
165
} else {
166
flock($fp, LOCK_SH);
167
rewind($fp);
168
}
169
}
170
171
// flf2a$ 6 5 20 15 3 0 143 229
172
// | | | | | | | | | |
173
// / / | | | | | | | \
174
// Signature / / | | | | | \ Codetag_Count
175
// Hardblank / / | | | \ Full_Layout
176
// Height / | | \ Print_Direction
177
// Baseline / \ Comment_Lines
178
// Max_Length Old_Layout
179
180
181
$header = explode(' ', fgets($fp, 2048));
182
183
if (substr($header[0], 0, 5) <> 'flf2a') {
184
return self::raiseError('Unknown FIGlet font format.', 4);
185
}
186
187
@list ($this->hardblank, $this->height,,,
188
$this->oldlayout, $cmt_count, $this->rtol) = $header;
189
190
$this->hardblank = substr($this->hardblank, -1, 1);
191
192
for ($i = 0; $i < $cmt_count; $i++) {
193
$this->font_comment .= fgets($fp, 2048);
194
}
195
196
// ASCII charcters
197
for ($i = 32; $i < 127; $i++) {
198
$this->font[$i] = $this->_char($fp);
199
}
200
201
foreach (array(196, 214, 220, 228, 246, 252, 223) as $i) {
202
if ($loadgerman) {
203
$letter = $this->_char($fp);
204
205
// Invalid character but main font is loaded and I can use it
206
if ($letter === false) {
207
fclose($fp);
208
return true;
209
}
210
211
// Load if it is not blank only
212
if (trim(implode('', $letter)) <> '') {
213
$this->font[$i] = $letter;
214
}
215
} else {
216
$this->_skip($fp);
217
}
218
}
219
220
// Extented characters
221
for ($n = 0; !feof($fp); $n++) {
222
list ($i) = explode(' ', rtrim(fgets($fp, 1024)), 2);
223
if ($i == '') {
224
continue;
225
}
226
227
// If comment
228
if (preg_match('/^\-0x/i', $i)) {
229
$this->_skip($fp);
230
} else {
231
// If Unicode
232
if (preg_match('/^0x/i', $i)) {
233
$i = hexdec(substr($i, 2));
234
} else {
235
// If octal
236
if ($i[0] === '0' && $i !== '0' || substr($i, 0, 2) == '-0') {
237
$i = octdec($i);
238
}
239
}
240
241
$letter = $this->_char($fp);
242
243
// Invalid character but main font is loaded and I can use it
244
if ($letter === false) {
245
fclose($fp);
246
return true;
247
}
248
249
$this->font[$i] = $letter;
250
}
251
}
252
253
fclose($fp);
254
return true;
255
}
256
257
258
259
/**
260
* Print string using font loaded by LoadFont method
261
*
262
* @param string $str string for printing
263
* @param bool $inhtml (optional) output mode
264
* - HTML (true) or plain text (false)
265
*
266
* @access public
267
* @return string contains
268
*/
269
function lineEcho($str, $inhtml = false)
270
{
271
$out = array();
272
273
for ($i = 0; $i<strlen($str); $i++) {
274
// Pseudo Unicode support
275
if (substr($str, $i, 2) == '%u') {
276
$lt = hexdec(substr($str, $i+2, 4));
277
$i += 5;
278
} else {
279
$lt = ord($str[$i]);
280
}
281
282
$hb = preg_quote($this->hardblank, '/');
283
$sp = "$hb\\x00\\s";
284
285
// If chosen character not found try to use default
286
// If default character is not defined skip it
287
288
if (!isset($this->font[$lt])) {
289
if (isset($this->font[0])) {
290
$lt = 0;
291
} else {
292
continue;
293
}
294
}
295
296
for ($j = 0; $j < $this->height; $j++) {
297
$line = $this->font[$lt][$j];
298
299
// Replace hardblanks
300
if (isset($out[$j])) {
301
if ($this->rtol) {
302
$out[$j] = $line . $out[$j];
303
} else {
304
$out[$j] .= $line;
305
}
306
} else {
307
$out[$j] = $line;
308
}
309
}
310
311
if ($this->oldlayout > -1 && $i) {
312
// Calculate minimal distance between two last letters
313
314
$mindiff = -1;
315
316
for ($j = 0; $j < $this->height; $j++) {
317
if (preg_match("/\S(\s*\\x00\s*)\S/", $out[$j], $r)) {
318
if ($mindiff == -1) {
319
$mindiff = strlen($r[1]);
320
} else {
321
$mindiff = min($mindiff, strlen($r[1]));
322
}
323
}
324
}
325
326
// Remove spaces between two last letter
327
// dec mindiff for exclude \x00 symbol
328
329
if (--$mindiff > 0) {
330
for ($j = 0; $j < $this->height; $j++) {
331
if (preg_match("/\\x00(\s{0,{$mindiff}})/", $out[$j], $r)) {
332
$l = strlen($r[1]);
333
$b = $mindiff - $l;
334
$out[$j] = preg_replace("/\s{0,$b}\\x00\s{{$l}}/",
335
"\0",
336
$out[$j],
337
1);
338
}
339
}
340
}
341
// Smushing
342
343
$this->smush_flag = 0;
344
345
for ($j = 0; $j < $this->height; $j++) {
346
$out[$j] = preg_replace_callback("#([^$sp])\\x00([^$sp])#",
347
array(&$this, '_rep'),
348
$out[$j]);
349
}
350
351
// Remove one space if smushing
352
// and remove all \x00 except tail whenever
353
354
if ($this->smush_flag) {
355
$pat = array("/\s\\x00(?!$)|\\x00\s/", "/\\x00(?!$)/");
356
$rep = array('', '');
357
} else {
358
$pat = "/\\x00(?!$)/";
359
$rep = '';
360
}
361
362
for ($j = 0; $j<$this->height; $j++) {
363
$out[$j] = preg_replace($pat, $rep, $out[$j]);
364
}
365
}
366
}
367
368
$trans = array("\0" => '', $this->hardblank => ' ');
369
$str = strtr(implode("\n", $out), $trans);
370
371
if ($inhtml) {
372
self::raiseError(
373
'Do not use the HTML escaping provided by this class in '.
374
'a Phabricator context.');
375
}
376
377
return $str;
378
}
379
380
381
382
/**
383
* It is preg_replace callback function that makes horizontal letter smushing
384
*
385
* @param array $r preg_replace matches array
386
*
387
* @return string
388
* @access private
389
*/
390
function _rep($r)
391
{
392
if ($this->oldlayout & 1 && $r[1] == $r[2]) {
393
$this->smush_flag = 1;
394
return $r[1];
395
}
396
397
if ($this->oldlayout & 2) {
398
$symb = '|/\\[]{}()<>';
399
400
if ($r[1] == '_' && strpos($symb, $r[2]) !== false ||
401
$r[2] == '_' && strpos($symb, $r[1]) !== false) {
402
$this->smush_flag = 1;
403
return $r[1];
404
}
405
}
406
407
if ($this->oldlayout & 4) {
408
$classes = '|/\\[]{}()<>';
409
410
if (($left = strpos($classes, $r[1])) !== false) {
411
if (($right = strpos($classes, $r[2])) !== false) {
412
$this->smush_flag = 1;
413
return $right > $left ? $r[2] : $r[1];
414
}
415
}
416
}
417
418
if ($this->oldlayout & 8) {
419
$t = array('[' => ']', ']' => '[', '{' => '}', '}' => '{',
420
'(' => ')', ')' => '(');
421
422
if (isset($t[$r[2]]) && $r[1] == $t[$r[2]]) {
423
$this->smush_flag = 1;
424
return '|';
425
}
426
}
427
428
if ($this->oldlayout & 16) {
429
$t = array("/\\" => '|', "\\/" => 'Y', '><' => 'X');
430
431
if (isset($t[$r[1].$r[2]])) {
432
$this->smush_flag = 1;
433
return $t[$r[1].$r[2]];
434
}
435
}
436
437
if ($this->oldlayout & 32) {
438
if ($r[1] == $r[2] && $r[1] == $this->hardblank) {
439
$this->smush_flag = 1;
440
return $this->hardblank;
441
}
442
}
443
444
return $r[1]."\00".$r[2];
445
}
446
447
448
449
/**
450
* Function loads one character in the internal array from file
451
*
452
* @param resource &$fp handle of font file
453
*
454
* @return mixed lines of the character or false if foef occured
455
* @access private
456
*/
457
function _char(&$fp)
458
{
459
$out = array();
460
461
for ($i = 0; $i < $this->height; $i++) {
462
if (feof($fp)) {
463
return false;
464
}
465
466
$line = rtrim(fgets($fp, 2048), "\r\n");
467
if (preg_match('/(.){1,2}$/', $line, $r)) {
468
$line = str_replace($r[1], '', $line);
469
}
470
471
$line .= "\x00";
472
473
$out[] = $line;
474
}
475
476
return $out;
477
}
478
479
480
481
/**
482
* Function for skipping one character in a font file
483
*
484
* @param resource &$fp handle of font file
485
*
486
* @return boolean always return true
487
* @access private
488
*/
489
function _skip(&$fp)
490
{
491
for ($i = 0; $i<$this->height && !feof($fp); $i++) {
492
fgets($fp, 2048);
493
}
494
495
return true;
496
}
497
498
499
private static function raiseError($message, $code = 1) {
500
throw new Exception($message);
501
}
502
}
503