You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/03/09 11:08:53 UTC

svn commit: r1575685 [5/13] - in /subversion/branches/fsfs-ucsnorm: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/cgi/ contrib/client-side/emacs/ contrib/client-side/svn2cl/ contrib/hook-scripts/ contrib/server-side/svn...

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_local.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_local.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_local.c Sun Mar  9 10:08:46 2014
@@ -44,11 +44,11 @@
 #include "svn_pools.h"
 #include "svn_props.h"
 #include "svn_sorts.h"
-#include "svn_subst.h"
 #include "client.h"
 
 #include "private/svn_sorts_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_diff_tree.h"
 
 
 /* Try to get properties for LOCAL_ABSPATH and return them in the property
@@ -82,559 +82,647 @@ get_props(apr_hash_t **props,
   return SVN_NO_ERROR;
 }
 
-/* Produce a diff between two arbitrary files at LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2, using the diff callbacks from CALLBACKS.
- * Use PATH as the name passed to diff callbacks.
- * FILE1_IS_EMPTY and FILE2_IS_EMPTY are used as hints which diff callback
- * function to use to compare the files (added/deleted/changed).
+/* Forward declaration */
+static svn_error_t *
+do_file_diff(const char *left_abspath,
+             const char *right_abspath,
+             const char *left_root_abspath,
+             const char *right_root_abspath,
+             svn_boolean_t left_only,
+             svn_boolean_t right_only,
+             void *parent_baton,
+             const svn_diff_tree_processor_t *diff_processor,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *scratch_pool);
+
+/* Forward declaration */
+static svn_error_t *
+do_dir_diff(const char *left_abspath,
+            const char *right_abspath,
+            const char *left_root_abspath,
+            const char *right_root_abspath,
+            svn_boolean_t left_only,
+            svn_boolean_t right_only,
+            svn_boolean_t left_before_right,
+            svn_depth_t depth,
+            void *parent_baton,
+            const svn_diff_tree_processor_t *diff_processor,
+            svn_client_ctx_t *ctx,
+            apr_pool_t *scratch_pool);
+
+/* Produce a diff of depth DEPTH between two arbitrary directories at
+ * LEFT_ABSPATH1 and RIGHT_ABSPATH2, using the provided diff callbacks
+ * to show file changes and, for versioned nodes, property changes.
  *
- * If ORIGINAL_PROPS_OVERRIDE is not NULL, use it as original properties
- * instead of reading properties from LOCAL_ABSPATH1. This is required when
- * a file replaces a directory, where LOCAL_ABSPATH1 is an empty file that
- * file content must be diffed against, but properties to diff against come
- * from the replaced directory. */
+ * Report paths as relative from LEFT_ROOT_ABSPATH/RIGHT_ROOT_ABSPATH.
+ *
+ * If LEFT_ONLY is TRUE, only the left source exists (= everything will
+ * be reported as deleted). If RIGHT_ONLY is TRUE, only the right source
+ * exists (= everything will be reported as added).
+ *
+ * If LEFT_BEFORE_RIGHT is TRUE and left and right are unrelated, left is
+ * reported first. If false, right is reported first. (This is to allow
+ * producing a proper inverse diff).
+ *
+ * Walk the sources according to depth, and report with parent baton
+ * PARENT_BATON. */
 static svn_error_t *
-do_arbitrary_files_diff(const char *local_abspath1,
-                        const char *local_abspath2,
-                        const char *path,
-                        svn_boolean_t file1_is_empty,
-                        svn_boolean_t file2_is_empty,
-                        apr_hash_t *original_props_override,
-                        const svn_wc_diff_callbacks4_t *callbacks,
-                        void *diff_baton,
-                        svn_client_ctx_t *ctx,
-                        apr_pool_t *scratch_pool)
+inner_dir_diff(const char *left_abspath,
+               const char *right_abspath,
+               const char *left_root_abspath,
+               const char *right_root_abspath,
+               svn_boolean_t left_only,
+               svn_boolean_t right_only,
+               svn_boolean_t left_before_right,
+               svn_depth_t depth,
+               void *parent_baton,
+               const svn_diff_tree_processor_t *diff_processor,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *scratch_pool)
 {
-  apr_hash_t *original_props;
-  apr_hash_t *modified_props;
-  apr_array_header_t *prop_changes;
-  svn_string_t *original_mime_type = NULL;
-  svn_string_t *modified_mime_type = NULL;
-
-  if (ctx->cancel_func)
-    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
-
-  /* Try to get properties from either file. It's OK if the files do not
-   * have properties, or if they are unversioned. */
-  if (original_props_override)
-    original_props = original_props_override;
-  else
-    SVN_ERR(get_props(&original_props, local_abspath1, ctx->wc_ctx,
-                      scratch_pool, scratch_pool));
-  SVN_ERR(get_props(&modified_props, local_abspath2, ctx->wc_ctx,
-                    scratch_pool, scratch_pool));
-
-  SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props,
-                         scratch_pool));
-
-  /* Try to determine the mime-type of each file. */
-  original_mime_type = svn_hash_gets(original_props, SVN_PROP_MIME_TYPE);
-  if (!file1_is_empty && !original_mime_type)
-    {
-      const char *mime_type;
-      SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1,
-                                      ctx->mimetypes_map, scratch_pool));
-
-      if (mime_type)
-        original_mime_type = svn_string_create(mime_type, scratch_pool);
-    }
-
-  modified_mime_type = svn_hash_gets(modified_props, SVN_PROP_MIME_TYPE);
-  if (!file2_is_empty && !modified_mime_type)
-    {
-      const char *mime_type;
-      SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1,
-                                      ctx->mimetypes_map, scratch_pool));
-
-      if (mime_type)
-        modified_mime_type = svn_string_create(mime_type, scratch_pool);
-    }
-
-  /* Produce the diff. */
-  if (file1_is_empty && !file2_is_empty)
-    SVN_ERR(callbacks->file_added(NULL, NULL, NULL, path,
-                                  local_abspath1, local_abspath2,
-                                  /* ### TODO get real revision info
-                                   * for versioned files? */
-                                  SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
-                                  original_mime_type ?
-                                    original_mime_type->data : NULL,
-                                  modified_mime_type ?
-                                    modified_mime_type->data : NULL,
-                                  /* ### TODO get copyfrom? */
-                                  NULL, SVN_INVALID_REVNUM,
-                                  prop_changes, original_props,
-                                  diff_baton, scratch_pool));
-  else if (!file1_is_empty && file2_is_empty)
-    SVN_ERR(callbacks->file_deleted(NULL, NULL, path,
-                                    local_abspath1, local_abspath2,
-                                    original_mime_type ?
-                                      original_mime_type->data : NULL,
-                                    modified_mime_type ?
-                                      modified_mime_type->data : NULL,
-                                    original_props,
-                                    diff_baton, scratch_pool));
-  else
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_t *left_dirents;
+  apr_hash_t *right_dirents;
+  apr_array_header_t *sorted_dirents;
+  svn_error_t *err;
+  svn_depth_t depth_below_here;
+  int i;
+
+  SVN_ERR_ASSERT(depth >= svn_depth_files && depth <= svn_depth_infinity);
+
+  if (!right_only)
     {
-      svn_stream_t *file1;
-      svn_stream_t *file2;
-      svn_boolean_t same;
-      svn_string_t *val;
-      /* We have two files, which may or may not be the same.
+      err = svn_io_get_dirents3(&left_dirents, left_abspath, FALSE,
+                                scratch_pool, iterpool);
 
-         ### Our caller assumes that we should ignore symlinks here and
-             handle them as normal paths. Perhaps that should change?
-      */
-      SVN_ERR(svn_stream_open_readonly(&file1, local_abspath1, scratch_pool,
-                                       scratch_pool));
+      if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+                  || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
+        {
+          svn_error_clear(err);
+          left_dirents = apr_hash_make(scratch_pool);
+          right_only = TRUE;
+        }
+      else
+        SVN_ERR(err);
+    }
+  else
+    left_dirents = apr_hash_make(scratch_pool);
 
