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
5package edn
6
7import (
8	"reflect"
9	"strconv"
10	"unicode/utf8"
11)
12
13// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
14// or it returns -1.
15func getu4(s []byte) rune {
16	if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
17		return -1
18	}
19	r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
20	if err != nil {
21		return -1
22	}
23	return rune(r)
24}
25
26// indirect walks down v allocating pointers as needed,
27// until it gets to a non-pointer.
28// if it encounters an Unmarshaler, indirect stops and returns that.
29// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
30func (d *Decoder) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
31	// If v is a named type and is addressable,
32	// start with its address, so that if the type has pointer methods,
33	// we find them.
34	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
35		v = v.Addr()
36	}
37	for {
38		// Load value from interface, but only if the result will be
39		// usefully addressable.
40		if v.Kind() == reflect.Interface && !v.IsNil() {
41			e := v.Elem()
42			if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
43				v = e
44				continue
45			}
46		}
47
48		if v.Kind() != reflect.Ptr {
49			break
50		}
51
52		if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
53			break
54		}
55		if v.IsNil() {
56			v.Set(reflect.New(v.Type().Elem()))
57		}
58		if v.Type().NumMethod() > 0 {
59			if u, ok := v.Interface().(Unmarshaler); ok {
60				return u, reflect.Value{}
61			}
62		}
63		v = v.Elem()
64	}
65	return nil, v
66}
67
68// unquote converts a quoted EDN string literal s into an actual string t.
69// The rules are different than for Go, so cannot use strconv.Unquote.
70func unquote(s []byte) (t string, ok bool) {
71	s, ok = unquoteBytes(s)
72	t = string(s)
73	return
74}
75
76func unquoteBytes(s []byte) (t []byte, ok bool) {
77	if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
78		return
79	}
80	s = s[1 : len(s)-1]
81
82	// Check for unusual characters. If there are none,
83	// then no unquoting is needed, so return a slice of the
84	// original bytes.
85	r := 0
86	for r < len(s) {
87		c := s[r]
88		if c == '\\' || c == '"' {
89			break
90		}
91		if c < utf8.RuneSelf {
92			r++
93			continue
94		}
95		rr, size := utf8.DecodeRune(s[r:])
96		if rr == utf8.RuneError && size == 1 {
97			break
98		}
99		r += size
100	}
101	if r == len(s) {
102		return s, true
103	}
104
105	b := make([]byte, len(s)+2*utf8.UTFMax)
106	w := copy(b, s[0:r])
107	for r < len(s) {
108		// Out of room?  Can only happen if s is full of
109		// malformed UTF-8 and we're replacing each
110		// byte with RuneError.
111		if w >= len(b)-2*utf8.UTFMax {
112			nb := make([]byte, (len(b)+utf8.UTFMax)*2)
113			copy(nb, b[0:w])
114			b = nb
115		}
116		switch c := s[r]; {
117		case c == '\\':
118			r++
119			if r >= len(s) {
120				return
121			}
122			switch s[r] {
123			default:
124				return
125			case '"', '\\', '/', '\'':
126				b[w] = s[r]
127				r++
128				w++
129			case 'b':
130				b[w] = '\b'
131				r++
132				w++
133			case 'f':
134				b[w] = '\f'
135				r++
136				w++
137			case 'n':
138				b[w] = '\n'
139				r++
140				w++
141			case 'r':
142				b[w] = '\r'
143				r++
144				w++
145			case 't':
146				b[w] = '\t'
147				r++
148				w++
149			case 'u':
150				r--
151				rr := getu4(s[r:])
152				if rr < 0 {
153					return
154				}
155				r += 6
156				w += utf8.EncodeRune(b[w:], rr)
157			}
158
159		// Quote is invalid
160		case c == '"':
161			return
162
163		// ASCII
164		case c < utf8.RuneSelf:
165			b[w] = c
166			r++
167			w++
168
169		// Coerce to well-formed UTF-8.
170		default:
171			rr, size := utf8.DecodeRune(s[r:])
172			r += size
173			w += utf8.EncodeRune(b[w:], rr)
174		}
175	}
176	return b[0:w], true
177}
178