Comment::inStringOrCommentEnd()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 3
b 0
f 0
nc 2
nop 3
dl 0
loc 3
rs 10
1
<?php
2
3
/*
4
 * This file is part of the PHP-JSON-COMMENT package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\Json;
13
14
/**
15
 * JSON comment stripper.
16
 *
17
 * @author Jitendra Adhikari <[email protected]>
18
 */
19
class Comment
20
{
21
    /** @var int The current index being scanned */
22
    protected $index   = -1;
23
24
    /** @var bool If current char is within a string */
25
    protected $inStr   = false;
26
27
    /** @var int Lines of comments 0 = no comment, 1 = single line, 2 = multi lines */
28
    protected $comment = 0;
29
30
    /**
31
     * Strip comments from JSON string.
32
     *
33
     * @param string $json
34
     *
35
     * @return string The comment stripped JSON.
36
     */
37
    public function strip($json)
38
    {
39
        if (!\preg_match('%\/(\/|\*)%', $json)) {
40
            return $json;
41
        }
42
43
        $this->reset();
44
45
        return $this->doStrip($json);
46
    }
47
48
    protected function reset()
49
    {
50
        $this->index   = -1;
51
        $this->inStr   = false;
52
        $this->comment = 0;
53
    }
54
55
    protected function doStrip($json)
56
    {
57
        $return = '';
58
59
        while (isset($json[++$this->index])) {
60
            list($prev, $char, $next) = $this->getSegments($json);
61
62
            if ($this->inStringOrCommentEnd($prev, $char, $char . $next)) {
63
                $return .= $char;
64
65
                continue;
66
            }
67
68
            $wasSingle = 1 === $this->comment;
69
            if ($this->hasCommentEnded($char, $char . $next) && $wasSingle) {
70
                $return = \rtrim($return) . $char;
71
            }
72
73
            $this->index += $char . $next === '*/' ? 1 : 0;
74
        }
75
76
        return $return;
77
    }
78
79
    protected function getSegments($json)
80
    {
81
        return [
82
            isset($json[$this->index - 1]) ? $json[$this->index - 1] : '',
83
            $json[$this->index],
84
            isset($json[$this->index + 1]) ? $json[$this->index + 1] : '',
85
        ];
86
    }
87
88
    protected function inStringOrCommentEnd($prev, $char, $charnext)
89
    {
90
        return $this->inString($char, $prev) || $this->inCommentEnd($charnext);
91
    }
92
93
    protected function inString($char, $prev)
94
    {
95
        if (0 === $this->comment && $char === '"' && $prev !== '\\') {
96
            $this->inStr = !$this->inStr;
97
        }
98
99
        return $this->inStr;
100
    }
101
102
    protected function inCommentEnd($charnext)
103
    {
104
        if (!$this->inStr && 0 === $this->comment) {
105
            $this->comment = $charnext === '//' ? 1 : ($charnext === '/*' ? 2 : 0);
106
        }
107
108
        return 0 === $this->comment;
109
    }
110
111
    protected function hasCommentEnded($char, $charnext)
112
    {
113
        $singleEnded = $this->comment === 1 && $char == "\n";
114
        $multiEnded  = $this->comment === 2 && $charnext == '*/';
115
116
        if ($singleEnded || $multiEnded) {
117
            $this->comment = 0;
118
119
            return true;
120
        }
121
122
        return false;
123
    }
124
125
    /**
126
     * Strip comments and decode JSON string.
127
     *
128
     * @param string    $json
129
     * @param bool|bool $assoc
130
     * @param int|int   $depth
131
     * @param int|int   $options
132
     *
133
     * @see http://php.net/json_decode [JSON decode native function]
134
     *
135
     * @throws \RuntimeException When decode fails.
136
     *
137
     * @return mixed
138
     */
139
    public function decode($json, $assoc = false, $depth = 512, $options = 0)
140
    {
141
        $decoded = \json_decode($this->strip($json), $assoc, $depth, $options);
142
143
        if (\JSON_ERROR_NONE !== $err = \json_last_error()) {
144
            $msg = 'JSON decode failed';
145
146
            if (\function_exists('json_last_error_msg')) {
147
                $msg .= ': ' . \json_last_error_msg();
148
            }
149
150
            throw new \RuntimeException($msg, $err);
151
        }
152
153
        return $decoded;
154
    }
155
156
    /**
157
     * Static alias of decode().
158
     */
159
    public static function parse($json, $assoc = false, $depth = 512, $options = 0)
160
    {
161
        static $parser;
162
163
        if (!$parser) {
164
            $parser = new static;
165
        }
166
167
        return $parser->decode($json, $assoc, $depth, $options);
168
    }
169
}
170