-      SVN_ERR(svn_stream_open_readonly(&file2, local_abspath2, scratch_pool,
-                                       scratch_pool));
+  if (!left_only)
+    {
+      err = svn_io_get_dirents3(&right_dirents, right_abspath, FALSE,
+                                scratch_pool, iterpool);
 
-      /* Wrap with normalization, etc. if necessary */
-      if (original_props)
+      if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+                  || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
         {
-          val = svn_hash_gets(original_props, SVN_PROP_EOL_STYLE);
+          svn_error_clear(err);
+          right_dirents = apr_hash_make(scratch_pool);
+          right_only = TRUE;
+        }
+      else
+        SVN_ERR(err);
+    }
+  else
+    right_dirents = apr_hash_make(scratch_pool);
+
+  if (left_only && right_only)
+    return SVN_NO_ERROR; /* Somebody deleted the directory?? */
+
+  if (depth != svn_depth_infinity)
+    depth_below_here = svn_depth_empty;
+  else
+    depth_below_here = svn_depth_infinity;
+
+  sorted_dirents = svn_sort__hash(apr_hash_merge(iterpool, left_dirents,
+                                                 right_dirents, NULL, NULL),
+                                  svn_sort_compare_items_as_paths,
+                                  scratch_pool);
+
+  for (i = 0; i < sorted_dirents->nelts; i++)
+    {
+      svn_sort__item_t* elt = &APR_ARRAY_IDX(sorted_dirents, i, svn_sort__item_t);
+      svn_io_dirent2_t *left_dirent;
+      svn_io_dirent2_t *right_dirent;
+      const char *child_left_abspath;
+      const char *child_right_abspath;
+
+      svn_pool_clear(iterpool);
+
+      if (ctx->cancel_func)
+        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
+      if (svn_wc_is_adm_dir(elt->key, iterpool))
+        continue;
+
+      left_dirent = right_only ? NULL : svn_hash_gets(left_dirents, elt->key);
+      right_dirent = left_only ? NULL : svn_hash_gets(right_dirents, elt->key);
+
+      child_left_abspath = svn_dirent_join(left_abspath, elt->key, iterpool);
+      child_right_abspath = svn_dirent_join(right_abspath, elt->key, iterpool);
 
-          if (val)
+      if (((left_dirent == NULL) != (right_dirent == NULL))
+          || (left_dirent->kind != right_dirent->kind))
+        {
+          /* Report delete and/or add */
+          if (left_dirent && left_before_right)
             {
-              svn_subst_eol_style_t style;
-              const char *eol;
-              svn_subst_eol_style_from_value(&style, &eol, val->data);
-
-              /* ### Ignoring keywords */
-              if (eol)
-                file1 = svn_subst_stream_translated(file1, eol, TRUE,
-                                                    NULL, FALSE,
-                                                    scratch_pool);
+              if (left_dirent->kind == svn_node_file)
+                SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, parent_baton,
+                                     diff_processor, ctx, iterpool));
+              else if (depth >= svn_depth_immediates)
+                SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE, left_before_right,
+                                    depth_below_here, parent_baton,
+                                    diff_processor, ctx, iterpool));
             }
-        }
 
-      if (modified_props)
-        {
-          val = svn_hash_gets(modified_props, SVN_PROP_EOL_STYLE);
+          if (right_dirent)
+            {
+              if (right_dirent->kind == svn_node_file)
+                SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     FALSE, TRUE, parent_baton,
+                                     diff_processor, ctx, iterpool));
+              else if (depth >= svn_depth_immediates)
+                SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    FALSE, TRUE,  left_before_right,
+                                    depth_below_here, parent_baton,
+                                    diff_processor, ctx, iterpool));
+            }
 
-          if (val)
+          if (left_dirent && !left_before_right)
             {
-              svn_subst_eol_style_t style;
-              const char *eol;
-              svn_subst_eol_style_from_value(&style, &eol, val->data);
-
-              /* ### Ignoring keywords */
-              if (eol)
-                file2 = svn_subst_stream_translated(file2, eol, TRUE,
-                                                    NULL, FALSE,
-                                                    scratch_pool);
+              if (left_dirent->kind == svn_node_file)
+                SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, parent_baton,
+                                     diff_processor, ctx, iterpool));
+              else if (depth >= svn_depth_immediates)
+                SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE,  left_before_right,
+                                    depth_below_here, parent_baton,
+                                    diff_processor, ctx, iterpool));
             }
         }
-
-      SVN_ERR(svn_stream_contents_same2(&same, file1, file2, scratch_pool));
-
-      if (! same || prop_changes->nelts > 0)
+      else if (left_dirent->kind == svn_node_file)
+        {
+          /* Perform file-file diff */
+          SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                               left_root_abspath, right_root_abspath,
+                               FALSE, FALSE, parent_baton,
+                               diff_processor, ctx, iterpool));
+        }
+      else if (depth >= svn_depth_immediates)
         {
-          /* ### We should probably pass the normalized data we created using
-                 the subst streams as that is what diff users expect */
-          SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, path,
-                                          same ? NULL : local_abspath1,
-                                          same ? NULL : local_abspath2,
-                                          /* ### TODO get real revision info
-                                           * for versioned files? */
-                                          SVN_INVALID_REVNUM /* rev1 */,
-                                          SVN_INVALID_REVNUM /* rev2 */,
-                                          original_mime_type ?
-                                            original_mime_type->data : NULL,
-                                          modified_mime_type ?
-                                            modified_mime_type->data : NULL,
-                                          prop_changes, original_props,
-                                          diff_baton, scratch_pool));
+          /* Perform dir-dir diff */
+          SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                              left_root_abspath, right_root_abspath,
+                              FALSE, FALSE,  left_before_right,
+                              depth_below_here, parent_baton,
+                              diff_processor, ctx, iterpool));
         }
     }
 
   return SVN_NO_ERROR;
 }
-
-struct arbitrary_diff_walker_baton {
-  /* The root directories of the trees being compared. */
-  const char *root1_abspath;
-  const char *root2_abspath;
-
-  /* TRUE if recursing within an added subtree of root2_abspath that
-   * does not exist in root1_abspath. */
-  svn_boolean_t recursing_within_added_subtree;
-
-  /* TRUE if recursing within an administrative (.i.e. .svn) directory. */
-  svn_boolean_t recursing_within_adm_dir;
-
-  /* The absolute path of the adm dir if RECURSING_WITHIN_ADM_DIR is TRUE.
-   * Else this is NULL.*/
-  const char *adm_dir_abspath;
-
-  /* A path to an empty file used for diffs that add/delete files. */
-  const char *empty_file_abspath;
-
-  const svn_wc_diff_callbacks4_t *callbacks;
-  void *diff_baton;
-  svn_client_ctx_t *ctx;
-  apr_pool_t *pool;
-} arbitrary_diff_walker_baton;
-
-/* Forward declaration needed because this function has a cyclic
- * dependency with do_arbitrary_dirs_diff(). */
+/* Handles reporting of a file for inner_dir_diff */
 static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
-                      const apr_finfo_t *finfo,
-                      apr_pool_t *scratch_pool);
+do_file_diff(const char *left_abspath,
+             const char *right_abspath,
+             const char *left_root_abspath,
+             const char *right_root_abspath,
+             svn_boolean_t left_only,
+             svn_boolean_t right_only,
+             void *parent_baton,
+             const svn_diff_tree_processor_t *diff_processor,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *scratch_pool)
+{
+  const char *relpath;
+  svn_diff_source_t *left_source;
+  svn_diff_source_t *right_source;
+  svn_boolean_t skip = FALSE;
+  apr_hash_t *left_props;
+  apr_hash_t *right_props;
+  void *file_baton;
 
-/* Another forward declaration. */
-static svn_error_t *
-arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b,
-                        const char *local_abspath,
-                        svn_depth_t depth,
-                        apr_pool_t *scratch_pool);
+  relpath = svn_dirent_skip_ancestor(left_root_abspath, left_abspath);
 
-/* Produce a diff of depth DEPTH between two arbitrary directories at
- * LOCAL_ABSPATH1 and LOCAL_ABSPATH2, using the provided diff callbacks
- * to show file changes and, for versioned nodes, property changes.
- *
- * If ROOT_ABSPATH1 and ROOT_ABSPATH2 are not NULL, show paths in diffs
- * relative to these roots, rather than relative to LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2. This is needed when crawling a subtree that exists
- * only within LOCAL_ABSPATH2. */
-static svn_error_t *
-do_arbitrary_dirs_diff(const char *local_abspath1,
-                       const char *local_abspath2,
-                       const char *root_abspath1,
-                       const char *root_abspath2,
-                       svn_depth_t depth,
-                       const svn_wc_diff_callbacks4_t *callbacks,
-                       void *diff_baton,
-                       svn_client_ctx_t *ctx,
-                       apr_pool_t *scratch_pool)
-{
-  apr_file_t *empty_file;
-  svn_node_kind_t kind1;
+ if (! right_only)
+    left_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+  else
+    left_source = NULL;
 
-  struct arbitrary_diff_walker_baton b;
+  if (! left_only)
+    right_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+  else
+    right_source = NULL;
 
-  /* If LOCAL_ABSPATH1 is not a directory, crawl LOCAL_ABSPATH2 instead
-   * and compare it to LOCAL_ABSPATH1, showing only additions.
-   * This case can only happen during recursion from arbitrary_diff_walker(),
-   * because do_arbitrary_nodes_diff() prevents this from happening at
-   * the root of the comparison. */
-  SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-  b.recursing_within_added_subtree = (kind1 != svn_node_dir);
-
-  b.root1_abspath = root_abspath1 ? root_abspath1 : local_abspath1;
-  b.root2_abspath = root_abspath2 ? root_abspath2 : local_abspath2;
-  b.recursing_within_adm_dir = FALSE;
-  b.adm_dir_abspath = NULL;
-  b.callbacks = callbacks;
-  b.diff_baton = diff_baton;
-  b.ctx = ctx;
-  b.pool = scratch_pool;
-
-  SVN_ERR(svn_io_open_unique_file3(&empty_file, &b.empty_file_abspath,
-                                   NULL, svn_io_file_del_on_pool_cleanup,
-                                   scratch_pool, scratch_pool));
-
-  if (depth <= svn_depth_immediates)
-    SVN_ERR(arbitrary_diff_this_dir(&b, local_abspath1, depth, scratch_pool));
-  else if (depth == svn_depth_infinity)
-    SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2
-                                                              : local_abspath1,
-                             0, arbitrary_diff_walker, &b, scratch_pool));
-  return SVN_NO_ERROR;
-}
+  SVN_ERR(diff_processor->file_opened(&file_baton, &skip,
+                                      relpath,
+                                      left_source,
+                                      right_source,
+                                      NULL /* copyfrom_source */,
+                                      parent_baton,
+                                      diff_processor,
+                                      scratch_pool,
+                                      scratch_pool));
 
