Merge from trunk


git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/svndiff1@857694 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configure.in b/configure.in
index cba7379..9fc67df 100644
--- a/configure.in
+++ b/configure.in
@@ -503,20 +503,12 @@
 
 ])
 
-AC_ARG_WITH(zlib,
-AC_HELP_STRING([--with-zlib], [enable zlib support]),
-[
-
-    if test "$withval" = "yes" ; then
-       AC_CHECK_HEADER(zlib.h, [
+AC_CHECK_HEADER(zlib.h, [
            AC_CHECK_LIB(z, inflate, [
                AC_DEFINE([SVN_HAVE_ZLIB], [1], [Is zlib support enabled?])
                LIBS="$LIBS -lz"
-           ])
+           ], [AC_MSG_ERROR([subversion requires zlib])])
        ])
-    fi
-
-])
     
 MOD_ACTIVATION="-a"
 AC_ARG_ENABLE(mod-activation,
diff --git a/notes/svndiff b/notes/svndiff
index 574baef..258549a 100644
--- a/notes/svndiff
+++ b/notes/svndiff
@@ -1,7 +1,7 @@
-This file describes the svndiff format used by the Subversion code.
-Its design borrows many ideas from the vdelta and vcdiff encoding
-formats from AT&T Research Labs, but it is much simpler and thus a
-little less compact.
+This file describes the svndiff version 0 and 1 format used by the
+Subversion code.  Its design borrows many ideas from the vdelta and
+vcdiff encoding formats from AT&T Research Labs, but it is much
+simpler and thus a little less compact.
 
 From the point of view of svndiff, a delta is a sequence of windows,
 each containing a list of instructions for reconstructing a contiguous
@@ -28,13 +28,21 @@
 	The target view length
 	The length of the instructions in bytes
 	The length of the new data in bytes
-	The window's instructions
-	The window's new data (as raw data)
+	The window's instructions section
+	The window's new data (as raw data) section
 
-Integers (including the first five items listed above) are encoded
-using a variable-length format.  The high bit of each byte is used as
-a continuation bit; 1 indicates that there is more data and 0
-indicates the final byte.  The other seven bits of each byte are data.
+In svndiff version 1, the instructions, and new data
+sections may be compressed by zlib.  In order to determine the
+original size, an integer is appended to the beginning of each of the
+sections.  If the original size matches the encoded size (minus the
+length of the original size integer)from the header, the data is not
+compressed.  If the original size is different than the encoded size
+from the header, the remaining data in the section.
+
+Integers (including the integers described bove) are encoded using a
+variable-length format.  The high bit of each byte is used as a
+continuation bit; 1 indicates that there is more data and 0 indicates
+the final byte.  The other seven bits of each byte are data.
 Higher-order bits are encoded before lower-order bits.  As an example,
 130 would be encoded as two bytes, 10000001 followed by 00000010.
 
diff --git a/notes/svndiff-v1 b/notes/svndiff-v1
new file mode 100644
index 0000000..79614d4
--- /dev/null
+++ b/notes/svndiff-v1
@@ -0,0 +1,222 @@
+This email is long, so i sectionized it into "Introduction and
+justification", "Changes I made", "Sparkly numbers", "Time Costs and
+Backwards Compatibility"
+:)
+
+Introduction and justification:
+
+First, I should probably explain what svndiff is, and what it looks like
+( which requires a bit of history), and why it needs improving:
+
+Basically, when subversion started, it was decided to keep the internal
+diff format stored on disk and transmitted over the wire
+different from the actual diff instructions, which was a good idea.
+In other words, the instructions that make up a binary diff are add and
+copy.
+How the binary diff is actually encoded, stored, and transmitted over
+the wire is different than that, however.
+
+Thus, if you look at the diffs as they are transmitted over the network,
+or stored in the actual repository revisions, you are looking at
+"svndiff" encoded data.
+
+Back in the old days, when there was discussion about what to make this
+format look like people were on a DAV kick, and the binary delta
+algorithm vdelta was chosen as the delta algorithm.  
+At the same time, a format called "VCDIFF" was being standardized.
+VCDIFF is now rfc 3284 (http://www.faqs.org/rfcs/rfc3284.html).
+VCDIFF defines a delta encoding format that is space efficient, but
+reasonably easy to decode.
+However, VCDIFF was seen as overkill for the internal diff format
+It was assumed we would store it in some nicer thing, and if we wanted,
+transform that to VCDIFF to be sent over the wire
+This was the right decision, and for most things, VCDIFF *is* overkill
+So some things were taken from VCDIFF, and the delta format we use,
+called "SVNDIFF", was born.
+It turns out, hoewver, that svndiff0 (the current version) is not so
+efficient in some particular use cases that are not uncommon.
+Prior to now, We relied on vdelta to compress these cases, instead of
+relying on having good delta encoding, which in hindsight, was probably
+not a good idea.
+Vdelta did an okay job, but generated horrible to combine deltas in some
+cases, which caused us to move to xdelta.
+As noted in 1.2 release notes, we pay about a 15% size penalty for using
+xdelta in the common case.
+
+The not-so-uncommon case where our encoding is not efficientis  when you
+are repeatedly merging things to branches. and adding new data from
+trunk.
+To understand why, you need to know a bit more about the internal
+machinations of svndiff:
+
+svndiff is split into sections:
+
+There is an instruction section, which contains encoded copy and new
+data instructions (IE copy from this part of the source, for this
+length, or "add this new data").
+
+There is also new data section, which contains the new data used by the
+"add this new data" instructions.
+
+When you repeatedly merge things from trunk to a branch, like say, a
+ChangeLog, you end up with a lot of data new to that branch.  This in
+turns, ends up completely uncompressed in the new data section of
+svndiff.
+
+If you stare at something like the on-disk gcc repository revision
+files, which have a lot of branch data, you will see there is just tons
+of files that large pieces of plaintext data that represent merges from
+trunk to branch.
+
+In fact, we have revision files that are 30 meg each, and in each case,
+80% of the data is just the new data section of a bunch of deltas.
+
+This is pretty bad.
+
+Changes I made:
+
+To alleviate this problem, back when the earth's crust was cooling
+(2002), i came up with an svndiff version 1, which compressed the new
+data section using a secondary compressor.  At the time, it was a
+standalone range encoder.
+
+I've recently revived that patch, and brought it up to date.  I've
+changed the compressor to use zlib, which is now *everywhere*.
+
+Sparkly numbers:
+This change buys about 40% of the disk space on the gcc repository.
+8.5 gig to 5.2
+
+A repository consisting of just gcc's changelog file, from all branches,
+used to take up:
+
+583178  db/revs
+
+With the svndiff 1 patch, it now takes up
+
+356591  gccrepo/db/revs
+
+a 39% savings.
+
+Time Costs and Backwards Compatibility
+
+I should first note the cost is essentially zero in terms of time.  We
+only bother to compress if the new data section ends up being bigger
+than some minimum size (currently 1024), and even then, the
+compression/decompression time is completely lost in the noise, AFAICT.
+
+In fact, for gcc's repo, it's actually faster, since it used to read 30
+meg of revision file, and now only needs to read 5 meg, and the i/o was
+slower than the decompression time.
+
+As far as backwards compatibility, let me start by assuaging the most
+common concern:
+
+svndiff0 works perfectly, and we can always tell whether we have
+svndiff1 or 0.  This was actually not true in 2002, but part of the
+patch back then (which made it in as part of some work c-mike as doing)
+was to make the 'SVN<byte> header contain the version number in byte.
+All our current code understands and respects this version number,
+except for one small thing:
+
+svn_txdelta_to_svndiff doesn't take a version number.
+
+I've simply rev'd it to take a version number (IE made
+svn_txdelta_to_svndiff2), and made the current function always use
+version 0.
+
+
+Parsing doesn't need to take an explicit version number, we can read it
+out of the header.
+
+
+The first thing i should note is that we now simply require zlib. I
+haven't yet copied any configure magic necessary to let people point at
+a place for it.  But i don't think this is an unreasonable requirement,
+as *everyone* ships zlib.
+
+We have two things we *actually* need to worry about
+
+Communicating with clients/servers using svndiff1 over the wire
+
+and
+
+Storing svndiff1 inside fsfs and bdb repositories.
+
+The first case is actually easy to make backwards compatible, and i have
+done so.
+
+svnserve has a capabilities list it outputs from the server, and sends
+from the client.  We can simply check to make sure the side we want to
+send svndiff1 to, supports it, by introducing a new capability and
+checking  for it. Unless we find a capability called "svndiff1", we only
+send svndiff0.
+
+mod_dav_svn + ra_dav lets us do a similiar thing with headers (I haven't
+quite started this one yet, but this is what i am told)
+
+
+The more interesting question is the stuff stored in the repo.
+
+If we store svndiff1 in fsfs or bdb, only things that know about
+svndiff1 can read it.  This means older clients trying to directly
+access the repo would fail.
+
+We currently have no easy way to tell what version is in an svn
+repository, other than the "format" file.
+
+So we have two options:
+
+1. Rev the format, allow creation of old/new format (defaulting to old),
+and require dump and load to take advantage of svndiff1.
+
+or a more interesting solution that came to my head, which is to borrow
+an idea from real fs'en, and introduce a "features" file.
+
+As an example, ext3 has feature bits set on the filesystem.   There is a
+feature bit for dir indexing, for whether the fs has a journal, etc.
+
+If we added a feature file to the fsfs format (and bdb format), we could
+actually let people control the features contained in their fs, and only
+need a dump + load to change between features, instead of *requiring*
+that they use certain features.
+
+IOW, later on, if we add hash-indexing, we could make it optional simply
+by adding a feature name for it, and putting that in the feature file.
+
+If you wanted to get rid of hash indexing, you simply create a repo
+without that feature (svnadmin would be extended to turn features on and
+off, and tell you whether you need dump/load to do this right), dump the
+old repo, and load into the new one.
+
+Boom, no more hash indexing, and we didn't need to change the format
+file back to and older revision.
+
+The same could be true of svndiff1.  We can simply make it optional, and
+instead of revving the format, make it a feature, much like how in
+svnserve it is simply a capability.
+
+The advantage here is that for something like svndiff1, if you don't
+want to dump/load, if you added it to the features, it would just cause
+newer revisions to use svndiff1, and the older ones would stay the way
+they are.  
+Dunno whether we care or not.
+
+If we go with this, the features file would mostly be a written hash
+containing the features, and read on fs open. If we find a feature we
+can't support, we error out.
+
+Or we could just rev the format :)
+
+Any hoo, i've attached the current patch, which i've cross-tested 1.2.x
+against patched 1.4.x servers, patched 1.4.x against 1.2.x servers, and
+the same type of deal for 1.3.x.
+
+I've not dealt with backwards compat for repos yet.  If you use this
+patch, you're created repos will use svndiff1.
+
+I obviously have no plans to commit this until we work out these issues,
+and revise the patch.  Thus, style nits, etc, are not necessary.  I'm
+aware it's non-perfect :)
+
+--Dan
\ No newline at end of file
diff --git a/subversion/include/svn_delta.h b/subversion/include/svn_delta.h
index c7ee24d..3b94409 100644
--- a/subversion/include/svn_delta.h
+++ b/subversion/include/svn_delta.h
@@ -242,6 +242,16 @@
                                       svn_txdelta_stream_t *stream,
                                       apr_pool_t *pool);
 
