static void PrintDiff(HashDiff diff)
        {
            StringBuilder sb = new StringBuilder();

            diff.Write(sb);
            System.Diagnostics.Debug.WriteLine(sb.ToString());
        }
Пример #2
0
        /// <summary>
        /// Merges two HashDifferences to a unified difference.
        /// </summary>
        public static HashDiff Merge(HashDiff left, HashDiff right)
        {
            // Find the combined key list.
            List <object> keys = left.Operations.Keys.ToList <object>();

            foreach (var kvp in right.Operations)
            {
                if (!left.Operations.ContainsKey(kvp.Key))
                {
                    keys.Add(kvp.Key);
                }
            }

            // Merge the operations for each key.
            HashDiff h = new HashDiff();

            foreach (object key in keys)
            {
                if (left.Operations.ContainsKey(key) && right.Operations.ContainsKey(key))
                {
                    h.Operations[key] = DiffOperation.Merge(left.Operations[key], right.Operations[key]);
                }
                else if (left.Operations.ContainsKey(key))
                {
                    h.Operations[key] = left.Operations[key];
                }
                else if (right.Operations.ContainsKey(key))
                {
                    h.Operations[key] = right.Operations[key];
                }
            }
            return(h);
        }
Пример #3
0
        /// <summary>
        /// Finds the difference between two Json arrays based on element IDs.
        /// </summary>
        public static HashDiff IdDiff(ArrayList a, ArrayList b)
        {
            HashDiff diff = new HashDiff();

            for (int i = 0; i < a.Count; ++i)
            {
                object        id = Id.GetId(a[i]);
                DiffOperation op = DiffValue(a[i], Id.FindObjectWithId(b, id));
                if (op != null)
                {
                    diff.Operations[id] = op;
                }
            }

            for (int i = 0; i < b.Count; ++i)
            {
                object id       = Id.GetId(b[i]);
                object a_object = Id.FindObjectWithId(a, id);
                if (a_object == null)
                {
                    diff.Operations[id] = new ChangeOperation(b[i]);
                }
            }

            return(diff);
        }
Пример #4
0
        /// <summary>
        /// Finds the difference between two Json hashtables.
        /// </summary>
        public static HashDiff Diff(Hashtable first, Hashtable second)
        {
            HashDiff diff = new HashDiff();

            foreach (DictionaryEntry de in first)
            {
                string key          = (de.Key as string);
                object first_value  = de.Value;
                object second_value = second.ContainsKey(key) ? second[key] : null;

                DiffOperation op = DiffValue(first_value, second_value);
                if (op != null)
                {
                    diff.Operations[key] = op;
                }
            }

            foreach (DictionaryEntry de in second)
            {
                string key = de.Key as string;
                if (!first.ContainsKey(key))
                {
                    diff.Operations[key] = new ChangeOperation(de.Value);
                }
            }

            return(diff);
        }
        static void TestValidDiff(Hashtable a, Hashtable b, HashDiff diff)
        {
            diff.Apply(a);
            HashDiff newdiff = JsonDiff.Diff(a, b);

            System.Diagnostics.Debug.Assert(newdiff.Empty());
        }
        static void TestDiff(string s_a, string s_b)
        {
            Hashtable a = Sjson(s_a);
            Hashtable b = Sjson(s_b);

            HashDiff diff = JsonDiff.Diff(a, b);

            PrintDiff(diff);
            TestValidDiff(a, b, diff);
        }
Пример #7
0
        /// <summary>
        /// Computes the three-way-merge of Json hashtables.
        /// </summary>
        public static Hashtable Merge(Hashtable parent, Hashtable left, Hashtable right)
        {
            HashDiff left_diff  = JsonDiff.Diff(parent, left);
            HashDiff right_diff = JsonDiff.Diff(parent, right);
            HashDiff diff       = HashDiff.Merge(left_diff, right_diff);

            Hashtable res = parent.DeepClone();

            diff.Apply(res);
            return(res);
        }