-/* Produce a diff of depth DEPTH for the directory at LOCAL_ABSPATH,
- * using information from the arbitrary_diff_walker_baton B.
- * LOCAL_ABSPATH is the path being crawled and can be on either side
- * of the diff depending on baton->recursing_within_added_subtree. */
-static svn_error_t *
-arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b,
-                        const char *local_abspath,
-                        svn_depth_t depth,
-                        apr_pool_t *scratch_pool)
-{
-  const char *local_abspath1;
-  const char *local_abspath2;
-  svn_node_kind_t kind1;
-  svn_node_kind_t kind2;
-  const char *child_relpath;
-  apr_hash_t *dirents1;
-  apr_hash_t *dirents2;
-  apr_hash_t *merged_dirents;
-  apr_array_header_t *sorted_dirents;
-  int i;
-  apr_pool_t *iterpool;
+  if (skip)
+    return SVN_NO_ERROR;
 
-  if (b->recursing_within_adm_dir)
+   if (! right_only)
     {
-      if (svn_dirent_skip_ancestor(b->adm_dir_abspath, local_abspath))
-        return SVN_NO_ERROR;
-      else
+      SVN_ERR(get_props(&left_props, left_abspath, ctx->wc_ctx,
+                        scratch_pool, scratch_pool));
+
+      /* We perform a mimetype detection to avoid diffing binary files
+         for textual changes.*/
+      if (! svn_hash_gets(left_props, SVN_PROP_MIME_TYPE))
         {
-          b->recursing_within_adm_dir = FALSE;
-          b->adm_dir_abspath = NULL;
+          const char *mime_type;
+
+          /* ### Use libmagic magic? */
+          SVN_ERR(svn_io_detect_mimetype2(&mime_type, left_abspath,
+                                          ctx->mimetypes_map, scratch_pool));
+
+          if (mime_type)
+            svn_hash_sets(left_props, SVN_PROP_MIME_TYPE,
+                          svn_string_create(mime_type, scratch_pool));
         }
     }
-  else if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, NULL),
-                             scratch_pool))
-    {
-      b->recursing_within_adm_dir = TRUE;
-      b->adm_dir_abspath = apr_pstrdup(b->pool, local_abspath);
-      return SVN_NO_ERROR;
-    }
-
-  if (b->recursing_within_added_subtree)
-    child_relpath = svn_dirent_skip_ancestor(b->root2_abspath, local_abspath);
   else
-    child_relpath = svn_dirent_skip_ancestor(b->root1_abspath, local_abspath);
-  if (!child_relpath)
-    return SVN_NO_ERROR;
-
-  local_abspath1 = svn_dirent_join(b->root1_abspath, child_relpath,
-                                   scratch_pool);
-  SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-
-  local_abspath2 = svn_dirent_join(b->root2_abspath, child_relpath,
-                                   scratch_pool);
-  SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
-
-  if (depth > svn_depth_empty)
-    {
-      if (kind1 == svn_node_dir)
-        SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1,
-                                    TRUE, /* only_check_type */
-                                    scratch_pool, scratch_pool));
-      else
-        dirents1 = apr_hash_make(scratch_pool);
-    }
+    left_props = NULL;
 
-  if (kind2 == svn_node_dir)
+  if (! left_only)
     {
-      apr_hash_t *original_props;
-      apr_hash_t *modified_props;
-      apr_array_header_t *prop_changes;
-
-      /* Show any property changes for this directory. */
-      SVN_ERR(get_props(&original_props, local_abspath1, b->ctx->wc_ctx,
-                        scratch_pool, scratch_pool));
-      SVN_ERR(get_props(&modified_props, local_abspath2, b->ctx->wc_ctx,
+      SVN_ERR(get_props(&right_props, right_abspath, ctx->wc_ctx,
                         scratch_pool, scratch_pool));
-      SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props,
-                             scratch_pool));
-      if (prop_changes->nelts > 0)
-        SVN_ERR(b->callbacks->dir_props_changed(NULL, NULL, child_relpath,
-                                                FALSE /* was_added */,
-                                                prop_changes, original_props,
-                                                b->diff_baton,
-                                                scratch_pool));
 
-      if (depth > svn_depth_empty)
+      /* We perform a mimetype detection to avoid diffing binary files
+         for textual changes.*/
+      if (! svn_hash_gets(right_props, SVN_PROP_MIME_TYPE))
         {
-          /* Read directory entries. */
-          SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2,
-                                      TRUE, /* only_check_type */
-                                      scratch_pool, scratch_pool));
+          const char *mime_type;
+
+          /* ### Use libmagic magic? */
+          SVN_ERR(svn_io_detect_mimetype2(&mime_type, right_abspath,
+                                          ctx->mimetypes_map, scratch_pool));
+
+          if (mime_type)
+            svn_hash_sets(right_props, SVN_PROP_MIME_TYPE,
+                          svn_string_create(mime_type, scratch_pool));
         }
     }
-  else if (depth > svn_depth_empty)
-    dirents2 = apr_hash_make(scratch_pool);
-
-  if (depth <= svn_depth_empty)
-    return SVN_NO_ERROR;
+  else
+    right_props = NULL;
 
-  /* Compare dirents1 to dirents2 and show added/deleted/changed files. */
-  merged_dirents = apr_hash_merge(scratch_pool, dirents1, dirents2,
-                                  NULL, NULL);
-  sorted_dirents = svn_sort__hash(merged_dirents,
-                                  svn_sort_compare_items_as_paths,
-                                  scratch_pool);
-  iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < sorted_dirents->nelts; i++)
+  if (left_only)
     {
-      svn_sort__item_t elt = APR_ARRAY_IDX(sorted_dirents, i, svn_sort__item_t);
-      const char *name = elt.key;
-      svn_io_dirent2_t *dirent1;
-      svn_io_dirent2_t *dirent2;
-      const char *child1_abspath;
-      const char *child2_abspath;
-
-      svn_pool_clear(iterpool);
+      SVN_ERR(diff_processor->file_deleted(relpath,
+                                           left_source,
+                                           left_abspath,
+                                           left_props,
+                                           file_baton,
+                                           diff_processor,
+                                           scratch_pool));
+    }
+  else if (right_only)
+    {
+      SVN_ERR(diff_processor->file_added(relpath,
+                                         NULL /* copyfrom_source */,
+                                         right_source,
+                                         NULL /* copyfrom_file */,
+                                         right_abspath,
+                                         NULL /* copyfrom_props */,
+                                         right_props,
+                                         file_baton,
+                                         diff_processor,
+                                         scratch_pool));
+    }
+  else
+    {
+      /* ### Perform diff -> close/changed */
+      svn_boolean_t same;
+      apr_array_header_t *prop_changes;
 
-      if (b->ctx->cancel_func)
-        SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+      SVN_ERR(svn_io_files_contents_same_p(&same, left_abspath, right_abspath,
+                                           scratch_pool));
 
-      if (strcmp(name, SVN_WC_ADM_DIR_NAME) == 0)
-        continue;
+      SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props,
+                             scratch_pool));
 
-      dirent1 = svn_hash_gets(dirents1, name);
-      if (!dirent1)
+      if (!same || prop_changes->nelts > 0)
         {
-          dirent1 = svn_io_dirent2_create(iterpool);
-          dirent1->kind = svn_node_none;
+          SVN_ERR(diff_processor->file_changed(relpath,
+                                               left_source,
+                                               right_source,
+                                               same ? NULL : left_abspath,
+                                               same ? NULL : right_abspath,
+                                               left_props,
+                                               right_props,
+                                               !same,
+                                               prop_changes,
+                                               file_baton,
+                                               diff_processor,
+                                               scratch_pool));
         }
