Passed
Push — master ( 119168...f07f0d )
by Sam
01:48
created

Normaliser::removeWhitespace()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

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