+/** Set @a *window to a pointer to the next window from the delta stream
+ * @a stream.  When we have completely reconstructed the target string,
+ * set @a *window to zero.
+ *
+ * The window will be allocated in @a pool.
+ */
+svn_error_t *svn_txdelta_next_window (svn_txdelta_window_t **window,
+                                      svn_txdelta_stream_t *stream,
+                                      apr_pool_t *pool);
+
 
 /** Return the @a md5 digest for the complete fulltext deltified by
  * @a stream, or @c NULL if @a stream has not yet returned its final 
@@ -355,6 +365,19 @@
  * @a output is a writable generic stream to write the svndiff data to.
  * Allocation takes place in a sub-pool of @a pool.  On return, @a *handler
  * is set to a window handler function and @a *handler_baton is set to
+ * the value to pass as the @a baton argument to @a *handler. The svndiff
+ * version is @a version.
+ */
+
+void svn_txdelta_to_svndiff2 (svn_stream_t *output,
+                              apr_pool_t *pool,
+                              svn_txdelta_window_handler_t *handler,
+                              void **handler_baton, unsigned int version);
+
+/** Prepare to produce an svndiff-format diff from text delta windows.
+ * @a output is a writable generic stream to write the svndiff data to.
+ * Allocation takes place in a sub-pool of @a pool.  On return, @a *handler
+ * is set to a window handler function and @a *handler_baton is set to
  * the value to pass as the @a baton argument to @a *handler.
  */
 void svn_txdelta_to_svndiff (svn_stream_t *output,
diff --git a/subversion/include/svn_error_codes.h b/subversion/include/svn_error_codes.h
index 7338fc3..e63d016 100644
--- a/subversion/include/svn_error_codes.h
+++ b/subversion/include/svn_error_codes.h
@@ -819,6 +819,15 @@
   SVN_ERRDEF (SVN_ERR_SVNDIFF_UNEXPECTED_END,
               SVN_ERR_SVNDIFF_CATEGORY_START + 4,
               "Svndiff data ends unexpectedly")
+  
+  SVN_ERRDEF (SVN_ERR_SVNDIFF_INVALID_VERSION,
+              SVN_ERR_SVNDIFF_CATEGORY_START + 5,
+              "Svndiff version greater than known max")
+
+  SVN_ERRDEF (SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA,
+              SVN_ERR_SVNDIFF_CATEGORY_START + 6,
+              "Svndiff compressed data is invalid")
+
 
   /* mod_dav_svn errors */
 
diff --git a/subversion/include/svn_fs.h b/subversion/include/svn_fs.h
index 6fde21b..7c65a73 100644
--- a/subversion/include/svn_fs.h
+++ b/subversion/include/svn_fs.h
@@ -66,6 +66,12 @@
 #define SVN_FS_TYPE_BDB                         "bdb"
 /** @since New in 1.1. */
 #define SVN_FS_TYPE_FSFS                        "fsfs"
+
+/** Don't allow svndiff1 to be used in the on-disk storage 
+ * 
+ *  @since New in 1.4. 
+ */
+#define SVN_FS_CONFIG_NO_SVNDIFF1                       "no-svndiff1"
 /** @} */
 
 
diff --git a/subversion/include/svn_ra_svn.h b/subversion/include/svn_ra_svn.h
index a5edd8a..9fd211f 100644
--- a/subversion/include/svn_ra_svn.h
+++ b/subversion/include/svn_ra_svn.h
@@ -41,6 +41,7 @@
 
 /** Currently-defined capabilities. */
 #define SVN_RA_SVN_CAP_EDIT_PIPELINE "edit-pipeline"
+#define SVN_RA_SVN_CAP_SVNDIFF1 "svndiff1"
 
 /** ra_svn passes @c svn_dirent_t fields over the wire as a list of
  * words, these are the values used to represent each field.
diff --git a/subversion/libsvn_delta/svndiff.c b/subversion/libsvn_delta/svndiff.c
index 662f012..c2365c5 100644
--- a/subversion/libsvn_delta/svndiff.c
+++ b/subversion/libsvn_delta/svndiff.c
@@ -24,7 +24,11 @@
 #include "delta.h"
 #include "svn_pools.h"
 #include "svn_private_config.h"
+#include <zlib.h>
 
+/* For svndiff1, address/instruction/new data under this size will not
+   be compressed using zlib as a secondary compressor.  */
+#define MIN_COMPRESS_SIZE 512
 #define NORMAL_BITS 7
 #define LENGTH_BITS 5
 
@@ -37,10 +41,10 @@
 struct encoder_baton {
   svn_stream_t *output;
   svn_boolean_t header_done;
+  unsigned int version;
   apr_pool_t *pool;
 };
 
-
 /* Encode VAL into the buffer P using the variable-length svndiff
    integer format.  Return the incremented value of P after the
    encoded bytes have been written.
@@ -99,6 +103,41 @@
   svn_stringbuf_appendbytes (header, buf, p - buf);
 }
 
+static svn_error_t *
+zlib_encode (svn_stringbuf_t *in, svn_stringbuf_t *out)
+{
+  unsigned long endlen;
+  unsigned int intlen;
+  
+  append_encoded_int (out, in->len, NULL);
+  intlen = out->len;
+  
+  if (in->len < MIN_COMPRESS_SIZE)
+    {
+      svn_stringbuf_appendstr (out, in);
+    }
+  else
+    {
+      svn_stringbuf_ensure (out, compressBound (in->len) + intlen);
+      endlen = out->blocksize;    
+      
+      if (compress2 ((unsigned char *)out->data + intlen, &endlen, 
+                     (const unsigned char *)in->data, in->len, 5) != Z_OK)
+        
+        return svn_error_create (SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, 
+                                 NULL,
+                                 _("compression of svndiff data failed"));
+
+      /* Compression didn't help :(, just append the original text */
+      if (endlen > in->len)
+        {
+          svn_stringbuf_appendstr (out, in);
+          return SVN_NO_ERROR;
+        }
+      out->len = endlen + intlen;
+    }
+  return SVN_NO_ERROR;
+}
 
 static svn_error_t *
 window_handler (svn_txdelta_window_t *window, void *baton)
