PluginProbe
Welcart e-Commerce / 2.12.4
Welcart e-Commerce v2.12.4
2.12.4 2.12.3 2.11.35 2.12.2 2.12.1 2.11.34 2.11.33 2.11.32 2.11.31 2.11.30 1.3.16 1.3.17 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 All 292 releases
← All changes | classes/fpdf/pdf_parser.php +659 -659 1.3.22.12.4 View file →
@@ -1,660 +1,660 @@
1 -<?php
2 -//
3 -// FPDI - Version 1.2
4 -//
5 -// Copyright 2004-2007 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 (!defined ('PDF_TYPE_NULL'))
21 - define ('PDF_TYPE_NULL', 0);
22 -if (!defined ('PDF_TYPE_NUMERIC'))
23 - define ('PDF_TYPE_NUMERIC', 1);
24 -if (!defined ('PDF_TYPE_TOKEN'))
25 - define ('PDF_TYPE_TOKEN', 2);
26 -if (!defined ('PDF_TYPE_HEX'))
27 - define ('PDF_TYPE_HEX', 3);
28 -if (!defined ('PDF_TYPE_STRING'))
29 - define ('PDF_TYPE_STRING', 4);
30 -if (!defined ('PDF_TYPE_DICTIONARY'))
31 - define ('PDF_TYPE_DICTIONARY', 5);
32 -if (!defined ('PDF_TYPE_ARRAY'))
33 - define ('PDF_TYPE_ARRAY', 6);
34 -if (!defined ('PDF_TYPE_OBJDEC'))
35 - define ('PDF_TYPE_OBJDEC', 7);
36 -if (!defined ('PDF_TYPE_OBJREF'))
37 - define ('PDF_TYPE_OBJREF', 8);
38 -if (!defined ('PDF_TYPE_OBJECT'))
39 - define ('PDF_TYPE_OBJECT', 9);
40 -if (!defined ('PDF_TYPE_STREAM'))
41 - define ('PDF_TYPE_STREAM', 10);
42 -
43 -require_once(USCES_PLUGIN_DIR.'/classes/fpdf/pdf_context.php');
44 -require_once(USCES_PLUGIN_DIR.'/classes/fpdf/wrapper_functions.php');
45 -
46 -class pdf_parser {
47 -
48 - /**
49 - * Filename
50 - * @var string
51 - */
52 - var $filename;
53 -
54 - /**
55 - * File resource
56 - * @var resource
57 - */
58 - var $f;
59 -
60 - /**
61 - * PDF Context
62 - * @var object pdf_context-Instance
63 - */
64 - var $c;
65 -
66 - /**
67 - * xref-Data
68 - * @var array
69 - */
70 - var $xref;
71 -
72 - /**
73 - * root-Object
74 - * @var array
75 - */
76 - var $root;
77 -
78 -
79 - /**
80 - * Constructor
81 - *
82 - * @param string $filename Source-Filename
83 - */
84 - function pdf_parser($filename) {
85 - $this->filename = $filename;
86 -
87 - $this->f = @fopen($this->filename, "rb");
88 -
89 - if (!$this->f)
90 - $this->error(sprintf("Cannot open %s !", $filename));
91 -
92 - $this->getPDFVersion();
93 -
94 - $this->c =& new pdf_context($this->f);
95 - // Read xref-Data
96 - $this->pdf_read_xref($this->xref, $this->pdf_find_xref());
97 -
98 - // Check for Encryption
99 - $this->getEncryption();
100 -
101 - // Read root
102 - $this->pdf_read_root();
103 - }
104 -
105 - /**
106 - * Close the opened file
107 - */
108 - function closeFile() {
109 - if (isset($this->f)) {
110 - fclose($this->f);
111 - unset($this->f);
112 - }
113 - }
114 -
115 - /**
116 - * Print Error and die
117 - *
118 - * @param string $msg Error-Message
119 - */
120 - function error($msg) {
121 - die("<b>PDF-Parser Error:</b> ".$msg);
122 - }
123 -
124 - /**
125 - * Check Trailer for Encryption
126 - */
127 - function getEncryption() {
128 - if (isset($this->xref['trailer'][1]['/Encrypt'])) {
129 - $this->error("File is encrypted!");
130 - }
131 - }
132 -
133 - /**
134 - * Find/Return /Root
135 - *
136 - * @return array
137 - */
138 - function pdf_find_root() {
139 - if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) {
140 - $this->error("Wrong Type of Root-Element! Must be an indirect reference");
141 - }
142 - return $this->xref['trailer'][1]['/Root'];
143 - }
144 -
145 - /**
146 - * Read the /Root
147 - */
148 - function pdf_read_root() {
149 - // read root
150 - $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root());
151 - }
152 -
153 - /**
154 - * Get PDF-Version
155 - *
156 - * And reset the PDF Version used in FPDI if needed
157 - */
158 - function getPDFVersion() {
159 - fseek($this->f, 0);
160 - preg_match("/\d\.\d/",fread($this->f,16),$m);
161 - $this->pdfVersion = $m[0];
162 - }
163 -
164 - /**
165 - * Find the xref-Table
166 - */
167 - function pdf_find_xref() {
168 - fseek ($this->f, -min(filesize($this->filename),1500), SEEK_END);
169 - $data = fread($this->f, 1500);
170 -
171 - $pos = strlen($data) - strpos(strrev($data), strrev('startxref'));
172 - $data = substr($data, $pos);
173 -
174 - if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) {
175 - $this->error("Unable to find pointer to xref table");
176 - }
177 -
178 - return (int) $matches[1];
179 - }
180 -
181 - /**
182 - * Read xref-table
183 - *
184 - * @param array $result Array of xref-table
185 - * @param integer $offset of xref-table
186 - * @param integer $start start-position in xref-table
187 - * @param integer $end end-position in xref-table
188 - */
189 - function pdf_read_xref(&$result, $offset, $start = null, $end = null) {
190 - if (is_null ($start) || is_null ($end)) {
191 - fseek($this->f, $o_pos = $offset);
192 - $data = trim(fgets($this->f,1024));
193 -
194 - if (strlen($data) == 0)
195 - $data = trim(fgets($this->f,1024));
196 -
197 - if ($data !== 'xref') {
198 - fseek($this->f, $o_pos);
199 - $data = trim(_fgets($this->f, true));
200 - if ($data !== 'xref') {
201 - if (preg_match('/(.*xref)(.*)/m', $data, $m)) { // xref 0 128 - in one line
202 - fseek($this->f, $o_pos+strlen($m[1]));
203 - } elseif (preg_match('/(x|r|e|f)+/', $data, $m)) { // correct invalid xref-pointer
204 - $tmpOffset = $offset-4+strlen($m[0]);
205 - $this->pdf_read_xref($result, $tmpOffset, $start, $end);
206 - return;
207 - } else {
208 - $this->error("Unable to find xref table - Maybe a Problem with 'auto_detect_line_endings'");
209 - }
210 - }
211 - }
212 -
213 - $o_pos = ftell($this->f);
214 - $data = explode(' ', trim(fgets($this->f,1024)));
215 - if (count($data) != 2) {
216 - fseek($this->f, $o_pos);
217 - $data = explode(' ', trim(_fgets($this->f, true)));
218 -
219 - if (count($data) != 2) {
220 - if (count($data) > 2) { // no lineending
221 - $n_pos = $o_pos+strlen($data[0])+strlen($data[1])+2;
222 - fseek($this->f, $n_pos);
223 - } else {
224 - $this->error("Unexpected header in xref table");
225 - }
226 - }
227 - }
228 - $start = $data[0];
229 - $end = $start + $data[1];
230 - }
231 -
232 - if (!isset($result['xref_location'])) {
233 - $result['xref_location'] = $offset;
234 - }
235 -
236 - if (!isset($result['max_object']) || $end > $result['max_object']) {
237 - $result['max_object'] = $end;
238 - }
239 -
240 - for (; $start < $end; $start++) {
241 - $data = ltrim(fread($this->f, 20)); // Spezifications says: 20 bytes including newlines
242 - $offset = substr($data, 0, 10);
243 - $generation = substr($data, 11, 5);
244 -
245 - if (!isset ($result['xref'][$start][(int) $generation])) {
246 - $result['xref'][$start][(int) $generation] = (int) $offset;
247 - }
248 - }
249 -
250 - $o_pos = ftell($this->f);
251 - $data = fgets($this->f,1024);
252 - if (strlen(trim($data)) == 0)
253 - $data = fgets($this->f, 1024);
254 -
255 - if (preg_match("/trailer/",$data)) {
256 - if (preg_match("/(.*trailer[ \n\r]*)/",$data,$m)) {
257 - fseek($this->f, $o_pos+strlen($m[1]));
258 - }
259 -
260 - $c =& new pdf_context($this->f);
261 - $trailer = $this->pdf_read_value($c);
262 -
263 - if (isset($trailer[1]['/Prev'])) {
264 - $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]);
265 - $result['trailer'][1] = array_merge($result['trailer'][1], $trailer[1]);
266 - } else {
267 - $result['trailer'] = $trailer;
268 - }
269 - } else {
270 - $data = explode(' ', trim($data));
271 -
272 - if (count($data) != 2) {
273 - fseek($this->f, $o_pos);
274 - $data = explode(' ', trim (_fgets ($this->f, true)));
275 -
276 - if (count($data) != 2) {
277 - $this->error("Unexpected data in xref table");
278 - }
279 - }
280 -
281 - $this->pdf_read_xref($result, null, (int) $data[0], (int) $data[0] + (int) $data[1]);
282 - }
283 - }
284 -
285 -
286 - /**
287 - * Reads an Value
288 - *
289 - * @param object $c pdf_context
290 - * @param string $token a Token
291 - * @return mixed
292 - */
293 - function pdf_read_value(&$c, $token = null) {
294 - if (is_null($token)) {
295 - $token = $this->pdf_read_token($c);
296 - }
297 -
298 - if ($token === false) {
299 - return false;
300 - }
301 -
302 - switch ($token) {
303 - case '<':
304 - // This is a hex string.
305 - // Read the value, then the terminator
306 -
307 - $pos = $c->offset;
308 -
309 - while(1) {
310 -
311 - $match = strpos ($c->buffer, '>', $pos);
312 -
313 - // If you can't find it, try
314 - // reading more data from the stream
315 -
316 - if ($match === false) {
317 - if (!$c->increase_length()) {
318 - return false;
319 - } else {
320 - continue;
321 - }
322 - }
323 -
324 - $result = substr ($c->buffer, $c->offset, $match - $c->offset);
325 - $c->offset = $match+1;
326 -
327 - return array (PDF_TYPE_HEX, $result);
328 - }
329 -
330 - break;
331 - case '<<':
332 - // This is a dictionary.
333 -
334 - $result = array();
335 -
336 - // Recurse into this function until we reach
337 - // the end of the dictionary.
338 - while (($key = $this->pdf_read_token($c)) !== '>>') {
339 - if ($key === false) {
340 - return false;
341 - }
342 -
343 - if (($value = $this->pdf_read_value($c)) === false) {
344 - return false;
345 - }
346 - $result[$key] = $value;
347 - }
348 -
349 - return array (PDF_TYPE_DICTIONARY, $result);
350 -
351 - case '[':
352 - // This is an array.
353 -
354 - $result = array();
355 -
356 - // Recurse into this function until we reach
357 - // the end of the array.
358 - while (($token = $this->pdf_read_token($c)) !== ']') {
359 - if ($token === false) {
360 - return false;
361 - }
362 -
363 - if (($value = $this->pdf_read_value($c, $token)) === false) {
364 - return false;
365 - }
366 -
367 - $result[] = $value;
368 - }
369 -
370 - return array (PDF_TYPE_ARRAY, $result);
371 -
372 - case '(' :
373 - // This is a string
374 -
375 - $pos = $c->offset;
376 -
377 - while(1) {
378 -
379 - // Start by finding the next closed
380 - // parenthesis
381 -
382 - $match = strpos ($c->buffer, ')', $pos);
383 -
384 - // If you can't find it, try
385 - // reading more data from the stream
386 -
387 - if ($match === false) {
388 - if (!$c->increase_length()) {
389 - return false;
390 - } else {
391 - continue;
392 - }
393 - }
394 -
395 - // Make sure that there is no backslash
396 - // before the parenthesis. If there is,
397 - // move on. Otherwise, return the string.
398 - $esc = preg_match('/([\\\\]+)$/', $tmpresult = substr($c->buffer, $c->offset, $match - $c->offset), $m);
399 -
400 - if ($esc === 0 || strlen($m[1]) % 2 == 0) {
401 - $result = $tmpresult;
402 - $c->offset = $match + 1;
403 - return array (PDF_TYPE_STRING, $result);
404 - } else {
405 - $pos = $match + 1;
406 -
407 - if ($pos > $c->offset + $c->length) {
408 - $c->increase_length();
409 - }
410 - }
411 - }
412 -
413 - case "stream":
414 - $o_pos = ftell($c->file)-strlen($c->buffer);
415 - $o_offset = $c->offset;
416 -
417 - $c->reset($startpos = $o_pos + $o_offset);
418 -
419 - $e = 0; // ensure line breaks in front of the stream
420 - if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13))
421 - $e++;
422 - if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10))
423 - $e++;
424 -
425 - if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) {
426 - $tmp_c =& new pdf_context($this->f);
427 - $tmp_length = $this->pdf_resolve_object($tmp_c,$this->actual_obj[1][1]['/Length']);
428 - $length = $tmp_length[1][1];
429 - } else {
430 - $length = $this->actual_obj[1][1]['/Length'][1];
431 - }
432 -
433 - if ($length > 0) {
434 - $c->reset($startpos+$e,$length);
435 - $v = $c->buffer;
436 - } else {
437 - $v = '';
438 - }
439 - $c->reset($startpos+$e+$length+9); // 9 = strlen("endstream")
440 -
441 - return array(PDF_TYPE_STREAM, $v);
442 -
443 - default :
444 - if (is_numeric ($token)) {
445 - // A numeric token. Make sure that
446 - // it is not part of something else.
447 - if (($tok2 = $this->pdf_read_token ($c)) !== false) {
448 - if (is_numeric ($tok2)) {
449 -
450 - // Two numeric tokens in a row.
451 - // In this case, we're probably in
452 - // front of either an object reference
453 - // or an object specification.
454 - // Determine the case and return the data
455 - if (($tok3 = $this->pdf_read_token ($c)) !== false) {
456 - switch ($tok3) {
457 - case 'obj' :
458 - return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2);
459 - case 'R' :
460 - return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2);
461 - }
462 - // If we get to this point, that numeric value up
463 - // there was just a numeric value. Push the extra
464 - // tokens back into the stack and return the value.
465 - array_push ($c->stack, $tok3);
466 - }
467 - }
468 -
469 - array_push ($c->stack, $tok2);
470 - }
471 -
472 - return array (PDF_TYPE_NUMERIC, $token);
473 - } else {
474 -
475 - // Just a token. Return it.
476 - return array (PDF_TYPE_TOKEN, $token);
477 - }
478 -
479 - }
480 - }
481 -
482 - /**
483 - * Resolve an object
484 - *
485 - * @param object $c pdf_context
486 - * @param array $obj_spec The object-data
487 - * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para
488 - */
489 - function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) {
490 - // Exit if we get invalid data
491 - if (!is_array($obj_spec)) {
492 - return false;
493 - }
494 -
495 - if ($obj_spec[0] == PDF_TYPE_OBJREF) {
496 -
497 - // This is a reference, resolve it
498 - if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) {
499 -
500 - // Save current file position
501 - // This is needed if you want to resolve
502 - // references while you're reading another object
503 - // (e.g.: if you need to determine the length
504 - // of a stream)
505 -
506 - $old_pos = ftell($c->file);
507 -
508 - // Reposition the file pointer and
509 - // load the object header.
510 -
511 - $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]);
512 -
513 - $header = $this->pdf_read_value($c,null,true);
514 -
515 - if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) {
516 - $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location");
517 - }
518 -
519 - // If we're being asked to store all the information
520 - // about the object, we add the object ID and generation
521 - // number for later use
522 - $this->actual_obj =& $result;
523 - if ($encapsulate) {
524 - $result = array (
525 - PDF_TYPE_OBJECT,
526 - 'obj' => $obj_spec[1],
527 - 'gen' => $obj_spec[2]
528 - );
529 - } else {
530 - $result = array();
531 - }
532 -
533 - // Now simply read the object data until
534 - // we encounter an end-of-object marker
535 - while(1) {
536 - $value = $this->pdf_read_value($c);
537 - if ($value === false || count($result) > 4) {
538 - // in this case the parser coudn't find an endobj so we break here
539 - break;
540 - }
541 -
542 - if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') {
543 - break;
544 - }
545 -
546 - $result[] = $value;
547 - }
548 -
549 - $c->reset($old_pos);
550 -
551 - if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) {
552 - $result[0] = PDF_TYPE_STREAM;
553 - }
554 -
555 - return $result;
556 - }
557 - } else {
558 - return $obj_spec;
559 - }
560 - }
561 -
562 -
563 -
564 - /**
565 - * Reads a token from the file
566 - *
567 - * @param object $c pdf_context
568 - * @return mixed
569 - */
570 - function pdf_read_token(&$c)
571 - {
572 - // If there is a token available
573 - // on the stack, pop it out and
574 - // return it.
575 -
576 - if (count($c->stack)) {
577 - return array_pop($c->stack);
578 - }
579 -
580 - // Strip away any whitespace
581 -
582 - do {
583 - if (!$c->ensure_content()) {
584 - return false;
585 - }
586 - $c->offset += _strspn($c->buffer, " \n\r\t", $c->offset);
587 - } while ($c->offset >= $c->length - 1);
588 -
589 - // Get the first character in the stream
590 -
591 - $char = $c->buffer[$c->offset++];
592 -
593 - switch ($char) {
594 -
595 - case '[' :
596 - case ']' :
597 - case '(' :
598 - case ')' :
599 -
600 - // This is either an array or literal string
601 - // delimiter, Return it
602 -
603 - return $char;
604 -
605 - case '<' :
606 - case '>' :
607 -
608 - // This could either be a hex string or
609 - // dictionary delimiter. Determine the
610 - // appropriate case and return the token
611 -
612 - if ($c->buffer[$c->offset] == $char) {
613 - if (!$c->ensure_content()) {
614 - return false;
615 - }
616 - $c->offset++;
617 - return $char . $char;
618 - } else {
619 - return $char;
620 - }
621 -
622 - default :
623 -
624 - // This is "another" type of token (probably
625 - // a dictionary entry or a numeric value)
626 - // Find the end and return it.
627 -
628 - if (!$c->ensure_content()) {
629 - return false;
630 - }
631 -
632 - while(1) {
633 -
634 - // Determine the length of the token
635 -
636 - $pos = _strcspn($c->buffer, " []<>()\r\n\t/", $c->offset);
637 - if ($c->offset + $pos <= $c->length - 1) {
638 - break;
639 - } else {
640 - // If the script reaches this point,
641 - // the token may span beyond the end
642 - // of the current buffer. Therefore,
643 - // we increase the size of the buffer
644 - // and try again--just to be safe.
645 -
646 - $c->increase_length();
647 - }
648 - }
649 -
650 - $result = substr($c->buffer, $c->offset - 1, $pos + 1);
651 -
652 - $c->offset += $pos;
653 - return $result;
654 - }
655 - }
656 -
657 -
658 -}
659 -
1 +<?php
2 +//
3 +// FPDI - Version 1.2
4 +//
5 +// Copyright 2004-2007 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 (!defined ('PDF_TYPE_NULL'))
21 + define ('PDF_TYPE_NULL', 0);
22 +if (!defined ('PDF_TYPE_NUMERIC'))
23 + define ('PDF_TYPE_NUMERIC', 1);
24 +if (!defined ('PDF_TYPE_TOKEN'))
25 + define ('PDF_TYPE_TOKEN', 2);
26 +if (!defined ('PDF_TYPE_HEX'))
27 + define ('PDF_TYPE_HEX', 3);
28 +if (!defined ('PDF_TYPE_STRING'))
29 + define ('PDF_TYPE_STRING', 4);
30 +if (!defined ('PDF_TYPE_DICTIONARY'))
31 + define ('PDF_TYPE_DICTIONARY', 5);
32 +if (!defined ('PDF_TYPE_ARRAY'))
33 + define ('PDF_TYPE_ARRAY', 6);
34 +if (!defined ('PDF_TYPE_OBJDEC'))
35 + define ('PDF_TYPE_OBJDEC', 7);
36 +if (!defined ('PDF_TYPE_OBJREF'))
37 + define ('PDF_TYPE_OBJREF', 8);
38 +if (!defined ('PDF_TYPE_OBJECT'))
39 + define ('PDF_TYPE_OBJECT', 9);
40 +if (!defined ('PDF_TYPE_STREAM'))
41 + define ('PDF_TYPE_STREAM', 10);
42 +
43 +require_once(USCES_PLUGIN_DIR.'/classes/fpdf/pdf_context.php');
44 +require_once(USCES_PLUGIN_DIR.'/classes/fpdf/wrapper_functions.php');
45 +
46 +class pdf_parser {
47 +
48 + /**
49 + * Filename
50 + * @var string
51 + */
52 + var $filename;
53 +
54 + /**
55 + * File resource
56 + * @var resource
57 + */
58 + var $f;
59 +
60 + /**
61 + * PDF Context
62 + * @var object pdf_context-Instance
63 + */
64 + var $c;
65 +
66 + /**
67 + * xref-Data
68 + * @var array
69 + */
70 + var $xref;
71 +
72 + /**
73 + * root-Object
74 + * @var array
75 + */
76 + var $root;
77 +
78 +
79 + /**
80 + * Constructor
81 + *
82 + * @param string $filename Source-Filename
83 + */
84 + function pdf_parser($filename) {
85 + $this->filename = $filename;
86 +
87 + $this->f = @fopen($this->filename, "rb");
88 +
89 + if (!$this->f)
90 + $this->error(sprintf("Cannot open %s !", $filename));
91 +
92 + $this->getPDFVersion();
93 +
94 + $this->c = new pdf_context($this->f);
95 + // Read xref-Data
96 + $this->pdf_read_xref($this->xref, $this->pdf_find_xref());
97 +
98 + // Check for Encryption
99 + $this->getEncryption();
100 +
101 + // Read root
102 + $this->pdf_read_root();
103 + }
104 +
105 + /**
106 + * Close the opened file
107 + */
108 + function closeFile() {
109 + if (isset($this->f)) {
110 + fclose($this->f);
111 + unset($this->f);
112 + }
113 + }
114 +
115 + /**
116 + * Print Error and die
117 + *
118 + * @param string $msg Error-Message
119 + */
120 + function error($msg) {
121 + die("<b>PDF-Parser Error:</b> ".$msg);
122 + }
123 +
124 + /**
125 + * Check Trailer for Encryption
126 + */
127 + function getEncryption() {
128 + if (isset($this->xref['trailer'][1]['/Encrypt'])) {
129 + $this->error("File is encrypted!");
130 + }
131 + }
132 +
133 + /**
134 + * Find/Return /Root
135 + *
136 + * @return array
137 + */
138 + function pdf_find_root() {
139 + if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) {
140 + $this->error("Wrong Type of Root-Element! Must be an indirect reference");
141 + }
142 + return $this->xref['trailer'][1]['/Root'];
143 + }
144 +
145 + /**
146 + * Read the /Root
147 + */
148 + function pdf_read_root() {
149 + // read root
150 + $this->root = $this->pdf_resolve_object($this->c, $this->pdf_find_root());
151 + }
152 +
153 + /**
154 + * Get PDF-Version
155 + *
156 + * And reset the PDF Version used in FPDI if needed
157 + */
158 + function getPDFVersion() {
159 + fseek($this->f, 0);
160 + preg_match("/\d\.\d/",fread($this->f,16),$m);
161 + $this->pdfVersion = $m[0];
162 + }
163 +
164 + /**
165 + * Find the xref-Table
166 + */
167 + function pdf_find_xref() {
168 + fseek ($this->f, -min(filesize($this->filename),1500), SEEK_END);
169 + $data = fread($this->f, 1500);
170 +
171 + $pos = strlen($data) - strpos(strrev($data), strrev('startxref'));
172 + $data = substr($data, $pos);
173 +
174 + if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) {
175 + $this->error("Unable to find pointer to xref table");
176 + }
177 +
178 + return (int) $matches[1];
179 + }
180 +
181 + /**
182 + * Read xref-table
183 + *
184 + * @param array $result Array of xref-table
185 + * @param integer $offset of xref-table
186 + * @param integer $start start-position in xref-table
187 + * @param integer $end end-position in xref-table
188 + */
189 + function pdf_read_xref(&$result, $offset, $start = null, $end = null) {
190 + if (is_null ($start) || is_null ($end)) {
191 + fseek($this->f, $o_pos = $offset);
192 + $data = trim(fgets($this->f,1024));
193 +
194 + if (strlen($data) == 0)
195 + $data = trim(fgets($this->f,1024));
196 +
197 + if ($data !== 'xref') {
198 + fseek($this->f, $o_pos);
199 + $data = trim(_fgets($this->f, true));
200 + if ($data !== 'xref') {
201 + if (preg_match('/(.*xref)(.*)/m', $data, $m)) { // xref 0 128 - in one line
202 + fseek($this->f, $o_pos+strlen($m[1]));
203 + } elseif (preg_match('/(x|r|e|f)+/', $data, $m)) { // correct invalid xref-pointer
204 + $tmpOffset = $offset-4+strlen($m[0]);
205 + $this->pdf_read_xref($result, $tmpOffset, $start, $end);
206 + return;
207 + } else {
208 + $this->error("Unable to find xref table - Maybe a Problem with 'auto_detect_line_endings'");
209 + }
210 + }
211 + }
212 +
213 + $o_pos = ftell($this->f);
214 + $data = explode(' ', trim(fgets($this->f,1024)));
215 + if (count($data) != 2) {
216 + fseek($this->f, $o_pos);
217 + $data = explode(' ', trim(_fgets($this->f, true)));
218 +
219 + if (count($data) != 2) {
220 + if (count($data) > 2) { // no lineending
221 + $n_pos = $o_pos+strlen($data[0])+strlen($data[1])+2;
222 + fseek($this->f, $n_pos);
223 + } else {
224 + $this->error("Unexpected header in xref table");
225 + }
226 + }
227 + }
228 + $start = $data[0];
229 + $end = $start + $data[1];
230 + }
231 +
232 + if (!isset($result['xref_location'])) {
233 + $result['xref_location'] = $offset;
234 + }
235 +
236 + if (!isset($result['max_object']) || $end > $result['max_object']) {
237 + $result['max_object'] = $end;
238 + }
239 +
240 + for (; $start < $end; $start++) {
241 + $data = ltrim(fread($this->f, 20)); // Spezifications says: 20 bytes including newlines
242 + $offset = substr($data, 0, 10);
243 + $generation = substr($data, 11, 5);
244 +
245 + if (!isset ($result['xref'][$start][(int) $generation])) {
246 + $result['xref'][$start][(int) $generation] = (int) $offset;
247 + }
248 + }
249 +
250 + $o_pos = ftell($this->f);
251 + $data = fgets($this->f,1024);
252 + if (strlen(trim($data)) == 0)
253 + $data = fgets($this->f, 1024);
254 +
255 + if (preg_match("/trailer/",$data)) {
256 + if (preg_match("/(.*trailer[ \n\r]*)/",$data,$m)) {
257 + fseek($this->f, $o_pos+strlen($m[1]));
258 + }
259 +
260 + $c = new pdf_context($this->f);
261 + $trailer = $this->pdf_read_value($c);
262 +
263 + if (isset($trailer[1]['/Prev'])) {
264 + $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]);
265 + $result['trailer'][1] = array_merge($result['trailer'][1], $trailer[1]);
266 + } else {
267 + $result['trailer'] = $trailer;
268 + }
269 + } else {
270 + $data = explode(' ', trim($data));
271 +
272 + if (count($data) != 2) {
273 + fseek($this->f, $o_pos);
274 + $data = explode(' ', trim (_fgets ($this->f, true)));
275 +
276 + if (count($data) != 2) {
277 + $this->error("Unexpected data in xref table");
278 + }
279 + }
280 +
281 + $this->pdf_read_xref($result, null, (int) $data[0], (int) $data[0] + (int) $data[1]);
282 + }
283 + }
284 +
285 +
286 + /**
287 + * Reads an Value
288 + *
289 + * @param object $c pdf_context
290 + * @param string $token a Token
291 + * @return mixed
292 + */
293 + function pdf_read_value(&$c, $token = null) {
294 + if (is_null($token)) {
295 + $token = $this->pdf_read_token($c);
296 + }
297 +
298 + if ($token === false) {
299 + return false;
300 + }
301 +
302 + switch ($token) {
303 + case '<':
304 + // This is a hex string.
305 + // Read the value, then the terminator
306 +
307 + $pos = $c->offset;
308 +
309 + while(1) {
310 +
311 + $match = strpos ($c->buffer, '>', $pos);
312 +
313 + // If you can't find it, try
314 + // reading more data from the stream
315 +
316 + if ($match === false) {
317 + if (!$c->increase_length()) {
318 + return false;
319 + } else {
320 + continue;
321 + }
322 + }
323 +
324 + $result = substr ($c->buffer, $c->offset, $match - $c->offset);
325 + $c->offset = $match+1;
326 +
327 + return array (PDF_TYPE_HEX, $result);
328 + }
329 +
330 + break;
331 + case '<<':
332 + // This is a dictionary.
333 +
334 + $result = array();
335 +
336 + // Recurse into this function until we reach
337 + // the end of the dictionary.
338 + while (($key = $this->pdf_read_token($c)) !== '>>') {
339 + if ($key === false) {
340 + return false;
341 + }
342 +
343 + if (($value = $this->pdf_read_value($c)) === false) {
344 + return false;
345 + }
346 + $result[$key] = $value;
347 + }
348 +
349 + return array (PDF_TYPE_DICTIONARY, $result);
350 +
351 + case '[':
352 + // This is an array.
353 +
354 + $result = array();
355 +
356 + // Recurse into this function until we reach
357 + // the end of the array.
358 + while (($token = $this->pdf_read_token($c)) !== ']') {
359 + if ($token === false) {
360 + return false;
361 + }
362 +
363 + if (($value = $this->pdf_read_value($c, $token)) === false) {
364 + return false;
365 + }
366 +
367 + $result[] = $value;
368 + }
369 +
370 + return array (PDF_TYPE_ARRAY, $result);
371 +
372 + case '(' :
373 + // This is a string
374 +
375 + $pos = $c->offset;
376 +
377 + while(1) {
378 +
379 + // Start by finding the next closed
380 + // parenthesis
381 +
382 + $match = strpos ($c->buffer, ')', $pos);
383 +
384 + // If you can't find it, try
385 + // reading more data from the stream
386 +
387 + if ($match === false) {
388 + if (!$c->increase_length()) {
389 + return false;
390 + } else {
391 + continue;
392 + }
393 + }
394 +
395 + // Make sure that there is no backslash
396 + // before the parenthesis. If there is,
397 + // move on. Otherwise, return the string.
398 + $esc = preg_match('/([\\\\]+)$/', $tmpresult = substr($c->buffer, $c->offset, $match - $c->offset), $m);
399 +
400 + if ($esc === 0 || strlen($m[1]) % 2 == 0) {
401 + $result = $tmpresult;
402 + $c->offset = $match + 1;
403 + return array (PDF_TYPE_STRING, $result);
404 + } else {
405 + $pos = $match + 1;
406 +
407 + if ($pos > $c->offset + $c->length) {
408 + $c->increase_length();
409 + }
410 + }
411 + }
412 +
413 + case "stream":
414 + $o_pos = ftell($c->file)-strlen($c->buffer);
415 + $o_offset = $c->offset;
416 +
417 + $c->reset($startpos = $o_pos + $o_offset);
418 +
419 + $e = 0; // ensure line breaks in front of the stream
420 + if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13))
421 + $e++;
422 + if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10))
423 + $e++;
424 +
425 + if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) {
426 + $tmp_c = new pdf_context($this->f);
427 + $tmp_length = $this->pdf_resolve_object($tmp_c,$this->actual_obj[1][1]['/Length']);
428 + $length = $tmp_length[1][1];
429 + } else {
430 + $length = $this->actual_obj[1][1]['/Length'][1];
431 + }
432 +
433 + if ($length > 0) {
434 + $c->reset($startpos+$e,$length);
435 + $v = $c->buffer;
436 + } else {
437 + $v = '';
438 + }
439 + $c->reset($startpos+$e+$length+9); // 9 = strlen("endstream")
440 +
441 + return array(PDF_TYPE_STREAM, $v);
442 +
443 + default :
444 + if (is_numeric ($token)) {
445 + // A numeric token. Make sure that
446 + // it is not part of something else.
447 + if (($tok2 = $this->pdf_read_token ($c)) !== false) {
448 + if (is_numeric ($tok2)) {
449 +
450 + // Two numeric tokens in a row.
451 + // In this case, we're probably in
452 + // front of either an object reference
453 + // or an object specification.
454 + // Determine the case and return the data
455 + if (($tok3 = $this->pdf_read_token ($c)) !== false) {
456 + switch ($tok3) {
457 + case 'obj' :
458 + return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2);
459 + case 'R' :
460 + return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2);
461 + }
462 + // If we get to this point, that numeric value up
463 + // there was just a numeric value. Push the extra
464 + // tokens back into the stack and return the value.
465 + array_push ($c->stack, $tok3);
466 + }
467 + }
468 +
469 + array_push ($c->stack, $tok2);
470 + }
471 +
472 + return array (PDF_TYPE_NUMERIC, $token);
473 + } else {
474 +
475 + // Just a token. Return it.
476 + return array (PDF_TYPE_TOKEN, $token);
477 + }
478 +
479 + }
480 + }
481 +
482 + /**
483 + * Resolve an object
484 + *
485 + * @param object $c pdf_context
486 + * @param array $obj_spec The object-data
487 + * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para
488 + */
489 + function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) {
490 + // Exit if we get invalid data
491 + if (!is_array($obj_spec)) {
492 + return false;
493 + }
494 +
495 + if ($obj_spec[0] == PDF_TYPE_OBJREF) {
496 +
497 + // This is a reference, resolve it
498 + if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) {
499 +
500 + // Save current file position
501 + // This is needed if you want to resolve
502 + // references while you're reading another object
503 + // (e.g.: if you need to determine the length
504 + // of a stream)
505 +
506 + $old_pos = ftell($c->file);
507 +
508 + // Reposition the file pointer and
509 + // load the object header.
510 +
511 + $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]);
512 +
513 + $header = $this->pdf_read_value($c,null,true);
514 +
515 + if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) {
516 + $this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location");
517 + }
518 +
519 + // If we're being asked to store all the information
520 + // about the object, we add the object ID and generation
521 + // number for later use
522 + $this->actual_obj =& $result;
523 + if ($encapsulate) {
524 + $result = array (
525 + PDF_TYPE_OBJECT,
526 + 'obj' => $obj_spec[1],
527 + 'gen' => $obj_spec[2]
528 + );
529 + } else {
530 + $result = array();
531 + }
532 +
533 + // Now simply read the object data until
534 + // we encounter an end-of-object marker
535 + while(1) {
536 + $value = $this->pdf_read_value($c);
537 + if ($value === false || count($result) > 4) {
538 + // in this case the parser coudn't find an endobj so we break here
539 + break;
540 + }
541 +
542 + if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') {
543 + break;
544 + }
545 +
546 + $result[] = $value;
547 + }
548 +
549 + $c->reset($old_pos);
550 +
551 + if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) {
552 + $result[0] = PDF_TYPE_STREAM;
553 + }
554 +
555 + return $result;
556 + }
557 + } else {
558 + return $obj_spec;
559 + }
560 + }
561 +
562 +
563 +
564 + /**
565 + * Reads a token from the file
566 + *
567 + * @param object $c pdf_context
568 + * @return mixed
569 + */
570 + function pdf_read_token(&$c)
571 + {
572 + // If there is a token available
573 + // on the stack, pop it out and
574 + // return it.
575 +
576 + if (count($c->stack)) {
577 + return array_pop($c->stack);
578 + }
579 +
580 + // Strip away any whitespace
581 +
582 + do {
583 + if (!$c->ensure_content()) {
584 + return false;
585 + }
586 + $c->offset += _strspn($c->buffer, " \n\r\t", $c->offset);
587 + } while ($c->offset >= $c->length - 1);
588 +
589 + // Get the first character in the stream
590 +
591 + $char = $c->buffer[$c->offset++];
592 +
593 + switch ($char) {
594 +
595 + case '[' :
596 + case ']' :
597 + case '(' :
598 + case ')' :
599 +
600 + // This is either an array or literal string
601 + // delimiter, Return it
602 +
603 + return $char;
604 +
605 + case '<' :
606 + case '>' :
607 +
608 + // This could either be a hex string or
609 + // dictionary delimiter. Determine the
610 + // appropriate case and return the token
611 +
612 + if ($c->buffer[$c->offset] == $char) {
613 + if (!$c->ensure_content()) {
614 + return false;
615 + }
616 + $c->offset++;
617 + return $char . $char;
618 + } else {
619 + return $char;
620 + }
621 +
622 + default :
623 +
624 + // This is "another" type of token (probably
625 + // a dictionary entry or a numeric value)
626 + // Find the end and return it.
627 +
628 + if (!$c->ensure_content()) {
629 + return false;
630 + }
631 +
632 + while(1) {
633 +
634 + // Determine the length of the token
635 +
636 + $pos = _strcspn($c->buffer, " []<>()\r\n\t/", $c->offset);
637 + if ($c->offset + $pos <= $c->length - 1) {
638 + break;
639 + } else {
640 + // If the script reaches this point,
641 + // the token may span beyond the end
642 + // of the current buffer. Therefore,
643 + // we increase the size of the buffer
644 + // and try again--just to be safe.
645 +
646 + $c->increase_length();
647 + }
648 + }
649 +
650 + $result = substr($c->buffer, $c->offset - 1, $pos + 1);
651 +
652 + $c->offset += $pos;
653 + return $result;
654 + }
655 + }
656 +
657 +
658 +}
659 +
660 660 ?>