1<?php
2
3/**
4 * This file contains the BinaryReader class.
5 * For more information see the class description below.
6 *
7 * @author Peter Bathory <peter.bathory@cartographia.hu>
8 * @since 2016-02-18
9 *
10 * This code is open-source and licenced under the Modified BSD License.
11 * For the full copyright and license information, please view the LICENSE
12 * file that was distributed with this source code.
13 */
14
15namespace geoPHP\Adapter;
16
17/**
18 * Helper class BinaryWriter
19 *
20 * A simple binary writer supporting both byte orders
21 */
22class BinaryWriter
23{
24
25    const BIG_ENDIAN = 0;
26    const LITTLE_ENDIAN = 1;
27
28    private $endianness = 0;
29
30    public function __construct($endianness = 0)
31    {
32        $this->endianness = $endianness;
33    }
34
35    /**
36     * @return bool Returns true if Writer is in BigEndian mode
37     */
38    public function isBigEndian()
39    {
40        return $this->endianness === self::BIG_ENDIAN;
41    }
42
43    /**
44     * @return bool Returns true if Writer is in LittleEndian mode
45     */
46    public function isLittleEndian()
47    {
48        return $this->endianness === self::LITTLE_ENDIAN;
49    }
50
51    /**
52     * Writes a signed 8-bit integer
53     * @param int $value
54     * @return string The integer as a binary string
55     */
56    public function writeSInt8($value)
57    {
58        return pack('c', $value);
59    }
60
61    /**
62     * Writes an unsigned 8-bit integer
63     * @param int $value
64     * @return string The integer as a binary string
65     */
66    public function writeUInt8($value)
67    {
68        return pack('C', $value);
69    }
70
71    /**
72     * Writes an unsigned 32-bit integer
73     * @param int $value
74     * @return string The integer as a binary string
75     */
76    public function writeUInt32($value)
77    {
78        return pack($this->isLittleEndian() ? 'V' : 'N', $value);
79    }
80
81    /**
82     * Writes a double
83     * @param float $value
84     * @return string The floating point number as a binary string
85     */
86    public function writeDouble($value)
87    {
88        return $this->isLittleEndian() ? pack('d', $value) : strrev(pack('d', $value));
89    }
90
91    /**
92     * Writes a positive integer as an unsigned base-128 varint
93     *
94     * Ported from https://github.com/cschwarz/wkx/blob/master/lib/binaryreader.js
95     *
96     * @param int $value
97     * @return string The integer as a binary string
98     */
99    public function writeUVarInt($value)
100    {
101        $out = '';
102
103        while (($value & 0xFFFFFF80) !== 0) {
104            $out .= $this->writeUInt8(($value & 0x7F) | 0x80);
105            // Zero fill by 7 zero
106            if ($value >= 0) {
107                $value >>= 7;
108            } else {
109                $value = ((~$value) >> 7) ^ (0x7fffffff >> (7 - 1));
110            }
111        }
112
113        $out .= $this->writeUInt8($value & 0x7F);
114
115        return $out;
116    }
117
118    /**
119     * Writes an integer as a signed base-128 varint
120     * @param int $value
121     * @return string The integer as a binary string
122     */
123    public function writeSVarInt($value)
124    {
125        return $this->writeUVarInt(self::zigZagEncode($value));
126    }
127
128    /**
129     * ZigZag encoding maps signed integers to unsigned integers
130     *
131     * @param int $value Signed integer
132     * @return int Encoded positive integer value
133     */
134    public static function zigZagEncode($value)
135    {
136        return ($value << 1) ^ ($value >> 31);
137    }
138}
139