-      dirent2 = svn_hash_gets(dirents2, name);
-      if (!dirent2)
+      else
         {
-          dirent2 = svn_io_dirent2_create(iterpool);
-          dirent2->kind = svn_node_none;
+          SVN_ERR(diff_processor->file_closed(relpath,
+                                            left_source,
+                                            right_source,
+                                            file_baton,
+                                            diff_processor,
+                                            scratch_pool));
         }
+    }
+  return SVN_NO_ERROR;
+}
 
-      child1_abspath = svn_dirent_join(local_abspath1, name, iterpool);
-      child2_abspath = svn_dirent_join(local_abspath2, name, iterpool);
 
-      if (dirent1->special)
-        SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent1->kind,
-                                           iterpool));
-      if (dirent2->special)
-        SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent2->kind,
-                                           iterpool));
+/* Handles reporting of a directory and its children for inner_dir_diff */
+static svn_error_t *
+do_dir_diff(const char *left_abspath,
+            const char *right_abspath,
+            const char *left_root_abspath,
+            const char *right_root_abspath,
+            svn_boolean_t left_only,
+            svn_boolean_t right_only,
+            svn_boolean_t left_before_right,
+            svn_depth_t depth,
+            void *parent_baton,
+            const svn_diff_tree_processor_t *diff_processor,
+            svn_client_ctx_t *ctx,
+            apr_pool_t *scratch_pool)
+{
+  const char *relpath;
+  svn_diff_source_t *left_source;
+  svn_diff_source_t *right_source;
+  svn_boolean_t skip = FALSE;
+  svn_boolean_t skip_children = FALSE;
+  void *dir_baton;
+  apr_hash_t *left_props;
+  apr_hash_t *right_props;
 
-      if (dirent1->kind == svn_node_dir &&
-          dirent2->kind == svn_node_dir)
-        {
-          if (depth == svn_depth_immediates)
-            {
-              /* Not using the walker, so show property diffs on these dirs. */
-              SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
-                                             b->root1_abspath, b->root2_abspath,
-                                             svn_depth_empty,
-                                             b->callbacks, b->diff_baton,
-                                             b->ctx, iterpool));
-            }
-          else
-            {
-              /* Either the walker will visit these directories (with
-               * depth=infinity) and they will be processed as 'this dir'
-               * later, or we're showing file children only (depth=files). */
-              continue;
-            }
+  relpath = svn_dirent_skip_ancestor(left_root_abspath, left_abspath);
 
-        }
+  if (! right_only)
+    {
+      left_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+      SVN_ERR(get_props(&left_props, left_abspath, ctx->wc_ctx,
+                        scratch_pool, scratch_pool));
+    }
+  else
+    {
+      left_source = NULL;
+      left_props = NULL;
+    }
 
-      /* Files that exist only in dirents1. */
-      if (dirent1->kind == svn_node_file &&
-          (dirent2->kind == svn_node_dir || dirent2->kind == svn_node_none))
-        SVN_ERR(do_arbitrary_files_diff(child1_abspath, b->empty_file_abspath,
-                                        svn_relpath_join(child_relpath, name,
-                                                         iterpool),
-                                        FALSE, TRUE, NULL,
-                                        b->callbacks, b->diff_baton,
-                                        b->ctx, iterpool));
-
-      /* Files that exist only in dirents2. */
-      if (dirent2->kind == svn_node_file &&
-          (dirent1->kind == svn_node_dir || dirent1->kind == svn_node_none))
-        {
-          apr_hash_t *original_props;
-
-          SVN_ERR(get_props(&original_props, child1_abspath, b->ctx->wc_ctx,
-                            scratch_pool, scratch_pool));
-          SVN_ERR(do_arbitrary_files_diff(b->empty_file_abspath, child2_abspath,
-                                          svn_relpath_join(child_relpath, name,
-                                                           iterpool),
-                                          TRUE, FALSE, original_props,
-                                          b->callbacks, b->diff_baton,
-                                          b->ctx, iterpool));
-        }
-
-      /* Files that exist in dirents1 and dirents2. */
-      if (dirent1->kind == svn_node_file && dirent2->kind == svn_node_file)
-        SVN_ERR(do_arbitrary_files_diff(child1_abspath, child2_abspath,
-                                        svn_relpath_join(child_relpath, name,
-                                                         iterpool),
-                                        FALSE, FALSE, NULL,
-                                        b->callbacks, b->diff_baton,
-                                        b->ctx, scratch_pool));
-
-      /* Directories that only exist in dirents2. These aren't crawled
-       * by this walker so we have to crawl them separately. */
-      if (depth > svn_depth_files &&
-          dirent2->kind == svn_node_dir &&
-          (dirent1->kind == svn_node_file || dirent1->kind == svn_node_none))
-        SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
-                                       b->root1_abspath, b->root2_abspath,
-                                       depth <= svn_depth_immediates
-                                         ? svn_depth_empty
-                                         : svn_depth_infinity ,
-                                       b->callbacks, b->diff_baton,
-                                       b->ctx, iterpool));
+  if (! left_only)
+    {
+      right_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+      SVN_ERR(get_props(&right_props, right_abspath, ctx->wc_ctx,
+                        scratch_pool, scratch_pool));
+    }
+  else
+    {
+      right_source = NULL;
+      right_props = NULL;
     }
 
-  svn_pool_destroy(iterpool);
+  SVN_ERR(diff_processor->dir_opened(&dir_baton, &skip, &skip_children,
+                                     relpath,
+                                     left_source,
+                                     right_source,
+                                     NULL /* copyfrom_source */,
+                                     parent_baton,
+                                     diff_processor,
+                                     scratch_pool, scratch_pool));
 
-  return SVN_NO_ERROR;
-}
+  if (!skip_children)
+    {
+      if (depth >= svn_depth_files)
+        SVN_ERR(inner_dir_diff(left_abspath, right_abspath,
+                               left_root_abspath, right_root_abspath,
+                               left_only, right_only,
+                               left_before_right, depth,
+                               dir_baton,
+                               diff_processor, ctx, scratch_pool));
+    }
+  else if (skip)
+    return SVN_NO_ERROR;
 
