Passed
Pull Request — master (#510)
by Jeremy
04:33 queued 02:18
created

Header::getElements()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 1
b 0
f 0
ccs 4
cts 4
cp 1
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
/**
4
 * @file
5
 *          This file is part of the PdfParser library.
6
 *
7
 * @author  Sébastien MALOT <[email protected]>
8
 * @date    2017-01-03
9
 *
10
 * @license LGPLv3
11
 * @url     <https://github.com/smalot/pdfparser>
12
 *
13
 *  PdfParser is a pdf library written in PHP, extraction oriented.
14
 *  Copyright (C) 2017 - Sébastien MALOT <[email protected]>
15
 *
16
 *  This program is free software: you can redistribute it and/or modify
17
 *  it under the terms of the GNU Lesser General Public License as published by
18
 *  the Free Software Foundation, either version 3 of the License, or
19
 *  (at your option) any later version.
20
 *
21
 *  This program is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU Lesser General Public License for more details.
25
 *
26
 *  You should have received a copy of the GNU Lesser General Public License
27
 *  along with this program.
28
 *  If not, see <http://www.pdfparser.org/sites/default/LICENSE.txt>.
29
 */
30
31
namespace Smalot\PdfParser;
32
33
use Smalot\PdfParser\Element\ElementArray;
34
use Smalot\PdfParser\Element\ElementMissing;
35
use Smalot\PdfParser\Element\ElementStruct;
36
use Smalot\PdfParser\Element\ElementXRef;
37
38
/**
39
 * Class Header
40
 */
41
class Header
42
{
43
    /**
44
     * @var Document
45
     */
46
    protected $document = null;
47
48
    /**
49
     * @var Element[]
50
     */
51
    protected $elements = null;
52
53
    /**
54
     * @param Element[] $elements list of elements
55
     * @param Document  $document document
56
     */
57 68
    public function __construct(array $elements = [], ?Document $document = null)
58
    {
59 68
        $this->elements = $elements;
60 68
        $this->document = $document;
61 68
    }
62
63 45
    public function init()
64
    {
65 45
        foreach ($this->elements as $element) {
66 45
            if ($element instanceof Element) {
67 45
                $element->init();
68
            }
69
        }
70 45
    }
71
72
    /**
73
     * Returns all elements.
74
     */
75 39
    public function getElements()
76
    {
77 39
        foreach ($this->elements as $name => $element) {
78 39
            $this->resolveXRef($name);
79
        }
80
81 39
        return $this->elements;
82
    }
83
84
    /**
85
     * Used only for debug.
86
     */
87 1
    public function getElementTypes(): array
88
    {
89 1
        $types = [];
90
91 1
        foreach ($this->elements as $key => $element) {
92 1
            $types[$key] = \get_class($element);
93
        }
94
95 1
        return $types;
96
    }
97
98 37
    public function getDetails(bool $deep = true): array
99
    {
100 37
        $values = [];
101 37
        $elements = $this->getElements();
102
103 37
        foreach ($elements as $key => $element) {
104 37
            if ($element instanceof self && $deep) {
105
                $values[$key] = $element->getDetails($deep);
106 37
            } elseif ($element instanceof PDFObject && $deep) {
107 2
                $values[$key] = $element->getDetails(false);
108 37
            } elseif ($element instanceof ElementArray) {
109 2
                if ($deep) {
110 2
                    $values[$key] = $element->getDetails();
111
                }
112 37
            } elseif ($element instanceof Element) {
113 37
                $values[$key] = (string) $element;
114
            }
115
        }
116
117 37
        return $this->ensureProperDetailEncoding($values);
118
    }
119
120
    /**
121
     * Indicate if an element name is available in header.
122
     *
123
     * @param string $name the name of the element
124
     */
125 49
    public function has(string $name): bool
126
    {
127 49
        return \array_key_exists($name, $this->elements);
128
    }
129
130
    /**
131
     * @return Element|PDFObject
132
     */
133 52
    public function get(string $name)
134
    {
135 52
        if (\array_key_exists($name, $this->elements)) {
136 51
            return $this->resolveXRef($name);
137
        }
138
139 49
        return new ElementMissing();
140
    }
141
142
    /**
143
     * Resolve XRef to object.
144
     *
145
     * @return Element|PDFObject
146
     *
147
     * @throws \Exception
148
     */
149 53
    protected function resolveXRef(string $name)
150
    {
151 53
        if (($obj = $this->elements[$name]) instanceof ElementXRef && null !== $this->document) {
152
            /** @var ElementXRef $obj */
153 40
            $object = $this->document->getObjectById($obj->getId());
154
155 40
            if (null === $object) {
156 2
                return new ElementMissing();
157
            }
158
159
            // Update elements list for future calls.
160 40
            $this->elements[$name] = $object;
161
        }
162
163 53
        return $this->elements[$name];
164
    }
165
166
    /**
167
     * @param string   $content  The content to parse
168
     * @param Document $document The document
169
     * @param int      $position The new position of the cursor after parsing
170
     */
171 22
    public static function parse(string $content, Document $document, int &$position = 0): self
172
    {
173
        /* @var Header $header */
174 22
        if ('<<' == substr(trim($content), 0, 2)) {
175 21
            $header = ElementStruct::parse($content, $document, $position);
176
        } else {
177 8
            $elements = ElementArray::parse($content, $document, $position);
178 8
            $header = new self([], $document);
179
180 8
            if ($elements) {
181 7
                $header = new self($elements->getRawContent(), null);
182
            }
183
        }
184
185 22
        if ($header) {
186 22
            return $header;
187
        }
188
189
        // Build an empty header.
190
        return new self([], $document);
191
    }
192
193
    /**
194
     * Ensure detail information aren't badly encoded.
195
     */
196 37
    private function ensureProperDetailEncoding(array $values): array
197
    {
198 37
        foreach ($values as $key => $value) {
199 37
            if (\is_array($value)) {
200 3
                $values[$key] = $this->ensureProperDetailEncoding($value);
201
202 3
                continue;
203
            }
204
205 37
            if (false === preg_match('!!u', $value)) {
206 4
                $font = $this->document->getFirstFont();
207 4
                if ($font) {
208 4
                    $newValue = $font->decodeContent($value);
209
                } else {
210
                    $newValue = mb_convert_encoding($value, 'UTF-8', 'Windows-1252');
211
                }
212
213 4
                $values[$key] = $newValue;
214
            }
215
        }
216
217 37
        return $values;
218
    }
219
}
220