Пример #1
0
static int parse_hunk_header(
	git_patch_hunk *hunk,
	git_patch_parse_ctx *ctx)
{
	const char *header_start = ctx->parse_ctx.line;
	char c;

	hunk->hunk.old_lines = 1;
	hunk->hunk.new_lines = 1;

	if (git_parse_advance_expected_str(&ctx->parse_ctx, "@@ -") < 0 ||
		parse_int(&hunk->hunk.old_start, ctx) < 0)
		goto fail;

	if (git_parse_peek(&c, &ctx->parse_ctx, 0) == 0 && c == ',') {
		if (git_parse_advance_expected_str(&ctx->parse_ctx, ",") < 0 ||
			parse_int(&hunk->hunk.old_lines, ctx) < 0)
			goto fail;
	}

	if (git_parse_advance_expected_str(&ctx->parse_ctx, " +") < 0 ||
		parse_int(&hunk->hunk.new_start, ctx) < 0)
		goto fail;

	if (git_parse_peek(&c, &ctx->parse_ctx, 0) == 0 && c == ',') {
		if (git_parse_advance_expected_str(&ctx->parse_ctx, ",") < 0 ||
			parse_int(&hunk->hunk.new_lines, ctx) < 0)
			goto fail;
	}

	if (git_parse_advance_expected_str(&ctx->parse_ctx, " @@") < 0)
		goto fail;

	git_parse_advance_line(&ctx->parse_ctx);

	if (!hunk->hunk.old_lines && !hunk->hunk.new_lines)
		goto fail;

	hunk->hunk.header_len = ctx->parse_ctx.line - header_start;
	if (hunk->hunk.header_len > (GIT_DIFF_HUNK_HEADER_SIZE - 1))
		return git_parse_err("oversized patch hunk header at line %"PRIuZ,
			ctx->parse_ctx.line_num);

	memcpy(hunk->hunk.header, header_start, hunk->hunk.header_len);
	hunk->hunk.header[hunk->hunk.header_len] = '\0';

	return 0;

fail:
	giterr_set(GITERR_PATCH, "invalid patch hunk header at line %"PRIuZ,
		ctx->parse_ctx.line_num);
	return -1;
}
Пример #2
0
static int parse_header_git_index(
	git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{
	char c;

	if (parse_header_oid(&patch->base.delta->old_file.id,
			&patch->base.delta->old_file.id_abbrev, ctx) < 0 ||
		git_parse_advance_expected_str(&ctx->parse_ctx, "..") < 0 ||
		parse_header_oid(&patch->base.delta->new_file.id,
			&patch->base.delta->new_file.id_abbrev, ctx) < 0)
		return -1;

	if (git_parse_peek(&c, &ctx->parse_ctx, 0) == 0 && c == ' ') {
		uint16_t mode;

		git_parse_advance_chars(&ctx->parse_ctx, 1);

		if (parse_header_mode(&mode, ctx) < 0)
			return -1;

		if (!patch->base.delta->new_file.mode)
			patch->base.delta->new_file.mode = mode;

		if (!patch->base.delta->old_file.mode)
			patch->base.delta->old_file.mode = mode;
	}

	return 0;
}
Пример #3
0
static int parse_patch_binary_side(
	git_diff_binary_file *binary,
	git_patch_parse_ctx *ctx)
{
	git_diff_binary_t type = GIT_DIFF_BINARY_NONE;
	git_buf base85 = GIT_BUF_INIT, decoded = GIT_BUF_INIT;
	git_off_t len;
	int error = 0;

	if (git_parse_ctx_contains_s(&ctx->parse_ctx, "literal ")) {
		type = GIT_DIFF_BINARY_LITERAL;
		git_parse_advance_chars(&ctx->parse_ctx, 8);
	} else if (git_parse_ctx_contains_s(&ctx->parse_ctx, "delta ")) {
		type = GIT_DIFF_BINARY_DELTA;
		git_parse_advance_chars(&ctx->parse_ctx, 6);
	} else {
		error = git_parse_err(
			"unknown binary delta type at line %"PRIuZ, ctx->parse_ctx.line_num);
		goto done;
	}

	if (git_parse_advance_digit(&len, &ctx->parse_ctx, 10) < 0 ||
	    git_parse_advance_nl(&ctx->parse_ctx) < 0 || len < 0) {
		error = git_parse_err("invalid binary size at line %"PRIuZ, ctx->parse_ctx.line_num);
		goto done;
	}

	while (ctx->parse_ctx.line_len) {
		char c;
		size_t encoded_len, decoded_len = 0, decoded_orig = decoded.size;

		git_parse_peek(&c, &ctx->parse_ctx, 0);

		if (c == '\n')
			break;
		else if (c >= 'A' && c <= 'Z')
			decoded_len = c - 'A' + 1;
		else if (c >= 'a' && c <= 'z')
			decoded_len = c - 'a' + (('z' - 'a') + 1) + 1;

		if (!decoded_len) {
			error = git_parse_err("invalid binary length at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}

		git_parse_advance_chars(&ctx->parse_ctx, 1);

		encoded_len = ((decoded_len / 4) + !!(decoded_len % 4)) * 5;

		if (encoded_len > ctx->parse_ctx.line_len - 1) {
			error = git_parse_err("truncated binary data at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}

		if ((error = git_buf_decode_base85(
			&decoded, ctx->parse_ctx.line, encoded_len, decoded_len)) < 0)
			goto done;

		if (decoded.size - decoded_orig != decoded_len) {
			error = git_parse_err("truncated binary data at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}

		git_parse_advance_chars(&ctx->parse_ctx, encoded_len);

		if (git_parse_advance_nl(&ctx->parse_ctx) < 0) {
			error = git_parse_err("trailing data at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}
	}

	binary->type = type;
	binary->inflatedlen = (size_t)len;
	binary->datalen = decoded.size;
	binary->data = git_buf_detach(&decoded);

done:
	git_buf_dispose(&base85);
	git_buf_dispose(&decoded);
	return error;
}
Пример #4
0
static int parse_hunk_body(
	git_patch_parsed *patch,
	git_patch_hunk *hunk,
	git_patch_parse_ctx *ctx)
{
	git_diff_line *line;
	int error = 0;

	int oldlines = hunk->hunk.old_lines;
	int newlines = hunk->hunk.new_lines;

	for (;
		ctx->parse_ctx.remain_len > 1 &&
		(oldlines || newlines) &&
		!git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -");
		git_parse_advance_line(&ctx->parse_ctx)) {

		char c;
		int origin;
		int prefix = 1;

		if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') {
			error = git_parse_err("invalid patch instruction at line %"PRIuZ,
				ctx->parse_ctx.line_num);
			goto done;
		}

		git_parse_peek(&c, &ctx->parse_ctx, 0);

		switch (c) {
		case '\n':
			prefix = 0;
			/* fall through */

		case ' ':
			origin = GIT_DIFF_LINE_CONTEXT;
			oldlines--;
			newlines--;
			break;

		case '-':
			origin = GIT_DIFF_LINE_DELETION;
			oldlines--;
			break;

		case '+':
			origin = GIT_DIFF_LINE_ADDITION;
			newlines--;
			break;

		default:
			error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}

		line = git_array_alloc(patch->base.lines);
		GITERR_CHECK_ALLOC(line);

		memset(line, 0x0, sizeof(git_diff_line));

		line->content = ctx->parse_ctx.line + prefix;
		line->content_len = ctx->parse_ctx.line_len - prefix;
		line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
		line->origin = origin;

		hunk->line_count++;
	}

	if (oldlines || newlines) {
		error = git_parse_err(
			"invalid patch hunk, expected %d old lines and %d new lines",
			hunk->hunk.old_lines, hunk->hunk.new_lines);
		goto done;
	}

	/* Handle "\ No newline at end of file".  Only expect the leading
	 * backslash, though, because the rest of the string could be
	 * localized.  Because `diff` optimizes for the case where you
	 * want to apply the patch by hand.
	 */
	if (git_parse_ctx_contains_s(&ctx->parse_ctx, "\\ ") &&
		git_array_size(patch->base.lines) > 0) {

		line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1);

		if (line->content_len < 1) {
			error = git_parse_err("cannot trim trailing newline of empty line");
			goto done;
		}

		line->content_len--;

		git_parse_advance_line(&ctx->parse_ctx);
	}

done:
	return error;
}
Пример #5
0
int git_config_parse(
	git_config_parser *parser,
	git_config_parser_section_cb on_section,
	git_config_parser_variable_cb on_variable,
	git_config_parser_comment_cb on_comment,
	git_config_parser_eof_cb on_eof,
	void *data)
{
	git_parse_ctx *ctx;
	char *current_section = NULL, *var_name, *var_value;
	int result = 0;

	ctx = &parser->ctx;

	skip_bom(ctx);

	for (; ctx->remain_len > 0; git_parse_advance_line(ctx)) {
		const char *line_start = parser->ctx.line;
		size_t line_len = parser->ctx.line_len;
		char c;

		if (git_parse_peek(&c, ctx, GIT_PARSE_PEEK_SKIP_WHITESPACE) < 0 &&
		    git_parse_peek(&c, ctx, 0) < 0)
			continue;

		switch (c) {
		case '[': /* section header, new section begins */
			git__free(current_section);
			current_section = NULL;

			if ((result = parse_section_header(parser, &current_section)) == 0 && on_section) {
				result = on_section(parser, current_section, line_start, line_len, data);
			}
			break;

		case '\n': /* comment or whitespace-only */
		case ' ':
		case '\t':
		case ';':
		case '#':
			if (on_comment) {
				result = on_comment(parser, line_start, line_len, data);
			}
			break;

		default: /* assume variable declaration */
			if ((result = parse_variable(parser, &var_name, &var_value)) == 0 && on_variable) {
				result = on_variable(parser, current_section, var_name, var_value, line_start, line_len, data);
			}
			break;
		}

		if (result < 0)
			goto out;
	}

	if (on_eof)
		result = on_eof(parser, current_section, data);

out:
	git__free(current_section);
	return result;
}