@@ -106,17 +145,23 @@
   struct encoder_baton *eb = baton;
   apr_pool_t *pool = svn_pool_create (eb->pool);
   svn_stringbuf_t *instructions = svn_stringbuf_create ("", pool);
+  svn_stringbuf_t *i1 = svn_stringbuf_create ("", pool);
   svn_stringbuf_t *header = svn_stringbuf_create ("", pool);
+  svn_stringbuf_t *newdata = svn_stringbuf_create ("", pool);
   char ibuf[128], *ip;
+  char abuf[128], *ap;
   const svn_txdelta_op_t *op;
-  svn_error_t *err;
   apr_size_t len;
+  apr_size_t lastoffset = 0;
+  apr_size_t bits = 0;  
 
   /* Make sure we write the header.  */
   if (eb->header_done == FALSE)
     {
+      char svnver[4] = "SVN\0";
       len = 4;
-      SVN_ERR (svn_stream_write (eb->output, "SVN\0", &len));
+      svnver[3] = eb->version;
+      SVN_ERR (svn_stream_write (eb->output, svnver, &len));
       eb->header_done = TRUE;
     }
 
@@ -146,6 +191,7 @@
     {
       /* Encode the action code and length.  */
       ip = ibuf;
+      ap = abuf;
       switch (op->action_code)
         {
         case svn_txdelta_source: *ip = (char)0; break;
@@ -156,8 +202,11 @@
         *ip++ |= op->length;
       else
         ip = encode_int (ip + 1, op->length);
+
       if (op->action_code != svn_txdelta_new)
-        ip = encode_int (ip, op->offset);
+       {       
+           ip = encode_int (ip, op->offset);
+       }
       svn_stringbuf_appendbytes (instructions, ibuf, ip - ibuf);
     }
 
@@ -165,25 +214,58 @@
   append_encoded_int (header, window->sview_offset, pool);
   append_encoded_int (header, window->sview_len, pool);
   append_encoded_int (header, window->tview_len, pool);
+  if (eb->version == 1)
+    {
+      SVN_ERR (zlib_encode (instructions, i1));
+      instructions = i1;
+    }
   append_encoded_int (header, instructions->len, pool);
+  if (eb->version == 1)
+    {
+      svn_stringbuf_t *temp;
+      temp = svn_stringbuf_create_from_string (window->new_data, pool);
+      SVN_ERR (zlib_encode (temp, newdata));
+      window->new_data = svn_string_create_from_buf (newdata, pool);
+    }
+
   append_encoded_int (header, window->new_data->len, pool);
 
   /* Write out the window.  */
   len = header->len;
-  err = svn_stream_write (eb->output, header->data, &len);
-  if (err == SVN_NO_ERROR && instructions->len > 0)
+  SVN_ERR (svn_stream_write (eb->output, header->data, &len));
+  if (instructions->len > 0)
     {
       len = instructions->len;
-      err = svn_stream_write (eb->output, instructions->data, &len);
+      SVN_ERR (svn_stream_write (eb->output, instructions->data, &len));
     }
-  if (err == SVN_NO_ERROR && window->new_data->len > 0)
+  if (window->new_data->len > 0)
     {
       len = window->new_data->len;
-      err = svn_stream_write (eb->output, window->new_data->data, &len);
+      SVN_ERR (svn_stream_write (eb->output, window->new_data->data, &len));
     }
 
   svn_pool_destroy (pool);
-  return err;
+  return SVN_NO_ERROR;
+}
+
+void
+svn_txdelta_to_svndiff2 (svn_stream_t *output,
+                         apr_pool_t *pool,
+                         svn_txdelta_window_handler_t *handler,
+                         void **handler_baton,
+                         unsigned int version)
+{
+  apr_pool_t *subpool = svn_pool_create (pool);
+  struct encoder_baton *eb;
+
+  eb = apr_palloc (subpool, sizeof (*eb));
+  eb->output = output;
+  eb->header_done = FALSE;
+  eb->pool = subpool;
+  eb->version = version;
+  
+  *handler = window_handler;
+  *handler_baton = eb;
 }
 
 void
@@ -199,6 +281,7 @@
   eb->output = output;
   eb->header_done = FALSE;
   eb->pool = subpool;
+  eb->version = 0;
 
   *handler = window_handler;
   *handler_baton = eb;
@@ -240,6 +323,10 @@
      not transmit the whole svndiff data stream, you will want this to
      be FALSE. */
   svn_boolean_t error_on_early_close;
+  
+  /* svndiff version in use by delta.  */
+  unsigned char version;
+  
 };
 
 
@@ -283,6 +370,48 @@
   return NULL;
 }
 
