1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "diff_parse.h"
9 
10 #include "diff.h"
11 #include "patch.h"
12 #include "patch_parse.h"
13 
diff_parsed_free(git_diff * d)14 static void diff_parsed_free(git_diff *d)
15 {
16 	git_diff_parsed *diff = (git_diff_parsed *)d;
17 	git_patch *patch;
18 	size_t i;
19 
20 	git_vector_foreach(&diff->patches, i, patch)
21 		git_patch_free(patch);
22 
23 	git_vector_free(&diff->patches);
24 
25 	git_vector_free(&diff->base.deltas);
26 	git_pool_clear(&diff->base.pool);
27 
28 	git__memzero(diff, sizeof(*diff));
29 	git__free(diff);
30 }
31 
diff_parsed_alloc(void)32 static git_diff_parsed *diff_parsed_alloc(void)
33 {
34 	git_diff_parsed *diff;
35 
36 	if ((diff = git__calloc(1, sizeof(git_diff_parsed))) == NULL)
37 		return NULL;
38 
39 	GIT_REFCOUNT_INC(&diff->base);
40 	diff->base.type = GIT_DIFF_TYPE_PARSED;
41 	diff->base.strcomp = git__strcmp;
42 	diff->base.strncomp = git__strncmp;
43 	diff->base.pfxcomp = git__prefixcmp;
44 	diff->base.entrycomp = git_diff__entry_cmp;
45 	diff->base.patch_fn = git_patch_parsed_from_diff;
46 	diff->base.free_fn = diff_parsed_free;
47 
48 	if (git_diff_options_init(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION) < 0) {
49 		git__free(diff);
50 		return NULL;
51 	}
52 
53 	diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
54 
55 	if (git_pool_init(&diff->base.pool, 1) < 0 ||
56 	    git_vector_init(&diff->patches, 0, NULL) < 0 ||
57 		git_vector_init(&diff->base.deltas, 0, git_diff_delta__cmp) < 0) {
58 		git_diff_free(&diff->base);
59 		return NULL;
60 	}
61 
62 	git_vector_set_cmp(&diff->base.deltas, git_diff_delta__cmp);
63 
64 	return diff;
65 }
66 
git_diff_from_buffer(git_diff ** out,const char * content,size_t content_len)67 int git_diff_from_buffer(
68 	git_diff **out,
69 	const char *content,
70 	size_t content_len)
71 {
72 	git_diff_parsed *diff;
73 	git_patch *patch;
74 	git_patch_parse_ctx *ctx = NULL;
75 	int error = 0;
76 
77 	*out = NULL;
78 
79 	diff = diff_parsed_alloc();
80 	GIT_ERROR_CHECK_ALLOC(diff);
81 
82 	ctx = git_patch_parse_ctx_init(content, content_len, NULL);
83 	GIT_ERROR_CHECK_ALLOC(ctx);
84 
85 	while (ctx->parse_ctx.remain_len) {
86 		if ((error = git_patch_parse(&patch, ctx)) < 0)
87 			break;
88 
89 		git_vector_insert(&diff->patches, patch);
90 		git_vector_insert(&diff->base.deltas, patch->delta);
91 	}
92 
93 	if (error == GIT_ENOTFOUND && git_vector_length(&diff->patches) > 0) {
94 		git_error_clear();
95 		error = 0;
96 	}
97 
98 	git_patch_parse_ctx_free(ctx);
99 
100 	if (error < 0)
101 		git_diff_free(&diff->base);
102 	else
103 		*out = &diff->base;
104 
105 	return error;
106 }
107 
108