PHP7 compatibility fixes.
[fa-stable.git] / reporting / includes / fpdi / fpdi_pdf_parser.php
1 <?php
2 //
3 //  FPDI - Version 1.2.1
4 //
5 //    Copyright 2004-2008 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 require_once("pdf_parser.php");
21
22 class fpdi_pdf_parser extends pdf_parser {
23
24     /**
25      * Pages
26      * Index beginns at 0
27      *
28      * @var array
29      */
30     var $pages;
31     
32     /**
33      * Page count
34      * @var integer
35      */
36     var $page_count;
37     
38     /**
39      * actual page number
40      * @var integer
41      */
42     var $pageno;
43     
44     /**
45      * PDF Version of imported Document
46      * @var string
47      */
48     var $pdfVersion;
49     
50     /**
51      * FPDI Reference
52      * @var object
53      */
54     var $fpdi;
55     
56     /**
57      * Available BoxTypes
58      *
59      * @var array
60      */
61     var $availableBoxes = array("/MediaBox","/CropBox","/BleedBox","/TrimBox","/ArtBox");
62         
63     /**
64      * Constructor
65      *
66      * @param string $filename  Source-Filename
67      * @param object $fpdi      Object of type fpdi
68      */
69     function __construct($filename,&$fpdi) {
70         $this->fpdi =& $fpdi;
71                 $this->filename = $filename;
72                 
73         parent::__construct($filename);
74
75         // resolve Pages-Dictonary
76         $pages = $this->pdf_resolve_object($this->c, $this->root[1][1]['/Pages']);
77
78         // Read pages
79         $this->read_pages($this->c, $pages, $this->pages);
80         
81         // count pages;
82         $this->page_count = count($this->pages);
83     }
84     
85     /**
86      * Overwrite parent::error()
87      *
88      * @param string $msg  Error-Message
89      */
90     function error($msg) {
91         $this->fpdi->error($msg);       
92     }
93     
94     /**
95      * Get pagecount from sourcefile
96      *
97      * @return int
98      */
99     function getPageCount() {
100         return $this->page_count;
101     }
102
103
104     /**
105      * Set pageno
106      *
107      * @param int $pageno Pagenumber to use
108      */
109     function setPageno($pageno) {
110         $pageno = ((int) $pageno) - 1;
111
112         if ($pageno < 0 || $pageno >= $this->getPageCount()) {
113             $this->fpdi->error("Pagenumber is wrong!");
114         }
115
116         $this->pageno = $pageno;
117     }
118     
119     /**
120      * Get page-resources from current page
121      *
122      * @return array
123      */
124     function getPageResources() {
125         return $this->_getPageResources($this->pages[$this->pageno]);
126     }
127     
128     /**
129      * Get page-resources from /Page
130      *
131      * @param array $obj Array of pdf-data
132      */
133     function _getPageResources ($obj) { // $obj = /Page
134         $obj = $this->pdf_resolve_object($this->c, $obj);
135
136         // If the current object has a resources
137         // dictionary associated with it, we use
138         // it. Otherwise, we move back to its
139         // parent object.
140         if (isset ($obj[1][1]['/Resources'])) {
141                 $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Resources']);
142                 if ($res[0] == PDF_TYPE_OBJECT)
143                 return $res[1];
144             return $res;
145         } else {
146                 if (!isset ($obj[1][1]['/Parent'])) {
147                         return false;
148                 } else {
149                 $res = $this->_getPageResources($obj[1][1]['/Parent']);
150                 if ($res[0] == PDF_TYPE_OBJECT)
151                     return $res[1];
152                 return $res;
153                 }
154         }
155     }
156
157
158     /**
159      * Get content of current page
160      *
161      * If more /Contents is an array, the streams are concated
162      *
163      * @return string
164      */
165     function getContent() {
166         $buffer = "";
167         
168         if (isset($this->pages[$this->pageno][1][1]['/Contents'])) {
169             $contents = $this->_getPageContent($this->pages[$this->pageno][1][1]['/Contents']);
170             foreach($contents AS $tmp_content) {
171                 $buffer .= $this->_rebuildContentStream($tmp_content).' ';
172             }
173         }
174         
175         return $buffer;
176     }
177     
178     
179     /**
180      * Resolve all content-objects
181      *
182      * @param array $content_ref
183      * @return array
184      */
185     function _getPageContent($content_ref) {
186         $contents = array();
187         
188         if ($content_ref[0] == PDF_TYPE_OBJREF) {
189             $content = $this->pdf_resolve_object($this->c, $content_ref);
190             if ($content[1][0] == PDF_TYPE_ARRAY) {
191                 $contents = $this->_getPageContent($content[1]);
192             } else {
193                 $contents[] = $content;
194             }
195         } else if ($content_ref[0] == PDF_TYPE_ARRAY) {
196             foreach ($content_ref[1] AS $tmp_content_ref) {
197                 $contents = array_merge($contents,$this->_getPageContent($tmp_content_ref));
198             }
199         }
200
201         return $contents;
202     }
203
204
205     /**
206      * Rebuild content-streams
207      *
208      * @param array $obj
209      * @return string
210      */
211     function _rebuildContentStream($obj) {
212         $filters = array();
213         
214         if (isset($obj[1][1]['/Filter'])) {
215             $_filter = $obj[1][1]['/Filter'];
216
217             if ($_filter[0] == PDF_TYPE_TOKEN) {
218                 $filters[] = $_filter;
219             } else if ($_filter[0] == PDF_TYPE_ARRAY) {
220                 $filters = $_filter[1];
221             }
222         }
223
224         $stream = $obj[2][1];
225
226         foreach ($filters AS $_filter) {
227             switch ($_filter[1]) {
228                 case "/FlateDecode":
229                     if (function_exists('gzuncompress')) {
230                         $stream = (strlen($stream) > 0) ? @gzuncompress($stream) : '';                        
231                     } else {
232                         $this->fpdi->error(sprintf("To handle %s filter, please compile php with zlib support.",$_filter[1]));
233                     }
234                     if ($stream === false) {
235                         $this->fpdi->error("Error while decompressing stream.");
236                     }
237                 break;
238                 case null:
239                     $stream = $stream;
240                 break;
241                 default:
242                     if (preg_match("/^\/[a-z85]*$/i", $_filter[1], $filterName) && @include_once('decoders'.$_filter[1].'.php')) {
243                         $filterName = substr($_filter[1],1);
244                         if (class_exists($filterName)) {
245                                 $decoder = new $filterName($this->fpdi);
246                             $stream = $decoder->decode(trim($stream));
247                         } else {
248                                 $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1]));
249                         }
250                     } else {
251                         $this->fpdi->error(sprintf("Unsupported Filter: %s",$_filter[1]));
252                     }
253             }
254         }
255         
256         return $stream;
257     }
258     
259     
260     /**
261      * Get a Box from a page
262      * Arrayformat is same as used by fpdf_tpl
263      *
264      * @param array $page a /Page
265      * @param string $box_index Type of Box @see $availableBoxes
266      * @return array
267      */
268     function getPageBox($page, $box_index) {
269         $page = $this->pdf_resolve_object($this->c,$page);
270         $box = null;
271         if (isset($page[1][1][$box_index]))
272             $box =& $page[1][1][$box_index];
273         
274         if (!is_null($box) && $box[0] == PDF_TYPE_OBJREF) {
275             $tmp_box = $this->pdf_resolve_object($this->c,$box);
276             $box = $tmp_box[1];
277         }
278             
279         if (!is_null($box) && $box[0] == PDF_TYPE_ARRAY) {
280             $b =& $box[1];
281             return array("x" => $b[0][1]/$this->fpdi->k,
282                          "y" => $b[1][1]/$this->fpdi->k,
283                          "w" => abs($b[0][1]-$b[2][1])/$this->fpdi->k,
284                          "h" => abs($b[1][1]-$b[3][1])/$this->fpdi->k);
285         } else if (!isset ($page[1][1]['/Parent'])) {
286             return false;
287         } else {
288             return $this->getPageBox($this->pdf_resolve_object($this->c, $page[1][1]['/Parent']), $box_index);
289         }
290     }
291
292     function getPageBoxes($pageno) {
293         return $this->_getPageBoxes($this->pages[$pageno-1]);
294     }
295     
296     /**
297      * Get all Boxes from /Page
298      *
299      * @param array a /Page
300      * @return array
301      */
302     function _getPageBoxes($page) {
303         $boxes = array();
304
305         foreach($this->availableBoxes AS $box) {
306             if ($_box = $this->getPageBox($page,$box)) {
307                 $boxes[$box] = $_box;
308             }
309         }
310
311         return $boxes;
312     }
313
314     /**
315      * Get the page rotation by pageno
316      *
317      * @param integer $pageno
318      * @return array
319      */
320     function getPageRotation($pageno) {
321         return $this->_getPageRotation($this->pages[$pageno-1]);
322     }
323     
324     function _getPageRotation ($obj) { // $obj = /Page
325         $obj = $this->pdf_resolve_object($this->c, $obj);
326         if (isset ($obj[1][1]['/Rotate'])) {
327                 $res = $this->pdf_resolve_object($this->c, $obj[1][1]['/Rotate']);
328                 if ($res[0] == PDF_TYPE_OBJECT)
329                 return $res[1];
330             return $res;
331         } else {
332                 if (!isset ($obj[1][1]['/Parent'])) {
333                         return false;
334                 } else {
335                 $res = $this->_getPageRotation($obj[1][1]['/Parent']);
336                 if ($res[0] == PDF_TYPE_OBJECT)
337                     return $res[1];
338                 return $res;
339                 }
340         }
341     }
342     
343     /**
344      * Read all /Page(es)
345      *
346      * @param object pdf_context
347      * @param array /Pages
348      * @param array the result-array
349      */
350     function read_pages (&$c, &$pages, &$result) {
351         // Get the kids dictionary
352         $kids = $this->pdf_resolve_object ($c, $pages[1][1]['/Kids']);
353
354         if (!is_array($kids))
355             $this->fpdi->Error("Cannot find /Kids in current /Page-Dictionary");
356         foreach ($kids[1] as $v) {
357                 $pg = $this->pdf_resolve_object ($c, $v);
358             if ($pg[1][1]['/Type'][1] === '/Pages') {
359                 // If one of the kids is an embedded
360                         // /Pages array, resolve it as well.
361                 $this->read_pages ($c, $pg, $result);
362                 } else {
363                         $result[] = $pg;
364                 }
365         }
366     }
367
368     
369     
370     /**
371      * Get PDF-Version
372      *
373      * And reset the PDF Version used in FPDI if needed
374      */
375     function getPDFVersion() {
376         parent::getPDFVersion();
377         $this->fpdi->PDFVersion = max($this->fpdi->PDFVersion, $this->pdfVersion);
378     }
379     
380 }