Projet

Général

Profil

Paste
Télécharger (22,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / libraries / fpdi-1.5.4 / fpdi.php @ a1cafe7e

1
<?php
2
//
3
//  FPDI - Version 1.5.4
4
//
5
//    Copyright 2004-2015 Setasign - Jan Slabon
6
//
7
//  Licensed under the Apache License, Version 2.0 (the "License");
8
//  you may not use this file except in compliance with the License.
9
//  You may obtain a copy of the License at
10
//
11
//      http://www.apache.org/licenses/LICENSE-2.0
12
//
13
//  Unless required by applicable law or agreed to in writing, software
14
//  distributed under the License is distributed on an "AS IS" BASIS,
15
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
//  See the License for the specific language governing permissions and
17
//  limitations under the License.
18
//
19

    
20
if (!class_exists('FPDF_TPL')) {
21
    require_once('fpdf_tpl.php');
22
}
23

    
24
/**
25
 * Class FPDI
26
 */
27
class FPDI extends FPDF_TPL
28
{
29
    /**
30
     * FPDI version
31
     *
32
     * @string
33
     */
34
    const VERSION = '1.5.3';
35

    
36
    /**
37
     * Actual filename
38
     *
39
     * @var string
40
     */
41
    public $currentFilename;
42

    
43
    /**
44
     * Parser-Objects
45
     *
46
     * @var fpdi_pdf_parser[]
47
     */
48
    public $parsers = array();
49
    
50
    /**
51
     * Current parser
52
     *
53
     * @var fpdi_pdf_parser
54
     */
55
    public $currentParser;
56

    
57
    /**
58
     * The name of the last imported page box
59
     *
60
     * @var string
61
     */
62
    public $lastUsedPageBox;
63

    
64
    /**
65
     * Object stack
66
     *
67
     * @var array
68
     */
69
    protected $_objStack;
70
    
71
    /**
72
     * Done object stack
73
     *
74
     * @var array
75
     */
76
    protected $_doneObjStack;
77

    
78
    /**
79
     * Current Object Id.
80
     *
81
     * @var integer
82
     */
83
    protected $_currentObjId;
84
    
85
    /**
86
     * Cache for imported pages/template ids
87
     *
88
     * @var array
89
     */
90
    protected $_importedPages = array();
91
    
92
    /**
93
     * Set a source-file.
94
     *
95
     * Depending on the PDF version of the used document the PDF version of the resulting document will
96
     * be adjusted to the higher version.
97
     *
98
     * @param string $filename A valid path to the PDF document from which pages should be imported from
99
     * @return int The number of pages in the document
100
     */
101
    public function setSourceFile($filename)
102
    {
103
        $_filename = realpath($filename);
104
        if (false !== $_filename)
105
            $filename = $_filename;
106

    
107
        $this->currentFilename = $filename;
108
        
109
        if (!isset($this->parsers[$filename])) {
110
            $this->parsers[$filename] = $this->_getPdfParser($filename);
111
            $this->setPdfVersion(
112
                max($this->getPdfVersion(), $this->parsers[$filename]->getPdfVersion())
113
            );
114
        }
115

    
116
        $this->currentParser = $this->parsers[$filename];
117
        
118
        return $this->parsers[$filename]->getPageCount();
119
    }
120
    
121
    /**
122
     * Returns a PDF parser object
123
     *
124
     * @param string $filename
125
     * @return fpdi_pdf_parser
126
     */
127
    protected function _getPdfParser($filename)
128
    {
129
        if (!class_exists('fpdi_pdf_parser')) {
130
            require_once('fpdi_pdf_parser.php');
131
        }
132
            return new fpdi_pdf_parser($filename);
133
    }
134
    
135
    /**
136
     * Get the current PDF version.
137
     *
138
     * @return string
139
     */
140
    public function getPdfVersion()
141
    {
142
                return $this->PDFVersion;
143
        }
144
    
145
    /**
146
     * Set the PDF version.
147
     *
148
     * @param string $version
149
     */
150
    public function setPdfVersion($version = '1.3')
151
    {
152
        $this->PDFVersion = sprintf('%.1F', $version);
153
    }
154
        
155
    /**
156
     * Import a page.
157
     *
158
     * The second parameter defines the bounding box that should be used to transform the page into a
159
     * form XObject.
160
     *
161
     * Following values are available: MediaBox, CropBox, BleedBox, TrimBox, ArtBox.
162
     * If a box is not especially defined its default box will be used:
163
     *
164
     * <ul>
165
     *   <li>CropBox: Default -> MediaBox</li>
166
     *   <li>BleedBox: Default -> CropBox</li>
167
     *   <li>TrimBox: Default -> CropBox</li>
168
     *   <li>ArtBox: Default -> CropBox</li>
169
     * </ul>
170
     *
171
     * It is possible to get the used page box by the {@link getLastUsedPageBox()} method.
172
     *
173
     * @param int $pageNo The page number
174
     * @param string $boxName The boundary box to use when transforming the page into a form XObject
175
     * @param boolean $groupXObject Define the form XObject as a group XObject to support transparency (if used)
176
     * @return int An id of the imported page/template to use with e.g. fpdf_tpl::useTemplate()
177
     * @throws LogicException|InvalidArgumentException
178
     * @see getLastUsedPageBox()
179
     */
180
    public function importPage($pageNo, $boxName = 'CropBox', $groupXObject = true)
181
    {
182
        if ($this->_inTpl) {
183
            throw new LogicException('Please import the desired pages before creating a new template.');
184
        }
185
        
186
        $fn = $this->currentFilename;
187
        $boxName = '/' . ltrim($boxName, '/');
188

    
189
        // check if page already imported
190
        $pageKey = $fn . '-' . ((int)$pageNo) . $boxName;
191
        if (isset($this->_importedPages[$pageKey])) {
192
            return $this->_importedPages[$pageKey];
193
        }
194
        
195
        $parser = $this->parsers[$fn];
196
        $parser->setPageNo($pageNo);
197

    
198
        if (!in_array($boxName, $parser->availableBoxes)) {
199
            throw new InvalidArgumentException(sprintf('Unknown box: %s', $boxName));
200
        }
201
            
202
        $pageBoxes = $parser->getPageBoxes($pageNo, $this->k);
203
        
204
        /**
205
         * MediaBox
206
         * CropBox: Default -> MediaBox
207
         * BleedBox: Default -> CropBox
208
         * TrimBox: Default -> CropBox
209
         * ArtBox: Default -> CropBox
210
         */
211
        if (!isset($pageBoxes[$boxName]) && ($boxName == '/BleedBox' || $boxName == '/TrimBox' || $boxName == '/ArtBox'))
212
            $boxName = '/CropBox';
213
        if (!isset($pageBoxes[$boxName]) && $boxName == '/CropBox')
214
            $boxName = '/MediaBox';
215
        
216
        if (!isset($pageBoxes[$boxName]))
217
            return false;
218
            
219
        $this->lastUsedPageBox = $boxName;
220
        
221
        $box = $pageBoxes[$boxName];
222
        
223
        $this->tpl++;
224
        $this->_tpls[$this->tpl] = array();
225
        $tpl =& $this->_tpls[$this->tpl];
226
        $tpl['parser'] = $parser;
227
        $tpl['resources'] = $parser->getPageResources();
228
        $tpl['buffer'] = $parser->getContent();
229
        $tpl['box'] = $box;
230
        $tpl['groupXObject'] = $groupXObject;
231
        if ($groupXObject) {
232
            $this->setPdfVersion(max($this->getPdfVersion(), 1.4));
233
        }
234

    
235
        // To build an array that can be used by PDF_TPL::useTemplate()
236
        $this->_tpls[$this->tpl] = array_merge($this->_tpls[$this->tpl], $box);
237
        
238
        // An imported page will start at 0,0 all the time. Translation will be set in _putformxobjects()
239
        $tpl['x'] = 0;
240
        $tpl['y'] = 0;
241
        
242
        // handle rotated pages
243
        $rotation = $parser->getPageRotation($pageNo);
244
        $tpl['_rotationAngle'] = 0;
245
        if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) {
246
                $steps = $angle / 90;
247
                
248
            $_w = $tpl['w'];
249
            $_h = $tpl['h'];
250
            $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;
251
            $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;
252
            
253
            if ($angle < 0)
254
                    $angle += 360;
255
            
256
                $tpl['_rotationAngle'] = $angle * -1;
257
        }
258
        
259
        $this->_importedPages[$pageKey] = $this->tpl;
260
        
261
        return $this->tpl;
262
    }
263
    
264
    /**
265
     * Returns the last used page boundary box.
266
     *
267
     * @return string The used boundary box: MediaBox, CropBox, BleedBox, TrimBox or ArtBox
268
     */
269
    public function getLastUsedPageBox()
270
    {
271
        return $this->lastUsedPageBox;
272
    }
273

    
274
    /**
275
     * Use a template or imported page in current page or other template.
276
     *
277
     * You can use a template in a page or in another template.
278
     * You can give the used template a new size. All parameters are optional.
279
     * The width or height is calculated automatically if one is given. If no
280
     * parameter is given the origin size as defined in beginTemplate() or of
281
     * the imported page is used.
282
     *
283
     * The calculated or used width and height are returned as an array.
284
     *
285
     * @param int $tplIdx A valid template-id
286
     * @param int $x The x-position
287
     * @param int $y The y-position
288
     * @param int $w The new width of the template
289
     * @param int $h The new height of the template
290
     * @param boolean $adjustPageSize If set to true the current page will be resized to fit the dimensions
291
     *                                of the template
292
     *
293
     * @return array The height and width of the template (array('w' => ..., 'h' => ...))
294
     * @throws LogicException|InvalidArgumentException
295
     */
296
    public function useTemplate($tplIdx, $x = null, $y = null, $w = 0, $h = 0, $adjustPageSize = false)
297
    {
298
        if ($adjustPageSize == true && is_null($x) && is_null($y)) {
299
            $size = $this->getTemplateSize($tplIdx, $w, $h);
300
            $orientation = $size['w'] > $size['h'] ? 'L' : 'P';
301
            $size = array($size['w'], $size['h']);
302
            
303
            if (is_subclass_of($this, 'TCPDF')) {
304
                    $this->setPageFormat($size, $orientation);
305
            } else {
306
                    $size = $this->_getpagesize($size);
307
                    
308
                    if($orientation != $this->CurOrientation ||
309
                    $size[0] != $this->CurPageSize[0] ||
310
                    $size[1] != $this->CurPageSize[1]
311
                ) {
312
                                        // New size or orientation
313
                                        if ($orientation=='P') {
314
                                                $this->w = $size[0];
315
                                                $this->h = $size[1];
316
                                        } else {
317
                                                $this->w = $size[1];
318
                                                $this->h = $size[0];
319
                                        }
320
                                        $this->wPt = $this->w * $this->k;
321
                                        $this->hPt = $this->h * $this->k;
322
                                        $this->PageBreakTrigger = $this->h - $this->bMargin;
323
                                        $this->CurOrientation = $orientation;
324
                                        $this->CurPageSize = $size;
325
                                        $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
326
                                }
327
            } 
328
        }
329
        
330
        $this->_out('q 0 J 1 w 0 j 0 G 0 g'); // reset standard values
331
        $size = parent::useTemplate($tplIdx, $x, $y, $w, $h);
332
        $this->_out('Q');
333
        
334
        return $size;
335
    }
336
    
337
    /**
338
     * Copy all imported objects to the resulting document.
339
     */
340
    protected function _putimportedobjects()
341
    {
342
        foreach($this->parsers AS $filename => $p) {
343
            $this->currentParser = $p;
344
            if (!isset($this->_objStack[$filename]) || !is_array($this->_objStack[$filename])) {
345
                continue;
346
            }
347
            while(($n = key($this->_objStack[$filename])) !== null) {
348
                try {
349
                    $nObj = $this->currentParser->resolveObject($this->_objStack[$filename][$n][1]);
350
                } catch (Exception $e) {
351
                    $nObj = array(pdf_parser::TYPE_OBJECT, pdf_parser::TYPE_NULL);
352
                }
353

    
354
                $this->_newobj($this->_objStack[$filename][$n][0]);
355

    
356
                if ($nObj[0] == pdf_parser::TYPE_STREAM) {
357
                    $this->_writeValue($nObj);
358
                } else {
359
                    $this->_writeValue($nObj[1]);
360
                }
361

    
362
                $this->_out("\nendobj");
363
                $this->_objStack[$filename][$n] = null; // free memory
364
                unset($this->_objStack[$filename][$n]);
365
                reset($this->_objStack[$filename]);
366
            }
367
        }
368
    }
369

    
370
    /**
371
     * Writes the form XObjects to the PDF document.
372
     */
373
    protected function _putformxobjects()
374
    {
375
        $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
376
            reset($this->_tpls);
377
        foreach($this->_tpls AS $tplIdx => $tpl) {
378
            $this->_newobj();
379
                    $currentN = $this->n; // TCPDF/Protection: rem current "n"
380
                    
381
                    $this->_tpls[$tplIdx]['n'] = $this->n;
382
                    $this->_out('<<' . $filter . '/Type /XObject');
383
            $this->_out('/Subtype /Form');
384
            $this->_out('/FormType 1');
385
            
386
            $this->_out(sprintf('/BBox [%.2F %.2F %.2F %.2F]', 
387
                (isset($tpl['box']['llx']) ? $tpl['box']['llx'] : $tpl['x']) * $this->k,
388
                (isset($tpl['box']['lly']) ? $tpl['box']['lly'] : -$tpl['y']) * $this->k,
389
                (isset($tpl['box']['urx']) ? $tpl['box']['urx'] : $tpl['w'] + $tpl['x']) * $this->k,
390
                (isset($tpl['box']['ury']) ? $tpl['box']['ury'] : $tpl['h'] - $tpl['y']) * $this->k
391
            ));
392
            
393
            $c = 1;
394
            $s = 0;
395
            $tx = 0;
396
            $ty = 0;
397
            
398
            if (isset($tpl['box'])) {
399
                $tx = -$tpl['box']['llx'];
400
                $ty = -$tpl['box']['lly']; 
401
                
402
                if ($tpl['_rotationAngle'] <> 0) {
403
                    $angle = $tpl['_rotationAngle'] * M_PI/180;
404
                    $c = cos($angle);
405
                    $s = sin($angle);
406
                    
407
                    switch($tpl['_rotationAngle']) {
408
                        case -90:
409
                           $tx = -$tpl['box']['lly'];
410
                           $ty = $tpl['box']['urx'];
411
                           break;
412
                        case -180:
413
                            $tx = $tpl['box']['urx'];
414
                            $ty = $tpl['box']['ury'];
415
                            break;
416
                        case -270:
417
                                $tx = $tpl['box']['ury'];
418
                            $ty = -$tpl['box']['llx'];
419
                            break;
420
                    }
421
                }
422
            } else if ($tpl['x'] != 0 || $tpl['y'] != 0) {
423
                $tx = -$tpl['x'] * 2;
424
                $ty = $tpl['y'] * 2;
425
            }
426
            
427
            $tx *= $this->k;
428
            $ty *= $this->k;
429
            
430
            if ($c != 1 || $s != 0 || $tx != 0 || $ty != 0) {
431
                $this->_out(sprintf('/Matrix [%.5F %.5F %.5F %.5F %.5F %.5F]',
432
                    $c, $s, -$s, $c, $tx, $ty
433
                ));
434
            }
435
            
436
            $this->_out('/Resources ');
437

    
438
            if (isset($tpl['resources'])) {
439
                $this->currentParser = $tpl['parser'];
440
                $this->_writeValue($tpl['resources']); // "n" will be changed
441
            } else {
442

    
443
                $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
444
                if (isset($this->_res['tpl'][$tplIdx])) {
445
                    $res = $this->_res['tpl'][$tplIdx];
446

    
447
                    if (isset($res['fonts']) && count($res['fonts'])) {
448
                        $this->_out('/Font <<');
449
                        foreach ($res['fonts'] as $font)
450
                            $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
451
                        $this->_out('>>');
452
                    }
453
                    if (isset($res['images']) && count($res['images']) ||
454
                       isset($res['tpls']) && count($res['tpls']))
455
                    {
456
                        $this->_out('/XObject <<');
457
                        if (isset($res['images'])) {
458
                            foreach ($res['images'] as $image)
459
                                $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
460
                        }
461
                        if (isset($res['tpls'])) {
462
                            foreach ($res['tpls'] as $i => $_tpl)
463
                                $this->_out($this->tplPrefix . $i . ' ' . $_tpl['n'] . ' 0 R');
464
                        }
465
                        $this->_out('>>');
466
                    }
467
                    $this->_out('>>');
468
                }
469
            }
470

    
471
            if (isset($tpl['groupXObject']) && $tpl['groupXObject']) {
472
                $this->_out('/Group <</Type/Group/S/Transparency>>');
473
            }
474

    
475
            $newN = $this->n; // TCPDF: rem new "n"
476
            $this->n = $currentN; // TCPDF: reset to current "n"
477

    
478
            $buffer = ($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
479

    
480
            if (is_subclass_of($this, 'TCPDF')) {
481
                    $buffer = $this->_getrawstream($buffer);
482
                    $this->_out('/Length ' . strlen($buffer) . ' >>');
483
                    $this->_out("stream\n" . $buffer . "\nendstream");
484
            } else {
485
                    $this->_out('/Length ' . strlen($buffer) . ' >>');
486
                            $this->_putstream($buffer);
487
            }
488
                    $this->_out('endobj');
489
                    $this->n = $newN; // TCPDF: reset to new "n"
490
        }
491
        
492
        $this->_putimportedobjects();
493
    }
494

    
495
    /**
496
     * Creates and optionally write the object definition to the document.
497
     *
498
     * Rewritten to handle existing own defined objects
499
     *
500
     * @param bool $objId
501
     * @param bool $onlyNewObj
502
     * @return bool|int
503
     */
504
    public function _newobj($objId = false, $onlyNewObj = false)
505
    {
506
        if (!$objId) {
507
            $objId = ++$this->n;
508
        }
509

    
510
        //Begin a new object
511
        if (!$onlyNewObj) {
512
            $this->offsets[$objId] = is_subclass_of($this, 'TCPDF') ? $this->bufferlen : strlen($this->buffer);
513
            $this->_out($objId . ' 0 obj');
514
            $this->_currentObjId = $objId; // for later use with encryption
515
        }
516
        
517
        return $objId;
518
    }
519

    
520
    /**
521
     * Writes a PDF value to the resulting document.
522
     *
523
     * Needed to rebuild the source document
524
     *
525
     * @param mixed $value A PDF-Value. Structure of values see cases in this method
526
     */
527
    protected function _writeValue(&$value)
528
    {
529
        if (is_subclass_of($this, 'TCPDF')) {
530
            parent::_prepareValue($value);
531
        }
532
        
533
        switch ($value[0]) {
534

    
535
                    case pdf_parser::TYPE_TOKEN:
536
                $this->_straightOut($value[1] . ' ');
537
                            break;
538
                    case pdf_parser::TYPE_NUMERIC:
539
                    case pdf_parser::TYPE_REAL:
540
                if (is_float($value[1]) && $value[1] != 0) {
541
                                $this->_straightOut(rtrim(rtrim(sprintf('%F', $value[1]), '0'), '.') . ' ');
542
                            } else {
543
                                $this->_straightOut($value[1] . ' ');
544
                            }
545
                            break;
546
                            
547
                    case pdf_parser::TYPE_ARRAY:
548

    
549
                            // An array. Output the proper
550
                            // structure and move on.
551

    
552
                            $this->_straightOut('[');
553
                for ($i = 0; $i < count($value[1]); $i++) {
554
                                    $this->_writeValue($value[1][$i]);
555
                            }
556

    
557
                            $this->_out(']');
558
                            break;
559

    
560
                    case pdf_parser::TYPE_DICTIONARY:
561

    
562
                            // A dictionary.
563
                            $this->_straightOut('<<');
564

    
565
                            reset ($value[1]);
566

    
567
                            while (list($k, $v) = each($value[1])) {
568
                                    $this->_straightOut($k . ' ');
569
                                    $this->_writeValue($v);
570
                            }
571

    
572
                            $this->_straightOut('>>');
573
                            break;
574

    
575
                    case pdf_parser::TYPE_OBJREF:
576

    
577
                            // An indirect object reference
578
                            // Fill the object stack if needed
579
                            $cpfn =& $this->currentParser->filename;
580
                            if (!isset($this->_doneObjStack[$cpfn][$value[1]])) {
581
                                $this->_newobj(false, true);
582
                                $this->_objStack[$cpfn][$value[1]] = array($this->n, $value);
583
                    $this->_doneObjStack[$cpfn][$value[1]] = array($this->n, $value);
584
                }
585
                $objId = $this->_doneObjStack[$cpfn][$value[1]][0];
586

    
587
                            $this->_out($objId . ' 0 R');
588
                            break;
589

    
590
                    case pdf_parser::TYPE_STRING:
591

    
592
                            // A string.
593
                $this->_straightOut('(' . $value[1] . ')');
594

    
595
                            break;
596

    
597
                    case pdf_parser::TYPE_STREAM:
598

    
599
                            // A stream. First, output the
600
                            // stream dictionary, then the
601
                            // stream data itself.
602
                $this->_writeValue($value[1]);
603
                            $this->_out('stream');
604
                            $this->_out($value[2][1]);
605
                            $this->_straightOut("endstream");
606
                            break;
607
                            
608
            case pdf_parser::TYPE_HEX:
609
                $this->_straightOut('<' . $value[1] . '>');
610
                break;
611

    
612
            case pdf_parser::TYPE_BOOLEAN:
613
                        $this->_straightOut($value[1] ? 'true ' : 'false ');
614
                        break;
615
            
616
                    case pdf_parser::TYPE_NULL:
617
                // The null object.
618

    
619
                            $this->_straightOut('null ');
620
                            break;
621
            }
622
    }
623
    
624
    
625
    /**
626
     * Modified _out() method so not each call will add a newline to the output.
627
     */
628
    protected function _straightOut($s)
629
    {
630
        if (!is_subclass_of($this, 'TCPDF')) {
631
            if ($this->state == 2) {
632
                        $this->pages[$this->page] .= $s;
633
            } else {
634
                        $this->buffer .= $s;
635
            }
636

    
637
        } else {
638
            if ($this->state == 2) {
639
                                if ($this->inxobj) {
640
                                        // we are inside an XObject template
641
                                        $this->xobjects[$this->xobjid]['outdata'] .= $s;
642
                                } else if ((!$this->InFooter) AND isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) {
643
                                        // puts data before page footer
644
                                        $pagebuff = $this->getPageBuffer($this->page);
645
                                        $page = substr($pagebuff, 0, -$this->footerlen[$this->page]);
646
                                        $footer = substr($pagebuff, -$this->footerlen[$this->page]);
647
                                        $this->setPageBuffer($this->page, $page . $s . $footer);
648
                                        // update footer position
649
                                        $this->footerpos[$this->page] += strlen($s);
650
                                } else {
651
                                        // set page data
652
                                        $this->setPageBuffer($this->page, $s, true);
653
                                }
654
                        } else if ($this->state > 0) {
655
                                // set general data
656
                                $this->setBuffer($s);
657
                        }
658
        }
659
    }
660

    
661
    /**
662
     * Ends the document
663
     *
664
     * Overwritten to close opened parsers
665
     */
666
    public function _enddoc()
667
    {
668
        parent::_enddoc();
669
        $this->_closeParsers();
670
    }
671
    
672
    /**
673
     * Close all files opened by parsers.
674
     *
675
     * @return boolean
676
     */
677
    protected function _closeParsers()
678
    {
679
        if ($this->state > 2) {
680
                  $this->cleanUp();
681
            return true;
682
        }
683

    
684
        return false;
685
    }
686
    
687
    /**
688
     * Removes cycled references and closes the file handles of the parser objects.
689
     */
690
    public function cleanUp()
691
    {
692
        while (($parser = array_pop($this->parsers)) !== null) {
693
            /**
694
             * @var fpdi_pdf_parser $parser
695
             */
696
            $parser->closeFile();
697
        }
698
    }
699
}