Passed
Push — master ( 5a1acc...523cb4 )
by Sam
01:57
created

Normaliser::handleMultiline()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 31
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 8.2327

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 31
ccs 22
cts 26
cp 0.8462
rs 8.4444
c 0
b 0
f 0
cc 8
nc 8
nop 0
crap 8.2327
1
<?php
2
3
namespace Badcow\DNS\Parser;
4
5
use LTDBeget\ascii\AsciiChar;
6
7
class Normaliser
8
{
9
    /**
10
     * @var StringIterator
11
     */
12
    private $string;
13
14
    /**
15
     * @var string
16
     */
17
    private $normalisedString = '';
18
19
    /**
20
     * Normaliser constructor.
21
     *
22
     * @param string $zone
23
     */
24 4
    public function __construct(string $zone)
25
    {
26
        //Remove Windows line feeds and tabs
27 4
        $zone = str_replace(["\r\n", "\t"], ["\n", ' '], $zone);
28
29 4
        $this->string = new StringIterator($zone);
30 4
    }
31
32
    /**
33
     * @param string $zone
34
     *
35
     * @return string
36
     *
37
     * @throws ParseException
38
     */
39 4
    public static function normalise(string $zone): string
40
    {
41 4
        $normaliser = new self($zone);
42
43 4
        return $normaliser->process();
44
    }
45
46
    /**
47
     * @return string
48
     *
49
     * @throws ParseException
50
     */
51 4
    public function process(): string
52
    {
53 4
        while ($this->string->valid()) {
54 4
            switch ($this->string->ord()) {
55 4
                case AsciiChar::DOUBLE_QUOTES:
56 3
                    $this->handleTxt();
57 3
                    break;
58 4
                case AsciiChar::SEMICOLON:
59 4
                    $this->handleComment();
60 4
                    break;
61 4
                case AsciiChar::OPEN_BRACKET:
62 3
                    $this->handleMultiline();
63 3
                    break;
64
            }
65
66 4
            $this->append();
67
        }
68
69 4
        $this->removeWhitespace();
70
71 4
        return $this->normalisedString;
72
    }
73
74
    /**
75
     * Ignores the comment section.
76
     *
77
     * @throws ParseException
78
     */
79 4
    private function handleComment(): void
80
    {
81 4
        if (AsciiChar::SEMICOLON !== $this->string->ord()) {
82
            throw new ParseException(sprintf('Semicolon (;) expected as current entry, character "%s" instead.',
83
                $this->string->current()),
84
                $this->string
85
            );
86
        }
87
88 4
        while (AsciiChar::LINE_FEED !== $this->string->ord() && $this->string->valid()) {
89 4
            $this->string->next();
90
        }
91 4
    }
92
93
    /**
94
     * Handle text inside of double quotations. When this function is called, the String pointer MUST be at the
95
     * double quotation mark.
96
     *
97
     * @throws ParseException
98
     */
99 3
    private function handleTxt(): void
100
    {
101 3
        if (AsciiChar::DOUBLE_QUOTES !== $this->string->ord()) {
102
            throw new ParseException(sprintf('Double Quotes (") expected as current entry, character "%s" instead.',
103
                $this->string->current()),
104
                $this->string
105
            );
106
        }
107
108 3
        $this->append();
109
110 3
        while (AsciiChar::DOUBLE_QUOTES !== $this->string->ord()) {
111 3
            if (!$this->string->valid()) {
112
                throw new ParseException('Unbalanced double quotation marks. End of file reached.');
113
            }
114
115
            //If escape character
116 3
            if (AsciiChar::BACKSLASH === $this->string->ord()) {
117 3
                $this->append();
118
            }
119
120 3
            if (AsciiChar::LINE_FEED === $this->string->ord()) {
121
                throw new ParseException('Line Feed found within double quotation marks context', $this->string);
122
            }
123
124 3
            $this->append();
125
        }
126 3
    }
127
128
    /**
129
     * Move multi-line records onto single line.
130
     *
131
     * @throws ParseException
132
     */
133 3
    private function handleMultiline(): void
134
    {
135 3
        if (AsciiChar::OPEN_BRACKET !== $this->string->ord()) {
136
            throw new ParseException(sprintf('Open bracket "(" expected as current entry, character "%s" instead.',
137
                $this->string->current()),
138
                $this->string
139
            );
140
        }
141
142 3
        $openBracket = true;
143 3
        $this->string->next();
144 3
        while ($openBracket) {
145 3
            switch ($this->string->ord()) {
146 3
                case AsciiChar::DOUBLE_QUOTES:
147 1
                    $this->handleTxt();
148 1
                    $this->append();
149 1
                    break;
150 3
                case AsciiChar::SEMICOLON:
151 3
                    $this->handleComment();
152 3
                    break;
153 3
                case AsciiChar::LINE_FEED:
154 3
                    $this->string->next();
155 3
                    break;
156 3
                case AsciiChar::CLOSE_BRACKET:
157 3
                    $openBracket = false;
158 3
                    $this->string->next();
159 3
                    break;
160 3
                case AsciiChar::NULL:
161
                    throw new ParseException('End of file reached. Unclosed bracket.');
162
                default:
163 3
                    $this->append();
164
            }
165
        }
166 3
    }
167
168
    /**
169
     * Remove superfluous whitespace characters from string.
170
     */
171 4
    private function removeWhitespace(): void
172
    {
173 4
        $this->normalisedString = preg_replace('/ {2,}/', ' ', $this->normalisedString);
174 4
        $lines = explode("\n", $this->normalisedString);
175 4
        $this->normalisedString = '';
176 4
        foreach ($lines as $line) {
177 4
            $line = trim($line);
178 4
            if ('' !== $line) {
179 4
                $this->normalisedString .= $line."\n";
180
            }
181
        }
182 4
        $this->normalisedString = rtrim($this->normalisedString);
183 4
    }
184
185
    /**
186
     * Add current entry to nomalisedString and moves to next entry.
187
     */
188 4
    private function append()
189
    {
190 4
        $this->normalisedString .= $this->string->current();
191 4
        $this->string->next();
192 4
    }
193
}
194