composer package updates
[openemr.git] / vendor / phenx / php-font-lib / src / FontLib / BinaryStream.php
blobab10454469283040908b8ac072f69d880485cc1d
1 <?php
2 /**
3 * @package php-font-lib
4 * @link https://github.com/PhenX/php-font-lib
5 * @author Fabien Ménager <fabien.menager@gmail.com>
6 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7 */
9 namespace FontLib;
11 /**
12 * Generic font file binary stream.
14 * @package php-font-lib
16 class BinaryStream {
17 /**
18 * @var resource The file pointer
20 protected $f;
22 const uint8 = 1;
23 const int8 = 2;
24 const uint16 = 3;
25 const int16 = 4;
26 const uint32 = 5;
27 const int32 = 6;
28 const shortFrac = 7;
29 const Fixed = 8;
30 const FWord = 9;
31 const uFWord = 10;
32 const F2Dot14 = 11;
33 const longDateTime = 12;
34 const char = 13;
36 const modeRead = "rb";
37 const modeWrite = "wb";
38 const modeReadWrite = "rb+";
40 static function backtrace() {
41 var_dump(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
44 /**
45 * Open a font file in read mode
47 * @param string $filename The file name of the font to open
49 * @return bool
51 public function load($filename) {
52 return $this->open($filename, self::modeRead);
55 /**
56 * Open a font file in a chosen mode
58 * @param string $filename The file name of the font to open
59 * @param string $mode The opening mode
61 * @throws \Exception
62 * @return bool
64 public function open($filename, $mode = self::modeRead) {
65 if (!in_array($mode, array(self::modeRead, self::modeWrite, self::modeReadWrite))) {
66 throw new \Exception("Unkown file open mode");
69 $this->f = fopen($filename, $mode);
71 return $this->f != false;
74 /**
75 * Close the internal file pointer
77 public function close() {
78 return fclose($this->f) != false;
81 /**
82 * Change the internal file pointer
84 * @param resource $fp
86 * @throws \Exception
88 public function setFile($fp) {
89 if (!is_resource($fp)) {
90 throw new \Exception('$fp is not a valid resource');
93 $this->f = $fp;
96 /**
97 * Create a temporary file in write mode
99 * @param bool $allow_memory Allow in-memory files
101 * @return resource the temporary file pointer resource
103 public static function getTempFile($allow_memory = true) {
104 $f = null;
106 if ($allow_memory) {
107 $f = fopen("php://temp", "rb+");
109 else {
110 $f = fopen(tempnam(sys_get_temp_dir(), "fnt"), "rb+");
113 return $f;
117 * Move the internal file pinter to $offset bytes
119 * @param int $offset
121 * @return bool True if the $offset position exists in the file
123 public function seek($offset) {
124 return fseek($this->f, $offset, SEEK_SET) == 0;
128 * Gives the current position in the file
130 * @return int The current position
132 public function pos() {
133 return ftell($this->f);
136 public function skip($n) {
137 fseek($this->f, $n, SEEK_CUR);
140 public function read($n) {
141 if ($n < 1) {
142 return "";
145 return fread($this->f, $n);
148 public function write($data, $length = null) {
149 if ($data === null || $data === "" || $data === false) {
150 return 0;
153 return fwrite($this->f, $data, $length);
156 public function readUInt8() {
157 return ord($this->read(1));
160 public function readUInt8Many($count) {
161 return array_values(unpack("C*", $this->read($count)));
164 public function writeUInt8($data) {
165 return $this->write(chr($data), 1);
168 public function readInt8() {
169 $v = $this->readUInt8();
171 if ($v >= 0x80) {
172 $v -= 0x100;
175 return $v;
178 public function readInt8Many($count) {
179 return array_values(unpack("c*", $this->read($count)));
182 public function writeInt8($data) {
183 if ($data < 0) {
184 $data += 0x100;
187 return $this->writeUInt8($data);
190 public function readUInt16() {
191 $a = unpack("nn", $this->read(2));
193 return $a["n"];
196 public function readUInt16Many($count) {
197 return array_values(unpack("n*", $this->read($count * 2)));
200 public function readUFWord() {
201 return $this->readUInt16();
204 public function writeUInt16($data) {
205 return $this->write(pack("n", $data), 2);
208 public function writeUFWord($data) {
209 return $this->writeUInt16($data);
212 public function readInt16() {
213 $a = unpack("nn", $this->read(2));
214 $v = $a["n"];
216 if ($v >= 0x8000) {
217 $v -= 0x10000;
220 return $v;
223 public function readInt16Many($count) {
224 $vals = array_values(unpack("n*", $this->read($count * 2)));
225 foreach ($vals as &$v) {
226 if ($v >= 0x8000) {
227 $v -= 0x10000;
231 return $vals;
234 public function readFWord() {
235 return $this->readInt16();
238 public function writeInt16($data) {
239 if ($data < 0) {
240 $data += 0x10000;
243 return $this->writeUInt16($data);
246 public function writeFWord($data) {
247 return $this->writeInt16($data);
250 public function readUInt32() {
251 $a = unpack("NN", $this->read(4));
253 return $a["N"];
256 public function writeUInt32($data) {
257 return $this->write(pack("N", $data), 4);
260 public function readFixed() {
261 $d = $this->readInt16();
262 $d2 = $this->readUInt16();
264 return round($d + $d2 / 0x10000, 4);
267 public function writeFixed($data) {
268 $left = floor($data);
269 $right = ($data - $left) * 0x10000;
271 return $this->writeInt16($left) + $this->writeUInt16($right);
274 public function readLongDateTime() {
275 $this->readUInt32(); // ignored
276 $date = $this->readUInt32() - 2082844800;
278 # PHP_INT_MIN isn't defined in PHP < 7.0
279 $php_int_min = defined("PHP_INT_MIN") ? PHP_INT_MIN : ~PHP_INT_MAX;
281 if (is_string($date) || $date > PHP_INT_MAX || $date < $php_int_min) {
282 $date = 0;
285 return strftime("%Y-%m-%d %H:%M:%S", $date);
288 public function writeLongDateTime($data) {
289 $date = strtotime($data);
290 $date += 2082844800;
292 return $this->writeUInt32(0) + $this->writeUInt32($date);
295 public function unpack($def) {
296 $d = array();
297 foreach ($def as $name => $type) {
298 $d[$name] = $this->r($type);
301 return $d;
304 public function pack($def, $data) {
305 $bytes = 0;
306 foreach ($def as $name => $type) {
307 $bytes += $this->w($type, $data[$name]);
310 return $bytes;
314 * Read a data of type $type in the file from the current position
316 * @param mixed $type The data type to read
318 * @return mixed The data that was read
320 public function r($type) {
321 switch ($type) {
322 case self::uint8:
323 return $this->readUInt8();
324 case self::int8:
325 return $this->readInt8();
326 case self::uint16:
327 return $this->readUInt16();
328 case self::int16:
329 return $this->readInt16();
330 case self::uint32:
331 return $this->readUInt32();
332 case self::int32:
333 return $this->readUInt32();
334 case self::shortFrac:
335 return $this->readFixed();
336 case self::Fixed:
337 return $this->readFixed();
338 case self::FWord:
339 return $this->readInt16();
340 case self::uFWord:
341 return $this->readUInt16();
342 case self::F2Dot14:
343 return $this->readInt16();
344 case self::longDateTime:
345 return $this->readLongDateTime();
346 case self::char:
347 return $this->read(1);
348 default:
349 if (is_array($type)) {
350 if ($type[0] == self::char) {
351 return $this->read($type[1]);
353 if ($type[0] == self::uint16) {
354 return $this->readUInt16Many($type[1]);
356 if ($type[0] == self::int16) {
357 return $this->readInt16Many($type[1]);
359 if ($type[0] == self::uint8) {
360 return $this->readUInt8Many($type[1]);
362 if ($type[0] == self::int8) {
363 return $this->readInt8Many($type[1]);
366 $ret = array();
367 for ($i = 0; $i < $type[1]; $i++) {
368 $ret[] = $this->r($type[0]);
371 return $ret;
374 return null;
379 * Write $data of type $type in the file from the current position
381 * @param mixed $type The data type to write
382 * @param mixed $data The data to write
384 * @return int The number of bytes read
386 public function w($type, $data) {
387 switch ($type) {
388 case self::uint8:
389 return $this->writeUInt8($data);
390 case self::int8:
391 return $this->writeInt8($data);
392 case self::uint16:
393 return $this->writeUInt16($data);
394 case self::int16:
395 return $this->writeInt16($data);
396 case self::uint32:
397 return $this->writeUInt32($data);
398 case self::int32:
399 return $this->writeUInt32($data);
400 case self::shortFrac:
401 return $this->writeFixed($data);
402 case self::Fixed:
403 return $this->writeFixed($data);
404 case self::FWord:
405 return $this->writeInt16($data);
406 case self::uFWord:
407 return $this->writeUInt16($data);
408 case self::F2Dot14:
409 return $this->writeInt16($data);
410 case self::longDateTime:
411 return $this->writeLongDateTime($data);
412 case self::char:
413 return $this->write($data, 1);
414 default:
415 if (is_array($type)) {
416 if ($type[0] == self::char) {
417 return $this->write($data, $type[1]);
420 $ret = 0;
421 for ($i = 0; $i < $type[1]; $i++) {
422 if (isset($data[$i])) {
423 $ret += $this->w($type[0], $data[$i]);
427 return $ret;
430 return null;
435 * Converts a Uint32 value to string
437 * @param int $uint32
439 * @return string The string
441 public function convertUInt32ToStr($uint32) {
442 return chr(($uint32 >> 24) & 0xFF) . chr(($uint32 >> 16) & 0xFF) . chr(($uint32 >> 8) & 0xFF) . chr($uint32 & 0xFF);