/// <summary> /// Unpatch a JSON object /// </summary> /// <param name="right">Patched JSON object</param> /// <param name="patch">JSON Patch Document</param> /// <returns>Unpatched JSON object</returns> /// <exception cref="System.IO.InvalidDataException">Thrown if the patch document is invalid</exception> public JToken Unpatch(JToken right, JToken patch) { if (patch == null) return right; if (patch.Type == JTokenType.Object) { var patchObj = (JObject)patch; JProperty arrayDiffCanary = patchObj.Property("_t"); if (right != null && right.Type == JTokenType.Array && arrayDiffCanary != null && arrayDiffCanary.Value.Type == JTokenType.String && arrayDiffCanary.ToObject<string>() == "a") { return ArrayUnpatch((JArray)right, patchObj); } return ObjectUnpatch(right as JObject, patchObj); } if (patch.Type == JTokenType.Array) { var patchArray = (JArray)patch; if (patchArray.Count == 1) // Add (we need to remove the property) { return null; } else if (patchArray.Count == 2) // Replace { return patchArray[0]; } else if (patchArray.Count == 3) // Delete, Move or TextDiff { if (patchArray[2].Type != JTokenType.Integer) throw new InvalidDataException("Invalid patch object"); int op = patchArray[2].Value<int>(); if (op == 0) { return patchArray[0]; } else if (op == 2) { var dmp = new diff_match_patch(); List<Patch> patches = dmp.patch_fromText(patchArray[0].ToObject<string>()); if (patches.Count != 1) throw new InvalidDataException("Invalid textline"); string left = dmp.diff_text1(patches[0].diffs); return left; } else { throw new InvalidDataException("Invalid patch object"); } } else { throw new InvalidDataException("Invalid patch object"); } } return null; }