summaryrefslogtreecommitdiff
path: root/vcs-svn
diff options
context:
space:
mode:
Diffstat (limited to 'vcs-svn')
-rw-r--r--vcs-svn/LICENSE2
-rw-r--r--vcs-svn/sliding_window.c77
-rw-r--r--vcs-svn/sliding_window.h17
3 files changed, 96 insertions, 0 deletions
diff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE
index 0a5e3c43a0..805882c838 100644
--- a/vcs-svn/LICENSE
+++ b/vcs-svn/LICENSE
@@ -1,6 +1,8 @@
Copyright (C) 2010 David Barr <david.barr@cordelta.com>.
All rights reserved.
+Copyright (C) 2010 Jonathan Nieder <jrnieder@gmail.com>.
+
Copyright (C) 2008 Jason Evans <jasone@canonware.com>.
All rights reserved.
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;
+}
diff --git a/vcs-svn/sliding_window.h b/vcs-svn/sliding_window.h
new file mode 100644
index 0000000000..ed0bfdd65c
--- /dev/null
+++ b/vcs-svn/sliding_window.h
@@ -0,0 +1,17 @@
+#ifndef SLIDING_WINDOW_H_
+#define SLIDING_WINDOW_H_
+
+#include "strbuf.h"
+
+struct sliding_view {
+ struct line_buffer *file;
+ off_t off;
+ size_t width;
+ struct strbuf buf;
+};
+
+#define SLIDING_VIEW_INIT(input) { (input), 0, 0, STRBUF_INIT }
+
+extern int move_window(struct sliding_view *view, off_t off, size_t width);
+
+#endif