public static JsonPointer ToDefinitePath(this JsonPointer pointer, JsonDocumentBuilder value)
 {
     if (value.ValueKind == JsonValueKind.Array && pointer.Tokens.Count > 0 && pointer.Tokens[pointer.Tokens.Count - 1] == "-")
     {
         var tokens = new List <string>();
         for (int i = 0; i < pointer.Tokens.Count - 1; ++i)
         {
             tokens.Add(pointer.Tokens[i]);
         }
         tokens.Add(value.GetArrayLength().ToString());
         return(new JsonPointer(tokens));
     }
     else
     {
         return(pointer);
     }
 }
Esempio n. 2
0
 /// <summary>
 /// Determines whether two JSONPointer objects have the same value.
 /// </summary>
 /// <param name="other"></param>
 /// <returns><c>true</c> if other is a <see cref="JsonPointer"/> and has exactly the same reference tokens as this instance; otherwise, <c>false</c>.
 /// If other is <c>null</c>, the method returns <c>false</c>.</returns>
 public bool Equals(JsonPointer other)
 {
     if (other == null)
     {
         return(false);
     }
     if (Tokens.Count != other.Tokens.Count)
     {
         return(false);
     }
     for (int i = 0; i < Tokens.Count; ++i)
     {
         if (!Tokens[i].Equals(other.Tokens[i]))
         {
             return(false);
         }
     }
     return(true);
 }
Esempio n. 3
0
        /// <summary>
        /// Parses a JSON Pointer represented as a string value or a
        /// fragment identifier (starts with <c>#</c>) into a <see cref="JsonPointer"/>.
        /// </summary>
        /// <param name="input">A JSON Pointer represented as a string or a fragment identifier.</param>
        /// <param name="pointer">The JsonPointer.</param>
        /// <returns><c>true</c> if the input string can be parsed into a list of reference tokens, <c>false</c> otherwise.</returns>
        /// <exception cref="ArgumentNullException">
        ///   The <paramref name="input"/> is <see langword="null"/>.
        /// </exception>
        public static bool TryParse(string input, out JsonPointer pointer)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }
            var tokens = new List <string>();

            if (input.Length == 0 || input.Equals("#"))
            {
                pointer = new JsonPointer(tokens);
                return(true);
            }

            JsonPointerState state = JsonPointerState.Start;
            int index  = 0;
            var buffer = new StringBuilder();

            if (input[0] == '#')
            {
                input = Uri.UnescapeDataString(input);
                index = 1;
            }

            while (index < input.Length)
            {
                bool done = false;
                while (index < input.Length && !done)
                {
                    switch (state)
                    {
                    case JsonPointerState.Start:
                        switch (input[index])
                        {
                        case '/':
                            state = JsonPointerState.Delim;
                            break;

                        default:
                            pointer = JsonPointer.Default;
                            return(false);
                        }
                        ;
                        break;

                    case JsonPointerState.Delim:
                        switch (input[index])
                        {
                        case '/':
                            done = true;
                            break;

                        case '~':
                            state = JsonPointerState.Escaped;
                            break;

                        default:
                            buffer.Append(input[index]);
                            break;
                        }
                        ;
                        break;

                    case JsonPointerState.Escaped:
                        switch (input[index])
                        {
                        case '0':
                            buffer.Append('~');
                            state = JsonPointerState.Delim;
                            break;

                        case '1':
                            buffer.Append('/');
                            state = JsonPointerState.Delim;
                            break;

                        default:
                            pointer = JsonPointer.Default;
                            return(false);
                        }
                        ;
                        break;

                    default:
                        pointer = JsonPointer.Default;
                        return(false);
                    }
                    ++index;
                }
                tokens.Add(buffer.ToString());
                buffer.Clear();
            }
            if (buffer.Length > 0)
            {
                tokens.Add(buffer.ToString());
            }
            pointer = new JsonPointer(tokens);
            return(true);
        }
