44 require_once(dirname(__FILE__).
'/include/tcpdf_filters.php');
85 'die_for_errors' =>
false,
86 'ignore_filter_decoding_errors' =>
true,
87 'ignore_missing_filter_decoders' =>
true,
104 $this->
Error(
'Empty PDF data.');
107 if (($trimpos = strpos($data,
'%PDF-')) === FALSE) {
108 $this->
Error(
'Invalid PDF data: missing %PDF header.');
111 $this->pdfdata = substr($data, $trimpos);
113 $pdflen = strlen($this->pdfdata);
119 $this->objects = array();
120 foreach ($this->xref[
'xref'] as $obj => $offset) {
121 if (!isset($this->objects[$obj]) AND ($offset > 0)) {
127 unset($this->pdfdata);
140 if (isset(
$cfg[
'die_for_errors'])) {
141 $this->cfg[
'die_for_errors'] = !!
$cfg[
'die_for_errors'];
143 if (isset(
$cfg[
'ignore_filter_decoding_errors'])) {
144 $this->cfg[
'ignore_filter_decoding_errors'] = !!
$cfg[
'ignore_filter_decoding_errors'];
146 if (isset(
$cfg[
'ignore_missing_filter_decoders'])) {
147 $this->cfg[
'ignore_missing_filter_decoders'] = !!
$cfg[
'ignore_missing_filter_decoders'];
158 return array($this->xref, $this->objects);
172 if (preg_match_all(
'/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) {
173 $this->
Error(
'Unable to find startxref');
175 $matches = array_pop($matches);
176 $startxref = $matches[1];
177 } elseif (strpos($this->pdfdata,
'xref', $offset) == $offset) {
179 $startxref = $offset;
180 } elseif (preg_match(
'/([0-9]+[\s][0-9]+[\s]obj)/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
182 $startxref = $offset;
183 } elseif (preg_match(
'/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
185 $startxref = $matches[1][0];
187 $this->
Error(
'Unable to find startxref');
190 if (strpos($this->pdfdata,
'xref', $startxref) == $startxref) {
198 $this->
Error(
'Unable to find xref');
214 $offset = $startxref + strspn($this->pdfdata,
"\x00\x09\x0a\x0c\x0d\x20", $startxref);
218 while (preg_match(
'/([0-9]+)[\x20]([0-9]+)[\x20]?([nf]?)(\r\n|[\x20]?[\r\n])/', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
219 if ($matches[0][1] != $offset) {
223 $offset += strlen($matches[0][0]);
224 if ($matches[3][0] ==
'n') {
226 $index = $obj_num.
'_'.intval($matches[2][0]);
228 if (!isset(
$xref[
'xref'][$index])) {
230 $xref[
'xref'][$index] = intval($matches[1][0]);
233 } elseif ($matches[3][0] ==
'f') {
237 $obj_num = intval($matches[1][0]);
241 if (preg_match(
'/trailer[\s]*<<(.*)>>/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
242 $trailer_data = $matches[1][0];
243 if (!isset(
$xref[
'trailer']) OR empty(
$xref[
'trailer'])) {
245 $xref[
'trailer'] = array();
247 if (preg_match(
'/Size[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
248 $xref[
'trailer'][
'size'] = intval($matches[1]);
250 if (preg_match(
'/Root[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
251 $xref[
'trailer'][
'root'] = intval($matches[1]).
'_'.intval($matches[2]);
253 if (preg_match(
'/Encrypt[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
254 $xref[
'trailer'][
'encrypt'] = intval($matches[1]).
'_'.intval($matches[2]);
256 if (preg_match(
'/Info[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
257 $xref[
'trailer'][
'info'] = intval($matches[1]).
'_'.intval($matches[2]);
259 if (preg_match(
'/ID[\s]*[\[][\s]*[<]([^>]*)[>][\s]*[<]([^>]*)[>]/i', $trailer_data, $matches) > 0) {
260 $xref[
'trailer'][
'id'] = array();
261 $xref[
'trailer'][
'id'][0] = $matches[1];
262 $xref[
'trailer'][
'id'][1] = $matches[2];
265 if (preg_match(
'/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
270 $this->
Error(
'Unable to find trailer');
287 if (!isset(
$xref[
'trailer']) OR empty(
$xref[
'trailer'])) {
289 $xref[
'trailer'] = array();
292 $filltrailer =
false;
294 if (!isset(
$xref[
'xref'])) {
295 $xref[
'xref'] = array();
299 $sarr = $xrefcrs[0][1];
300 foreach ($sarr as $k => $v) {
301 if (($v[0] ==
'/') AND ($v[1] ==
'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'/') AND ($sarr[($k +1)][1] ==
'XRef'))) {
303 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Index') AND (isset($sarr[($k +1)]))) {
305 $index_first = intval($sarr[($k +1)][1][0][1]);
307 $index_entries = intval($sarr[($k +1)][1][1][1]);
308 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Prev') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'numeric'))) {
310 $prevxref = intval($sarr[($k +1)][1]);
311 } elseif (($v[0] ==
'/') AND ($v[1] ==
'W') AND (isset($sarr[($k +1)]))) {
314 $wb[0] = intval($sarr[($k +1)][1][0][1]);
315 $wb[1] = intval($sarr[($k +1)][1][1][1]);
316 $wb[2] = intval($sarr[($k +1)][1][2][1]);
317 } elseif (($v[0] ==
'/') AND ($v[1] ==
'DecodeParms') AND (isset($sarr[($k +1)][1]))) {
318 $decpar = $sarr[($k +1)][1];
319 foreach ($decpar as $kdc => $vdc) {
320 if (($vdc[0] ==
'/') AND ($vdc[1] ==
'Columns') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] ==
'numeric'))) {
321 $columns = intval($decpar[($kdc +1)][1]);
322 } elseif (($vdc[0] ==
'/') AND ($vdc[1] ==
'Predictor') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] ==
'numeric'))) {
323 $predictor = intval($decpar[($kdc +1)][1]);
326 } elseif ($filltrailer) {
327 if (($v[0] ==
'/') AND ($v[1] ==
'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'numeric'))) {
328 $xref[
'trailer'][
'size'] = $sarr[($k +1)][1];
329 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'objref'))) {
330 $xref[
'trailer'][
'root'] = $sarr[($k +1)][1];
331 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'objref'))) {
332 $xref[
'trailer'][
'info'] = $sarr[($k +1)][1];
333 } elseif (($v[0] ==
'/') AND ($v[1] ==
'Encrypt') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] ==
'objref'))) {
334 $xref[
'trailer'][
'encrypt'] = $sarr[($k +1)][1];
335 } elseif (($v[0] ==
'/') AND ($v[1] ==
'ID') AND (isset($sarr[($k +1)]))) {
336 $xref[
'trailer'][
'id'] = array();
337 $xref[
'trailer'][
'id'][0] = $sarr[($k +1)][1][0][1];
338 $xref[
'trailer'][
'id'][1] = $sarr[($k +1)][1][1][1];
343 if ($valid_crs AND isset($xrefcrs[1][3][0])) {
345 $rowlen = ($columns + 1);
347 $sdata = unpack(
'C*', $xrefcrs[1][3][0]);
349 $sdata = array_chunk($sdata, $rowlen);
353 $prev_row = array_fill (0, $rowlen, 0);
355 foreach ($sdata as $k => $row) {
357 $ddata[$k] = array();
359 $predictor = (10 + $row[0]);
361 for ($i=1; $i<=$columns; ++$i) {
364 $row_up = $prev_row[$j];
369 $row_left = $row[($i - 1)];
370 $row_upleft = $prev_row[($j - 1)];
372 switch ($predictor) {
374 $ddata[$k][$j] = $row[$i];
378 $ddata[$k][$j] = (($row[$i] + $row_left) & 0xff);
382 $ddata[$k][$j] = (($row[$i] + $row_up) & 0xff);
386 $ddata[$k][$j] = (($row[$i] + (($row_left + $row_up) / 2)) & 0xff);
391 $p = ($row_left + $row_up - $row_upleft);
393 $pa = abs($p - $row_left);
394 $pb = abs($p - $row_up);
395 $pc = abs($p - $row_upleft);
396 $pmin = min($pa, $pb, $pc);
400 $ddata[$k][$j] = (($row[$i] + $row_left) & 0xff);
404 $ddata[$k][$j] = (($row[$i] + $row_up) & 0xff);
408 $ddata[$k][$j] = (($row[$i] + $row_upleft) & 0xff);
415 $this->
Error(
'Unknown PNG predictor');
420 $prev_row = $ddata[$k];
425 foreach ($ddata as $k => $row) {
427 $sdata[$k] = array(0, 0, 0);
434 for ($c = 0; $c < 3; ++$c) {
436 for ($b = 0; $b < $wb[$c]; ++$b) {
437 if (isset($row[$i])) {
438 $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8));
446 if (isset($index_first)) {
447 $obj_num = $index_first;
451 foreach ($sdata as $k => $row) {
458 $index = $obj_num.
'_'.$row[2];
460 if (!isset(
$xref[
'xref'][$index])) {
462 $xref[
'xref'][$index] = $row[1];
469 $index = $row[1].
'_0_'.$row[2];
470 $xref[
'xref'][$index] = -1;
480 if (isset($prevxref)) {
498 $offset += strspn($this->pdfdata,
"\x00\x09\x0a\x0c\x0d\x20", $offset);
500 $char = $this->pdfdata[$offset];
505 $next = strcspn($this->pdfdata,
"\r\n", $offset);
516 if (preg_match(
'/^([^\x00\x09\x0a\x0c\x0d\x20\s\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]+)/', substr($this->pdfdata, $offset, 256), $matches) == 1) {
517 $objval = $matches[1];
518 $offset += strlen($objval);
530 while ($open_bracket > 0) {
531 if (!isset($this->pdfdata{$strpos})) {
534 $ch = $this->pdfdata{$strpos};
552 $objval = substr($this->pdfdata, $offset, ($strpos - $offset - 1));
568 $offset = $element[2];
569 $objval[] = $element;
570 }
while ($element[0] !=
']');
578 if (isset($this->pdfdata{($offset + 1)}) AND ($this->pdfdata{($offset + 1)} == $char)) {
580 $objtype = $char.$char;
588 $offset = $element[2];
589 $objval[] = $element;
590 }
while ($element[0] !=
'>>');
598 if (($char ==
'<') AND (preg_match(
'/^([0-9A-Fa-f\x09\x0a\x0c\x0d\x20]+)>/iU', substr($this->pdfdata, $offset), $matches) == 1)) {
600 $objval = strtr($matches[1],
"\x09\x0a\x0c\x0d\x20",
'');
601 $offset += strlen($matches[0]);
602 } elseif (($endpos = strpos($this->pdfdata,
'>', $offset)) !== FALSE) {
603 $offset = $endpos + 1;
609 if (substr($this->pdfdata, $offset, 6) ==
'endobj') {
613 } elseif (substr($this->pdfdata, $offset, 4) ==
'null') {
618 } elseif (substr($this->pdfdata, $offset, 4) ==
'true') {
620 $objtype =
'boolean';
623 } elseif (substr($this->pdfdata, $offset, 5) ==
'false') {
625 $objtype =
'boolean';
628 } elseif (substr($this->pdfdata, $offset, 6) ==
'stream') {
632 if (preg_match(
'/^([\r]?[\n])/isU', substr($this->pdfdata, $offset), $matches) == 1) {
633 $offset += strlen($matches[0]);
634 if (preg_match(
'/(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) {
635 $objval = substr($this->pdfdata, $offset, $matches[0][1]);
636 $offset += $matches[1][1];
639 } elseif (substr($this->pdfdata, $offset, 9) ==
'endstream') {
641 $objtype =
'endstream';
643 } elseif (preg_match(
'/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
646 $offset += strlen($matches[0]);
647 $objval = intval($matches[1]).
'_'.intval($matches[2]);
648 } elseif (preg_match(
'/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
651 $objval = intval($matches[1]).
'_'.intval($matches[2]);
652 $offset += strlen ($matches[0]);
653 } elseif (($numlen = strspn($this->pdfdata,
'+-.0123456789', $offset)) > 0) {
655 $objtype =
'numeric';
656 $objval = substr($this->pdfdata, $offset, $numlen);
662 return array($objtype, $objval, $offset);
675 $obj = explode(
'_', $obj_ref);
676 if (($obj ===
false) OR (count($obj) != 2)) {
677 $this->
Error(
'Invalid object reference: '.$obj);
680 $objref = $obj[0].
' '.$obj[1].
' obj';
682 $offset += strspn($this->pdfdata,
'0', $offset);
683 if (strpos($this->pdfdata, $objref, $offset) != $offset) {
685 return array(
'null',
'null', $offset);
688 $offset += strlen($objref);
695 $offset = $element[2];
697 if ($decoding AND ($element[0] ==
'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] ==
'<<')) {
698 $element[3] = $this->
decodeStream($objdata[($i - 1)][1], $element[1]);
700 $objdata[$i] = $element;
702 }
while ($element[0] !=
'endobj');
717 if ($obj[0] ==
'objref') {
719 if (isset($this->objects[$obj[1]])) {
721 return $this->objects[$obj[1]];
722 } elseif (isset($this->xref[$obj[1]])) {
724 $this->objects[$obj[1]] = $this->
getIndirectObject($obj[1], $this->xref[$obj[1]],
false);
725 return $this->objects[$obj[1]];
741 $slength = strlen($stream);
743 return array(
'', array());
746 foreach ($sdic as $k => $v) {
748 if (($v[1] ==
'Length') AND (isset($sdic[($k + 1)])) AND ($sdic[($k + 1)][0] ==
'numeric')) {
750 $declength = intval($sdic[($k + 1)][1]);
751 if ($declength < $slength) {
752 $stream = substr($stream, 0, $declength);
753 $slength = $declength;
755 } elseif (($v[1] ==
'Filter') AND (isset($sdic[($k + 1)]))) {
758 if ($objval[0] ==
'/') {
760 $filters[] = $objval[1];
761 } elseif ($objval[0] ==
'[') {
763 foreach ($objval[1] as $flt) {
764 if ($flt[0] ==
'/') {
765 $filters[] = $flt[1];
773 $remaining_filters = array();
774 foreach ($filters as $filter) {
778 }
catch (Exception $e) {
779 $emsg = $e->getMessage();
780 if ((($emsg[0] ==
'~') AND !$this->cfg[
'ignore_missing_filter_decoders'])
781 OR (($emsg[0] !=
'~') AND !$this->cfg[
'ignore_filter_decoding_errors'])) {
782 $this->
Error($e->getMessage());
787 $remaining_filters[] = $filter;
790 return array($stream, $remaining_filters);
800 if ($this->cfg[
'die_for_errors']) {
801 die(
'<strong>TCPDF_PARSER ERROR: </strong>'.$msg);
803 throw new Exception(
'TCPDF_PARSER ERROR: '.$msg);