+static svn_error_t *
+zlib_decode (svn_stringbuf_t *in, svn_stringbuf_t *out)
+{
+  apr_size_t len;
+  unsigned long zliblen;
+  unsigned long origlen;
+  char *oldplace = in->data;
+
+  assert (sizeof (zliblen) >= sizeof (len));
+  /* First thing in the string is the original length.  */
+  in->data = (char *)decode_size (&len, (unsigned char *)in->data, 
+                                  (unsigned char *)in->data+in->len);  
+  /* We need to subtract the size of the encoded original length off the
+   *      still remaining input length.  */
+  in->len -= (in->data - oldplace);
+  if (in->len == len)
+    {
+      svn_stringbuf_appendstr (out, in);
+      return SVN_NO_ERROR;
+    }
+  else
+    {
+      svn_stringbuf_ensure (out, len);
+      
+      origlen = len;
+      zliblen = len;
+      if (uncompress  ((unsigned char *)out->data, &zliblen, 
+                       (const unsigned char *)in->data, in->len) != Z_OK)
+        return svn_error_create (SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, 
+                                 NULL,
+                                 _("decompression of svndiff data failed"));
+      
+      /* Zlib should not produce something that has a different size than the
+         original length we stored. */
+      assert (zliblen == origlen);
+      out->len = zliblen;
+    }
+  return SVN_NO_ERROR;  
+}
+
+
+
 
 /* Decode an instruction into OP, returning a pointer to the text
    after the instruction.  Note that if the action code is
@@ -405,30 +534,55 @@
 static svn_error_t *
 decode_window (svn_txdelta_window_t *window, svn_filesize_t sview_offset,
                apr_size_t sview_len, apr_size_t tview_len, apr_size_t inslen,
-               apr_size_t newlen, const unsigned char *data, apr_pool_t *pool)
+               apr_size_t newlen, const unsigned char *data, apr_pool_t *pool,
+               unsigned int version)
 {
-  const unsigned char *end;
+  const unsigned char *insend;
   int ninst;
+  apr_size_t saved_inslen, saved_newlen;
   apr_size_t npos;
   svn_txdelta_op_t *ops, *op;
   svn_string_t *new_data;
+  svn_stringbuf_t *instin, *instout;
+  svn_stringbuf_t *ndin, *ndout;
 
   window->sview_offset = sview_offset;
   window->sview_len = sview_len;
   window->tview_len = tview_len;
+  saved_inslen = inslen;
+  saved_newlen = newlen;
 
+  insend = data + inslen;
+  
+  if (version == 1)
+    {
+      instin = svn_stringbuf_ncreate ((const char *)data, insend - data, pool);
+      instout = svn_stringbuf_create ("", pool);
+      SVN_ERR (zlib_decode (instin, instout));
+      
+      ndin = svn_stringbuf_ncreate ((const char *)insend, newlen, pool);
+      ndout = svn_stringbuf_create ("", pool);
+      SVN_ERR (zlib_decode (ndin, ndout));
+      
+      newlen = ndout->len;
+      data = (unsigned char *)instout->data;
+      insend = (unsigned char *)instout->data + instout->len;
+    }
+  
   /* Count the instructions and make sure they are all valid.  */
-  end = data + inslen;
-  SVN_ERR (count_and_verify_instructions (&ninst, data, end, sview_len, 
-                                          tview_len, newlen));
+  
+  SVN_ERR (count_and_verify_instructions (&ninst, data, insend, 
+                                          sview_len, tview_len, newlen));
 
+  
   /* Allocate a buffer for the instructions and decode them. */
   ops = apr_palloc (pool, ninst * sizeof (*ops));
   npos = 0;
+  
   window->src_ops = 0;
   for (op = ops; op < ops + ninst; op++)
     {
-      data = decode_instruction (op, data, end);
+      data = decode_instruction (op, data, insend);
       if (op->action_code == svn_txdelta_source)
         ++window->src_ops;
       else if (op->action_code == svn_txdelta_new)
@@ -442,7 +596,12 @@
   window->num_ops = ninst;
 
   new_data = apr_palloc (pool, sizeof (*new_data));
-  new_data->data = (const char *) data;
+
+  if (version == 1)
+    new_data->data = (const char *)ndout->data;
+  else
+    new_data->data = (const char *) data;
+
   new_data->len = newlen;
   window->new_data = new_data;
 
@@ -466,7 +625,8 @@
       apr_size_t nheader = 4 - db->header_bytes;
       if (nheader > buflen)
         nheader = buflen;
-      if (memcmp (buffer, "SVN\0" + db->header_bytes, nheader) != 0)
+      db->version = buffer[3];
+      if (memcmp (buffer, "SVN" + db->header_bytes, nheader - 1) != 0)
         return svn_error_create (SVN_ERR_SVNDIFF_INVALID_HEADER, NULL,
                                  _("Svndiff has invalid header"));
       buflen -= nheader;
@@ -541,7 +701,8 @@
 
       /* Decode the window and send it off. */
       SVN_ERR (decode_window (&window, sview_offset, sview_len, tview_len,
-                              inslen, newlen, p, db->subpool));
+                              inslen, newlen, p, db->subpool,
+                              db->version));
       SVN_ERR (db->consumer_func (&window, db->consumer_baton));
 
       /* Make a new subpool and buffer, saving aside the remaining
@@ -651,7 +812,8 @@
 
 /* Read a window header from STREAM and check it for integer overflow. */
 static svn_error_t *
-read_window_header (svn_stream_t *stream, svn_filesize_t *sview_offset,
+read_window_header (svn_stream_t *stream, unsigned int version,
+                    svn_filesize_t *sview_offset,
                     apr_size_t *sview_len, apr_size_t *tview_len,
                     apr_size_t *inslen, apr_size_t *newlen)
 {
@@ -667,7 +829,7 @@
         break;
     }
 
-  /* Read the four size fields. */
+  /* Read the four size fields.  */
   SVN_ERR (read_one_size (sview_len, stream));
   SVN_ERR (read_one_size (tview_len, stream));
   SVN_ERR (read_one_size (inslen, stream));
@@ -692,8 +854,9 @@
   svn_filesize_t sview_offset;
   apr_size_t sview_len, tview_len, inslen, newlen, len;
   unsigned char *buf;
-
-  SVN_ERR (read_window_header (stream, &sview_offset, &sview_len, &tview_len,
+  
+  SVN_ERR (read_window_header (stream, svndiff_version,
+                               &sview_offset, &sview_len, &tview_len,
                                &inslen, &newlen));
   len = inslen + newlen;
   buf = apr_palloc(pool, len);
@@ -702,8 +865,9 @@
     return svn_error_create (SVN_ERR_SVNDIFF_UNEXPECTED_END, NULL,
                              _("Unexpected end of svndiff input"));
   *window = apr_palloc (pool, sizeof(**window));
+
   SVN_ERR (decode_window (*window, sview_offset, sview_len, tview_len, inslen,
-                          newlen, buf, pool));
+                          newlen, buf, pool, svndiff_version));
   return SVN_NO_ERROR;
 }
 
@@ -718,7 +882,8 @@
   apr_size_t sview_len, tview_len, inslen, newlen;
   apr_off_t offset;
 