Пример #8
0
        /// <summary>
        /// Computes the three-way-merge of Json hashtables and returns the intermediate diff results.
        /// </summary>
        public static Hashtable MergeDetailed(Hashtable parent, Hashtable left, Hashtable right,
                                              out HashDiff left_diff, out HashDiff right_diff, out HashDiff merged_diff)
        {
            left_diff   = JsonDiff.Diff(parent, left);
            right_diff  = JsonDiff.Diff(parent, right);
            merged_diff = HashDiff.Merge(left_diff, right_diff);

            Hashtable res = parent.DeepClone();

            merged_diff.Apply(res);
            return(res);
        }
Пример #9
0
 /// <summary>
 /// Finds the difference operation between two Json value items.
 /// </summary>
 private static DiffOperation DiffValue(object first, object second)
 {
     if (first == null && second == null)
     {
         return(null);
     }
     else if (second == null)
     {
         return(new RemoveOperation());
     }
     else if (first == null)
     {
         return(new ChangeOperation(second));
     }
     else if (first.GetType() != second.GetType())
     {
         return(new ChangeOperation(second));
     }
     else if (first is double)
     {
         return((double)first == (double)second ? null : new ChangeOperation(second));
     }
     else if (first is bool)
     {
         return((bool)first == (bool)second ? null : new ChangeOperation(second));
     }
     else if (first is string)
     {
         return((string)first == (string)second ? null : new ChangeOperation(second));
     }
     else if (first is Hashtable)
     {
         HashDiff subdiff = Diff(first as Hashtable, second as Hashtable);
         return(subdiff.Empty() ? null : new ChangeObjectOperation(subdiff));
     }
     else if (first is ArrayList)
     {
         if (AreIdArrays(first as ArrayList, second as ArrayList))
         {
             HashDiff subdiff = IdDiff(first as ArrayList, second as ArrayList);
             return(subdiff.Empty() ? null : new ChangeIdArrayOperation(subdiff));
         }
         else
         {
             PositionArrayDiff subdiff = PositionDiff(first as ArrayList, second as ArrayList);
             return(subdiff.Empty() ? null : new ChangePositionArrayOperation(subdiff));
         }
     }
     else
     {
         throw new System.Exception("error");
     }
 }
        // Shows the difference between two hash tables.
        private void DisplayDiff(Hashtable a, Hashtable b, HashDiff diff, int indent)
        {
            HashSet <string> keys = new HashSet <string>();

            foreach (string key in a.Keys)
            {
                keys.Add(key);
            }
            foreach (string key in b.Keys)
            {
                keys.Add(key);
            }

            foreach (string key in keys.OrderBy(i => i))
            {
                if (diff.Operations.ContainsKey(key))
                {
                    DiffOperation dop = diff.Operations[key];
                    if (dop is RemoveOperation)
                    {
                        RemovedText(_af.ObjectField(a, key, indent), "");
                    }
                    else if (dop is ChangeOperation)
                    {
                        ChangedText(_af.ObjectField(a, key, indent), _bf.ObjectField(b, key, indent));
                    }
                    else if (dop is ChangeObjectOperation)
                    {
                        SameText(_af.ObjectStart(key, indent), _bf.ObjectStart(key, indent));
                        DisplayDiff(a[key] as Hashtable, b[key] as Hashtable, (dop as ChangeObjectOperation).Diff, indent + 1);
                        SameText(_af.ObjectEnd(indent), _bf.ObjectEnd(indent));
                    }
                    else if (dop is ChangePositionArrayOperation)
                    {
                        SameText(_af.ArrayStart(key, indent), _bf.ArrayStart(key, indent));
                        DisplayDiff(a[key] as ArrayList, b[key] as ArrayList, (dop as ChangePositionArrayOperation).Diff, indent + 1);
                        SameText(_af.ArrayEnd(indent), _bf.ArrayEnd(indent));
                    }
                    else if (dop is ChangeIdArrayOperation)
                    {
                        SameText(_af.ArrayStart(key, indent), _bf.ArrayStart(key, indent));
                        DisplayDiff(a[key] as ArrayList, b[key] as ArrayList, (dop as ChangeIdArrayOperation).Diff, indent + 1);
                        SameText(_af.ArrayEnd(indent), _bf.ArrayEnd(indent));
                    }
                }
                else
                {
                    SameText(_af.ObjectField(a, key, indent), _bf.ObjectField(a, key, indent));
                }
            }
        }
        // Shows the difference between two arrays that use the id-merge method.
        private void DisplayDiff(ArrayList a, ArrayList b, HashDiff diff, int indent)
        {
            HashSet <object> keys = new HashSet <object>();

            foreach (object h in a)
            {
                keys.Add(Id.GetId(h));
            }
            foreach (object h in b)
            {
                keys.Add(Id.GetId(h));
            }

            foreach (object key in keys.OrderBy(i => i))
            {
                object ao = Id.FindObjectWithId(a, key);
                object bo = Id.FindObjectWithId(b, key);
                DisplayArrayDiff(ao, bo, diff.Operations.GetValueOrDefault(key, null), indent);
            }
        }
        /// <summary>
        /// Shows the difference between the two JSON objects a and b.
        /// Diff is the computed difference between the objects.
        /// If json is set to true, the output is showed in JSON format,
        /// otherwise SJSON format is used.
        /// </summary>
        public DiffVisualForm(Hashtable a, Hashtable b, HashDiff diff, bool json)
        {
            InitializeComponent();

            _json = json;
            if (_json)
            {
                _af = new JsonFormatter();
                _bf = new JsonFormatter();
            }
            else
            {
                _af = new SjsonFormatter();
                _bf = new SjsonFormatter();
            }

            _diff_lines.Add(0);

            // Enforce object creation (you can get a highlighting bug otherwise).
            IntPtr ah = aTextBox.Handle;
            IntPtr bh = bTextBox.Handle;

            if (_json)
            {
                SameText("{", "{");
                DisplayDiff(a, b, diff, 1);
                SameText("\n}", "\n}");
            }
            else
            {
                DisplayDiff(a, b, diff, 0);
            }

            _diff_lines.Add(aTextBox.Lines.Count());

            aTextBox.SelectionStart  = 0;
            aTextBox.SelectionLength = 0;
            bTextBox.SelectionStart  = 0;
            bTextBox.SelectionLength = 0;
        }
        // Shows the difference between a and b in the text box.
        private void DisplayDiff(RichTextBox rtb, IFormatter f, Hashtable a, Hashtable b, HashDiff diff,
                                 int indent, string path)
        {
            HashSet <string> keys = new HashSet <string>();

            foreach (string key in a.Keys)
            {
                keys.Add(key);
            }
            foreach (string key in b.Keys)
            {
                keys.Add(key);
            }

            foreach (string key in keys.OrderBy(i => i))
            {
                string subpath = path + "." + key;
                CheckLineNumber(rtb, subpath);

                if (diff.Operations.ContainsKey(key))
                {
                    DiffOperation dop = diff.Operations[key];
                    if (dop is RemoveOperation)
                    {
                        RemovedText(rtb, f.ObjectField(a, key, indent));
                    }
                    else if (dop is ChangeOperation)
                    {
                        ChangedText(rtb, f.ObjectField(a, key, indent), f.ObjectField(b, key, indent));
                    }
                    else if (dop is ChangeObjectOperation)
                    {
                        SameText(rtb, f.ObjectStart(key, indent));
                        DisplayDiff(rtb, f, a[key] as Hashtable, b[key] as Hashtable, (dop as ChangeObjectOperation).Diff, indent + 1, subpath);
                        SameText(rtb, f.ObjectEnd(indent));
                    }
                    else if (dop is ChangePositionArrayOperation)
                    {
                        SameText(rtb, f.ArrayStart(key, indent));
                        DisplayDiff(rtb, f, a[key] as ArrayList, b[key] as ArrayList, (dop as ChangePositionArrayOperation).Diff, indent + 1, subpath);
                        SameText(rtb, f.ArrayEnd(indent));
                    }
                    else if (dop is ChangeIdArrayOperation)
                    {
                        SameText(rtb, f.ArrayStart(key, indent));
                        DisplayDiff(rtb, f, a[key] as ArrayList, b[key] as ArrayList, (dop as ChangeIdArrayOperation).Diff, indent + 1, subpath);
                        SameText(rtb, f.ArrayEnd(indent));
                    }
                }
                else
                {
                    SameText(rtb, f.ObjectField(b, key, indent));
                }
            }
        }