-/* An implementation of svn_io_walk_func_t.
- * Note: LOCAL_ABSPATH is the path being crawled and can be on either side
- * of the diff depending on baton->recursing_within_added_subtree. */
-static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
-                      const apr_finfo_t *finfo,
-                      apr_pool_t *scratch_pool)
-{
-  struct arbitrary_diff_walker_baton *b = baton;
+  if (left_props && right_props)
+    {
+      apr_array_header_t *prop_diffs;
 
-  if (b->ctx->cancel_func)
-    SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+      SVN_ERR(svn_prop_diffs(&prop_diffs, right_props, left_props,
+                             scratch_pool));
 
-  if (finfo->filetype != APR_DIR)
-    return SVN_NO_ERROR;
+      if (prop_diffs->nelts)
+        {
+          SVN_ERR(diff_processor->dir_changed(relpath,
+                                              left_source,
+                                              right_source,
+                                              left_props,
+                                              right_props,
+                                              prop_diffs,
+                                              dir_baton,
+                                              diff_processor,
+                                              scratch_pool));
+          return SVN_NO_ERROR;
+        }
+    }
 
-  SVN_ERR(arbitrary_diff_this_dir(b, local_abspath, svn_depth_infinity,
-                                  scratch_pool));
+  if (left_source && right_source)
+    {
+      SVN_ERR(diff_processor->dir_closed(relpath,
+                                         left_source,
+                                         right_source,
+                                         dir_baton,
+                                         diff_processor,
+                                         scratch_pool));
+    }
+  else if (left_source)
+    {
+      SVN_ERR(diff_processor->dir_deleted(relpath,
+                                          left_source,
+                                          left_props,
+                                          dir_baton,
+                                          diff_processor,
+                                          scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(diff_processor->dir_added(relpath,
+                                        NULL /* copyfrom_source */,
+                                        right_source,
+                                        NULL /* copyfrom_props */,
+                                        right_props,
+                                        dir_baton,
+                                        diff_processor,
+                                        scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client__arbitrary_nodes_diff(const char *local_abspath1,
-                                 const char *local_abspath2,
+svn_client__arbitrary_nodes_diff(const char **root_relpath,
+                                 svn_boolean_t *root_is_dir,
+                                 const char *left_abspath,
+                                 const char *right_abspath,
                                  svn_depth_t depth,
-                                 const svn_wc_diff_callbacks4_t *callbacks,
-                                 void *diff_baton,
+                                 const svn_diff_tree_processor_t *diff_processor,
                                  svn_client_ctx_t *ctx,
+                                 apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
-  svn_node_kind_t kind1;
-  svn_node_kind_t kind2;
+  svn_node_kind_t left_kind;
+  svn_node_kind_t right_kind;
+  const char *left_root_abspath;
+  const char *right_root_abspath;
+  svn_boolean_t left_before_right = TRUE; /* Future argument? */
 
-  SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-  SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
+  if (depth == svn_depth_unknown)
+    depth = svn_depth_infinity;
 
-  if (kind1 != kind2)
-    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
-                             _("'%s' is not the same node kind as '%s'"),
-                             svn_dirent_local_style(local_abspath1,
-                                                    scratch_pool),
-                             svn_dirent_local_style(local_abspath2,
-                                                    scratch_pool));
+  SVN_ERR(svn_io_check_resolved_path(left_abspath, &left_kind, scratch_pool));
+  SVN_ERR(svn_io_check_resolved_path(right_abspath, &right_kind, scratch_pool));
 
   if (depth == svn_depth_unknown)
     depth = svn_depth_infinity;
 
-  if (kind1 == svn_node_file)
-    SVN_ERR(do_arbitrary_files_diff(local_abspath1, local_abspath2,
-                                    svn_dirent_basename(local_abspath1,
-                                                        scratch_pool),
-                                    FALSE, FALSE, NULL,
-                                    callbacks, diff_baton,
-                                    ctx, scratch_pool));
-  else if (kind1 == svn_node_dir)
-    SVN_ERR(do_arbitrary_dirs_diff(local_abspath1, local_abspath2,
-                                   NULL, NULL, depth,
-                                   callbacks, diff_baton,
-                                   ctx, scratch_pool));
+  if (left_kind == svn_node_dir && right_kind == svn_node_dir)
+    {
+      left_root_abspath = left_abspath;
+      right_root_abspath = right_abspath;
+
+      if (root_relpath)
+        *root_relpath = "";
+      if (root_is_dir)
+        *root_is_dir = TRUE;
+    }
+  else
+    {
+      svn_dirent_split(&left_root_abspath, root_relpath, left_abspath,
+                       scratch_pool);
+      right_root_abspath = svn_dirent_dirname(right_abspath, scratch_pool);
+
+      if (root_relpath)
+        *root_relpath = apr_pstrdup(result_pool, *root_relpath);
+      if (root_is_dir)
+        *root_is_dir = FALSE;
+    }
+
+  if (left_kind == svn_node_dir && right_kind == svn_node_dir)
+    {
+      SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                          left_root_abspath, right_root_abspath,
+                          FALSE, FALSE, left_before_right,
+                          depth, NULL /* parent_baton */,
+                          diff_processor, ctx, scratch_pool));
+    }
+  else if (left_kind == svn_node_file && right_kind == svn_node_file)
+    {
+      SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                           left_root_abspath, right_root_abspath,
+                           FALSE, FALSE,
+                           NULL /* parent_baton */,
+                           diff_processor, ctx, scratch_pool));
+    }
+  else if (left_kind == svn_node_file || left_kind == svn_node_dir
+           || right_kind == svn_node_file || right_kind == svn_node_dir)
+    {
+      void *dir_baton;
+      svn_boolean_t skip = FALSE;
+      svn_boolean_t skip_children = FALSE;
+      svn_diff_source_t *left_src;
+      svn_diff_source_t *right_src;
+
+      left_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+      right_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+
+      /* The root is replaced... */
+      /* Report delete and/or add */
+
+      SVN_ERR(diff_processor->dir_opened(&dir_baton, &skip, &skip_children, "",
+                                         left_src,
+                                         right_src,
+                                         NULL /* copyfrom_src */,
+                                         NULL,
+                                         diff_processor,
+                                         scratch_pool, scratch_pool));
+
+      if (skip)
+        return SVN_NO_ERROR;
+      else if (!skip_children)
+        {
+          if (left_before_right)
+            {
+              if (left_kind == svn_node_file)
+                SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, NULL /* parent_baton */,
+                                     diff_processor, ctx, scratch_pool));
+              else if (left_kind == svn_node_dir)
+                SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE, left_before_right,
+                                    depth, NULL /* parent_baton */,
+                                    diff_processor, ctx, scratch_pool));
+            }
+
+          if (right_kind == svn_node_file)
+            SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                                 left_root_abspath, right_root_abspath,
+                                 FALSE, TRUE, NULL /* parent_baton */,
+                                 diff_processor, ctx, scratch_pool));
+          else if (right_kind == svn_node_dir)
+            SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                                left_root_abspath, right_root_abspath,
+                                FALSE, TRUE,  left_before_right,
+                                depth, NULL /* parent_baton */,
+                                diff_processor, ctx, scratch_pool));
+
+          if (! left_before_right)
+            {
+              if (left_kind == svn_node_file)
+                SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, NULL /* parent_baton */,
+                                     diff_processor, ctx, scratch_pool));
+              else if (left_kind == svn_node_dir)
+                SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE,  left_before_right,
+                                    depth, NULL /* parent_baton */,
+                                    diff_processor, ctx, scratch_pool));
+            }
+        }
+
+      SVN_ERR(diff_processor->dir_closed("",
+                                         left_src,
+                                         right_src,
+                                         dir_baton,
+                                         diff_processor,
+                                         scratch_pool));
+    }
   else
     return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                              _("'%s' is not a file or directory"),
-                             kind1 == svn_node_none
-                               ? svn_dirent_local_style(local_abspath1,
-                                                        scratch_pool)
-                               : svn_dirent_local_style(local_abspath2,
-                                                        scratch_pool));
+                             svn_dirent_local_style(
+                                    (left_kind == svn_node_none)
+                                        ? left_abspath
+                                        : right_abspath,
+                                    scratch_pool));
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_summarize.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_summarize.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_summarize.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/diff_summarize.c Sun Mar  9 10:08:46 2014
@@ -25,32 +25,29 @@
 #include "svn_private_config.h"
 #include "svn_dirent_uri.h"
 #include "svn_hash.h"
+#include "svn_path.h"
 #include "svn_props.h"
 #include "svn_pools.h"
 
+#include "private/svn_wc_private.h"
+
 #include "client.h"
 
 
 /* Diff callbacks baton.  */
 struct summarize_baton_t {
+  apr_pool_t *baton_pool; /* For allocating skip_path */
+
   /* The target path of the diff, relative to the anchor; "" if target == anchor. */
-  const char *target;
+  const char *skip_relpath;
 
   /* The summarize callback passed down from the API */
   svn_client_diff_summarize_func_t summarize_func;
 
-  /* Is the diff handling reversed? (add<->delete) */
-  svn_boolean_t reversed;
-
   /* The summarize callback baton */
   void *summarize_func_baton;
-
-  /* Which paths have a prop change. Key is a (const char *) path; the value
-   * is any non-null pointer to indicate that this path has a prop change. */
-  apr_hash_t *prop_changes;
 };
 
-
 /* Call B->summarize_func with B->summarize_func_baton, passing it a
  * summary object composed from PATH (but made to be relative to the target
  * of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an
@@ -68,24 +65,9 @@ send_summary(struct summarize_baton_t *b
   SVN_ERR_ASSERT(summarize_kind != svn_client_diff_summarize_kind_normal
                  || prop_changed);
 
-  if (b->reversed)
-    {
-      switch(summarize_kind)
-        {
-          case svn_client_diff_summarize_kind_added:
-            summarize_kind = svn_client_diff_summarize_kind_deleted;
-            break;
-          case svn_client_diff_summarize_kind_deleted:
-            summarize_kind = svn_client_diff_summarize_kind_added;
-            break;
-          default:
-            break;
-        }
-    }
-
   /* PATH is relative to the anchor of the diff, but SUM->path needs to be
      relative to the target of the diff. */
-  sum->path = svn_relpath_skip_ancestor(b->target, path);
+  sum->path = svn_relpath_skip_ancestor(b->skip_relpath, path);
   sum->summarize_kind = summarize_kind;
   if (summarize_kind == svn_client_diff_summarize_kind_modified
       || summarize_kind == svn_client_diff_summarize_kind_normal)
@@ -96,6 +78,29 @@ send_summary(struct summarize_baton_t *b
   return SVN_NO_ERROR;
 }
 