-  SVN_ERR (read_window_header (stream, &sview_offset, &sview_len, &tview_len,
+  SVN_ERR (read_window_header (stream, svndiff_version,
+                               &sview_offset, &sview_len, &tview_len,
                                &inslen, &newlen));
 
   offset = inslen + newlen;
diff --git a/subversion/libsvn_fs_base/fs.c b/subversion/libsvn_fs_base/fs.c
index acbded8..595f875 100644
--- a/subversion/libsvn_fs_base/fs.c
+++ b/subversion/libsvn_fs_base/fs.c
@@ -568,6 +568,8 @@
   svn_error_t *svn_err;
   const char *path_native;
   base_fs_data_t *bfd;
+  const char *formatval;
+  int format = SVN_FS_BASE__FORMAT_NUMBER;
 
   SVN_ERR (check_already_open (fs));
 
@@ -646,10 +648,15 @@
   svn_err = svn_fs_base__dag_init_fs (fs);
   if (svn_err) goto error;
 
+  /* See if we had an explicitly specified no svndiff1.  */
+  formatval = apr_hash_get (fs->config, SVN_FS_CONFIG_NO_SVNDIFF1,
+                            APR_HASH_KEY_STRING);
+  if (formatval)
+    format = 1;
+
   /* This filesystem is ready.  Stamp it with a format number. */
   svn_err = svn_io_write_version_file
-    (svn_path_join (fs->path, FORMAT_FILE, pool),
-     SVN_FS_BASE__FORMAT_NUMBER, pool);
+    (svn_path_join (fs->path, FORMAT_FILE, pool), format, pool);
   if (svn_err) goto error;
 
   return SVN_NO_ERROR;
@@ -669,6 +676,10 @@
 static svn_error_t *
 check_format (int format)
 {
+  /* We support format 1 and 2 simultaneously.  */
+  if (format == 1 && SVN_FS_BASE__FORMAT_NUMBER == 2)
+    return SVN_NO_ERROR;
+
   if (format != SVN_FS_BASE__FORMAT_NUMBER)
     {
       return svn_error_createf 
diff --git a/subversion/libsvn_fs_base/fs.h b/subversion/libsvn_fs_base/fs.h
index 076845c..4f68a5b 100644
--- a/subversion/libsvn_fs_base/fs.h
+++ b/subversion/libsvn_fs_base/fs.h
@@ -36,7 +36,10 @@
 /* The format number of this filesystem.
    This is independent of the repository format number, and
    independent of any other FS back ends. */
-#define SVN_FS_BASE__FORMAT_NUMBER   1
+#define SVN_FS_BASE__FORMAT_NUMBER   2
+
+/* Minimum format number that supports svndiff version 1.  */
+#define SVN_FS_BASE__MIN_SVNDIFF1_FORMAT 2
 
 #define BDB_ERRCALL_BATON_ERRPFX_STRING "svn (bdb): "
 typedef struct
diff --git a/subversion/libsvn_fs_base/reps-strings.c b/subversion/libsvn_fs_base/reps-strings.c
index e2ccbb8..fa709c6 100644
--- a/subversion/libsvn_fs_base/reps-strings.c
+++ b/subversion/libsvn_fs_base/reps-strings.c
@@ -33,6 +33,8 @@
 #include "bdb/reps-table.h"
 #include "bdb/strings-table.h"
 
+#include "../libsvn_fs/fs-loader.h"
+
 #include "svn_private_config.h"
 
 
@@ -1360,6 +1362,7 @@
                           trail_t *trail,
                           apr_pool_t *pool)
 {
+  base_fs_data_t *bfd = fs->fsap_data;
   svn_stream_t *source_stream; /* stream to read the source */
   svn_stream_t *target_stream; /* stream to read the target */
   svn_txdelta_stream_t *txdelta_stream; /* stream to read delta windows  */
@@ -1424,8 +1427,15 @@
 
   /* Setup a stream to convert the textdelta data into svndiff windows. */
   svn_txdelta (&txdelta_stream, source_stream, target_stream, pool);
-  svn_txdelta_to_svndiff (new_target_stream, pool,
-                          &new_target_handler, &new_target_handler_baton);
+
+  if (bfd->format >= SVN_FS_BASE__MIN_SVNDIFF1_FORMAT)
+    svn_txdelta_to_svndiff2 (new_target_stream, pool,
+                             &new_target_handler, 
+                             &new_target_handler_baton, 1);
+  else
+    svn_txdelta_to_svndiff2 (new_target_stream, pool,
+                             &new_target_handler, 
+                             &new_target_handler_baton, 0);
 
   /* subpool for the windows */
   wpool = svn_pool_create (pool);
diff --git a/subversion/libsvn_fs_base/util/fs_skels.c b/subversion/libsvn_fs_base/util/fs_skels.c
index b9b6ec4..a1c50e3 100644
--- a/subversion/libsvn_fs_base/util/fs_skels.c
+++ b/subversion/libsvn_fs_base/util/fs_skels.c
@@ -144,7 +144,8 @@
   diff = window->children;
   if ((svn_fs_base__list_length (diff) == 3)
       && (svn_fs_base__matches_atom (diff->children, "svndiff"))
-      && (svn_fs_base__matches_atom (diff->children->next, "0"))
+      && ((svn_fs_base__matches_atom (diff->children->next, "0"))
+	  || (svn_fs_base__matches_atom (diff->children->next, "1")))
       && (diff->children->next->next->is_atom))
     return TRUE;
 
diff --git a/subversion/libsvn_fs_fs/fs.h b/subversion/libsvn_fs_fs/fs.h
index 56b61ec..4a7bcdd 100644
--- a/subversion/libsvn_fs_fs/fs.h
+++ b/subversion/libsvn_fs_fs/fs.h
@@ -34,7 +34,10 @@
 /* The format number of this filesystem.
    This is independent of the repository format number, and
    independent of any other FS back ends. */
-#define SVN_FS_FS__FORMAT_NUMBER   1
+#define SVN_FS_FS__FORMAT_NUMBER   2
+
+/* The minimum format number that supports svndiff version 1.  */
+#define SVN_FS_FS__MIN_SVNDIFF1_FORMAT 2
 
 /* Maximum number of directories to cache dirents for. 
    This *must* be a power of 2 for DIR_CACHE_ENTRIES_INDEX
diff --git a/subversion/libsvn_fs_fs/fs_fs.c b/subversion/libsvn_fs_fs/fs_fs.c
index 2540f9b..2288a48 100644
--- a/subversion/libsvn_fs_fs/fs_fs.c
+++ b/subversion/libsvn_fs_fs/fs_fs.c
@@ -265,6 +265,11 @@
 static svn_error_t *
 check_format (int format)
 {
+  
+  /* We support format 1 and 2 simultaneously */
+  if (format == 1 && SVN_FS_FS__FORMAT_NUMBER == 2)
+    return SVN_NO_ERROR;
+
   if (format != SVN_FS_FS__FORMAT_NUMBER)
     {
       return svn_error_createf 
@@ -3025,6 +3030,7 @@
   const char *txn_id, *header;
   svn_txdelta_window_handler_t wh;
   void *whb;
+  fs_fs_data_t *ffd = fs->fsap_data;
 
   b = apr_pcalloc (pool, sizeof (*b));
 
@@ -3072,7 +3078,11 @@
   SVN_ERR (get_file_offset (&b->delta_start, file, b->pool));
 
   /* Prepare to write the svndiff data. */
-  svn_txdelta_to_svndiff (b->rep_stream, pool, &wh, &whb);
+  if (ffd->format >= SVN_FS_FS__MIN_SVNDIFF1_FORMAT)
+    svn_txdelta_to_svndiff2 (b->rep_stream, pool, &wh, &whb, 1);
+  else
+    svn_txdelta_to_svndiff2 (b->rep_stream, pool, &wh, &whb, 0);
+
   b->delta_stream = svn_txdelta_target_push (wh, whb, source, b->pool);
       
   *wb_p = b;
@@ -3947,7 +3957,8 @@
 {
   char buffer [APR_UUID_FORMATTED_LENGTH + 1];
   apr_uuid_t uuid;
-  
+  const char *formatval;
+  int format = SVN_FS_FS__FORMAT_NUMBER;
   fs->path = apr_pstrdup (pool, path);
 
   SVN_ERR (svn_io_make_dir_recursively (svn_path_join (path, PATH_REVS_DIR,
@@ -3967,11 +3978,17 @@
   svn_fs_fs__set_uuid (fs, buffer, pool);
   
   SVN_ERR (svn_fs_fs__dag_init_fs (fs));
-
+  
+  /* See if we had an explicitly requested no svndiff1.  */
+  formatval = apr_hash_get (fs->config, SVN_FS_CONFIG_NO_SVNDIFF1,
+                            APR_HASH_KEY_STRING);
+  if (formatval)
+    format = 1;
+  
   /* This filesystem is ready.  Stamp it with a format number. */
   SVN_ERR (svn_io_write_version_file
-           (path_format (fs, pool), SVN_FS_FS__FORMAT_NUMBER, pool));
-  ((fs_fs_data_t *) fs->fsap_data)->format = SVN_FS_FS__FORMAT_NUMBER;
+           (path_format (fs, pool), format, pool));
+  ((fs_fs_data_t *) fs->fsap_data)->format = format;
 
   return SVN_NO_ERROR;
 }
diff --git a/subversion/libsvn_ra_dav/fetch.c b/subversion/libsvn_ra_dav/fetch.c
index a5c6903..935012a 100644
--- a/subversion/libsvn_ra_dav/fetch.c
+++ b/subversion/libsvn_ra_dav/fetch.c
@@ -2949,6 +2949,10 @@
   report_baton_t *rb = report_baton;
   svn_error_t *err;
   const char *vcc;
+  apr_hash_t *request_headers = apr_hash_make (pool);
+  apr_hash_set(request_headers, "Accept-Encoding", APR_HASH_KEY_STRING, 
+               "svndiff1;q=0.9,svndiff;q=0.8");
+
 
 #define SVN_RA_DAV__REPORT_TAIL  "</S:update-report>" DEBUG_CR
   /* write the final closing gunk to our request body. */
@@ -2981,7 +2985,7 @@
                                    cdata_handler,
                                    end_element,
                                    rb,
-                                   NULL, NULL,
+                                   request_headers, NULL,
                                    rb->spool_response, pool);
 
   /* we're done with the file */
diff --git a/subversion/libsvn_ra_dav/file_revs.c b/subversion/libsvn_ra_dav/file_revs.c
index 3b7d984..601482e 100644
--- a/subversion/libsvn_ra_dav/file_revs.c
+++ b/subversion/libsvn_ra_dav/file_revs.c
@@ -306,6 +306,9 @@
   int http_status = 0;
   struct report_baton rb;
   svn_error_t *err;
+  apr_hash_t *request_headers = apr_hash_make (pool);
+  apr_hash_set(request_headers, "Accept-Encoding", APR_HASH_KEY_STRING, 
+               "svndiff1;q=0.9,svndiff;q=0.8");
 
   static const char request_head[]
     = "<S:file-revs-report xmlns:S=\"" SVN_XML_NAMESPACE "\">" DEBUG_CR;
@@ -350,7 +353,7 @@
   err = svn_ra_dav__parsed_request (ras->sess, "REPORT", final_bc_url,
                                     request_body->data, NULL, NULL,
                                     start_element, cdata_handler, end_element,
-                                    &rb, NULL, &http_status, FALSE,
+                                    &rb, request_headers, &http_status, FALSE,
                                     pool);
 
   /* Map status 501: Method Not Implemented to our not implemented error.
diff --git a/subversion/libsvn_ra_svn/client.c b/subversion/libsvn_ra_svn/client.c
index 3142565..01802ec 100644
--- a/subversion/libsvn_ra_svn/client.c
+++ b/subversion/libsvn_ra_svn/client.c
@@ -273,9 +273,9 @@
                                   svn_boolean_t compat)
 {
   if (compat)
-    return svn_ra_svn_write_tuple(conn, pool, "nw(?c)(w)", (apr_uint64_t) 1,
+    return svn_ra_svn_write_tuple(conn, pool, "nw(?c)(ww)", (apr_uint64_t) 1,
                                   mech, mech_arg,
-                                  SVN_RA_SVN_CAP_EDIT_PIPELINE);
+                                  SVN_RA_SVN_CAP_EDIT_PIPELINE, SVN_RA_SVN_CAP_SVNDIFF1);
   else
     return svn_ra_svn_write_tuple(conn, pool, "w(?c)", mech, mech_arg);
 }
@@ -674,8 +674,8 @@
     }
   else
     {
-      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "n(w)c", (apr_uint64_t) 2,
-                                     SVN_RA_SVN_CAP_EDIT_PIPELINE, url));
+      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "n(ww)c", (apr_uint64_t) 2,
+                                     SVN_RA_SVN_CAP_EDIT_PIPELINE, SVN_RA_SVN_CAP_SVNDIFF1, url));
       SVN_ERR(handle_auth_request(sess, pool));
     }
 
diff --git a/subversion/libsvn_ra_svn/editor.c b/subversion/libsvn_ra_svn/editor.c
index 897db9b..22afa83 100644
--- a/subversion/libsvn_ra_svn/editor.c
+++ b/subversion/libsvn_ra_svn/editor.c
@@ -255,7 +255,10 @@
   diff_stream = svn_stream_create(b, pool);
   svn_stream_set_write(diff_stream, ra_svn_svndiff_handler);
   svn_stream_set_close(diff_stream, ra_svn_svndiff_close_handler);
-  svn_txdelta_to_svndiff(diff_stream, pool, wh, wh_baton);
+  if (svn_ra_svn_has_capability(b->conn, SVN_RA_SVN_CAP_SVNDIFF1))
+    svn_txdelta_to_svndiff2(diff_stream, pool, wh, wh_baton, 1);
+  else
+    svn_txdelta_to_svndiff2(diff_stream, pool, wh, wh_baton, 0);
   return SVN_NO_ERROR;
 }
   
diff --git a/subversion/libsvn_ra_svn/editorp.c b/subversion/libsvn_ra_svn/editorp.c
index 29c68cf..f556424 100644
--- a/subversion/libsvn_ra_svn/editorp.c
+++ b/subversion/libsvn_ra_svn/editorp.c
@@ -294,7 +294,10 @@
   diff_stream = svn_stream_create(b, pool);
   svn_stream_set_write(diff_stream, ra_svn_svndiff_handler);
   svn_stream_set_close(diff_stream, ra_svn_svndiff_close_handler);
-  svn_txdelta_to_svndiff(diff_stream, pool, wh, wh_baton);
+  if (svn_ra_svn_has_capability(b->conn, SVN_RA_SVN_CAP_SVNDIFF1))
+    svn_txdelta_to_svndiff2(diff_stream, pool, wh, wh_baton, 1);
+  else
+    svn_txdelta_to_svndiff2(diff_stream, pool, wh, wh_baton, 0);
   return SVN_NO_ERROR;
 }
   
diff --git a/subversion/libsvn_ra_svn/protocol b/subversion/libsvn_ra_svn/protocol
index 84ab3a9..1d3b3ff 100644
--- a/subversion/libsvn_ra_svn/protocol
+++ b/subversion/libsvn_ra_svn/protocol
@@ -164,6 +164,9 @@
   edit-pipeline     If both the client and server present this
                     capability, edit operations will use pipelining.
                     See section 3.1.2.
+  svndiff1          If both the client and server support svndiff version
+                    1, this will be used as the on-the-wire format for svndiff
+		    instead of svndiff version 0.
 
 3. Commands
 -----------
diff --git a/subversion/libsvn_repos/dump.c b/subversion/libsvn_repos/dump.c
index 69a020a..38e609b 100644
--- a/subversion/libsvn_repos/dump.c
+++ b/subversion/libsvn_repos/dump.c
@@ -148,7 +148,7 @@
   /* Compute the delta and send it to the temporary file. */
   SVN_ERR (svn_fs_get_file_delta_stream (&delta_stream, oldroot, oldpath,
                                          newroot, newpath, pool));
-  svn_txdelta_to_svndiff (temp_stream, pool, &wh, &whb);
+  svn_txdelta_to_svndiff2 (temp_stream, pool, &wh, &whb, 1);
   SVN_ERR (svn_txdelta_send_txstream (delta_stream, wh, whb, pool));
 
   /* Get the length of the temporary file and rewind it. */
diff --git a/subversion/mod_dav_svn/dav_svn.h b/subversion/mod_dav_svn/dav_svn.h
index a630a7f..9c7a74e 100644
--- a/subversion/mod_dav_svn/dav_svn.h
+++ b/subversion/mod_dav_svn/dav_svn.h
@@ -211,6 +211,9 @@
   /* ### record the base for computing a delta during a GET */
   const char *delta_base;
 
+  /* SVNDIFF version we can transmit to the client.  */
+  int svndiff_version;
+
   /* the value of any SVN_DAV_OPTIONS_HEADER that came in the request */
   const char *svn_client_options;
 
diff --git a/subversion/mod_dav_svn/file_revs.c b/subversion/mod_dav_svn/file_revs.c
index b31b7aa..294a9d9 100644
--- a/subversion/mod_dav_svn/file_revs.c
+++ b/subversion/mod_dav_svn/file_revs.c
@@ -41,6 +41,9 @@
      writes to support mod_dav-based error handling. */
   svn_boolean_t needs_header;
 
+  /* SVNDIFF version to use when sending to client.  */
+  int svndiff_version;
+
   /* Used by the delta iwndow handler. */
   svn_txdelta_window_handler_t window_handler;
   void *window_baton;
@@ -176,8 +179,8 @@
 
       base64_stream = dav_svn_make_base64_output_stream(frb->bb, frb->output,
                                                         pool);
-      svn_txdelta_to_svndiff(base64_stream, pool, &frb->window_handler,
-                             &frb->window_baton);
+      svn_txdelta_to_svndiff2(base64_stream, pool, &frb->window_handler,
+                             &frb->window_baton, frb->svndiff_version);
       *window_handler = delta_window_handler;
       *window_baton = frb;
       /* Start the txdelta element wich will be terminated by the window
@@ -255,6 +258,7 @@
                               output->c->bucket_alloc);
   frb.output = output;
   frb.needs_header = TRUE;
+  frb.svndiff_version = resource->info->svndiff_version;
 
   /* file_rev_handler will send header first time it is called. */
 
diff --git a/subversion/mod_dav_svn/repos.c b/subversion/mod_dav_svn/repos.c
index 275a479..3411a06 100644
--- a/subversion/mod_dav_svn/repos.c
+++ b/subversion/mod_dav_svn/repos.c
@@ -29,6 +29,7 @@
 #include <apr_want.h>
 #include <apr_strings.h>
 #include <apr_hash.h>
+#include <apr_lib.h>
 
 #include "svn_types.h"
 #include "svn_pools.h"
@@ -1241,6 +1242,182 @@
   return NULL;
 }
 
+/* --------------- Borrowed from httpd's mod_negotiation.c -------------- */
+
+typedef struct accept_rec {
+  char *name;                 /* MUST be lowercase */
+  float quality;
+} accept_rec;
+
+/*
+ * Get a single mime type entry --- one media type and parameters;
+ * enter the values we recognize into the argument accept_rec
+ */
+
+static const char *get_entry(apr_pool_t *p, accept_rec *result,
+                             const char *accept_line)
+{
+    result->quality = 1.0f;
+
+    /*
+     * Note that this handles what I gather is the "old format",
+     *
+     *    Accept: text/html text/plain moo/zot
+     *
+     * without any compatibility kludges --- if the token after the
+     * MIME type begins with a semicolon, we know we're looking at parms,
+     * otherwise, we know we aren't.  (So why all the pissing and moaning
+     * in the CERN server code?  I must be missing something).
+     */
+
+    result->name = ap_get_token(p, &accept_line, 0);
+    ap_str_tolower(result->name);     /* You want case insensitive,
+                                       * you'll *get* case insensitive.
+                                       */
+
+    while (*accept_line == ';')
+      {
+        /* Parameters ... */
+
+        char *parm;
+        char *cp;
+        char *end;
+
+        ++accept_line;
+        parm = ap_get_token(p, &accept_line, 1);
+
+        /* Look for 'var = value' --- and make sure the var is in lcase. */
+
+        for (cp = parm; (*cp && !apr_isspace(*cp) && *cp != '='); ++cp)
+          {
+            *cp = apr_tolower(*cp);
+          }
+
+        if (!*cp)
+          {
+            continue;           /* No '='; just ignore it. */
+          }
+
+        *cp++ = '\0';           /* Delimit var */
+        while (*cp && (apr_isspace(*cp) || *cp == '='))
+          {
+            ++cp;
+          }
+
+        if (*cp == '"')
+          {
+            ++cp;
+            for (end = cp;
+                 (*end && *end != '\n' && *end != '\r' && *end != '\"');
+                 end++);
+          }
+        else
+          {
+            for (end = cp; (*end && !apr_isspace(*end)); end++);
+          }
+        if (*end)
+          {
+            *end = '\0';        /* strip ending quote or return */
+          }
+        ap_str_tolower(cp);
+
+        if (parm[0] == 'q'
+            && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0')))
+          {
+            result->quality = atof(cp);
+          }
+      }
+
+    if (*accept_line == ',')
+      {
+        ++accept_line;
+      }
+
+    return accept_line;
+}
+
+/* @a accept_line is the Accept-Encoding header, which is of the
+   format:
+
+     Accept-Language: name; q=N;
+*/
+static apr_array_header_t *do_header_line(apr_pool_t *p,
+                                          const char *accept_line)
+{
+    apr_array_header_t *accept_recs;
+
+    if (!accept_line)
+      return NULL;
+
+    accept_recs = apr_array_make(p, 10, sizeof(accept_rec));
+
+    while (*accept_line)
+      {
+        accept_rec *prefs = (accept_rec *) apr_array_push(accept_recs);
+        accept_line = get_entry(p, prefs, accept_line);
+      }
+
+    return accept_recs;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+/* qsort implementation for the quality field of the accept_rec
+   structure */
+static int sort_encoding_pref(const void *accept_rec1, const void *accept_rec2)
+{
+  float diff = ((const accept_rec *) accept_rec1)->quality -
+      ((const accept_rec *) accept_rec2)->quality;
+  return (diff == 0 ? 0 : (diff > 0 ? -1 : 1));
+}
+
+/* It would be nice if this function could be unit-tested.  Paul
+   Querna suggested
+   http://svn.apache.org/repos/asf/httpd/httpd/trunk/server/request.c's
+   make_sub_request(), and noted that httpd manually constructs
+   request_rec's in a few spots. */
+
+static void
+svn_dav__negotiate_encoding_prefs(request_rec *r,
+                                  int *svndiff_version)
+{
+  /* It would be nice if mod_negotiation
+     <http://httpd.apache.org/docs-2.1/mod/mod_negotiation.html> could
+     handle the Accept-Encoding header parsing for us.  Sadly, it
+     looks like its data structures and routines are private (see
+     httpd/modules/mappers/mod_negotiation.c).  Thus, we duplicate the
+     necessary ones in this file. */
+  size_t i;
+  const apr_array_header_t *encoding_prefs;
+  encoding_prefs = do_header_line(r->pool, 
+                                  apr_table_get(r->headers_in, 
+                                                "Accept-Encoding"));
+
+  if (encoding_prefs && apr_is_empty_array(encoding_prefs))
+    {
+      *svndiff_version = 0;
+      return;
+    }
+  *svndiff_version = 0;
+  qsort(encoding_prefs->elts, (size_t) encoding_prefs->nelts,
+        sizeof(accept_rec), sort_encoding_pref);
+  for (i = 0; i < encoding_prefs->nelts; i++)
+    {
+      struct accept_rec rec = APR_ARRAY_IDX (encoding_prefs, i,
+                                              struct accept_rec);
+      if (strcmp (rec.name, "svndiff1") == 0)
+        {
+          *svndiff_version = 1;
+          break;
+        }
+      else if (strcmp (rec.name, "svndiff") == 0)
+        {
+          *svndiff_version = 0;
+          break;
+        }
+    } 
+}
 
 
 static dav_error * dav_svn_get_resource(request_rec *r,
@@ -1336,6 +1513,7 @@
       && strcmp(ct, SVN_SVNDIFF_MIME_TYPE) == 0;
   }
 
+  svn_dav__negotiate_encoding_prefs (r, &comb->priv.svndiff_version);
   /* ### and another hack for computing diffs to send to the client */
   comb->priv.delta_base = apr_table_get(r->headers_in,
                                         SVN_DAV_DELTA_BASE_HEADER);
@@ -2627,7 +2805,8 @@
           svn_stream_set_close(o_stream, dav_svn_close_filter);
 
           /* get a handler/baton for writing into the output stream */
-          svn_txdelta_to_svndiff(o_stream, resource->pool, &handler, &h_baton);
+          svn_txdelta_to_svndiff2(o_stream, resource->pool, &handler, &h_baton,
+                                  resource->info->svndiff_version);
 
           /* got everything set up. read in delta windows and shove them into
              the handler, which pushes data into the output stream, which goes
diff --git a/subversion/mod_dav_svn/update.c b/subversion/mod_dav_svn/update.c
index c5a211b..6e48929 100644
--- a/subversion/mod_dav_svn/update.c
+++ b/subversion/mod_dav_svn/update.c
@@ -74,6 +74,9 @@
   /* True iff client requested all data inline in the report. */
   svn_boolean_t send_all;
 
+  /* SVNDIFF version to send to client.  */
+  int svndiff_version;
+
 } update_ctx_t;
 
 typedef struct item_baton_t {
@@ -951,8 +954,9 @@
   base64_stream = dav_svn_make_base64_output_stream(wb->uc->bb, wb->uc->output,
                                                     file->pool);
 
-  svn_txdelta_to_svndiff(base64_stream, file->pool,
-                         &(wb->handler), &(wb->handler_baton));
+  svn_txdelta_to_svndiff2(base64_stream, file->pool,
+                          &(wb->handler), &(wb->handler_baton), 
+                          file->uc->svndiff_version);
 
   *handler = window_handler;
   *handler_baton = wb;
@@ -1191,6 +1195,7 @@
                                    resource->pool);
     }
 
+  uc.svndiff_version = resource->info->svndiff_version;
   uc.resource = resource;
   uc.output = output;  
   uc.anchor = src_path;
diff --git a/subversion/svnadmin/main.c b/subversion/svnadmin/main.c
index b33e8a4..5228a22 100644
--- a/subversion/svnadmin/main.c
+++ b/subversion/svnadmin/main.c
@@ -213,7 +213,8 @@
     svnadmin__use_pre_commit_hook,
     svnadmin__use_post_commit_hook,
     svnadmin__clean_logs,
-    svnadmin__wait
+    svnadmin__wait,
+    svnadmin__no_svndiff1,
   };
 
 /* Option codes and descriptions.
@@ -283,6 +284,9 @@
      N_("wait instead of exit if the repository is in\n"
         "                             use by another process")},
 
+    {"no-svndiff1",     svnadmin__no_svndiff1, 0,
+     N_("disallow use of SVNDIFF1 in on-disk storage, for backwards compatibility")},
+
     {NULL}
   };
 
@@ -302,7 +306,7 @@
    ("usage: svnadmin create REPOS_PATH\n\n"
     "Create a new, empty repository at REPOS_PATH.\n"),
    {svnadmin__bdb_txn_nosync, svnadmin__bdb_log_keep,
-    svnadmin__config_dir, svnadmin__fs_type} },
+    svnadmin__config_dir, svnadmin__fs_type, svnadmin__no_svndiff1} },
 
   {"deltify", subcommand_deltify, {0}, N_
    ("usage: svnadmin deltify [-r LOWER[:UPPER]] REPOS_PATH\n\n"
@@ -410,6 +414,7 @@
   const char *repository_path;
   const char *new_repository_path;                  /* hotcopy dest. path */
   const char *fs_type;                              /* --fs-type */
+  svn_boolean_t no_svndiff1;                        /* --no-svndiff1 */
   svn_opt_revision_t start_revision, end_revision;  /* -r X[:Y] */
   svn_boolean_t help;                               /* --help or -? */
   svn_boolean_t version;                            /* --version */
@@ -483,6 +488,11 @@
                   APR_HASH_KEY_STRING,
                   opt_state->fs_type);
 
+  if (opt_state->no_svndiff1)
+    apr_hash_set (fs_config, SVN_FS_CONFIG_NO_SVNDIFF1,
+                  APR_HASH_KEY_STRING,
+                  "1");
+
   SVN_ERR (svn_config_get_config (&config, opt_state->config_dir, pool));
   SVN_ERR (svn_repos_create (&repos, opt_state->repository_path,
                              NULL, NULL, 
@@ -1253,6 +1263,9 @@
       case svnadmin__force_uuid:
         opt_state.uuid_action = svn_repos_load_uuid_force;
         break;
+      case svnadmin__no_svndiff1:
+        opt_state.no_svndiff1 = TRUE;
+        break;        
       case svnadmin__fs_type:
         err = svn_utf_cstring_to_utf8 (&opt_state.fs_type, opt_arg, pool);
         if (err)
diff --git a/subversion/svnserve/serve.c b/subversion/svnserve/serve.c
index ebdc4ac..8f65e4d 100644
--- a/subversion/svnserve/serve.c
+++ b/subversion/svnserve/serve.c
@@ -2166,8 +2166,8 @@
   SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(nn(!", "success",
                                  (apr_uint64_t) 1, (apr_uint64_t) 2));
   SVN_ERR(send_mechs(conn, pool, &b, READ_ACCESS, FALSE));
-  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)(w))",
-                                 SVN_RA_SVN_CAP_EDIT_PIPELINE));
+  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)(ww))",
+                                 SVN_RA_SVN_CAP_EDIT_PIPELINE, SVN_RA_SVN_CAP_SVNDIFF1));
 
   /* Read client response.  Because the client response form changed
    * between version 1 and version 2, we have to do some of this by
diff --git a/subversion/tests/libsvn_delta/random-test.c b/subversion/tests/libsvn_delta/random-test.c
index 291e997..3cec8d7 100644
--- a/subversion/tests/libsvn_delta/random-test.c
+++ b/subversion/tests/libsvn_delta/random-test.c
@@ -337,7 +337,7 @@
                                           delta_pool);
 
       /* Make stage 2: encode the text delta in svndiff format.  */