Esempio n. 4
0
        static JsonDocumentBuilder _FromDiff(JsonElement source,
                                             JsonElement target,
                                             string path)
        {
            var builder = new JsonDocumentBuilder(JsonValueKind.Array);

            JsonElementEqualityComparer comparer = JsonElementEqualityComparer.Instance;

            if (comparer.Equals(source, target))
            {
                return(builder);
            }

            if (source.ValueKind == JsonValueKind.Array && target.ValueKind == JsonValueKind.Array)
            {
                int common = Math.Min(source.GetArrayLength(), target.GetArrayLength());
                for (int i = 0; i < common; ++i)
                {
                    var buffer = new StringBuilder(path);
                    buffer.Append("/");
                    buffer.Append(i.ToString());
                    var temp_diff = _FromDiff(source[i], target[i], buffer.ToString());
                    foreach (var item in temp_diff.EnumerateArray())
                    {
                        builder.AddArrayItem(item);
                    }
                }
                // Element in source, not in target - remove
                for (int i = source.GetArrayLength(); i-- > target.GetArrayLength();)
                {
                    var buffer = new StringBuilder(path);
                    buffer.Append("/");
                    buffer.Append(i.ToString());
                    var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object);
                    valBuilder.AddProperty("op", new JsonDocumentBuilder("remove"));
                    valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString()));
                    builder.AddArrayItem(valBuilder);
                }
                // Element in target, not in source - add,
                for (int i = source.GetArrayLength(); i < target.GetArrayLength(); ++i)
                {
                    var a      = target[i];
                    var buffer = new StringBuilder(path);
                    buffer.Append("/");
                    buffer.Append(i.ToString());
                    var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object);
                    valBuilder.AddProperty("op", new JsonDocumentBuilder("add"));
                    valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString()));
                    valBuilder.AddProperty("value", new JsonDocumentBuilder(a));
                    builder.AddArrayItem(valBuilder);
                }
            }
            else if (source.ValueKind == JsonValueKind.Object && target.ValueKind == JsonValueKind.Object)
            {
                foreach (var a in source.EnumerateObject())
                {
                    var buffer = new StringBuilder(path);
                    buffer.Append("/");
                    buffer.Append(JsonPointer.Escape(a.Name));

                    JsonElement element;
                    if (target.TryGetProperty(a.Name, out element))
                    {
                        var temp_diff = _FromDiff(a.Value, element, buffer.ToString());
                        foreach (var item in temp_diff.EnumerateArray())
                        {
                            builder.AddArrayItem(item);
                        }
                    }
                    else
                    {
                        var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object);
                        valBuilder.AddProperty("op", new JsonDocumentBuilder("remove"));
                        valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString()));
                        builder.AddArrayItem(valBuilder);
                    }
                }
                foreach (var a in target.EnumerateObject())
                {
                    JsonElement element;
                    if (!source.TryGetProperty(a.Name, out element))
                    {
                        var buffer = new StringBuilder(path);
                        buffer.Append("/");
                        buffer.Append(JsonPointer.Escape(a.Name));
                        var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object);
                        valBuilder.AddProperty("op", new JsonDocumentBuilder("add"));
                        valBuilder.AddProperty("path", new JsonDocumentBuilder(buffer.ToString()));
                        valBuilder.AddProperty("value", new JsonDocumentBuilder(a.Value));
                        builder.AddArrayItem(valBuilder);
                    }
                }
            }
            else
            {
                var valBuilder = new JsonDocumentBuilder(JsonValueKind.Object);
                valBuilder.AddProperty("op", new JsonDocumentBuilder("replace"));
                valBuilder.AddProperty("path", new JsonDocumentBuilder(path));
                valBuilder.AddProperty("value", new JsonDocumentBuilder(target));
                builder.AddArrayItem(valBuilder);
            }

            return(builder);
        }
