summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blob.c51
-rw-r--r--src/buf_text.c19
-rw-r--r--src/buf_text.h8
-rw-r--r--src/buffer.c54
-rw-r--r--src/crlf.c20
-rw-r--r--src/filter.h19
6 files changed, 141 insertions, 30 deletions
diff --git a/src/blob.c b/src/blob.c
index 6a289f43b..6a866538c 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -338,3 +338,54 @@ int git_blob_is_binary(git_blob *blob)
return git_buf_text_is_binary(&content);
}
+
+int git_blob_filtered_content(
+ git_buffer *out,
+ git_blob *blob,
+ const char *as_path,
+ int check_for_binary_data)
+{
+ int error = 0, num_filters = 0;
+ git_buf filtered = GIT_BUF_INIT, unfiltered = GIT_BUF_INIT;
+ git_vector filters = GIT_VECTOR_INIT;
+
+ assert(blob && as_path && out);
+
+ /* Create a fake git_buf from the blob raw data... */
+ filtered.ptr = (void *)git_blob_rawcontent(blob);
+ filtered.size = (size_t)git_blob_rawsize(blob);
+ filtered.asize = 0;
+
+ if (check_for_binary_data && git_buf_text_is_binary(&filtered))
+ return 0;
+
+ num_filters = git_filters_load(
+ &filters, git_blob_owner(blob), as_path, GIT_FILTER_TO_WORKTREE);
+ if (num_filters < 0)
+ return num_filters;
+
+ if (num_filters > 0) {
+ if (out->ptr && out->available) {
+ filtered.ptr = out->ptr;
+ filtered.size = out->size;
+ filtered.asize = out->available;
+ } else {
+ git_buf_init(&filtered, filtered.size + 1);
+ }
+
+ if (!(error = git_blob__getbuf(&unfiltered, blob)))
+ error = git_filters_apply(&filtered, &unfiltered, &filters);
+
+ git_filters_free(&filters);
+ git_buf_free(&unfiltered);
+ }
+
+ if (!error) {
+ out->ptr = filtered.ptr;
+ out->size = filtered.size;
+ out->available = filtered.asize;
+ }
+
+ return error;
+}
+
diff --git a/src/buf_text.c b/src/buf_text.c
index ecf592b51..eda86adb3 100644
--- a/src/buf_text.c
+++ b/src/buf_text.c
@@ -70,10 +70,10 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
assert(tgt != src);
if (!next)
- return GIT_ENOTFOUND;
+ return git_buf_set(tgt, src->ptr, src->size);
/* reduce reallocs while in the loop */
- if (git_buf_grow(tgt, src->size) < 0)
+ if (git_buf_grow(tgt, src->size + 1) < 0)
return -1;
out = tgt->ptr;
tgt->size = 0;
@@ -81,7 +81,7 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
/* Find the next \r and copy whole chunk up to there to tgt */
for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) {
if (next > scan) {
- size_t copylen = next - scan;
+ size_t copylen = (size_t)(next - scan);
memcpy(out, scan, copylen);
out += copylen;
}
@@ -92,9 +92,14 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
}
/* Copy remaining input into dest */
- memcpy(out, scan, scan_end - scan + 1); /* +1 for NUL byte */
- out += (scan_end - scan);
- tgt->size = out - tgt->ptr;
+ if (scan < scan_end) {
+ size_t remaining = (size_t)(scan_end - scan);
+ memcpy(out, scan, remaining);
+ out += remaining;
+ }
+
+ tgt->size = (size_t)(out - tgt->ptr);
+ tgt->ptr[tgt->size] = '\0';
return 0;
}
@@ -109,7 +114,7 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
assert(tgt != src);
if (!next)
- return GIT_ENOTFOUND;
+ return git_buf_set(tgt, src->ptr, src->size);
/* attempt to reduce reallocs while in the loop */
if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0)
diff --git a/src/buf_text.h b/src/buf_text.h
index 58e4e26a7..3ac9d1443 100644
--- a/src/buf_text.h
+++ b/src/buf_text.h
@@ -56,16 +56,16 @@ GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string)
extern void git_buf_text_unescape(git_buf *buf);
/**
- * Replace all \r\n with \n (or do nothing if no \r\n are found)
+ * Replace all \r\n with \n. Does not modify \r without trailing \n.
*
- * @return 0 on success, GIT_ENOTFOUND if no \r\n, -1 on memory error
+ * @return 0 on success, -1 on memory error
*/
extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src);
/**
- * Replace all \n with \r\n (or do nothing if no \n are found)
+ * Replace all \n with \r\n. Does not modify existing \r\n.
*
- * @return 0 on success, GIT_ENOTFOUND if no \n, -1 on memory error
+ * @return 0 on success, -1 on memory error
*/
extern int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src);
diff --git a/src/buffer.c b/src/buffer.c
index b5b2fd678..a92133674 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -6,6 +6,7 @@
*/
#include "buffer.h"
#include "posix.h"
+#include "git2/buffer.h"
#include <stdarg.h>
#include <ctype.h>
@@ -484,3 +485,56 @@ int git_buf_splice(
buf->ptr[buf->size] = '\0';
return 0;
}
+
+/*
+ * Public buffers API
+ */
+
+void git_buffer_free(git_buffer *buffer)
+{
+ if (!buffer)
+ return;
+
+ if (buffer->ptr != NULL && buffer->available > 0)
+ git__free(buffer->ptr);
+
+ git__memzero(buffer, sizeof(*buffer));
+}
+
+int git_buffer_resize(git_buffer *buffer, size_t want_size)
+{
+ int non_allocated_buffer = 0;
+ char *new_ptr;
+
+ assert(buffer);
+
+ /* check if buffer->ptr points to memory owned elsewhere */
+ non_allocated_buffer = (buffer->ptr != NULL && buffer->available == 0);
+
+ if (non_allocated_buffer && !want_size)
+ want_size = buffer->size;
+
+ if (buffer->available <= want_size)
+ return 0;
+
+ if (non_allocated_buffer) {
+ new_ptr = NULL;
+ if (want_size < buffer->size)
+ want_size = buffer->size;
+ } else {
+ new_ptr = buffer->ptr;
+ }
+
+ want_size = (want_size + 7) & ~7; /* round up to multiple of 8 */
+
+ new_ptr = git__realloc(new_ptr, want_size);
+ GITERR_CHECK_ALLOC(new_ptr);
+
+ if (non_allocated_buffer)
+ memcpy(new_ptr, buffer->ptr, buffer->size);
+
+ buffer->ptr = new_ptr;
+ buffer->available = want_size;
+
+ return 0;
+}
diff --git a/src/crlf.c b/src/crlf.c
index 65039f9cc..fbb3ba2dd 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -235,32 +235,36 @@ line_ending_error:
}
static int crlf_apply_to_workdir(
- git_filter *self, git_buf *dest, const git_buf *source)
+ git_filter *self, git_buf *tgt, const git_buf *src)
{
struct crlf_filter *filter = (struct crlf_filter *)self;
const char *workdir_ending = NULL;
- assert(self && dest && source);
+ assert(self && tgt && src);
/* Empty file? Nothing to do. */
- if (git_buf_len(source) == 0)
+ if (git_buf_len(src) == 0)
return -1;
/* Determine proper line ending */
workdir_ending = line_ending(filter);
if (!workdir_ending)
return -1;
- if (!strcmp("\n", workdir_ending)) /* do nothing for \n ending */
- return -1;
- /* for now, only lf->crlf conversion is supported here */
+ if (!strcmp("\n", workdir_ending)) {
+ if (git_buf_find(src, '\r') < 0)
+ return -1;
+ return git_buf_text_crlf_to_lf(tgt, src);
+ }
+
+ /* only other supported option is lf->crlf conversion */
assert(!strcmp("\r\n", workdir_ending));
- return git_buf_text_lf_to_crlf(dest, source);
+ return git_buf_text_lf_to_crlf(tgt, src);
}
static int find_and_add_filter(
git_vector *filters, git_repository *repo, const char *path,
- int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source))
+ int (*apply)(struct git_filter *self, git_buf *tgt, const git_buf *src))
{
struct crlf_attrs ca;
struct crlf_filter *filter;
diff --git a/src/filter.h b/src/filter.h
index 42a44ebdb..67845ad6a 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -11,16 +11,12 @@
#include "buffer.h"
#include "git2/odb.h"
#include "git2/repository.h"
+#include "git2/filter.h"
-typedef struct git_filter {
+struct git_filter {
int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source);
void (*do_free)(struct git_filter *self);
-} git_filter;
-
-typedef enum {
- GIT_FILTER_TO_WORKTREE,
- GIT_FILTER_TO_ODB
-} git_filter_mode;
+};
typedef enum {
GIT_CRLF_GUESS = -1,
@@ -60,13 +56,14 @@ extern int git_filters_load(git_vector *filters, git_repository *repo, const cha
* and `dest` buffers are owned by the caller and must be freed once
* they are no longer needed.
*
- * NOTE: Because of the double-buffering schema, the `source` buffer that contains
- * the original file may be tampered once the filtering is complete. Regardless,
- * the `dest` buffer will always contain the final result of the filtering
+ * NOTE: Because of the double-buffering schema, the `source` buffer that
+ * contains the original file may be tampered once the filtering is
+ * complete. Regardless, the `dest` buffer will always contain the final
+ * result of the filtering
*
* @param dest Buffer to store the result of the filtering
* @param source Buffer containing the document to filter
- * @param filters A non-empty vector of filters as supplied by `git_filters_load`
+ * @param filters Vector of filters as supplied by `git_filters_load`
* @return 0 on success, an error code otherwise
*/
extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters);