~chroot64bit/zivios/gentoo-experimental

« back to all changes in this revision

Viewing changes to application/library/Zend/Text/Figlet.php

  • Committer: Mustafa A. Hashmi
  • Date: 2008-12-04 13:32:21 UTC
  • Revision ID: mhashmi@zivios.org-20081204133221-0nd1trunwevijj38
Inclusion of new installation framework with ties to zend layout and dojo layout

Show diffs side-by-side

added added

removed removed

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