Esempio n. 5
0
        static void ApplyPatch(ref JsonDocumentBuilder target,
                               JsonElement patch)
        {
            JsonElementEqualityComparer comparer = JsonElementEqualityComparer.Instance;

            Debug.Assert(target != null);

            if (patch.ValueKind != JsonValueKind.Array)
            {
                throw new ArgumentException("Patch must be an array");
            }

            foreach (var operation in patch.EnumerateArray())
            {
                JsonElement opElement;
                if (!operation.TryGetProperty("op", out opElement))
                {
                    throw new ArgumentException("Invalid patch");
                }
                string op = opElement.GetString() ?? throw new InvalidOperationException("Operation cannot be null");

                JsonElement pathElement;
                if (!operation.TryGetProperty("path", out pathElement))
                {
                    throw new ArgumentException(op, "Invalid patch");
                }
                string path = pathElement.GetString() ?? throw new InvalidOperationException("Operation cannot be null");;

                JsonPointer location;
                if (!JsonPointer.TryParse(path, out location))
                {
                    throw new ArgumentException(op, "Invalid patch");
                }

                if (op == "test")
                {
                    JsonElement value;
                    if (!operation.TryGetProperty("value", out value))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }

                    JsonDocumentBuilder tested;
                    if (!location.TryGetValue(target, out tested))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }

                    using (var doc = tested.ToJsonDocument())
                    {
                        if (!comparer.Equals(doc.RootElement, value))
                        {
                            throw new JsonPatchException(op, "Test failed");
                        }
                    }
                }
                else if (op == "add")
                {
                    JsonElement value;
                    if (!operation.TryGetProperty("value", out value))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }
                    var valueBuilder = new JsonDocumentBuilder(value);
                    if (!location.TryAddIfAbsent(ref target, valueBuilder)) // try insert without replace
                    {
                        if (!location.TryReplace(ref target, valueBuilder)) // try insert without replace
                        {
                            throw new JsonPatchException(op, "Add failed");
                        }
                    }
                }
                else if (op == "remove")
                {
                    if (!location.TryRemove(ref target))
                    {
                        throw new JsonPatchException(op, "Add failed");
                    }
                }
                else if (op == "replace")
                {
                    JsonElement value;
                    if (!operation.TryGetProperty("value", out value))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }
                    var valueBuilder = new JsonDocumentBuilder(value);
                    if (!location.TryReplace(ref target, valueBuilder))
                    {
                        throw new JsonPatchException(op, "Replace failed");
                    }
                }
                else if (op == "move")
                {
                    JsonElement fromElement;
                    if (!operation.TryGetProperty("from", out fromElement))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }
                    string from = fromElement.GetString() ?? throw new InvalidOperationException("From element cannot be null");;

                    JsonPointer fromPointer;
                    if (!JsonPointer.TryParse(from, out fromPointer))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }

                    JsonDocumentBuilder value;
                    if (!fromPointer.TryGetValue(target, out value))
                    {
                        throw new JsonPatchException(op, "Move failed");
                    }

                    if (!fromPointer.TryRemove(ref target))
                    {
                        throw new JsonPatchException(op, "Move failed");
                    }
                    if (!location.TryAddIfAbsent(ref target, value))
                    {
                        if (!location.TryReplace(ref target, value)) // try insert without replace
                        {
                            throw new JsonPatchException(op, "Move failed");
                        }
                    }
                }
                else if (op == "copy")
                {
                    JsonElement fromElement;
                    if (!operation.TryGetProperty("from", out fromElement))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }
                    string      from = fromElement.GetString() ?? throw new InvalidOperationException("from cannot be null");
                    JsonPointer fromPointer;
                    if (!JsonPointer.TryParse(from, out fromPointer))
                    {
                        throw new ArgumentException(op, "Invalid patch");
                    }

                    JsonDocumentBuilder value;
                    if (!fromPointer.TryGetValue(target, out value))
                    {
                        throw new JsonPatchException(op, "Copy failed");
                    }
                    if (!location.TryAddIfAbsent(ref target, value))
                    {
                        if (!location.TryReplace(ref target, value)) // try insert without replace
                        {
                            throw new JsonPatchException(op, "Move failed");
                        }
                    }
                }
            }
        }
        public static bool TryAdd(this JsonPointer location,
                                  ref JsonDocumentBuilder root,
                                  JsonDocumentBuilder value)
        {
            JsonDocumentBuilder current = root;
            string token = "";

            var  enumerator = location.GetEnumerator();
            bool more       = enumerator.MoveNext();

            if (!more)
            {
                return(false);
            }
            while (more)
            {
                token = enumerator.Current;
                more  = enumerator.MoveNext();
                if (more)
                {
                    if (!TryResolve(token, current, out current))
                    {
                        return(false);
                    }
                }
            }

            if (current.ValueKind == JsonValueKind.Array)
            {
                if (token.Length == 1 && token[0] == '-')
                {
                    current.AddArrayItem(value);
                    current = current[current.GetArrayLength() - 1];
                }
                else
                {
                    int index;
                    if (!int.TryParse(token, out index))
                    {
                        return(false);
                    }
                    if (index > current.GetArrayLength())
                    {
                        return(false);
                    }
                    if (index == current.GetArrayLength())
                    {
                        current.AddArrayItem(value);
                        current = value;
                    }
                    else
                    {
                        current.InsertArrayItem(index, value);
                        current = value;
                    }
                }
            }
            else if (current.ValueKind == JsonValueKind.Object)
            {
                if (current.ContainsPropertyName(token))
                {
                    current.RemoveProperty(token);
                }
                current.AddProperty(token, value);
                current = value;
            }
            else
            {
                return(false);
            }
            return(true);
        }
        static bool TryUnflattenArray(JsonElement value, out JsonDocumentBuilder result)
        {
            if (value.ValueKind != JsonValueKind.Object)
            {
                throw new ArgumentException("The value to unflatten is not a JSON object");
            }

            result = new JsonDocumentBuilder(JsonValueKind.Object);

            foreach (var item in value.EnumerateObject())
            {
                JsonDocumentBuilder? parent = null;
                JsonDocumentBuilder part = result;
                int parentIndex = 0;
                string parentName = "";

                JsonPointer ptr;
                if (!JsonPointer.TryParse(item.Name, out ptr))
                {
                    throw new ArgumentException("Name contains invalid JSON Pointer");
                }
                int index = 0;

                var it = ptr.GetEnumerator();
                bool more = it.MoveNext();
                while (more)
                {
                    string token = it.Current;
                    int n;

                    if (int.TryParse(token, out n) && index++ == n)
                    {
                        if (part.ValueKind != JsonValueKind.Array)
                        {
                            if (parent != null && parent.ValueKind == JsonValueKind.Object)
                            {
                                parent.RemoveProperty(parentName);
                                var val = new JsonDocumentBuilder(JsonValueKind.Array);
                                parent.AddProperty(parentName, val);
                                part = val;
                            }
                            else if (parent != null && parent.ValueKind == JsonValueKind.Array)
                            {
                                var val = new JsonDocumentBuilder(JsonValueKind.Array);
                                parent[parentIndex] = val;
                                part = val;
                            }
                            else
                            {
                                return false;
                            }
                        }
                        parent = part;
                        parentIndex = n;
                        parentName = token;
                        more = it.MoveNext();
                        if (more)
                        {
                            if (n >= part.GetArrayLength())
                            {
                                part.AddArrayItem(new JsonDocumentBuilder(JsonValueKind.Object));
                                part = part[part.GetArrayLength() - 1];
                            }
                            else
                            {
                                part = part[n];
                            }
                        }
                        else
                        {
                            part.AddArrayItem(new JsonDocumentBuilder(item.Value));
                            part = part[part.GetArrayLength() - 1];
                        }
                    }
                    else if (part.ValueKind == JsonValueKind.Object)
                    {
                        more = it.MoveNext();
                        if (more)
                        {
                            JsonDocumentBuilder val;
                            if (part.TryGetProperty(token, out val))
                            {
                                part = val;
                            }
                            else
                            {
                                val = new JsonDocumentBuilder(JsonValueKind.Object);
                                part.AddProperty(token,val);
                                part = val;
                            }
                        }
                        else
                        {
                            JsonDocumentBuilder val;
                            if (part.TryGetProperty(token, out val))
                            {
                                part = val;
                            }
                            else
                            {
                                val = new JsonDocumentBuilder(item.Value);
                                part.AddProperty(token,val);
                                part = val;
                            }
                        }
                    }
                    else 
                    {
                        return false;
                    }
                }
            }

            return true;
        }