Пример #14
0
 public static ChangeIdArrayOperation Merge(ChangeIdArrayOperation left, ChangeIdArrayOperation right)
 {
     return(new ChangeIdArrayOperation(HashDiff.Merge(left.Diff, right.Diff)));
 }
        // Shows the difference between a and b in the text box.
        private void DisplayDiff(RichTextBox rtb, IFormatter f, ArrayList a, ArrayList b, HashDiff diff,
                                 int indent, string path)
        {
            HashSet <object> keys = new HashSet <object>();

            foreach (object h in a)
            {
                keys.Add(Id.GetId(h));
            }
            foreach (object h in b)
            {
                keys.Add(Id.GetId(h));
            }

            foreach (object key in keys.OrderBy(i => i))
            {
                object ao      = Id.FindObjectWithId(a, key);
                object bo      = Id.FindObjectWithId(b, key);
                string subpath = string.Format("{0}.{1}", path, key);
                DisplayArrayDiff(rtb, f, ao, bo, diff.Operations.GetValueOrDefault(key, null), indent, subpath);
            }
        }
        public MergeVisualForm(Hashtable parent, Hashtable a, HashDiff adiff,
                               Hashtable b, HashDiff bdiff, Hashtable c, HashDiff cdiff, bool json)
        {
            InitializeComponent();

            _json = json;
            if (_json)
            {
                _af = new JsonFormatter();
                _bf = new JsonFormatter();
                _cf = new JsonFormatter();
            }
            else
            {
                _af = new SjsonFormatter();
                _bf = new SjsonFormatter();
                _cf = new SjsonFormatter();
            }

            // Enforce object creation (you can get a highlighting bug otherwise).
            IntPtr ah = aTextBox.Handle;
            IntPtr bh = bTextBox.Handle;
            IntPtr ch = cTextBox.Handle;

            // This while loop is a rather ugly thing.
            //
            // We use the _line_number Dictionary to store the highest line number where
            // a particular key path (e.g. items.size.x) have been displayed in any of the
            // views. When a view wants to display a particular key, it pads the text with
            // newlines so that the key appears at the maximum line number where it has
            // appeared before. If the current line number is higher than the previous
            // maximum, the _line_number Dictionary is updated with the new maximum and
            // _line_numbers_changed is true.
            //
            // By looping here and reformatting the text until _line_number is no longer
            // changing we ensure that all keys are displayed at the same line in all three
            // views, so that we can scroll them simultaneously.
            //
            // In theory, this could take quite some time for the worst-case scenario and
            // it would be better to rewrite the code so that we are formatting the three views
            // simultaneously, padding with newlines as we go along. However, that is rather
            // hairy to write and this seems to work well for now.
            do
            {
                _diff_lines_set.Clear();

                aTextBox.Text         = "";
                bTextBox.Text         = "";
                cTextBox.Text         = "";
                _line_numbers_changed = false;
                int indent = 0;

                if (_json)
                {
                    SameText(aTextBox, "{");
                    SameText(bTextBox, "{");
                    SameText(cTextBox, "{");
                    indent = 1;
                }

                DisplayDiff(aTextBox, _af, parent, a, adiff, indent, "");
                DisplayDiff(bTextBox, _bf, parent, b, bdiff, indent, "");
                DisplayDiff(cTextBox, _cf, parent, c, cdiff, indent, "");

                if (_json)
                {
                    SameText(aTextBox, "\n}");
                    SameText(bTextBox, "\n}");
                    SameText(cTextBox, "\n}");
                }
            } while (_line_numbers_changed);

            _diff_lines_set.Add(0);
            _diff_lines_set.Add(aTextBox.Lines.Count());
            _diff_lines   = _diff_lines_set.OrderBy(i => i).ToList();
            _current_diff = 0;

            aTextBox.SelectionStart  = 0;
            aTextBox.SelectionLength = 0;
            bTextBox.SelectionStart  = 0;
            bTextBox.SelectionLength = 0;
            cTextBox.SelectionStart  = 0;
            cTextBox.SelectionLength = 0;
        }