+/* Are there any changes to relevant (normal) props in PROPS? */
+static svn_boolean_t
+props_changed_hash(apr_hash_t *props,
+                   apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  if (!props)
+    return FALSE;
+
+  for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+
+      if (svn_property_kind2(name) == svn_prop_regular_kind)
+        {
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 /* Are there any changes to relevant (normal) props in PROPCHANGES? */
 static svn_boolean_t
 props_changed(const apr_array_header_t *propchanges,
@@ -108,210 +113,201 @@ props_changed(const apr_array_header_t *
   return (props->nelts != 0);
 }
 
-
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_dir_deleted(svn_wc_notify_state_t *state,
-               svn_boolean_t *tree_conflicted,
-               const char *path,
-               void *diff_baton,
-               apr_pool_t *scratch_pool)
+diff_dir_opened(void **new_dir_baton,
+                svn_boolean_t *skip,
+                svn_boolean_t *skip_children,
+                const char *relpath,
+                const svn_diff_source_t *left_source,
+                const svn_diff_source_t *right_source,
+                const svn_diff_source_t *copyfrom_source,
+                void *parent_dir_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
-  struct summarize_baton_t *b = diff_baton;
+  /* struct summarize_baton_t *b = processor->baton; */
 
-  SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted,
-                       FALSE, svn_node_dir, scratch_pool));
+  /* ### Send here instead of from dir_added() ? */
+  /*if (!left_source)
+    {
+      SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added,
+                           FALSE, svn_node_dir, scratch_pool));
+    }*/
 
   return SVN_NO_ERROR;
 }
 
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_file_deleted(svn_wc_notify_state_t *state,
-                svn_boolean_t *tree_conflicted,
-                const char *path,
-                const char *tmpfile1,
-                const char *tmpfile2,
-                const char *mimetype1,
-                const char *mimetype2,
-                apr_hash_t *originalprops,
-                void *diff_baton,
-                apr_pool_t *scratch_pool)
+diff_dir_changed(const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 const svn_diff_source_t *right_source,
+                 /*const*/ apr_hash_t *left_props,
+                 /*const*/ apr_hash_t *right_props,
+                 const apr_array_header_t *prop_changes,
+                 void *dir_baton,
+                 const struct svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool)
 {
-  struct summarize_baton_t *b = diff_baton;
+  struct summarize_baton_t *b = processor->baton;
 
-  SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted,
-                       FALSE, svn_node_file, scratch_pool));
+  SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_normal,
+                       TRUE, svn_node_dir, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_dir_added(svn_wc_notify_state_t *state,
-             svn_boolean_t *tree_conflicted,
-             svn_boolean_t *skip,
-             svn_boolean_t *skip_children,
-             const char *path,
-             svn_revnum_t rev,
-             const char *copyfrom_path,
-             svn_revnum_t copyfrom_revision,
-             void *diff_baton,
-             apr_pool_t *scratch_pool)
+diff_dir_added(const char *relpath,
+               const svn_diff_source_t *copyfrom_source,
+               const svn_diff_source_t *right_source,
+               /*const*/ apr_hash_t *copyfrom_props,
+               /*const*/ apr_hash_t *right_props,
+               void *dir_baton,
+               const struct svn_diff_tree_processor_t *processor,
+               apr_pool_t *scratch_pool)
 {
-  return SVN_NO_ERROR;
-}
+  struct summarize_baton_t *b = processor->baton;
+
+  /* ### Send from dir_opened without prop info? */
+  SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added,
+                       props_changed_hash(right_props, scratch_pool),
+                       svn_node_dir, scratch_pool));
 