-      svn_txdelta_to_svndiff (stream, delta_pool, &handler, &handler_baton);
+      svn_txdelta_to_svndiff2 (stream, delta_pool, &handler, &handler_baton, 1);
 
       /* Make stage 1: create the text delta.  */
       svn_txdelta (&txdelta_stream,
@@ -429,7 +429,7 @@
                                           delta_pool);
 
       /* Make stage 2: encode the text delta in svndiff format.  */
-      svn_txdelta_to_svndiff (stream, delta_pool, &handler, &handler_baton);
+      svn_txdelta_to_svndiff2 (stream, delta_pool, &handler, &handler_baton, 1);
 
       /* Make stage 1: create the text deltas.  */
 
diff --git a/subversion/tests/libsvn_delta/svndiff-test.c b/subversion/tests/libsvn_delta/svndiff-test.c
index b32c455..06dbff6 100644
--- a/subversion/tests/libsvn_delta/svndiff-test.c
+++ b/subversion/tests/libsvn_delta/svndiff-test.c
@@ -39,10 +39,11 @@
   svn_stream_t *encoder;
   void *svndiff_baton;
   apr_pool_t *pool;
+  int version = 0;
 
   if (argc < 3)
     {
-      printf ("usage: %s source target\n", argv[0]);
+      printf ("usage: %s source target [version]\n", argv[0]);
       exit (0);
     }
 
@@ -63,6 +64,8 @@
       fprintf (stderr, "unable to open \"%s\" for reading\n", argv[2]);
       exit (1);
     }
+  if (argc == 4)
+    version = atoi (argv[3]);
 
   svn_txdelta (&txdelta_stream,
                svn_stream_from_aprfile (source_file, pool),
@@ -78,7 +81,8 @@
 #else
   encoder = svn_base64_encode (stdout_stream, pool);
 #endif
-  svn_txdelta_to_svndiff (encoder, pool, &svndiff_handler, &svndiff_baton);
+  svn_txdelta_to_svndiff2 (encoder, pool, &svndiff_handler, &svndiff_baton, 
+			   version);
   err = svn_txdelta_send_txstream (txdelta_stream,
                                    svndiff_handler,
                                    svndiff_baton,