/
json_decode.js
99 lines (89 loc) · 3.55 KB
/
json_decode.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
module.exports = function json_decode(strJson) {
// discuss at: https://phpjs.org/functions/json_decode/
// original by: Public Domain (https://www.json.org/json2.js)
// reimplemented by: Kevin van Zonneveld (https://kevin.vanzonneveld.net)
// improved by: T.J. Leahy
// improved by: Michael White
// note 1: If node or the browser does not offer JSON.parse,
// note 1: this function falls backslash
// note 1: to its own implementation using eval, and hence should be considered unsafe
// example 1: json_decode('[ 1 ]')
// returns 1: [1]
/*
https://www.JSON.org/json2.js
2008-11-19
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See https://www.JSON.org/js.html
*/
const $global = typeof window !== 'undefined' ? window : global
$global.$locutus = $global.$locutus || {}
const $locutus = $global.$locutus
$locutus.php = $locutus.php || {}
const json = $global.JSON
if (typeof json === 'object' && typeof json.parse === 'function') {
try {
return json.parse(strJson)
} catch (err) {
if (!(err instanceof SyntaxError)) {
throw new Error('Unexpected error type in json_decode()')
}
// usable by json_last_error()
$locutus.php.last_error_json = 4
return null
}
}
const chars = [
'\u0000',
'\u00ad',
'\u0600-\u0604',
'\u070f',
'\u17b4',
'\u17b5',
'\u200c-\u200f',
'\u2028-\u202f',
'\u2060-\u206f',
'\ufeff',
'\ufff0-\uffff',
].join('')
const cx = new RegExp('[' + chars + ']', 'g')
let j
let text = strJson
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
cx.lastIndex = 0
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)
})
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
const m = /^[\],:{}\s]*$/.test(
text
.replace(/\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''),
)
if (m) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')') // eslint-disable-line no-eval
return j
}
// usable by json_last_error()
$locutus.php.last_error_json = 4
return null
}