Skip to content

Commit ff55b7a

Browse files
authored
Merge pull request #743 from Milly/Web.JSON-fix-char-encodes
Web.JSON: fix char encodes
2 parents 755bfc2 + c308a9c commit ff55b7a

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

autoload/vital/__vital__/Web/JSON.vim

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,43 @@
11
let s:save_cpo = &cpo
22
set cpo&vim
33

4+
let s:control_chars = {
5+
\ '\': '\\',
6+
\ '"': '\"',
7+
\ "\x01": '\u0001',
8+
\ "\x02": '\u0002',
9+
\ "\x03": '\u0003',
10+
\ "\x04": '\u0004',
11+
\ "\x05": '\u0005',
12+
\ "\x06": '\u0006',
13+
\ "\x07": '\u0007',
14+
\ "\x08": '\b',
15+
\ "\x09": '\t',
16+
\ "\x0a": '\n',
17+
\ "\x0b": '\u000b',
18+
\ "\x0c": '\f',
19+
\ "\x0d": '\r',
20+
\ "\x0e": '\u000e',
21+
\ "\x0f": '\u000f',
22+
\ "\x10": '\u0010',
23+
\ "\x11": '\u0011',
24+
\ "\x12": '\u0012',
25+
\ "\x13": '\u0013',
26+
\ "\x14": '\u0014',
27+
\ "\x15": '\u0015',
28+
\ "\x16": '\u0016',
29+
\ "\x17": '\u0017',
30+
\ "\x18": '\u0018',
31+
\ "\x19": '\u0019',
32+
\ "\x1a": '\u001a',
33+
\ "\x1b": '\u001b',
34+
\ "\x1c": '\u001c',
35+
\ "\x1d": '\u001d',
36+
\ "\x1e": '\u001e',
37+
\ "\x1f": '\u001f',
38+
\ }
39+
lockvar s:control_chars
40+
441
function! s:_true() abort
542
return 1
643
endfunction
@@ -26,7 +63,6 @@ function! s:_resolve(val, prefix) abort
2663
return a:val
2764
endfunction
2865

29-
3066
function! s:_vital_created(module) abort
3167
" define constant variables
3268
if !exists('s:const')
@@ -59,6 +95,10 @@ function! s:decode(json, ...) abort
5995
let json = join(split(json, "\n"), '')
6096
let json = substitute(json, '\\u34;', '\\"', 'g')
6197
let json = substitute(json, '\\u\(\x\x\x\x\)', '\=s:string.nr2enc_char("0x".submatch(1))', 'g')
98+
" convert surrogate pair
99+
let json = substitute(json, '\([\uD800-\uDBFF]\)\([\uDC00-\uDFFF]\)',
100+
\ '\=nr2char(0x10000+and(0x7ff,char2nr(submatch(1)))*0x400+and(0x3ff,char2nr(submatch(2))))',
101+
\ 'g')
62102
if settings.use_token
63103
let prefix = '__Web.JSON__'
64104
while stridx(json, prefix) != -1
@@ -83,11 +123,9 @@ function! s:encode(val, ...) abort
83123
if type(a:val) == 0
84124
return a:val
85125
elseif type(a:val) == 1
86-
let json = '"' . escape(a:val, '\"') . '"'
87-
let json = substitute(json, "\r", '\\r', 'g')
88-
let json = substitute(json, "\n", '\\n', 'g')
89-
let json = substitute(json, "\t", '\\t', 'g')
90-
return iconv(json, &encoding, 'utf-8')
126+
let s = substitute(a:val, '[\x01-\x1f\\"]', '\=s:control_chars[submatch(0)]', 'g')
127+
let s = iconv(s, &encoding, 'utf-8')
128+
return '"' . s . '"'
91129
elseif type(a:val) == 2
92130
if s:const.true == a:val
93131
return 'true'

test/Web/JSON.vimspec

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,17 @@ Describe Web.JSON
2929
\ JSON.decode('"He said \"I''m a vimmer\""'),
3030
\ 'He said "I''m a vimmer"'
3131
\)
32-
" there should be iconv tests as well
32+
" control chars
33+
Assert Equals(JSON.decode('"\u0001\u0002\u0003\u0004\u0005\u0006\u0007"'), "\x01\x02\x03\x04\x05\x06\x07")
34+
Assert Equals(JSON.decode('"\b\t\n\u000b\f\r\u000e\u000f"'), "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f")
35+
Assert Equals(JSON.decode('"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"'), "\x10\x11\x12\x13\x14\x15\x16\x17")
36+
Assert Equals(JSON.decode('"\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"'), "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f")
37+
" multibyte
38+
Assert Equals(JSON.decode('"s¢cĴgё"'), "s¢cĴgё")
39+
" UTF-16 surrogate pair
40+
Assert Equals(JSON.decode('"\ud83c\udf63"'), "\xf0\x9f\x8d\xa3")
41+
" unpaired UTF-16 surrogate
42+
Assert Equals(JSON.decode('"\ud83c\u00a0"'), "\ud83c\u00a0")
3343
End
3444

3545
It decodes lists
@@ -91,7 +101,15 @@ Describe Web.JSON
91101
\ JSON.encode('He said "I''m a vimmer"'),
92102
\ '"He said \"I''m a vimmer\""'
93103
\)
94-
" there should be iconv tests as well
104+
" control chars
105+
Assert Equals(JSON.encode("\x01\x02\x03\x04\x05\x06\x07"), '"\u0001\u0002\u0003\u0004\u0005\u0006\u0007"')
106+
Assert Equals(JSON.encode("\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"), '"\b\t\n\u000b\f\r\u000e\u000f"')
107+
Assert Equals(JSON.encode("\x10\x11\x12\x13\x14\x15\x16\x17"), '"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"')
108+
Assert Equals(JSON.encode("\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"), '"\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"')
109+
" multibyte
110+
Assert Equals(JSON.encode("s¢cĴgё"), '"s¢cĴgё"')
111+
" UTF-16 surrogate pair
112+
Assert Equals(JSON.encode("\xf0\x9f\x8d\xa3"), "\"\xf0\x9f\x8d\xa3\"")
95113
End
96114

97115
It encodes lists

0 commit comments

Comments
 (0)