+++ /dev/null
-<?php
-//
-// FPDI - Version 1.2
-//
-// Copyright 2004-2007 Setasign - Jan Slabon
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-if (!defined ('PDF_TYPE_NULL'))
- define ('PDF_TYPE_NULL', 0);
-if (!defined ('PDF_TYPE_NUMERIC'))
- define ('PDF_TYPE_NUMERIC', 1);
-if (!defined ('PDF_TYPE_TOKEN'))
- define ('PDF_TYPE_TOKEN', 2);
-if (!defined ('PDF_TYPE_HEX'))
- define ('PDF_TYPE_HEX', 3);
-if (!defined ('PDF_TYPE_STRING'))
- define ('PDF_TYPE_STRING', 4);
-if (!defined ('PDF_TYPE_DICTIONARY'))
- define ('PDF_TYPE_DICTIONARY', 5);
-if (!defined ('PDF_TYPE_ARRAY'))
- define ('PDF_TYPE_ARRAY', 6);
-if (!defined ('PDF_TYPE_OBJDEC'))
- define ('PDF_TYPE_OBJDEC', 7);
-if (!defined ('PDF_TYPE_OBJREF'))
- define ('PDF_TYPE_OBJREF', 8);
-if (!defined ('PDF_TYPE_OBJECT'))
- define ('PDF_TYPE_OBJECT', 9);
-if (!defined ('PDF_TYPE_STREAM'))
- define ('PDF_TYPE_STREAM', 10);
-
-
-class pdf_parser {
-
- /**
- * Filename
- * @var string
- */
- var $filename;
-
- /**
- * File resource
- * @var resource
- */
- var $f;
-
- /**
- * PDF Context
- * @var object pdf_context-Instance
- */
- var $c;
-
- /**
- * xref-Data
- * @var array
- */
- var $xref;
-
- /**
- * root-Object
- * @var array
- */
- var $root;
-
- // mPDF 4.0 Added flag to show success on loading file
- var $success;
- var $errormsg;
-
- /**
- * Constructor
- *
- * @param string $filename Source-Filename
- */
- function pdf_parser($filename) {
- $this->filename = $filename;
- // mPDF 4.0
- $this->success = true;
-
- $this->f = @fopen($this->filename, "rb");
-
- if (!$this->f) {
- $this->success = false;
- $this->errormsg = sprintf("Cannot open %s !", $filename);
- return false;
- }
- // mPDF 5.0 Removed pass by reference =&
- $this->c = new pdf_context($this->f);
- // Read xref-Data
- $offset = $this->pdf_find_xref();
- if ($offset===false) {
- $this->success = false;
- $this->errormsg = sprintf("Cannot open %s !", $filename);
- return false;
- }
- $this->pdf_read_xref($this->xref, $offset);
- if ($this->success == false) { return false; }
-
- // Check for Encryption
- $this->getEncryption();
- if ($this->success == false) { return false; }
-
- // Read root
- $this->pdf_read_root();
- if ($this->success == false) { return false; }
- }
-
- /**
- * Close the opened file
- */
- function closeFile() {
- if (isset($this->f)) {
- fclose($this->f);
- unset($this->f);
- }
- }
-
- /**
- * Print Error and die
- *
- * @param string $msg Error-Message
- */
- function error($msg) {
- die("<b>PDF-Parser Error:</b> ".$msg);
- }
-
- /**
- * Check Trailer for Encryption
- */
- function getEncryption() {
- if (isset($this->xref['trailer'][1]['/Encrypt'])) {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("File is encrypted!");
- return false;
- }
- }
-
- /**
- * Find/Return /Root
- *
- * @return array
- */
- function pdf_find_root() {
- if ($this->xref['trailer'][1]['/Root'][0] != PDF_TYPE_OBJREF) {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("Wrong Type of Root-Element! Must be an indirect reference");
- return false;
- }
- return $this->xref['trailer'][1]['/Root'];
- }
-
- /**
- * Read the /Root
- */
- function pdf_read_root() {
- // read root
- $root = $this->pdf_find_root();
- if ($root ===false) {
- $this->success = false;
- return false;
- }
- $this->root = $this->pdf_resolve_object($this->c, $root);
- }
-
- /**
- * Find the xref-Table
- */
- function pdf_find_xref() {
- fseek ($this->f, -min(filesize($this->filename),1500), SEEK_END);
- $data = fread($this->f, 1500);
-
- $pos = strlen($data) - strpos(strrev($data), strrev('startxref'));
- $data = substr($data, $pos);
-
- if (!preg_match('/\s*(\d+).*$/s', $data, $matches)) {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("Unable to find pointer to xref table");
- return false;
- }
-
- return (int) $matches[1];
- }
-
- /**
- * Read xref-table
- *
- * @param array $result Array of xref-table
- * @param integer $offset of xref-table
- * @param integer $start start-position in xref-table
- * @param integer $end end-position in xref-table
- */
- function pdf_read_xref(&$result, $offset, $start = null, $end = null) {
- if (is_null ($start) || is_null ($end)) {
- fseek($this->f, $o_pos = $offset);
- $data = trim(fgets($this->f,1024));
-
- if (strlen($data) == 0)
- $data = trim(fgets($this->f,1024));
-
- if ($data !== 'xref') {
- fseek($this->f, $o_pos);
- $data = trim(_fgets($this->f, true));
- if ($data !== 'xref') {
- if (preg_match('/(.*xref)(.*)/m', $data, $m)) { // xref 0 128 - in one line
- fseek($this->f, $o_pos+strlen($m[1]));
- } elseif (preg_match('/(x|r|e|f)+/', $data, $m)) { // correct invalid xref-pointer
- $tmpOffset = $offset-4+strlen($m[0]);
- $this->pdf_read_xref($result, $tmpOffset, $start, $end);
- return;
- } else {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("Unable to find xref table - Maybe a Problem with 'auto_detect_line_endings'");
- return;
- }
- }
- }
-
- $o_pos = ftell($this->f);
- $data = explode(' ', trim(fgets($this->f,1024)));
- if (count($data) != 2) {
- fseek($this->f, $o_pos);
- $data = explode(' ', trim(_fgets($this->f, true)));
-
- if (count($data) != 2) {
- if (count($data) > 2) { // no lineending
- $n_pos = $o_pos+strlen($data[0])+strlen($data[1])+2;
- fseek($this->f, $n_pos);
- } else {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("Unexpected header in xref table");
- return;
- }
- }
- }
- $start = $data[0];
- $end = $start + $data[1];
- }
-
- if (!isset($result['xref_location'])) {
- $result['xref_location'] = $offset;
- }
-
- if (!isset($result['max_object']) || $end > $result['max_object']) {
- $result['max_object'] = $end;
- }
-
- for (; $start < $end; $start++) {
- $data = ltrim(fread($this->f, 20)); // Spezifications says: 20 bytes including newlines
- $offset = substr($data, 0, 10);
- $generation = substr($data, 11, 5);
-
- if (!isset ($result['xref'][$start][(int) $generation])) {
- $result['xref'][$start][(int) $generation] = (int) $offset;
- }
- }
-
- $o_pos = ftell($this->f);
- $data = fgets($this->f,1024);
- if (strlen(trim($data)) == 0)
- $data = fgets($this->f, 1024);
-
- if (preg_match("/trailer/",$data)) {
- if (preg_match("/(.*trailer[ \n\r]*)/",$data,$m)) {
- fseek($this->f, $o_pos+strlen($m[1]));
- }
-
- // mPDF 5.0 Removed pass by reference =&
- $c = new pdf_context($this->f);
- $trailer = $this->pdf_read_value($c);
-
- if (isset($trailer[1]['/Prev'])) {
- $this->pdf_read_xref($result, $trailer[1]['/Prev'][1]);
- $result['trailer'][1] = array_merge($result['trailer'][1], $trailer[1]);
- } else {
- $result['trailer'] = $trailer;
- }
- } else {
- $data = explode(' ', trim($data));
-
- if (count($data) != 2) {
- fseek($this->f, $o_pos);
- $data = explode(' ', trim (_fgets ($this->f, true)));
-
- if (count($data) != 2) {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("Unexpected data in xref table");
- return;
- }
- }
-
- $this->pdf_read_xref($result, null, (int) $data[0], (int) $data[0] + (int) $data[1]);
- }
- }
-
-
- /**
- * Reads an Value
- *
- * @param object $c pdf_context
- * @param string $token a Token
- * @return mixed
- */
- function pdf_read_value(&$c, $token = null) {
- if (is_null($token)) {
- $token = $this->pdf_read_token($c);
- }
-
- if ($token === false) {
- return false;
- }
-
- switch ($token) {
- case '<':
- // This is a hex string.
- // Read the value, then the terminator
-
- $pos = $c->offset;
-
- while(1) {
-
- $match = strpos ($c->buffer, '>', $pos);
-
- // If you can't find it, try
- // reading more data from the stream
-
- if ($match === false) {
- if (!$c->increase_length()) {
- return false;
- } else {
- continue;
- }
- }
-
- $result = substr ($c->buffer, $c->offset, $match - $c->offset);
- $c->offset = $match+1;
-
- return array (PDF_TYPE_HEX, $result);
- }
-
- break;
- case '<<':
- // This is a dictionary.
-
- $result = array();
-
- // Recurse into this function until we reach
- // the end of the dictionary.
- while (($key = $this->pdf_read_token($c)) !== '>>') {
- if ($key === false) {
- return false;
- }
-
- if (($value = $this->pdf_read_value($c)) === false) {
- return false;
- }
- $result[$key] = $value;
- }
-
- return array (PDF_TYPE_DICTIONARY, $result);
-
- case '[':
- // This is an array.
-
- $result = array();
-
- // Recurse into this function until we reach
- // the end of the array.
- while (($token = $this->pdf_read_token($c)) !== ']') {
- if ($token === false) {
- return false;
- }
-
- if (($value = $this->pdf_read_value($c, $token)) === false) {
- return false;
- }
-
- $result[] = $value;
- }
-
- return array (PDF_TYPE_ARRAY, $result);
-
- case '(' :
- // This is a string
-
- $pos = $c->offset;
-
- while(1) {
-
- // Start by finding the next closed
- // parenthesis
-
- $match = strpos ($c->buffer, ')', $pos);
-
- // If you can't find it, try
- // reading more data from the stream
-
- if ($match === false) {
- if (!$c->increase_length()) {
- return false;
- } else {
- continue;
- }
- }
-
- // Make sure that there is no backslash
- // before the parenthesis. If there is,
- // move on. Otherwise, return the string.
- $esc = preg_match('/([\\\\]+)$/', $tmpresult = substr($c->buffer, $c->offset, $match - $c->offset), $m);
-
- if ($esc === 0 || strlen($m[1]) % 2 == 0) {
- $result = $tmpresult;
- $c->offset = $match + 1;
- return array (PDF_TYPE_STRING, $result);
- } else {
- $pos = $match + 1;
-
- if ($pos > $c->offset + $c->length) {
- $c->increase_length();
- }
- }
- }
-
- case "stream":
- $o_pos = ftell($c->file)-strlen($c->buffer);
- $o_offset = $c->offset;
-
- $c->reset($startpos = $o_pos + $o_offset);
-
- $e = 0; // ensure line breaks in front of the stream
- if ($c->buffer[0] == chr(10) || $c->buffer[0] == chr(13))
- $e++;
- if ($c->buffer[1] == chr(10) && $c->buffer[0] != chr(10))
- $e++;
-
- if ($this->actual_obj[1][1]['/Length'][0] == PDF_TYPE_OBJREF) {
- // mPDF 5.0 Removed pass by reference =&
- $tmp_c = new pdf_context($this->f);
- $tmp_length = $this->pdf_resolve_object($tmp_c,$this->actual_obj[1][1]['/Length']);
- $length = $tmp_length[1][1];
- } else {
- $length = $this->actual_obj[1][1]['/Length'][1];
- }
-
- if ($length > 0) {
- $c->reset($startpos+$e,$length);
- $v = $c->buffer;
- } else {
- $v = '';
- }
- $c->reset($startpos+$e+$length+9); // 9 = strlen("endstream")
-
- return array(PDF_TYPE_STREAM, $v);
-
- default :
- if (is_numeric ($token)) {
- // A numeric token. Make sure that
- // it is not part of something else.
- if (($tok2 = $this->pdf_read_token ($c)) !== false) {
- if (is_numeric ($tok2)) {
-
- // Two numeric tokens in a row.
- // In this case, we're probably in
- // front of either an object reference
- // or an object specification.
- // Determine the case and return the data
- if (($tok3 = $this->pdf_read_token ($c)) !== false) {
- switch ($tok3) {
- case 'obj' :
- return array (PDF_TYPE_OBJDEC, (int) $token, (int) $tok2);
- case 'R' :
- return array (PDF_TYPE_OBJREF, (int) $token, (int) $tok2);
- }
- // If we get to this point, that numeric value up
- // there was just a numeric value. Push the extra
- // tokens back into the stack and return the value.
- array_push ($c->stack, $tok3);
- }
- }
-
- array_push ($c->stack, $tok2);
- }
-
- return array (PDF_TYPE_NUMERIC, $token);
- } else {
-
- // Just a token. Return it.
- return array (PDF_TYPE_TOKEN, $token);
- }
-
- }
- }
-
- /**
- * Resolve an object
- *
- * @param object $c pdf_context
- * @param array $obj_spec The object-data
- * @param boolean $encapsulate Must set to true, cause the parsing and fpdi use this method only without this para
- */
- function pdf_resolve_object(&$c, $obj_spec, $encapsulate = true) {
- // Exit if we get invalid data
- if (!is_array($obj_spec)) {
- return false;
- }
-
- if ($obj_spec[0] == PDF_TYPE_OBJREF) {
-
- // This is a reference, resolve it
- if (isset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]])) {
-
- // Save current file position
- // This is needed if you want to resolve
- // references while you're reading another object
- // (e.g.: if you need to determine the length
- // of a stream)
-
- $old_pos = ftell($c->file);
-
- // Reposition the file pointer and
- // load the object header.
-
- $c->reset($this->xref['xref'][$obj_spec[1]][$obj_spec[2]]);
-
- $header = $this->pdf_read_value($c,null,true);
-
- if ($header[0] != PDF_TYPE_OBJDEC || $header[1] != $obj_spec[1] || $header[2] != $obj_spec[2]) {
- // mPDF 4.0
- $this->success = false;
- $this->errormsg = sprintf("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location");
- return false;
- }
-
- // If we're being asked to store all the information
- // about the object, we add the object ID and generation
- // number for later use
- $this->actual_obj =& $result;
- if ($encapsulate) {
- $result = array (
- PDF_TYPE_OBJECT,
- 'obj' => $obj_spec[1],
- 'gen' => $obj_spec[2]
- );
- } else {
- $result = array();
- }
-
- // Now simply read the object data until
- // we encounter an end-of-object marker
- while(1) {
- $value = $this->pdf_read_value($c);
- if ($value === false || count($result) > 4) {
- // in this case the parser coudn't find an endobj so we break here
- break;
- }
-
- if ($value[0] == PDF_TYPE_TOKEN && $value[1] === 'endobj') {
- break;
- }
-
- $result[] = $value;
- }
-
- $c->reset($old_pos);
-
- if (isset($result[2][0]) && $result[2][0] == PDF_TYPE_STREAM) {
- $result[0] = PDF_TYPE_STREAM;
- }
-
- return $result;
- }
- } else {
- return $obj_spec;
- }
- }
-
-
-
- /**
- * Reads a token from the file
- *
- * @param object $c pdf_context
- * @return mixed
- */
- function pdf_read_token(&$c)
- {
- // If there is a token available
- // on the stack, pop it out and
- // return it.
-
- if (count($c->stack)) {
- return array_pop($c->stack);
- }
-
- // Strip away any whitespace
-
- do {
- if (!$c->ensure_content()) {
- return false;
- }
- $c->offset += _strspn($c->buffer, " \n\r\t", $c->offset);
- } while ($c->offset >= $c->length - 1);
-
- // Get the first character in the stream
-
- $char = $c->buffer[$c->offset++];
-
- switch ($char) {
-
- case '[' :
- case ']' :
- case '(' :
- case ')' :
-
- // This is either an array or literal string
- // delimiter, Return it
-
- return $char;
-
- case '<' :
- case '>' :
-
- // This could either be a hex string or
- // dictionary delimiter. Determine the
- // appropriate case and return the token
-
- if ($c->buffer[$c->offset] == $char) {
- if (!$c->ensure_content()) {
- return false;
- }
- $c->offset++;
- return $char . $char;
- } else {
- return $char;
- }
-
- default :
-
- // This is "another" type of token (probably
- // a dictionary entry or a numeric value)
- // Find the end and return it.
-
- if (!$c->ensure_content()) {
- return false;
- }
-
- while(1) {
-
- // Determine the length of the token
-
- $pos = _strcspn($c->buffer, " []<>()\r\n\t/", $c->offset);
- if ($c->offset + $pos <= $c->length - 1) {
- break;
- } else {
- // If the script reaches this point,
- // the token may span beyond the end
- // of the current buffer. Therefore,
- // we increase the size of the buffer
- // and try again--just to be safe.
-
- $c->increase_length();
- }
- }
-
- $result = substr($c->buffer, $c->offset - 1, $pos + 1);
-
- $c->offset += $pos;
- return $result;
- }
- }
-
-
-}
-
-?>
\ No newline at end of file