Completed
Branch Version3 (46305e)
by Sam
01:25
created

NSEC::fromText()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 9
cts 9
cp 1
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Badcow DNS Library.
7
 *
8
 * (c) Samuel Williams <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Badcow\DNS\Rdata;
15
16
use Badcow\DNS\Parser\Tokens;
17
18
class NSEC implements RdataInterface
19
{
20
    use RdataTrait;
21
22
    const TYPE = 'NSEC';
23
    const TYPE_CODE = 47;
24
25
    /**
26
     * The Next Domain field contains the next owner name (in the canonical
27
     * ordering of the zone) that has authoritative data or contains a
28
     * delegation point NS RR set.
29
     * {@link https://tools.ietf.org/html/rfc4034#section-4.1.1}.
30
     *
31
     * @var string
32
     */
33
    private $nextDomainName;
34
35
    /**
36
     * @var array
37
     */
38
    private $types = [];
39
40
    /**
41
     * @return string
42
     */
43 2
    public function getNextDomainName(): string
44
    {
45 2
        return $this->nextDomainName;
46
    }
47
48
    /**
49
     * @param string $nextDomainName
50
     */
51 4
    public function setNextDomainName(string $nextDomainName): void
52
    {
53 4
        $this->nextDomainName = $nextDomainName;
54 4
    }
55
56
    /**
57
     * @param string $type
58
     */
59 5
    public function addType(string $type): void
60
    {
61 5
        $this->types[] = $type;
62 5
    }
63
64
    /**
65
     * Clears the types from the RDATA.
66
     */
67 1
    public function clearTypes(): void
68
    {
69 1
        $this->types = [];
70 1
    }
71
72
    /**
73
     * @return array
74
     */
75 3
    public function getTypes(): array
76
    {
77 3
        return $this->types;
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83 2
    public function toText(): string
84
    {
85 2
        return sprintf(
86 2
            '%s %s',
87 2
            $this->nextDomainName,
88 2
            implode(' ', $this->types)
89
        );
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     *
95
     * @throws UnsupportedTypeException
96
     */
97 1
    public function toWire(): string
98
    {
99 1
        return self::encodeName($this->nextDomainName).self::renderBitmap($this->types);
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105 2
    public static function fromText(string $text): RdataInterface
106
    {
107 2
        $iterator = new \ArrayIterator(explode(Tokens::SPACE, $text));
108 2
        $nsec = new self();
109 2
        $nsec->setNextDomainName($iterator->current());
110 2
        $iterator->next();
111 2
        while ($iterator->valid()) {
112 2
            $nsec->addType($iterator->current());
113 2
            $iterator->next();
114
        }
115
116 2
        return $nsec;
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     *
122
     * @throws UnsupportedTypeException
123
     */
124 1
    public static function fromWire(string $rdata): RdataInterface
125
    {
126 1
        $nsec = new self();
127 1
        $offset = 0;
128 1
        $nsec->setNextDomainName(self::decodeName($rdata, $offset));
129 1
        $types = self::parseBitmap($rdata, $offset);
130 1
        array_map([$nsec, 'addType'], $types);
131
132 1
        return $nsec;
133
    }
134
135
    /**
136
     * @param string $rdata
137
     * @param int    $offset
138
     *
139
     * @return string[]
140
     *
141
     * @throws UnsupportedTypeException
142
     */
143 3
    public static function parseBitmap(string $rdata, int &$offset): array
144
    {
145 3
        $bytes = unpack('C*', $rdata, $offset);
146 3
        $types = [];
147
148 3
        while (count($bytes) > 0) {
149 3
            $mask = '';
150 3
            $window = array_shift($bytes);
151 3
            $len = array_shift($bytes);
152 3
            for ($i = 0; $i < $len; ++$i) {
153 3
                $mask .= str_pad(decbin(array_shift($bytes)), 8, '0', STR_PAD_LEFT);
154
            }
155 3
            $offset = 0;
156 3
            while (false !== $pos = strpos($mask, '1', $offset)) {
157 3
                $types[] = TypeCodes::getName((int) $window * 256 + $pos);
158 3
                $offset = $pos + 1;
159
            }
160
        }
161
162 3
        return $types;
163
    }
164
165
    /**
166
     * @param string[] $types
167
     *
168
     * @return string
169
     *
170
     * @throws UnsupportedTypeException
171
     */
172 3
    public static function renderBitmap(array $types): string
173
    {
174 3
        $blocks = [];
175
176 3
        foreach ($types as $type) {
177 3
            $int = TypeCodes::getTypeCode($type);
178 3
            $window = $int >> 8;
179 3
            $int = $int & 0b11111111;
180 3
            $mod = $int % 8;
181 3
            $mask = $blocks[$window] ?? str_repeat("\0", 32);
182 3
            $byteNum = ($int - $mod) / 8;
183 3
            $byte = ord($mask[$byteNum]) | (128 >> $mod);
184 3
            $mask[$byteNum] = chr($byte);
185 3
            $blocks[$window] = $mask;
186
        }
187
188 3
        $encoded = '';
189 3
        foreach ($blocks as $n => $mask) {
190 3
            $mask = rtrim($mask, "\0");
191 3
            $encoded .= chr($n).chr(strlen($mask)).$mask;
192
        }
193
194 3
        return $encoded;
195
    }
196
}
197