summaryrefslogtreecommitdiff
path: root/vcs-svn/sliding_window.c
diff options
context:
space:
mode:
authorJonathan Nieder <jrnieder@gmail.com>2011-05-26 02:27:48 -0500
committerJonathan Nieder <jrnieder@gmail.com>2011-05-26 02:27:48 -0500
commite9f3f8b6f4141dae526e9792ba6dede7aa038622 (patch)
treee4d1b8abaaef180f844b1d0f57afbc87e4c4f677 /vcs-svn/sliding_window.c
parentc19d653c4fcdc93169507c09f8f66ebffbdbb9a5 (diff)
parentc846e4107876936bed7177a811559bd74a72dcd8 (diff)
downloadgit-e9f3f8b6f4141dae526e9792ba6dede7aa038622.tar.gz
Merge branch 'db/delta-applier' into db/text-delta
* db/delta-applier: vcs-svn: let deltas use data from preimage vcs-svn: let deltas use data from postimage vcs-svn: verify that deltas consume all inline data vcs-svn: implement copyfrom_data delta instruction vcs-svn: read instructions from deltas vcs-svn: read inline data from deltas vcs-svn: read the preimage when applying deltas vcs-svn: parse svndiff0 window header vcs-svn: skeleton of an svn delta parser vcs-svn: make buffer_read_binary API more convenient vcs-svn: learn to maintain a sliding view of a file Makefile: list one vcs-svn/xdiff object or header per line Conflicts: Makefile vcs-svn/LICENSE
Diffstat (limited to 'vcs-svn/sliding_window.c')
-rw-r--r--vcs-svn/sliding_window.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
new file mode 100644
index 0000000000..1b8d9875ed
--- /dev/null
+++ b/vcs-svn/sliding_window.c
@@ -0,0 +1,77 @@
+/*
+ * Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "git-compat-util.h"
+#include "sliding_window.h"
+#include "line_buffer.h"
+#include "strbuf.h"
+
+static int input_error(struct line_buffer *file)
+{
+ if (!buffer_ferror(file))
+ return error("delta preimage ends early");
+ return error("cannot read delta preimage: %s", strerror(errno));
+}
+
+static int skip_or_whine(struct line_buffer *file, off_t gap)
+{
+ if (buffer_skip_bytes(file, gap) != gap)
+ return input_error(file);
+ return 0;
+}
+
+static int read_to_fill_or_whine(struct line_buffer *file,
+ struct strbuf *buf, size_t width)
+{
+ buffer_read_binary(file, buf, width - buf->len);
+ if (buf->len != width)
+ return input_error(file);
+ return 0;
+}
+
+static int check_overflow(off_t a, size_t b)
+{
+ if (b > maximum_signed_value_of_type(off_t))
+ return error("unrepresentable length in delta: "
+ "%"PRIuMAX" > OFF_MAX", (uintmax_t) b);
+ if (signed_add_overflows(a, (off_t) b))
+ return error("unrepresentable offset in delta: "
+ "%"PRIuMAX" + %"PRIuMAX" > OFF_MAX",
+ (uintmax_t) a, (uintmax_t) b);
+ return 0;
+}
+
+int move_window(struct sliding_view *view, off_t off, size_t width)
+{
+ off_t file_offset;
+ assert(view);
+ assert(view->width <= view->buf.len);
+ assert(!check_overflow(view->off, view->buf.len));
+
+ if (check_overflow(off, width))
+ return -1;
+ if (off < view->off || off + width < view->off + view->width)
+ return error("invalid delta: window slides left");
+
+ file_offset = view->off + view->buf.len;
+ if (off < file_offset) {
+ /* Move the overlapping region into place. */
+ strbuf_remove(&view->buf, 0, off - view->off);
+ } else {
+ /* Seek ahead to skip the gap. */
+ if (skip_or_whine(view->file, off - file_offset))
+ return -1;
+ strbuf_setlen(&view->buf, 0);
+ }
+
+ if (view->buf.len > width)
+ ; /* Already read. */
+ else if (read_to_fill_or_whine(view->file, &view->buf, width))
+ return -1;
+
+ view->off = off;
+ view->width = width;
+ return 0;
+}