File indexing completed on 2025-01-19 05:21:21
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Pdf 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 0023 /** Internally used classes */ 0024 // require_once 'Zend/Pdf/Element/Stream.php'; 0025 // require_once 'Zend/Pdf/Element/Dictionary.php'; 0026 // require_once 'Zend/Pdf/Element/Numeric.php'; 0027 0028 0029 /** Zend_Pdf_Element_Object */ 0030 // require_once 'Zend/Pdf/Element/Object.php'; 0031 0032 /** 0033 * PDF file 'stream object' element implementation 0034 * 0035 * @category Zend 0036 * @package Zend_Pdf 0037 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0038 * @license http://framework.zend.com/license/new-bsd New BSD License 0039 */ 0040 class Zend_Pdf_Element_Object_Stream extends Zend_Pdf_Element_Object 0041 { 0042 /** 0043 * StreamObject dictionary 0044 * Required enries: 0045 * Length 0046 * 0047 * @var Zend_Pdf_Element_Dictionary 0048 */ 0049 private $_dictionary; 0050 0051 /** 0052 * Flag which signals, that stream is decoded 0053 * 0054 * @var boolean 0055 */ 0056 private $_streamDecoded; 0057 0058 /** 0059 * Stored original stream object dictionary. 0060 * Used to decode stream at access time. 0061 * 0062 * The only properties affecting decoding are sored here. 0063 * 0064 * @var array|null 0065 */ 0066 private $_initialDictionaryData = null; 0067 0068 /** 0069 * Object constructor 0070 * 0071 * @param mixed $val 0072 * @param integer $objNum 0073 * @param integer $genNum 0074 * @param Zend_Pdf_ElementFactory $factory 0075 * @param Zend_Pdf_Element_Dictionary|null $dictionary 0076 * @throws Zend_Pdf_Exception 0077 */ 0078 public function __construct($val, $objNum, $genNum, Zend_Pdf_ElementFactory $factory, $dictionary = null) 0079 { 0080 parent::__construct(new Zend_Pdf_Element_Stream($val), $objNum, $genNum, $factory); 0081 0082 if ($dictionary === null) { 0083 $this->_dictionary = new Zend_Pdf_Element_Dictionary(); 0084 $this->_dictionary->Length = new Zend_Pdf_Element_Numeric(strlen( $val )); 0085 $this->_streamDecoded = true; 0086 } else { 0087 $this->_dictionary = $dictionary; 0088 $this->_streamDecoded = false; 0089 } 0090 } 0091 0092 0093 /** 0094 * Extract dictionary data which are used to store information and to normalize filters 0095 * information before defiltering. 0096 * 0097 * @return array 0098 */ 0099 private function _extractDictionaryData() 0100 { 0101 $dictionaryArray = array(); 0102 0103 $dictionaryArray['Filter'] = array(); 0104 $dictionaryArray['DecodeParms'] = array(); 0105 if ($this->_dictionary->Filter === null) { 0106 // Do nothing. 0107 } else if ($this->_dictionary->Filter->getType() == Zend_Pdf_Element::TYPE_ARRAY) { 0108 foreach ($this->_dictionary->Filter->items as $id => $filter) { 0109 $dictionaryArray['Filter'][$id] = $filter->value; 0110 $dictionaryArray['DecodeParms'][$id] = array(); 0111 0112 if ($this->_dictionary->DecodeParms !== null ) { 0113 if ($this->_dictionary->DecodeParms->items[$id] !== null && 0114 $this->_dictionary->DecodeParms->items[$id]->value !== null ) { 0115 foreach ($this->_dictionary->DecodeParms->items[$id]->getKeys() as $paramKey) { 0116 $dictionaryArray['DecodeParms'][$id][$paramKey] = 0117 $this->_dictionary->DecodeParms->items[$id]->$paramKey->value; 0118 } 0119 } 0120 } 0121 } 0122 } else if ($this->_dictionary->Filter->getType() != Zend_Pdf_Element::TYPE_NULL) { 0123 $dictionaryArray['Filter'][0] = $this->_dictionary->Filter->value; 0124 $dictionaryArray['DecodeParms'][0] = array(); 0125 if ($this->_dictionary->DecodeParms !== null ) { 0126 foreach ($this->_dictionary->DecodeParms->getKeys() as $paramKey) { 0127 $dictionaryArray['DecodeParms'][0][$paramKey] = 0128 $this->_dictionary->DecodeParms->$paramKey->value; 0129 } 0130 } 0131 } 0132 0133 if ($this->_dictionary->F !== null) { 0134 $dictionaryArray['F'] = $this->_dictionary->F->value; 0135 } 0136 0137 $dictionaryArray['FFilter'] = array(); 0138 $dictionaryArray['FDecodeParms'] = array(); 0139 if ($this->_dictionary->FFilter === null) { 0140 // Do nothing. 0141 } else if ($this->_dictionary->FFilter->getType() == Zend_Pdf_Element::TYPE_ARRAY) { 0142 foreach ($this->_dictionary->FFilter->items as $id => $filter) { 0143 $dictionaryArray['FFilter'][$id] = $filter->value; 0144 $dictionaryArray['FDecodeParms'][$id] = array(); 0145 0146 if ($this->_dictionary->FDecodeParms !== null ) { 0147 if ($this->_dictionary->FDecodeParms->items[$id] !== null && 0148 $this->_dictionary->FDecodeParms->items[$id]->value !== null) { 0149 foreach ($this->_dictionary->FDecodeParms->items[$id]->getKeys() as $paramKey) { 0150 $dictionaryArray['FDecodeParms'][$id][$paramKey] = 0151 $this->_dictionary->FDecodeParms->items[$id]->items[$paramKey]->value; 0152 } 0153 } 0154 } 0155 } 0156 } else { 0157 $dictionaryArray['FFilter'][0] = $this->_dictionary->FFilter->value; 0158 $dictionaryArray['FDecodeParms'][0] = array(); 0159 if ($this->_dictionary->FDecodeParms !== null ) { 0160 foreach ($this->_dictionary->FDecodeParms->getKeys() as $paramKey) { 0161 $dictionaryArray['FDecodeParms'][0][$paramKey] = 0162 $this->_dictionary->FDecodeParms->items[$paramKey]->value; 0163 } 0164 } 0165 } 0166 0167 return $dictionaryArray; 0168 } 0169 0170 /** 0171 * Decode stream 0172 * 0173 * @throws Zend_Pdf_Exception 0174 */ 0175 private function _decodeStream() 0176 { 0177 if ($this->_initialDictionaryData === null) { 0178 $this->_initialDictionaryData = $this->_extractDictionaryData(); 0179 } 0180 0181 /** 0182 * All applied stream filters must be processed to decode stream. 0183 * If we don't recognize any of applied filetrs an exception should be thrown here 0184 */ 0185 if (isset($this->_initialDictionaryData['F'])) { 0186 /** @todo Check, how external files can be processed. */ 0187 // require_once 'Zend/Pdf/Exception.php'; 0188 throw new Zend_Pdf_Exception('External filters are not supported now.'); 0189 } 0190 0191 foreach ($this->_initialDictionaryData['Filter'] as $id => $filterName ) { 0192 $valueRef = &$this->_value->value->getRef(); 0193 $this->_value->value->touch(); 0194 switch ($filterName) { 0195 case 'ASCIIHexDecode': 0196 // require_once 'Zend/Pdf/Filter/AsciiHex.php'; 0197 $valueRef = Zend_Pdf_Filter_AsciiHex::decode($valueRef); 0198 break; 0199 0200 case 'ASCII85Decode': 0201 // require_once 'Zend/Pdf/Filter/Ascii85.php'; 0202 $valueRef = Zend_Pdf_Filter_Ascii85::decode($valueRef); 0203 break; 0204 0205 case 'FlateDecode': 0206 // require_once 'Zend/Pdf/Filter/Compression/Flate.php'; 0207 $valueRef = Zend_Pdf_Filter_Compression_Flate::decode($valueRef, 0208 $this->_initialDictionaryData['DecodeParms'][$id]); 0209 break; 0210 0211 case 'LZWDecode': 0212 // require_once 'Zend/Pdf/Filter/Compression/Lzw.php'; 0213 $valueRef = Zend_Pdf_Filter_Compression_Lzw::decode($valueRef, 0214 $this->_initialDictionaryData['DecodeParms'][$id]); 0215 break; 0216 0217 case 'RunLengthDecode': 0218 // require_once 'Zend/Pdf/Filter/RunLength.php'; 0219 $valueRef = Zend_Pdf_Filter_RunLength::decode($valueRef); 0220 break; 0221 0222 default: 0223 // require_once 'Zend/Pdf/Exception.php'; 0224 throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.'); 0225 } 0226 } 0227 0228 $this->_streamDecoded = true; 0229 } 0230 0231 /** 0232 * Encode stream 0233 * 0234 * @throws Zend_Pdf_Exception 0235 */ 0236 private function _encodeStream() 0237 { 0238 /** 0239 * All applied stream filters must be processed to encode stream. 0240 * If we don't recognize any of applied filetrs an exception should be thrown here 0241 */ 0242 if (isset($this->_initialDictionaryData['F'])) { 0243 /** @todo Check, how external files can be processed. */ 0244 // require_once 'Zend/Pdf/Exception.php'; 0245 throw new Zend_Pdf_Exception('External filters are not supported now.'); 0246 } 0247 0248 $filters = array_reverse($this->_initialDictionaryData['Filter'], true); 0249 0250 foreach ($filters as $id => $filterName ) { 0251 $valueRef = &$this->_value->value->getRef(); 0252 $this->_value->value->touch(); 0253 switch ($filterName) { 0254 case 'ASCIIHexDecode': 0255 // require_once 'Zend/Pdf/Filter/AsciiHex.php'; 0256 $valueRef = Zend_Pdf_Filter_AsciiHex::encode($valueRef); 0257 break; 0258 0259 case 'ASCII85Decode': 0260 // require_once 'Zend/Pdf/Filter/Ascii85.php'; 0261 $valueRef = Zend_Pdf_Filter_Ascii85::encode($valueRef); 0262 break; 0263 0264 case 'FlateDecode': 0265 // require_once 'Zend/Pdf/Filter/Compression/Flate.php'; 0266 $valueRef = Zend_Pdf_Filter_Compression_Flate::encode($valueRef, 0267 $this->_initialDictionaryData['DecodeParms'][$id]); 0268 break; 0269 0270 case 'LZWDecode': 0271 // require_once 'Zend/Pdf/Filter/Compression/Lzw.php'; 0272 $valueRef = Zend_Pdf_Filter_Compression_Lzw::encode($valueRef, 0273 $this->_initialDictionaryData['DecodeParms'][$id]); 0274 break; 0275 0276 case 'RunLengthDecode': 0277 // require_once 'Zend/Pdf/Filter/RunLength.php'; 0278 $valueRef = Zend_Pdf_Filter_RunLength::encode($valueRef); 0279 break; 0280 0281 default: 0282 // require_once 'Zend/Pdf/Exception.php'; 0283 throw new Zend_Pdf_Exception('Unknown stream filter: \'' . $filterName . '\'.'); 0284 } 0285 } 0286 0287 $this->_streamDecoded = false; 0288 } 0289 0290 /** 0291 * Get handler 0292 * 0293 * @param string $property 0294 * @return mixed 0295 * @throws Zend_Pdf_Exception 0296 */ 0297 public function __get($property) 0298 { 0299 if ($property == 'dictionary') { 0300 /** 0301 * If stream is not decoded yet, then store original decoding options (do it only once). 0302 */ 0303 if (( !$this->_streamDecoded ) && ($this->_initialDictionaryData === null)) { 0304 $this->_initialDictionaryData = $this->_extractDictionaryData(); 0305 } 0306 0307 return $this->_dictionary; 0308 } 0309 0310 if ($property == 'value') { 0311 if (!$this->_streamDecoded) { 0312 $this->_decodeStream(); 0313 } 0314 0315 return $this->_value->value->getRef(); 0316 } 0317 0318 // require_once 'Zend/Pdf/Exception.php'; 0319 throw new Zend_Pdf_Exception('Unknown stream object property requested.'); 0320 } 0321 0322 0323 /** 0324 * Set handler 0325 * 0326 * @param string $property 0327 * @param mixed $value 0328 */ 0329 public function __set($property, $value) 0330 { 0331 if ($property == 'value') { 0332 $valueRef = &$this->_value->value->getRef(); 0333 $valueRef = $value; 0334 $this->_value->value->touch(); 0335 0336 $this->_streamDecoded = true; 0337 0338 return; 0339 } 0340 0341 // require_once 'Zend/Pdf/Exception.php'; 0342 throw new Zend_Pdf_Exception('Unknown stream object property: \'' . $property . '\'.'); 0343 } 0344 0345 0346 /** 0347 * Treat stream data as already encoded 0348 */ 0349 public function skipFilters() 0350 { 0351 $this->_streamDecoded = false; 0352 } 0353 0354 0355 /** 0356 * Call handler 0357 * 0358 * @param string $method 0359 * @param array $args 0360 * @return mixed 0361 */ 0362 public function __call($method, $args) 0363 { 0364 if (!$this->_streamDecoded) { 0365 $this->_decodeStream(); 0366 } 0367 0368 switch (count($args)) { 0369 case 0: 0370 return $this->_value->$method(); 0371 case 1: 0372 return $this->_value->$method($args[0]); 0373 default: 0374 // require_once 'Zend/Pdf/Exception.php'; 0375 throw new Zend_Pdf_Exception('Unsupported number of arguments'); 0376 } 0377 } 0378 0379 /** 0380 * Detach PDF object from the factory (if applicable), clone it and attach to new factory. 0381 * 0382 * @param Zend_Pdf_ElementFactory $factory The factory to attach 0383 * @param array &$processed List of already processed indirect objects, used to avoid objects duplication 0384 * @param integer $mode Cloning mode (defines filter for objects cloning) 0385 * @returns Zend_Pdf_Element 0386 */ 0387 public function makeClone(Zend_Pdf_ElementFactory $factory, array &$processed, $mode) 0388 { 0389 $id = spl_object_hash($this); 0390 if (isset($processed[$id])) { 0391 // Do nothing if object is already processed 0392 // return it 0393 return $processed[$id]; 0394 } 0395 0396 $streamValue = $this->_value; 0397 $streamDictionary = $this->_dictionary->makeClone($factory, $processed, $mode); 0398 0399 // Make new empty instance of stream object and register it in $processed container 0400 $processed[$id] = $clonedObject = $factory->newStreamObject(''); 0401 0402 // Copy current object data and state 0403 $clonedObject->_dictionary = $this->_dictionary->makeClone($factory, $processed, $mode); 0404 $clonedObject->_value = $this->_value->makeClone($factory, $processed, $mode); 0405 $clonedObject->_initialDictionaryData = $this->_initialDictionaryData; 0406 $clonedObject->_streamDecoded = $this->_streamDecoded; 0407 0408 return $clonedObject; 0409 } 0410 0411 /** 0412 * Dump object to a string to save within PDF file 0413 * 0414 * $factory parameter defines operation context. 0415 * 0416 * @param Zend_Pdf_ElementFactory $factory 0417 * @return string 0418 */ 0419 public function dump(Zend_Pdf_ElementFactory $factory) 0420 { 0421 $shift = $factory->getEnumerationShift($this->_factory); 0422 0423 if ($this->_streamDecoded) { 0424 $this->_initialDictionaryData = $this->_extractDictionaryData(); 0425 $this->_encodeStream(); 0426 } else if ($this->_initialDictionaryData != null) { 0427 $newDictionary = $this->_extractDictionaryData(); 0428 0429 if ($this->_initialDictionaryData !== $newDictionary) { 0430 $this->_decodeStream(); 0431 $this->_initialDictionaryData = $newDictionary; 0432 $this->_encodeStream(); 0433 } 0434 } 0435 0436 // Update stream length 0437 $this->dictionary->Length->value = $this->_value->length(); 0438 0439 return $this->_objNum + $shift . " " . $this->_genNum . " obj \n" 0440 . $this->dictionary->toString($factory) . "\n" 0441 . $this->_value->toString($factory) . "\n" 0442 . "endobj\n"; 0443 } 0444 0445 /** 0446 * Clean up resources, used by object 0447 */ 0448 public function cleanUp() 0449 { 0450 $this->_dictionary = null; 0451 $this->_value = null; 0452 } 0453 }