File indexing completed on 2024-12-22 05:36:56

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  * @subpackage Fonts
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * Abstract helper class for {@link Zend_Pdf_Resource_Font} which manages font
0026  * character maps.
0027  *
0028  * Defines the public interface for concrete subclasses which are responsible
0029  * for mapping Unicode characters to the font's glyph numbers. Also provides
0030  * shared utility methods.
0031  *
0032  * Cmap objects should ordinarily be obtained through the factory method
0033  * {@link cmapWithTypeData()}.
0034  *
0035  * The supported character map types are those found in the OpenType spec. For
0036  * additional detail on the internal binary format of these tables, see:
0037  * <ul>
0038  *  <li>{@link http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6cmap.html}
0039  *  <li>{@link http://www.microsoft.com/OpenType/OTSpec/cmap.htm}
0040  *  <li>{@link http://partners.adobe.com/public/developer/opentype/index_cmap.html}
0041  * </ul>
0042  *
0043  * @todo Write code for Zend_Pdf_FontCmap_HighByteMapping class.
0044  * @todo Write code for Zend_Pdf_FontCmap_MixedCoverage class.
0045  * @todo Write code for Zend_Pdf_FontCmap_TrimmedArray class.
0046  * @todo Write code for Zend_Pdf_FontCmap_SegmentedCoverage class.
0047  *
0048  * @package    Zend_Pdf
0049  * @subpackage Fonts
0050  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0051  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0052  */
0053 abstract class Zend_Pdf_Cmap
0054 {
0055   /**** Class Constants ****/
0056 
0057 
0058   /* Cmap Table Types */
0059 
0060     /**
0061      * Byte Encoding character map table type.
0062      */
0063     const TYPE_BYTE_ENCODING = 0x00;
0064 
0065     /**
0066      * High Byte Mapping character map table type.
0067      */
0068     const TYPE_HIGH_BYTE_MAPPING = 0x02;
0069 
0070     /**
0071      * Segment Value to Delta Mapping character map table type.
0072      */
0073     const TYPE_SEGMENT_TO_DELTA = 0x04;
0074 
0075     /**
0076      * Trimmed Table character map table type.
0077      */
0078     const TYPE_TRIMMED_TABLE = 0x06;
0079 
0080     /**
0081      * Mixed Coverage character map table type.
0082      */
0083     const TYPE_MIXED_COVERAGE = 0x08;
0084 
0085     /**
0086      * Trimmed Array character map table type.
0087      */
0088     const TYPE_TRIMMED_ARRAY = 0x0a;
0089 
0090     /**
0091      * Segmented Coverage character map table type.
0092      */
0093     const TYPE_SEGMENTED_COVERAGE = 0x0c;
0094 
0095     /**
0096      * Static Byte Encoding character map table type. Variant of
0097      * {@link TYPE_BYTEENCODING}.
0098      */
0099     const TYPE_BYTE_ENCODING_STATIC = 0xf1;
0100 
0101     /**
0102      * Unknown character map table type.
0103      */
0104     const TYPE_UNKNOWN = 0xff;
0105 
0106 
0107   /* Special Glyph Names */
0108 
0109     /**
0110      * Glyph representing missing characters.
0111      */
0112     const MISSING_CHARACTER_GLYPH = 0x00;
0113 
0114 
0115 
0116   /**** Public Interface ****/
0117 
0118 
0119   /* Factory Methods */
0120 
0121     /**
0122      * Instantiates the appropriate concrete subclass based on the type of cmap
0123      * table and returns the instance.
0124      *
0125      * The cmap type must be one of the following values:
0126      * <ul>
0127      *  <li>{@link Zend_Pdf_Cmap::TYPE_BYTE_ENCODING}
0128      *  <li>{@link Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC}
0129      *  <li>{@link Zend_Pdf_Cmap::TYPE_HIGH_BYTE_MAPPING}
0130      *  <li>{@link Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA}
0131      *  <li>{@link Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE}
0132      *  <li>{@link Zend_Pdf_Cmap::TYPE_MIXED_COVERAGE}
0133      *  <li>{@link Zend_Pdf_Cmap::TYPE_TRIMMED_ARRAY}
0134      *  <li>{@link Zend_Pdf_Cmap::TYPE_SEGMENTED_COVERAGE}
0135      * </ul>
0136      *
0137      * Throws an exception if the table type is invalid or the cmap table data
0138      * cannot be validated.
0139      *
0140      * @param integer $cmapType Type of cmap.
0141      * @param mixed $cmapData Cmap table data. Usually a string or array.
0142      * @return Zend_Pdf_Cmap
0143      * @throws Zend_Pdf_Exception
0144      */
0145     public static function cmapWithTypeData($cmapType, $cmapData)
0146     {
0147         switch ($cmapType) {
0148             case Zend_Pdf_Cmap::TYPE_BYTE_ENCODING:
0149                 // require_once 'Zend/Pdf/Cmap/ByteEncoding.php';
0150                 return new Zend_Pdf_Cmap_ByteEncoding($cmapData);
0151 
0152             case Zend_Pdf_Cmap::TYPE_BYTE_ENCODING_STATIC:
0153                 // require_once 'Zend/Pdf/Cmap/ByteEncoding/Static.php';
0154                 return new Zend_Pdf_Cmap_ByteEncoding_Static($cmapData);
0155 
0156             case Zend_Pdf_Cmap::TYPE_HIGH_BYTE_MAPPING:
0157                 // require_once 'Zend/Pdf/Exception.php';
0158                 throw new Zend_Pdf_Exception('High byte mapping cmap currently unsupported',
0159                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
0160 
0161             case Zend_Pdf_Cmap::TYPE_SEGMENT_TO_DELTA:
0162                 // require_once 'Zend/Pdf/Cmap/SegmentToDelta.php';
0163                 return new Zend_Pdf_Cmap_SegmentToDelta($cmapData);
0164 
0165             case Zend_Pdf_Cmap::TYPE_TRIMMED_TABLE:
0166                 // require_once 'Zend/Pdf/Cmap/TrimmedTable.php';
0167                 return new Zend_Pdf_Cmap_TrimmedTable($cmapData);
0168 
0169             case Zend_Pdf_Cmap::TYPE_MIXED_COVERAGE:
0170                 // require_once 'Zend/Pdf/Exception.php';
0171                 throw new Zend_Pdf_Exception('Mixed coverage cmap currently unsupported',
0172                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
0173 
0174             case Zend_Pdf_Cmap::TYPE_TRIMMED_ARRAY:
0175                 // require_once 'Zend/Pdf/Exception.php';
0176                 throw new Zend_Pdf_Exception('Trimmed array cmap currently unsupported',
0177                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
0178 
0179             case Zend_Pdf_Cmap::TYPE_SEGMENTED_COVERAGE:
0180                 // require_once 'Zend/Pdf/Exception.php';
0181                 throw new Zend_Pdf_Exception('Segmented coverage cmap currently unsupported',
0182                                              Zend_Pdf_Exception::CMAP_TYPE_UNSUPPORTED);
0183 
0184             default:
0185                 // require_once 'Zend/Pdf/Exception.php';
0186                 throw new Zend_Pdf_Exception("Unknown cmap type: $cmapType",
0187                                              Zend_Pdf_Exception::CMAP_UNKNOWN_TYPE);
0188         }
0189     }
0190 
0191 
0192   /* Abstract Methods */
0193 
0194     /**
0195      * Object constructor
0196      *
0197      * Parses the raw binary table data. Throws an exception if the table is
0198      * malformed.
0199      *
0200      * @param string $cmapData Raw binary cmap table data.
0201      * @throws Zend_Pdf_Exception
0202      */
0203     abstract public function __construct($cmapData);
0204 
0205     /**
0206      * Returns an array of glyph numbers corresponding to the Unicode characters.
0207      *
0208      * If a particular character doesn't exist in this font, the special 'missing
0209      * character glyph' will be substituted.
0210      *
0211      * See also {@link glyphNumberForCharacter()}.
0212      *
0213      * @param array $characterCodes Array of Unicode character codes (code points).
0214      * @return array Array of glyph numbers.
0215      */
0216     abstract public function glyphNumbersForCharacters($characterCodes);
0217 
0218     /**
0219      * Returns the glyph number corresponding to the Unicode character.
0220      *
0221      * If a particular character doesn't exist in this font, the special 'missing
0222      * character glyph' will be substituted.
0223      *
0224      * See also {@link glyphNumbersForCharacters()} which is optimized for bulk
0225      * operations.
0226      *
0227      * @param integer $characterCode Unicode character code (code point).
0228      * @return integer Glyph number.
0229      */
0230     abstract public function glyphNumberForCharacter($characterCode);
0231 
0232     /**
0233      * Returns an array containing the Unicode characters that have entries in
0234      * this character map.
0235      *
0236      * @return array Unicode character codes.
0237      */
0238     abstract public function getCoveredCharacters();
0239 
0240     /**
0241      * Returns an array containing the glyphs numbers that have entries in this character map.
0242      * Keys are Unicode character codes (integers)
0243      *
0244      * This functionality is partially covered by glyphNumbersForCharacters(getCoveredCharacters())
0245      * call, but this method do it in more effective way (prepare complete list instead of searching
0246      * glyph for each character code).
0247      *
0248      * @internal
0249      * @return array Array representing <Unicode character code> => <glyph number> pairs.
0250      */
0251     abstract public function getCoveredCharactersGlyphs();
0252 
0253 
0254   /**** Internal Methods ****/
0255 
0256 
0257   /* Internal Utility Methods */
0258 
0259     /**
0260      * Extracts a signed 2-byte integer from a string.
0261      *
0262      * Integers are always big-endian. Throws an exception if the index is out
0263      * of range.
0264      *
0265      * @param string &$data
0266      * @param integer $index Position in string of integer.
0267      * @return integer
0268      * @throws Zend_Pdf_Exception
0269      */
0270     protected function _extractInt2(&$data, $index)
0271     {
0272         if (($index < 0) | (($index + 1) > strlen($data))) {
0273             // require_once 'Zend/Pdf/Exception.php';
0274             throw new Zend_Pdf_Exception("Index out of range: $index",
0275                                          Zend_Pdf_Exception::INDEX_OUT_OF_RANGE);
0276         }
0277         $number = ord($data[$index]);
0278         if (($number & 0x80) == 0x80) {    // negative
0279             $number = ~((((~ $number) & 0xff) << 8) | ((~ ord($data[++$index])) & 0xff));
0280         } else {
0281             $number = ($number << 8) | ord($data[++$index]);
0282         }
0283         return $number;
0284     }
0285 
0286     /**
0287      * Extracts an unsigned 2-byte integer from a string.
0288      *
0289      * Integers are always big-endian. Throws an exception if the index is out
0290      * of range.
0291      *
0292      * @param string &$data
0293      * @param integer $index Position in string of integer.
0294      * @return integer
0295      * @throws Zend_Pdf_Exception
0296      */
0297     protected function _extractUInt2(&$data, $index)
0298     {
0299         if (($index < 0) | (($index + 1) > strlen($data))) {
0300             // require_once 'Zend/Pdf/Exception.php';
0301             throw new Zend_Pdf_Exception("Index out of range: $index",
0302                                          Zend_Pdf_Exception::INDEX_OUT_OF_RANGE);
0303         }
0304         $number = (ord($data[$index]) << 8) | ord($data[++$index]);
0305         return $number;
0306     }
0307 
0308     /**
0309      * Extracts an unsigned 4-byte integer from a string.
0310      *
0311      * Integers are always big-endian. Throws an exception if the index is out
0312      * of range.
0313      *
0314      * NOTE: If you ask for a 4-byte unsigned integer on a 32-bit machine, the
0315      * resulting value WILL BE SIGNED because PHP uses signed integers internally
0316      * for everything. To guarantee portability, be sure to use bitwise or
0317      * similar operators on large integers!
0318      *
0319      * @param string &$data
0320      * @param integer $index Position in string of integer.
0321      * @return integer
0322      * @throws Zend_Pdf_Exception
0323      */
0324     protected function _extractUInt4(&$data, $index)
0325     {
0326         if (($index < 0) | (($index + 3) > strlen($data))) {
0327             // require_once 'Zend/Pdf/Exception.php';
0328             throw new Zend_Pdf_Exception("Index out of range: $index",
0329                                          Zend_Pdf_Exception::INDEX_OUT_OF_RANGE);
0330         }
0331         $number = (ord($data[$index]) << 24) | (ord($data[++$index]) << 16) |
0332                   (ord($data[++$index]) << 8) | ord($data[++$index]);
0333         return $number;
0334     }
0335 
0336 }