Пример #17
0
        static void Main(string[] args)
        {
            // We need to set this to prevent parse errors in JSON/SJSON parsing.
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            // Print usage information if there where no arguments.
            if (args.Length == 0)
            {
                PrintUsage();
            }

            // -hold can be used as a debugging tool, to give a debugger the chance
            // to attach to the process when it is just starting up.
            bool escape_hold = false;

            int i = 0;

            while (i < args.Length)
            {
                if (args[i] == "-json")
                {
                    _use_json = true;
                    ++i;
                }
                else if (args[i] == "-window")
                {
                    _window = true;
                    ++i;
                }
                else if (args[i] == "-diff")
                {
                    if (i + 2 >= args.Length)
                    {
                        Error("Not enough arguments for -diff");
                    }
                    Hashtable a    = Load(args[i + 1]);
                    Hashtable b    = Load(args[i + 2]);
                    HashDiff  diff = JsonDiff.Diff(a, b);
                    if (_window)
                    {
                        DiffVisualForm form = new DiffVisualForm(a, b, diff, _use_json);
                        form.ShowDialog();
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        diff.Write(sb);
                        Show(sb.ToString(), "Diff");
                    }
                    i += 3;
                }
                else if (args[i] == "-merge")
                {
                    if (i + 4 >= args.Length)
                    {
                        Error("Not enough arguments for -merge");
                    }
                    Hashtable parent = Load(args[i + 1]);
                    Hashtable theirs = Load(args[i + 2]);
                    Hashtable mine   = Load(args[i + 3]);
                    if (_window)
                    {
                        HashDiff  theirs_diff, mine_diff, merged_diff;
                        Hashtable result = JsonDiff.MergeDetailed(parent, theirs, mine,
                                                                  out theirs_diff, out mine_diff, out merged_diff);
                        MergeVisualForm form = new MergeVisualForm(parent, theirs, theirs_diff,
                                                                   mine, mine_diff, result, merged_diff, _use_json);
                        form.ShowDialog();
                        Save(result, args[i + 4]);
                    }
                    else
                    {
                        Hashtable result = JsonDiff.Merge(parent, theirs, mine);
                        Save(result, args[i + 4]);
                    }

                    // Remove source files (should their be an option for this?)
                    File.Delete(args[i + 1]);
                    File.Delete(args[i + 2]);
                    File.Delete(args[i + 3]);
                    i += 5;
                }
                else if (args[i] == "-help")
                {
                    PrintUsage();
                    ++i;
                }
                else if (args[i] == "-hold")
                {
                    while (!escape_hold)
                    {
                        ;
                    }
                    ++i;
                }
                else if (args[i] == "-test")
                {
                    Test.TestAll();
                    ++i;
                }
            }
        }
Пример #18
0
 public ChangeObjectOperation(HashDiff diff)
 {
     Diff = diff;
 }
Пример #19
0
 public ChangeIdArrayOperation(HashDiff diff)
 {
     Diff = diff;
 }