123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- <?php
- /**
- * @package php-font-lib
- * @link https://github.com/PhenX/php-font-lib
- * @author Fabien Ménager <fabien.menager@gmail.com>
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-
- namespace FontLib;
-
- /**
- * Generic font file binary stream.
- *
- * @package php-font-lib
- */
- class BinaryStream {
- /**
- * @var resource The file pointer
- */
- protected $f;
-
- const uint8 = 1;
- const int8 = 2;
- const uint16 = 3;
- const int16 = 4;
- const uint32 = 5;
- const int32 = 6;
- const shortFrac = 7;
- const Fixed = 8;
- const FWord = 9;
- const uFWord = 10;
- const F2Dot14 = 11;
- const longDateTime = 12;
- const char = 13;
-
- const modeRead = "rb";
- const modeWrite = "wb";
- const modeReadWrite = "rb+";
-
- static function backtrace() {
- var_dump(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
- }
-
- /**
- * Open a font file in read mode
- *
- * @param string $filename The file name of the font to open
- *
- * @return bool
- */
- public function load($filename) {
- return $this->open($filename, self::modeRead);
- }
-
- /**
- * Open a font file in a chosen mode
- *
- * @param string $filename The file name of the font to open
- * @param string $mode The opening mode
- *
- * @throws \Exception
- * @return bool
- */
- public function open($filename, $mode = self::modeRead) {
- if (!in_array($mode, array(self::modeRead, self::modeWrite, self::modeReadWrite))) {
- throw new \Exception("Unknown file open mode");
- }
-
- $this->f = fopen($filename, $mode);
-
- return $this->f != false;
- }
-
- /**
- * Close the internal file pointer
- */
- public function close() {
- return fclose($this->f) != false;
- }
-
- /**
- * Change the internal file pointer
- *
- * @param resource $fp
- *
- * @throws \Exception
- */
- public function setFile($fp) {
- if (!is_resource($fp)) {
- throw new \Exception('$fp is not a valid resource');
- }
-
- $this->f = $fp;
- }
-
- /**
- * Create a temporary file in write mode
- *
- * @param bool $allow_memory Allow in-memory files
- *
- * @return resource the temporary file pointer resource
- */
- public static function getTempFile($allow_memory = true) {
- $f = null;
-
- if ($allow_memory) {
- $f = fopen("php://temp", "rb+");
- }
- else {
- $f = fopen(tempnam(sys_get_temp_dir(), "fnt"), "rb+");
- }
-
- return $f;
- }
-
- /**
- * Move the internal file pinter to $offset bytes
- *
- * @param int $offset
- *
- * @return bool True if the $offset position exists in the file
- */
- public function seek($offset) {
- return fseek($this->f, $offset, SEEK_SET) == 0;
- }
-
- /**
- * Gives the current position in the file
- *
- * @return int The current position
- */
- public function pos() {
- return ftell($this->f);
- }
-
- public function skip($n) {
- fseek($this->f, $n, SEEK_CUR);
- }
-
- /**
- * @param int $n The number of bytes to read
- *
- * @return string
- */
- public function read($n) {
- if ($n < 1) {
- return "";
- }
-
- return (string) fread($this->f, $n);
- }
-
- public function write($data, $length = null) {
- if ($data === null || $data === "" || $data === false) {
- return 0;
- }
-
- return fwrite($this->f, $data, $length);
- }
-
- public function readUInt8() {
- return ord($this->read(1));
- }
-
- public function readUInt8Many($count) {
- return array_values(unpack("C*", $this->read($count)));
- }
-
- public function writeUInt8($data) {
- return $this->write(chr($data), 1);
- }
-
- public function readInt8() {
- $v = $this->readUInt8();
-
- if ($v >= 0x80) {
- $v -= 0x100;
- }
-
- return $v;
- }
-
- public function readInt8Many($count) {
- return array_values(unpack("c*", $this->read($count)));
- }
-
- public function writeInt8($data) {
- if ($data < 0) {
- $data += 0x100;
- }
-
- return $this->writeUInt8($data);
- }
-
- public function readUInt16() {
- $a = unpack("nn", $this->read(2));
-
- return $a["n"];
- }
-
- public function readUInt16Many($count) {
- return array_values(unpack("n*", $this->read($count * 2)));
- }
-
- public function readUFWord() {
- return $this->readUInt16();
- }
-
- public function writeUInt16($data) {
- return $this->write(pack("n", $data), 2);
- }
-
- public function writeUFWord($data) {
- return $this->writeUInt16($data);
- }
-
- public function readInt16() {
- $a = unpack("nn", $this->read(2));
- $v = $a["n"];
-
- if ($v >= 0x8000) {
- $v -= 0x10000;
- }
-
- return $v;
- }
-
- public function readInt16Many($count) {
- $vals = array_values(unpack("n*", $this->read($count * 2)));
- foreach ($vals as &$v) {
- if ($v >= 0x8000) {
- $v -= 0x10000;
- }
- }
-
- return $vals;
- }
-
- public function readFWord() {
- return $this->readInt16();
- }
-
- public function writeInt16($data) {
- if ($data < 0) {
- $data += 0x10000;
- }
-
- return $this->writeUInt16($data);
- }
-
- public function writeFWord($data) {
- return $this->writeInt16($data);
- }
-
- public function readUInt32() {
- $a = unpack("NN", $this->read(4));
-
- return $a["N"];
- }
-
- public function writeUInt32($data) {
- return $this->write(pack("N", $data), 4);
- }
-
- public function readFixed() {
- $d = $this->readInt16();
- $d2 = $this->readUInt16();
-
- return round($d + $d2 / 0x10000, 4);
- }
-
- public function writeFixed($data) {
- $left = floor($data);
- $right = ($data - $left) * 0x10000;
-
- return $this->writeInt16($left) + $this->writeUInt16($right);
- }
-
- public function readLongDateTime() {
- $this->readUInt32(); // ignored
- $date = $this->readUInt32() - 2082844800;
-
- # PHP_INT_MIN isn't defined in PHP < 7.0
- $php_int_min = defined("PHP_INT_MIN") ? PHP_INT_MIN : ~PHP_INT_MAX;
-
- if (is_string($date) || $date > PHP_INT_MAX || $date < $php_int_min) {
- $date = 0;
- }
-
- return date("Y-m-d H:i:s", $date);
- }
-
- public function writeLongDateTime($data) {
- $date = strtotime($data);
- $date += 2082844800;
-
- return $this->writeUInt32(0) + $this->writeUInt32($date);
- }
-
- public function unpack($def) {
- $d = array();
- foreach ($def as $name => $type) {
- $d[$name] = $this->r($type);
- }
-
- return $d;
- }
-
- public function pack($def, $data) {
- $bytes = 0;
- foreach ($def as $name => $type) {
- $bytes += $this->w($type, $data[$name]);
- }
-
- return $bytes;
- }
-
- /**
- * Read a data of type $type in the file from the current position
- *
- * @param mixed $type The data type to read
- *
- * @return mixed The data that was read
- */
- public function r($type) {
- switch ($type) {
- case self::uint8:
- return $this->readUInt8();
- case self::int8:
- return $this->readInt8();
- case self::uint16:
- return $this->readUInt16();
- case self::int16:
- return $this->readInt16();
- case self::uint32:
- return $this->readUInt32();
- case self::int32:
- return $this->readUInt32();
- case self::shortFrac:
- return $this->readFixed();
- case self::Fixed:
- return $this->readFixed();
- case self::FWord:
- return $this->readInt16();
- case self::uFWord:
- return $this->readUInt16();
- case self::F2Dot14:
- return $this->readInt16();
- case self::longDateTime:
- return $this->readLongDateTime();
- case self::char:
- return $this->read(1);
- default:
- if (is_array($type)) {
- if ($type[0] == self::char) {
- return $this->read($type[1]);
- }
- if ($type[0] == self::uint16) {
- return $this->readUInt16Many($type[1]);
- }
- if ($type[0] == self::int16) {
- return $this->readInt16Many($type[1]);
- }
- if ($type[0] == self::uint8) {
- return $this->readUInt8Many($type[1]);
- }
- if ($type[0] == self::int8) {
- return $this->readInt8Many($type[1]);
- }
-
- $ret = array();
- for ($i = 0; $i < $type[1]; $i++) {
- $ret[] = $this->r($type[0]);
- }
-
- return $ret;
- }
-
- return null;
- }
- }
-
- /**
- * Write $data of type $type in the file from the current position
- *
- * @param mixed $type The data type to write
- * @param mixed $data The data to write
- *
- * @return int The number of bytes read
- */
- public function w($type, $data) {
- switch ($type) {
- case self::uint8:
- return $this->writeUInt8($data);
- case self::int8:
- return $this->writeInt8($data);
- case self::uint16:
- return $this->writeUInt16($data);
- case self::int16:
- return $this->writeInt16($data);
- case self::uint32:
- return $this->writeUInt32($data);
- case self::int32:
- return $this->writeUInt32($data);
- case self::shortFrac:
- return $this->writeFixed($data);
- case self::Fixed:
- return $this->writeFixed($data);
- case self::FWord:
- return $this->writeInt16($data);
- case self::uFWord:
- return $this->writeUInt16($data);
- case self::F2Dot14:
- return $this->writeInt16($data);
- case self::longDateTime:
- return $this->writeLongDateTime($data);
- case self::char:
- return $this->write($data, 1);
- default:
- if (is_array($type)) {
- if ($type[0] == self::char) {
- return $this->write($data, $type[1]);
- }
-
- $ret = 0;
- for ($i = 0; $i < $type[1]; $i++) {
- if (isset($data[$i])) {
- $ret += $this->w($type[0], $data[$i]);
- }
- }
-
- return $ret;
- }
-
- return null;
- }
- }
-
- /**
- * Converts a Uint32 value to string
- *
- * @param int $uint32
- *
- * @return string The string
- */
- public function convertUInt32ToStr($uint32) {
- return chr(($uint32 >> 24) & 0xFF) . chr(($uint32 >> 16) & 0xFF) . chr(($uint32 >> 8) & 0xFF) . chr($uint32 & 0xFF);
- }
- }
|