NSEC::fromText()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 8
cts 8
cp 1
rs 9.9332
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\Message;
17
use Badcow\DNS\Parser\Tokens;
18
19
class NSEC implements RdataInterface
20
{
21 1
    use RdataTrait;
22
23
    const TYPE = 'NSEC';
24
    const TYPE_CODE = 47;
25
26
    /**
27
     * The Next Domain field contains the next owner name (in the canonical
28
     * ordering of the zone) that has authoritative data or contains a
29
     * delegation point NS RR set.
30
     * {@link https://tools.ietf.org/html/rfc4034#section-4.1.1}.
31
     *
32
     * @var string
33
     */
34
    private $nextDomainName;
35
36
    /**
37
     * @var array
38
     */
39
    private $types = [];
40
41 2
    public function getNextDomainName(): string
42
    {
43 2
        return $this->nextDomainName;
44
    }
45
46 4
    public function setNextDomainName(string $nextDomainName): void
47
    {
48 4
        $this->nextDomainName = $nextDomainName;
49 4
    }
50
51 5
    public function addType(string $type): void
52
    {
53 5
        $this->types[] = $type;
54 5
    }
55
56
    /**
57
     * Clears the types from the RDATA.
58
     */
59 1
    public function clearTypes(): void
60
    {
61 1
        $this->types = [];
62 1
    }
63
64 3
    public function getTypes(): array
65
    {
66 3
        return $this->types;
67
    }
68
69 2
    public function toText(): string
70
    {
71 2
        return sprintf(
72 2
            '%s %s',
73 2
            $this->nextDomainName,
74 2
            implode(' ', $this->types)
75
        );
76
    }
77
78
    /**
79
     * @throws UnsupportedTypeException
80
     */
81 1
    public function toWire(): string
82
    {
83 1
        return Message::encodeName($this->nextDomainName).self::renderBitmap($this->types);
84
    }
85
86 2
    public function fromText(string $text): void
87
    {
88 2
        $iterator = new \ArrayIterator(explode(Tokens::SPACE, $text));
89 2
        $this->setNextDomainName($iterator->current());
90 2
        $iterator->next();
91 2
        while ($iterator->valid()) {
92 2
            $this->addType($iterator->current());
93 2
            $iterator->next();
94
        }
95 2
    }
96
97
    /**
98
     * @throws UnsupportedTypeException|DecodeException
99
     */
100 1
    public function fromWire(string $rdata, int &$offset = 0, ?int $rdLength = null): void
101
    {
102 1
        $this->setNextDomainName(Message::decodeName($rdata, $offset));
103 1
        $types = self::parseBitmap($rdata, $offset);
104 1
        array_map([$this, 'addType'], $types);
105 1
    }
106
107
    /**
108
     * @return string[]
109
     *
110
     * @throws UnsupportedTypeException
111
     * @throws DecodeException
112
     */
113 4
    public static function parseBitmap(string $rdata, int &$offset): array
114
    {
115 4
        $bytes = unpack('C*', $rdata, $offset);
116
117 4
        if (!is_array($bytes)) {
118
            throw new DecodeException(static::TYPE, $rdata);
119
        }
120
121 4
        $types = [];
122
123 4
        while (count($bytes) > 0) {
124 4
            $mask = '';
125 4
            $window = array_shift($bytes);
126 4
            $len = array_shift($bytes);
127 4
            for ($i = 0; $i < $len; ++$i) {
128 4
                $mask .= str_pad(decbin(array_shift($bytes)), 8, '0', STR_PAD_LEFT);
129
            }
130 4
            $offset = 0;
131 4
            while (false !== $pos = strpos($mask, '1', $offset)) {
132 4
                $types[] = Types::getName((int) $window * 256 + $pos);
133 4
                $offset = $pos + 1;
134
            }
135
        }
136
137 4
        return $types;
138
    }
139
140
    /**
141
     * @param string[] $types
142
     *
143
     * @throws UnsupportedTypeException
144
     */
145 4
    public static function renderBitmap(array $types): string
146
    {
147 4
        $blocks = [];
148
149 4
        foreach ($types as $type) {
150 4
            $int = Types::getTypeCode($type);
151 4
            $window = $int >> 8;
152 4
            $int = $int & 0b11111111;
153 4
            $mod = $int % 8;
154 4
            $mask = $blocks[$window] ?? str_repeat("\0", 32);
155 4
            $byteNum = ($int - $mod) / 8;
156 4
            $byte = ord($mask[$byteNum]) | (128 >> $mod);
157 4
            $mask[$byteNum] = chr($byte);
158 4
            $blocks[$window] = $mask;
159
        }
160
161 4
        $encoded = '';
162 4
        foreach ($blocks as $n => $mask) {
163 4
            $mask = rtrim($mask, "\0");
164 4
            $encoded .= chr($n).chr(strlen($mask)).$mask;
165
        }
166
167 4
        return $encoded;
168
    }
169
}
170