1// Copyright 2010 The Go Authors.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package json implements encoding and decoding of JSON objects as defined in
6// RFC 4627. The mapping between JSON objects and Go values is described
7// in the documentation for the Marshal and Unmarshal functions.
8//
9// See "JSON and Go" for an introduction to this package:
10// http://golang.org/doc/articles/json_and_go.html
11
12package collatejson
13
14import "unicode/utf8"
15
16var hex = "0123456789abcdef"
17
18// Copied from golang src/pkg/encoding/json/encode.go
19// Modified to use []byte as input and use DecodeRune() instead of
20// DecodeRuneInString.
21func encodeString(s []byte, text []byte) ([]byte, error) {
22	text = append(text, '"')
23	start := 0
24	for i := 0; i < len(s); {
25		if b := s[i]; b < utf8.RuneSelf {
26			if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
27				i++
28				continue
29			}
30			if start < i {
31				text = append(text, s[start:i]...)
32			}
33			switch b {
34			case '\\', '"':
35				text = append(text, '\\')
36				text = append(text, b)
37			case '\n':
38				text = append(text, '\\')
39				text = append(text, 'n')
40			case '\r':
41				text = append(text, '\\')
42				text = append(text, 'r')
43			default:
44				// This encodes bytes < 0x20 except for \n and \r,
45				// as well as <, > and &. The latter are escaped because they
46				// can lead to security holes when user-controlled strings
47				// are rendered into JSON and served to some browsers.
48
49				text = append(text, `\u00`...)
50				text = append(text, hex[b>>4])
51				text = append(text, hex[b&0xF])
52			}
53			i++
54			start = i
55			continue
56		}
57		c, size := utf8.DecodeRune(s[i:])
58		if c == utf8.RuneError && size == 1 {
59			if start < i {
60				text = append(text, s[start:i]...)
61			}
62			text = append(text, `\ufffd`...)
63			i += size
64			start = i
65			continue
66		}
67		// U+2028 is LINE SEPARATOR.
68		// U+2029 is PARAGRAPH SEPARATOR.
69		// They are both technically valid characters in JSON strings,
70		// but don't work in JSONP, which has to be evaluated as JavaScript,
71		// and can lead to security holes there. It is valid JSON to
72		// escape them, so we do so unconditionally.
73		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
74		if c == '\u2028' || c == '\u2029' {
75			if start < i {
76				text = append(text, s[start:i]...)
77			}
78			text = append(text, `\u202`...)
79			text = append(text, hex[c&0xF])
80			i += size
81			start = i
82			continue
83		}
84		i += size
85	}
86	if start < len(s) {
87		text = append(text, s[start:]...)
88	}
89	text = append(text, '"')
90	return text, nil
91}
92