Update dependencies
This commit is contained in:
106
vendor/github.com/tailscale/hujson/find.go
generated
vendored
Normal file
106
vendor/github.com/tailscale/hujson/find.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package hujson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var errNotFound = fmt.Errorf("value not found")
|
||||
|
||||
// Find locates the value specified by the JSON pointer (see RFC 6901).
|
||||
// It returns nil if the value does not exist or the pointer is invalid.
|
||||
// If a JSON object has multiple members matching a given name,
|
||||
// the first is returned. Object names are matched exactly,
|
||||
// rather than with a case-insensitive match.
|
||||
func (v *Value) Find(ptr string) *Value {
|
||||
if s, err := v.find(findState{pointer: ptr}); err == nil {
|
||||
return s.value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type findState struct {
|
||||
pointer string // pointer[:offset] is the current value, pointer[offset:] is the remainder
|
||||
offset int
|
||||
|
||||
parent composite // nil for root pointer
|
||||
name string // name into parent to obtain current value
|
||||
idx int // idx into parent to obtain current value
|
||||
value *Value // the current value
|
||||
}
|
||||
|
||||
func (v *Value) find(s findState) (findState, error) {
|
||||
// An empty pointer denotes the value itself.
|
||||
s.value = v
|
||||
if s.pointer[s.offset:] == "" {
|
||||
return s, nil
|
||||
}
|
||||
comp, ok := v.Value.(composite)
|
||||
if !ok {
|
||||
return s, fmt.Errorf("invalid pointer: cannot index into literal at %v", s.pointer[:s.offset])
|
||||
}
|
||||
|
||||
// There must be one or more fragments.
|
||||
s.parent, s.idx, s.name = nil, 0, ""
|
||||
if !strings.HasPrefix(s.pointer[s.offset:], "/") {
|
||||
return s, fmt.Errorf("invalid pointer: lacks a forward slash prefix")
|
||||
}
|
||||
n := len("/")
|
||||
if i := strings.IndexByte(s.pointer[s.offset+n:], '/'); i >= 0 {
|
||||
n += i
|
||||
} else {
|
||||
n = len(s.pointer) - s.offset
|
||||
}
|
||||
s.offset += n
|
||||
|
||||
// Unescape the name if necessary (section 4).
|
||||
name := s.pointer[s.offset-n : s.offset]
|
||||
if strings.IndexByte(name, '~') >= 0 {
|
||||
name = strings.ReplaceAll(name, "~1", "/")
|
||||
name = strings.ReplaceAll(name, "~0", "~")
|
||||
}
|
||||
name = name[len("/"):]
|
||||
|
||||
// Index into the object or array.
|
||||
s.parent, s.name, s.idx = comp, name, comp.length()
|
||||
switch comp := v.Value.(type) {
|
||||
case *Object:
|
||||
for i, m := range comp.Members {
|
||||
if m.Name.Value.(Literal).equalString(name) {
|
||||
s.idx = i
|
||||
return comp.Members[i].Value.find(s)
|
||||
}
|
||||
}
|
||||
case *Array:
|
||||
if name == "-" {
|
||||
return s, errNotFound
|
||||
}
|
||||
i, err := strconv.ParseUint(name, 10, 0)
|
||||
if err != nil || (i == 0 && name != "0") {
|
||||
return s, fmt.Errorf("invalid array index: %s", name)
|
||||
}
|
||||
if i < uint64(len(comp.Elements)) {
|
||||
s.idx = int(i)
|
||||
return comp.Elements[i].find(s)
|
||||
}
|
||||
}
|
||||
return s, errNotFound
|
||||
}
|
||||
|
||||
func (b Literal) equalString(s string) bool {
|
||||
// Fast-path: Assume there are no escape characters.
|
||||
if len(b) >= 2 && b[0] == '"' && b[len(b)-1] == '"' && bytes.IndexByte(b, '\\') < 0 {
|
||||
return string(b[len(`"`):len(b)-len(`"`)]) == s
|
||||
}
|
||||
// Slow-path: Unescape the string and then compare it.
|
||||
// TODO(dsnet): Implement allocation-free comparison.
|
||||
var s2 string
|
||||
return json.Unmarshal(b, &s2) == nil && s == s2
|
||||
}
|
||||
Reference in New Issue
Block a user