* Set - Receives existing data structure, path to set, and data to set at that key. Returns: `value` - modified byte array `err` - On any parsing error */ SYS-REQ-009, SYS-REQ-051, SYS-REQ-068, SYS-REQ-069, SYS-REQ-070
(data []byte, setValue []byte, keys ...string)
| 839 | */ |
| 840 | // SYS-REQ-009, SYS-REQ-051, SYS-REQ-068, SYS-REQ-069, SYS-REQ-070 |
| 841 | func Set(data []byte, setValue []byte, keys ...string) (value []byte, err error) { |
| 842 | // ensure keys are set |
| 843 | if len(keys) == 0 { |
| 844 | return nil, KeyPathNotFoundError |
| 845 | } |
| 846 | |
| 847 | _, _, startOffset, endOffset, err := internalGet(data, keys...) |
| 848 | if err != nil { |
| 849 | if err != KeyPathNotFoundError { |
| 850 | // problem parsing the data |
| 851 | return nil, err |
| 852 | } |
| 853 | // full path doesnt exist |
| 854 | // does any subpath exist? |
| 855 | var depth int |
| 856 | for i := range keys { |
| 857 | _, _, start, end, sErr := internalGet(data, keys[:i+1]...) |
| 858 | if sErr != nil { |
| 859 | break |
| 860 | } else { |
| 861 | endOffset = end |
| 862 | startOffset = start |
| 863 | depth++ |
| 864 | } |
| 865 | } |
| 866 | comma := true |
| 867 | object := false |
| 868 | if endOffset == -1 { |
| 869 | firstToken := nextToken(data) |
| 870 | // We can't set a top-level key if data isn't an object |
| 871 | if firstToken < 0 || data[firstToken] != '{' { |
| 872 | return nil, KeyPathNotFoundError |
| 873 | } |
| 874 | // Don't need a comma if the input is an empty object |
| 875 | secondToken := firstToken + 1 + nextToken(data[firstToken+1:]) |
| 876 | if data[secondToken] == '}' { |
| 877 | comma = false |
| 878 | } |
| 879 | // Set the top level key at the end (accounting for any trailing whitespace) |
| 880 | // This assumes last token is valid like '}', could check and return error |
| 881 | endOffset = lastToken(data) |
| 882 | } |
| 883 | depthOffset := endOffset |
| 884 | if depth != 0 { |
| 885 | // if subpath is a non-empty object, add to it |
| 886 | // or if subpath is a non-empty array, add to it |
| 887 | if (data[startOffset] == '{' && data[startOffset+1+nextToken(data[startOffset+1:])] != '}') || |
| 888 | (data[startOffset] == '[' && data[startOffset+1+nextToken(data[startOffset+1:])] == '{') && keys[depth:][0][0] == 91 { |
| 889 | depthOffset-- |
| 890 | startOffset = depthOffset |
| 891 | // otherwise, over-write it with a new object |
| 892 | } else { |
| 893 | comma = false |
| 894 | object = true |
| 895 | } |
| 896 | } else { |
| 897 | startOffset = depthOffset |
| 898 | } |