-static svn_error_t *
-cb_dir_opened(svn_boolean_t *tree_conflicted,
-              svn_boolean_t *skip,
-              svn_boolean_t *skip_children,
-              const char *path,
-              svn_revnum_t rev,
-              void *diff_baton,
-              apr_pool_t *scratch_pool)
-{
   return SVN_NO_ERROR;
 }
 
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_dir_closed(svn_wc_notify_state_t *contentstate,
-              svn_wc_notify_state_t *propstate,
-              svn_boolean_t *tree_conflicted,
-              const char *path,
-              svn_boolean_t dir_was_added,
-              void *diff_baton,
-              apr_pool_t *scratch_pool)
+diff_dir_deleted(const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 /*const*/ apr_hash_t *left_props,
+                 void *dir_baton,
+                 const struct svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool)
 {
-  struct summarize_baton_t *b = diff_baton;
-  svn_boolean_t prop_change;
-
-  if (! svn_relpath_skip_ancestor(b->target, path))
-    return SVN_NO_ERROR;
+  struct summarize_baton_t *b = processor->baton;
 
-  prop_change = svn_hash_gets(b->prop_changes, path) != NULL;
-  if (dir_was_added || prop_change)
-    SVN_ERR(send_summary(b, path,
-                         dir_was_added ? svn_client_diff_summarize_kind_added
-                                       : svn_client_diff_summarize_kind_normal,
-                         prop_change, svn_node_dir, scratch_pool));
+  SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_deleted,
+                       FALSE, svn_node_dir, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_file_added(svn_wc_notify_state_t *contentstate,
-              svn_wc_notify_state_t *propstate,
-              svn_boolean_t *tree_conflicted,
-              const char *path,
-              const char *tmpfile1,
-              const char *tmpfile2,
-              svn_revnum_t rev1,
-              svn_revnum_t rev2,
-              const char *mimetype1,
-              const char *mimetype2,
-              const char *copyfrom_path,
-              svn_revnum_t copyfrom_revision,
-              const apr_array_header_t *propchanges,
-              apr_hash_t *originalprops,
-              void *diff_baton,
-              apr_pool_t *scratch_pool)
+diff_file_added(const char *relpath,
+                const svn_diff_source_t *copyfrom_source,
+                const svn_diff_source_t *right_source,
+                const char *copyfrom_file,
+                const char *right_file,
+                /*const*/ apr_hash_t *copyfrom_props,
+                /*const*/ apr_hash_t *right_props,
+                void *file_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool)
 {
-  struct summarize_baton_t *b = diff_baton;
+  struct summarize_baton_t *b = processor->baton;
 
-  SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_added,
-                       props_changed(propchanges, scratch_pool),
+  SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added,
+                       props_changed_hash(right_props, scratch_pool),
                        svn_node_file, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_file_opened(svn_boolean_t *tree_conflicted,
-               svn_boolean_t *skip,
-               const char *path,
-               svn_revnum_t rev,
-               void *diff_baton,
-               apr_pool_t *scratch_pool)
+diff_file_changed(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const svn_diff_source_t *right_source,
+                  const char *left_file,
+                  const char *right_file,
+                  /*const*/ apr_hash_t *left_props,
+                  /*const*/ apr_hash_t *right_props,
+                  svn_boolean_t file_modified,
+                  const apr_array_header_t *prop_changes,
+                  void *file_baton,
+                  const struct svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
 {
-  return SVN_NO_ERROR;
-}
+  struct summarize_baton_t *b = processor->baton;
 
-static svn_error_t *
-cb_file_changed(svn_wc_notify_state_t *contentstate,
-                svn_wc_notify_state_t *propstate,
-                svn_boolean_t *tree_conflicted,
-                const char *path,
-                const char *tmpfile1,
-                const char *tmpfile2,
-                svn_revnum_t rev1,
-                svn_revnum_t rev2,
-                const char *mimetype1,
-                const char *mimetype2,
-                const apr_array_header_t *propchanges,
-                apr_hash_t *originalprops,
-                void *diff_baton,
-                apr_pool_t *scratch_pool)
-{
-  struct summarize_baton_t *b = diff_baton;
-  svn_boolean_t text_change = (tmpfile2 != NULL);
-  svn_boolean_t prop_change = props_changed(propchanges, scratch_pool);
-
-  if (text_change || prop_change)
-    SVN_ERR(send_summary(b, path,
-                         text_change ? svn_client_diff_summarize_kind_modified
+  SVN_ERR(send_summary(b, relpath,
+                       file_modified ? svn_client_diff_summarize_kind_modified
                                      : svn_client_diff_summarize_kind_normal,
-                         prop_change, svn_node_file, scratch_pool));
+                       props_changed(prop_changes, scratch_pool),
+                       svn_node_file, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
+/* svn_diff_tree_processor_t callback */
 static svn_error_t *
-cb_dir_props_changed(svn_wc_notify_state_t *propstate,
-                     svn_boolean_t *tree_conflicted,
-                     const char *path,
-                     svn_boolean_t dir_was_added,
-                     const apr_array_header_t *propchanges,
-                     apr_hash_t *original_props,
-                     void *diff_baton,
-                     apr_pool_t *scratch_pool)
+diff_file_deleted(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const char *left_file,
+                  /*const*/ apr_hash_t *left_props,
+                  void *file_baton,
+                  const struct svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
 {
-  struct summarize_baton_t *b = diff_baton;
+  struct summarize_baton_t *b = processor->baton;
 
-  if (props_changed(propchanges, scratch_pool))
-    svn_hash_sets(b->prop_changes, path, path);
+  SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_deleted,
+                       FALSE, svn_node_file, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
 svn_client__get_diff_summarize_callbacks(
-                        svn_wc_diff_callbacks4_t **callbacks,
-                        void **callback_baton,
-                        const char *target,
-                        svn_boolean_t reversed,
+                        const svn_diff_tree_processor_t **diff_processor,
+                        const char ***p_root_relpath,
                         svn_client_diff_summarize_func_t summarize_func,
                         void *summarize_baton,
-                        apr_pool_t *pool)
+                        const char *original_target,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
 {
-  svn_wc_diff_callbacks4_t *cb = apr_palloc(pool, sizeof(*cb));
-  struct summarize_baton_t *b = apr_palloc(pool, sizeof(*b));
+  svn_diff_tree_processor_t *dp;
+  struct summarize_baton_t *b = apr_pcalloc(result_pool, sizeof(*b));
 
-  b->target = target;
+  b->baton_pool = result_pool;
   b->summarize_func = summarize_func;
   b->summarize_func_baton = summarize_baton;
-  b->prop_changes = apr_hash_make(pool);
-  b->reversed = reversed;
 
-  cb->file_opened = cb_file_opened;
-  cb->file_changed = cb_file_changed;
-  cb->file_added = cb_file_added;
-  cb->file_deleted = cb_file_deleted;
-  cb->dir_deleted = cb_dir_deleted;
-  cb->dir_opened = cb_dir_opened;
-  cb->dir_added = cb_dir_added;
-  cb->dir_props_changed = cb_dir_props_changed;
-  cb->dir_closed = cb_dir_closed;
+  dp = svn_diff__tree_processor_create(b, result_pool);
+
+  /*dp->file_opened = diff_file_opened;*/
+  dp->file_added = diff_file_added;
+  dp->file_deleted = diff_file_deleted;
+  dp->file_changed = diff_file_changed;
 
-  *callbacks = cb;
-  *callback_baton = b;
+  dp->dir_opened = diff_dir_opened;
+  dp->dir_changed = diff_dir_changed;
+  dp->dir_deleted = diff_dir_deleted;
+  dp->dir_added = diff_dir_added;
+
+  *diff_processor = dp;
+  *p_root_relpath = &b->skip_relpath;
 
   return SVN_NO_ERROR;
 }
+
+svn_client_diff_summarize_t *
+svn_client_diff_summarize_dup(const svn_client_diff_summarize_t *diff,
+                              apr_pool_t *pool)
+{
+  svn_client_diff_summarize_t *dup_diff = apr_palloc(pool, sizeof(*dup_diff));
+
+  *dup_diff = *diff;
+
+  if (diff->path)
+    dup_diff->path = apr_pstrdup(pool, diff->path);
+
+  return dup_diff;
+}

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/export.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/export.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/export.c Sun Mar  9 10:08:46 2014
@@ -172,6 +172,7 @@ struct export_info_baton
   void *notify_baton;
   const char *origin_abspath;
   svn_boolean_t exported;
+  svn_boolean_t exporting_external;
 };
 
 /* Export a file or directory. Implements svn_wc_status_func4_t */
@@ -268,7 +269,7 @@ export_node(void *baton,
                                                       scratch_pool));
     }
 
-  if (status->file_external)
+  if (status->file_external && !eib->exporting_external)
     return SVN_NO_ERROR;
 
   /* Produce overwrite errors for the export root */
@@ -1364,23 +1365,20 @@ export_directory(const char *from_path_o
   return SVN_NO_ERROR;
 }
 
-
-
-/*** Public Interfaces ***/
-
-svn_error_t *
-svn_client_export5(svn_revnum_t *result_rev,
-                   const char *from_path_or_url,
-                   const char *to_path,
-                   const svn_opt_revision_t *peg_revision,
-                   const svn_opt_revision_t *revision,
-                   svn_boolean_t overwrite,
-                   svn_boolean_t ignore_externals,
-                   svn_boolean_t ignore_keywords,
-                   svn_depth_t depth,
-                   const char *native_eol,
-                   svn_client_ctx_t *ctx,
-                   apr_pool_t *pool)
+static svn_error_t *
+do_export(svn_revnum_t *result_rev,
+          const char *from_path_or_url,
+          const char *to_path,
+          const svn_opt_revision_t *peg_revision,
+          const svn_opt_revision_t *revision,
+          svn_boolean_t overwrite,
+          svn_boolean_t ignore_externals,
+          svn_boolean_t ignore_keywords,
+          svn_depth_t depth,
+          const char *native_eol,
+          svn_boolean_t exporting_external,
+          svn_client_ctx_t *ctx,
+          apr_pool_t *pool)
 {
   svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
   svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
@@ -1511,6 +1509,7 @@ svn_client_export5(svn_revnum_t *result_
       eib.notify_baton = ctx->notify_baton2;
       eib.origin_abspath = from_path_or_url;
       eib.exported = FALSE;
+      eib.exporting_external = exporting_external;
 
       SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, from_path_or_url, depth,
                                  TRUE /* get_all */,
@@ -1558,15 +1557,15 @@ svn_client_export5(svn_revnum_t *result_
                             svn_dirent_dirname(target_abspath, iterpool),
                             iterpool));
 
-              SVN_ERR(svn_client_export5(NULL,
-                                         svn_dirent_join(from_path_or_url,
-                                                         relpath,
-                                                         iterpool),
-                                         target_abspath,
-                                         peg_revision, revision,
-                                         TRUE, ignore_externals,
-                                         ignore_keywords, depth, native_eol,
-                                         ctx, iterpool));
+              SVN_ERR(do_export(NULL,
+                                svn_dirent_join(from_path_or_url,
+                                               relpath,
+                                               iterpool),
+                                target_abspath,
+                                peg_revision, revision,
+                                TRUE, ignore_externals,
+                                ignore_keywords, depth, native_eol,
+                                TRUE, ctx, iterpool));
             }
 
           svn_pool_destroy(iterpool);
@@ -1588,3 +1587,25 @@ svn_client_export5(svn_revnum_t *result_
 
   return SVN_NO_ERROR;
 }
+
+
+/*** Public Interfaces ***/
+svn_error_t *
+svn_client_export5(svn_revnum_t *result_rev,
+                   const char *from_path_or_url,
+                   const char *to_path,
+                   const svn_opt_revision_t *peg_revision,
+                   const svn_opt_revision_t *revision,
+                   svn_boolean_t overwrite,
+                   svn_boolean_t ignore_externals,
+                   svn_boolean_t ignore_keywords,
+                   svn_depth_t depth,
+                   const char *native_eol,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
+  return svn_error_trace(do_export(result_rev, from_path_or_url, to_path,
+                                   peg_revision, revision, overwrite,
+                                   ignore_externals, ignore_keywords,
+                                   depth, native_eol, FALSE, ctx, pool));
+}

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/import.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/import.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/import.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/import.c Sun Mar  9 10:08:46 2014
@@ -664,7 +664,7 @@ import(const char *local_abspath,
   const svn_io_dirent2_t *dirent;
 
   import_ctx->autoprops = autoprops;
-  svn_magic__init(&import_ctx->magic_cookie, pool);
+  SVN_ERR(svn_magic__init(&import_ctx->magic_cookie, ctx->config, pool));
 
   /* Get a root dir baton.  We pass the revnum we used for testing our
      assumptions and obtaining inherited properties. */

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/merge.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/merge.c Sun Mar  9 10:08:46 2014
@@ -2419,7 +2419,7 @@ merge_file_deleted(const char *relpath,
    When *SKIP is TRUE, the diff driver avoids work on getting the details
    for the closing callbacks.
 
-   The SKIP and SKIP_DESCENDANTS work independantly.
+   The SKIP and SKIP_DESCENDANTS work independently.
  */
 static svn_error_t *
 merge_dir_opened(void **new_dir_baton,
@@ -3133,7 +3133,7 @@ merge_dir_deleted(const char *relpath,
          descendants we haven't walked?
 
          Note that we aren't interested in changes, as we already verified
-         changes in the paths touched by the merge. And the existance of
+         changes in the paths touched by the merge. And the existence of
          other paths is enough to mark the directory edited */
       err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath,
                                svn_depth_infinity, TRUE /* get-all */,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.c Sun Mar  9 10:08:46 2014
@@ -361,7 +361,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
       SVN_ERR(svn_mergeinfo_inheritable2(mergeinfo, *mergeinfo, NULL,
                                          SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
                                          TRUE, result_pool, scratch_pool));
-      svn_mergeinfo__remove_empty_rangelists(*mergeinfo, result_pool);
+      svn_mergeinfo__remove_empty_rangelists(*mergeinfo, scratch_pool);
     }
 
   if (inherited_p)

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/mergeinfo.h Sun Mar  9 10:08:46 2014
@@ -316,7 +316,9 @@ svn_client__get_history_as_mergeinfo(svn
 
 /* Parse any explicit mergeinfo on LOCAL_ABSPATH and store it in
    *MERGEINFO.  If no record of any mergeinfo exists, set *MERGEINFO to NULL.
-   Does not acount for inherited mergeinfo. */
+   Does not acount for inherited mergeinfo.
+
+   Allocate the result deeply in @a result_pool. */
 svn_error_t *
 svn_client__parse_mergeinfo(svn_mergeinfo_t *mergeinfo,
                             svn_wc_context_t *wc_ctx,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/prop_commands.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_client/prop_commands.c Sun Mar  9 10:08:46 2014
@@ -1222,7 +1222,7 @@ recursive_proplist_receiver(void *baton,
          Report iprops anyway */
 
       SVN_ERR(b->wrapped_receiver(b->wrapped_receiver_baton,
-                                  b->anchor ? b->anchor : local_abspath,
+                                  b->anchor ? b->anchor : b->anchor_abspath,
                                   NULL /* prop_hash */,
                                   b->iprops,
                                   scratch_pool));

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -7,3 +7,5 @@ Release
 *~
 .*~
 libsvn_delta.def
+libsvn_delta.pc.in
+libsvn_delta.pc

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/compose_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/compose_delta.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/compose_delta.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/compose_delta.c Sun Mar  9 10:08:46 2014
@@ -649,7 +649,8 @@ copy_source_ops(apr_size_t offset, apr_s
       const svn_txdelta_op_t *const op = &window->ops[op_ndx];
       const apr_size_t *const off = &ndx->offs[op_ndx];
       const apr_size_t fix_offset = (offset > off[0] ? offset - off[0] : 0);
-      const apr_size_t fix_limit = (off[1] > limit ? off[1] - limit : 0);
+      const apr_size_t fix_limit = (off[0] >= limit ? 0
+                                    : (off[1] > limit ? off[1] - limit : 0));
 
       /* Ideally, we'd do this check before assigning fix_offset and
          fix_limit; but then we couldn't make them const whilst still

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/svndiff.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/svndiff.c Sun Mar  9 10:08:46 2014
@@ -872,23 +872,6 @@ svn_txdelta_read_svndiff_window(svn_txde
 
 
 svn_error_t *
-svn_txdelta__read_svndiff_window_sizes(svn_txdelta_window_t **window,
-                                       svn_stream_t *stream,
-                                       int svndiff_version,
-                                       apr_pool_t *pool)
-{
-  apr_size_t inslen, newlen;
-
-  *window = apr_pcalloc(pool, sizeof(**window));
-  SVN_ERR(read_window_header(stream, &(*window)->sview_offset,
-                             &(*window)->sview_len, &(*window)->tview_len,
-                             &inslen, &newlen));
-
-  return svn_error_trace(svn_stream_skip(stream, inslen + newlen));
-}
-
-
-svn_error_t *
 svn_txdelta_skip_svndiff_window(apr_file_t *file,
                                 int svndiff_version,
                                 apr_pool_t *pool)

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/xdelta.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/xdelta.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/xdelta.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_delta/xdelta.c Sun Mar  9 10:08:46 2014
@@ -45,7 +45,7 @@
  */
 #define MATCH_BLOCKSIZE 64
 
-/* Size of the checksum presense FLAGS array in BLOCKS_T.  With standard
+/* Size of the checksum presence FLAGS array in BLOCKS_T.  With standard
    MATCH_BLOCKSIZE and SVN_DELTA_WINDOW_SIZE, 32k entries is about 20x
    the number of checksums that actually occur, i.e. we expect a >95%
    probability that non-matching checksums get already detected by checking
@@ -408,7 +408,7 @@ compute_delta(svn_txdelta__ops_baton_t *
 
   /* Initialize our rolling checksum.  */
   rolling = init_adler32(b + lo);
-  while (lo < bsize)
+  while (lo < upper)
     {
       apr_size_t matchlen;
       apr_size_t apos;

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -7,4 +7,5 @@ Release
 *~
 .*~
 libsvn_diff.def
-
+libsvn_diff.pc.in
+libsvn_diff.pc

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/deprecated.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/deprecated.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/deprecated.c Sun Mar  9 10:08:46 2014
@@ -143,6 +143,33 @@ wrap_diff_fns(svn_diff_fns2_t **diff_fns
 
 
 /*** From diff_file.c ***/
+
+svn_error_t *
+svn_diff_file_output_unified3(svn_stream_t *output_stream,
+                              svn_diff_t *diff,
+                              const char *original_path,
+                              const char *modified_path,
+                              const char *original_header,
+                              const char *modified_header,
+                              const char *header_encoding,
+                              const char *relative_to_dir,
+                              svn_boolean_t show_c_function,
+                              apr_pool_t *pool)
+{
+  return svn_error_trace(
+              svn_diff_file_output_unified4(output_stream,
+                                            diff,
+                                            original_path,
+                                            modified_path,
+                                            original_header,
+                                            modified_header,
+                                            header_encoding,
+                                            relative_to_dir,
+                                            show_c_function,
+                                            NULL, NULL, /* cancel */
+                                            pool));
+}
+
 svn_error_t *
 svn_diff_file_output_unified2(svn_stream_t *output_stream,
                               svn_diff_t *diff,
@@ -287,3 +314,14 @@ svn_diff_diff4(svn_diff_t **diff,
   wrap_diff_fns(&diff_fns2, &fwb, vtable, diff_baton, pool);
   return svn_diff_diff4_2(diff, fwb, diff_fns2, pool);
 }
+
+/*** From util.c ***/
+svn_error_t *
+svn_diff_output(svn_diff_t *diff,
+                void *output_baton,
+                const svn_diff_output_fns_t *output_fns)
+{
+  return svn_error_trace(svn_diff_output2(diff, output_baton, output_fns,
+                                          NULL, NULL /* cancel */));
+}
+

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff4.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff4.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff4.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff4.c Sun Mar  9 10:08:46 2014
@@ -270,7 +270,7 @@ svn_diff_diff4_2(svn_diff_t **diff,
     }
 
   /* Get the lcs for common ancestor - original
-   * Do reverse adjustements
+   * Do reverse adjustments
    */
   lcs_adjust = svn_diff__lcs(position_list[3], position_list[2],
                              token_counts[3], token_counts[2],

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_file.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_file.c Sun Mar  9 10:08:46 2014
@@ -1815,7 +1815,7 @@ static const svn_diff_output_fns_t svn_d
 };
 
 svn_error_t *
-svn_diff_file_output_unified3(svn_stream_t *output_stream,
+svn_diff_file_output_unified4(svn_stream_t *output_stream,
                               svn_diff_t *diff,
                               const char *original_path,
                               const char *modified_path,
@@ -1824,6 +1824,8 @@ svn_diff_file_output_unified3(svn_stream
                               const char *header_encoding,
                               const char *relative_to_dir,
                               svn_boolean_t show_c_function,
+                              svn_cancel_func_t cancel_func,
+                              void *cancel_baton,
                               apr_pool_t *pool)
 {
   if (svn_diff_contains_diffs(diff))
@@ -1918,8 +1920,9 @@ svn_diff_file_output_unified3(svn_stream
                                              original_header, modified_header,
                                              pool));
 
-      SVN_ERR(svn_diff_output(diff, &baton,
-                              &svn_diff__file_output_unified_vtable));
+      SVN_ERR(svn_diff_output2(diff, &baton,
+                               &svn_diff__file_output_unified_vtable,
+                               cancel_func, cancel_baton));
       SVN_ERR(output_unified_flush_hunk(&baton));
 
       for (i = 0; i < 2; i++)
@@ -2191,7 +2194,25 @@ static const svn_diff_output_fns_t svn_d
   output_conflict
 };
 
+static svn_error_t *
+output_conflict_with_context_marker(svn_diff3__file_output_baton_t *btn,
+                                    const char *label,
+                                    apr_off_t start,
+                                    apr_off_t length)
+{
+  if (length == 1)
+    SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+                              "%s (%" APR_OFF_T_FMT ")",
+                              label, start + 1));
+  else
+    SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+                              "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")",
+                              label, start + 1, length));
+
+  SVN_ERR(output_marker_eol(btn));
 
+  return SVN_NO_ERROR;
+}
 
 static svn_error_t *
 output_conflict_with_context(svn_diff3__file_output_baton_t *btn,
@@ -2215,34 +2236,19 @@ output_conflict_with_context(svn_diff3__
   btn->output_stream = btn->real_output_stream;
 
   /* Output the conflict itself. */
-  SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
-                            (modified_length == 1
-                             ? "%s (%" APR_OFF_T_FMT ")"
-                             : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
-                            btn->conflict_modified,
-                            modified_start + 1, modified_length));
-  SVN_ERR(output_marker_eol(btn));
+  SVN_ERR(output_conflict_with_context_marker(btn, btn->conflict_modified,
+                                              modified_start, modified_length));
   SVN_ERR(output_hunk(btn, 1/*modified*/, modified_start, modified_length));
 
-  SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
-                            (original_length == 1
-                             ? "%s (%" APR_OFF_T_FMT ")"
-                             : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
-                            btn->conflict_original,
-                            original_start + 1, original_length));
-  SVN_ERR(output_marker_eol(btn));
+  SVN_ERR(output_conflict_with_context_marker(btn, btn->conflict_original,
+                                              original_start, original_length));
   SVN_ERR(output_hunk(btn, 0/*original*/, original_start, original_length));
 
   SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
                             "%s%s", btn->conflict_separator, btn->marker_eol));
   SVN_ERR(output_hunk(btn, 2/*latest*/, latest_start, latest_length));
-  SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
-                            (latest_length == 1
-                             ? "%s (%" APR_OFF_T_FMT ")"
-                             : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
-                            btn->conflict_latest,
-                            latest_start + 1, latest_length));
-  SVN_ERR(output_marker_eol(btn));
+  SVN_ERR(output_conflict_with_context_marker(btn, btn->conflict_latest,
+                                              latest_start, latest_length));
 
   /* Go into print-trailing-context mode instead. */
   make_trailing_context_printer(btn);