PluginProbe
Welcart e-Commerce / 2.12.3
Welcart e-Commerce v2.12.3
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
usc-e-shop / classes / fpdf / pdf_parser.php

pdf_parser.php in Welcart e-Commerce 2.12.3, at classes/fpdf/pdf_parser.php

660 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 ?>