Blame src/buffer.c

Packit Service 20376f
/*
Packit Service 20376f
 * Copyright (C) the libgit2 contributors. All rights reserved.
Packit Service 20376f
 *
Packit Service 20376f
 * This file is part of libgit2, distributed under the GNU GPL v2 with
Packit Service 20376f
 * a Linking Exception. For full terms see the included COPYING file.
Packit Service 20376f
 */
Packit Service 20376f
#include "buffer.h"
Packit Service 20376f
#include "posix.h"
Packit Service 20376f
#include "git2/buffer.h"
Packit Service 20376f
#include "buf_text.h"
Packit Service 20376f
#include <ctype.h>
Packit Service 20376f
Packit Service 20376f
/* Used as default value for git_buf->ptr so that people can always
Packit Service 20376f
 * assume ptr is non-NULL and zero terminated even for new git_bufs.
Packit Service 20376f
 */
Packit Service 20376f
char git_buf__initbuf[1];
Packit Service 20376f
Packit Service 20376f
char git_buf__oom[1];
Packit Service 20376f
Packit Service 20376f
#define ENSURE_SIZE(b, d) \
Packit Service 20376f
	if ((d) > (b)->asize && git_buf_grow((b), (d)) < 0)\
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
int git_buf_init(git_buf *buf, size_t initial_size)
Packit Service 20376f
{
Packit Service 20376f
	buf->asize = 0;
Packit Service 20376f
	buf->size = 0;
Packit Service 20376f
	buf->ptr = git_buf__initbuf;
Packit Service 20376f
Packit Service 20376f
	ENSURE_SIZE(buf, initial_size);
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_try_grow(
Packit Service 20376f
	git_buf *buf, size_t target_size, bool mark_oom)
Packit Service 20376f
{
Packit Service 20376f
	char *new_ptr;
Packit Service 20376f
	size_t new_size;
Packit Service 20376f
Packit Service 20376f
	if (buf->ptr == git_buf__oom)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	if (buf->asize == 0 && buf->size != 0) {
Packit Service 20376f
		giterr_set(GITERR_INVALID, "cannot grow a borrowed buffer");
Packit Service 20376f
		return GIT_EINVALID;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (!target_size)
Packit Service 20376f
		target_size = buf->size;
Packit Service 20376f
Packit Service 20376f
	if (target_size <= buf->asize)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	if (buf->asize == 0) {
Packit Service 20376f
		new_size = target_size;
Packit Service 20376f
		new_ptr = NULL;
Packit Service 20376f
	} else {
Packit Service 20376f
		new_size = buf->asize;
Packit Service 20376f
		new_ptr = buf->ptr;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/* grow the buffer size by 1.5, until it's big enough
Packit Service 20376f
	 * to fit our target size */
Packit Service 20376f
	while (new_size < target_size)
Packit Service 20376f
		new_size = (new_size << 1) - (new_size >> 1);
Packit Service 20376f
Packit Service 20376f
	/* round allocation up to multiple of 8 */
Packit Service 20376f
	new_size = (new_size + 7) & ~7;
Packit Service 20376f
Packit Service 20376f
	if (new_size < buf->size) {
Packit Service 20376f
		if (mark_oom)
Packit Service 20376f
			buf->ptr = git_buf__oom;
Packit Service 20376f
Packit Service 20376f
		giterr_set_oom();
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	new_ptr = git__realloc(new_ptr, new_size);
Packit Service 20376f
Packit Service 20376f
	if (!new_ptr) {
Packit Service 20376f
		if (mark_oom) {
Packit Service 20376f
			if (buf->ptr && (buf->ptr != git_buf__initbuf))
Packit Service 20376f
				git__free(buf->ptr);
Packit Service 20376f
			buf->ptr = git_buf__oom;
Packit Service 20376f
		}
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	buf->asize = new_size;
Packit Service 20376f
	buf->ptr   = new_ptr;
Packit Service 20376f
Packit Service 20376f
	/* truncate the existing buffer size if necessary */
Packit Service 20376f
	if (buf->size >= buf->asize)
Packit Service 20376f
		buf->size = buf->asize - 1;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_grow(git_buf *buffer, size_t target_size)
Packit Service 20376f
{
Packit Service 20376f
	return git_buf_try_grow(buffer, target_size, true);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_grow_by(git_buf *buffer, size_t additional_size)
Packit Service 20376f
{
Packit Service 20376f
	size_t newsize;
Packit Service 20376f
Packit Service 20376f
	if (GIT_ADD_SIZET_OVERFLOW(&newsize, buffer->size, additional_size)) {
Packit Service 20376f
		buffer->ptr = git_buf__oom;
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return git_buf_try_grow(buffer, newsize, true);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_free(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	if (!buf) return;
Packit Service 20376f
Packit Service 20376f
	if (buf->asize > 0 && buf->ptr != NULL && buf->ptr != git_buf__oom)
Packit Service 20376f
		git__free(buf->ptr);
Packit Service 20376f
Packit Service 20376f
	git_buf_init(buf, 0);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_sanitize(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	if (buf->ptr == NULL) {
Packit Service 20376f
		assert(buf->size == 0 && buf->asize == 0);
Packit Service 20376f
		buf->ptr = git_buf__initbuf;
Packit Service 20376f
	} else if (buf->asize > buf->size)
Packit Service 20376f
		buf->ptr[buf->size] = '\0';
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_clear(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	buf->size = 0;
Packit Service 20376f
Packit Service 20376f
	if (!buf->ptr) {
Packit Service 20376f
		buf->ptr = git_buf__initbuf;
Packit Service 20376f
		buf->asize = 0;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (buf->asize > 0)
Packit Service 20376f
		buf->ptr[0] = '\0';
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_set(git_buf *buf, const void *data, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	size_t alloclen;
Packit Service 20376f
Packit Service 20376f
	if (len == 0 || data == NULL) {
Packit Service 20376f
		git_buf_clear(buf);
Packit Service 20376f
	} else {
Packit Service 20376f
		if (data != buf->ptr) {
Packit Service 20376f
			GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
Packit Service 20376f
			ENSURE_SIZE(buf, alloclen);
Packit Service 20376f
			memmove(buf->ptr, data, len);
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		buf->size = len;
Packit Service 20376f
		if (buf->asize > buf->size)
Packit Service 20376f
			buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	}
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_is_binary(const git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	return git_buf_text_is_binary(buf);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_contains_nul(const git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	return git_buf_text_contains_nul(buf);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_sets(git_buf *buf, const char *string)
Packit Service 20376f
{
Packit Service 20376f
	return git_buf_set(buf, string, string ? strlen(string) : 0);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_putc(git_buf *buf, char c)
Packit Service 20376f
{
Packit Service 20376f
	size_t new_size;
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, 2);
Packit Service 20376f
	ENSURE_SIZE(buf, new_size);
Packit Service 20376f
	buf->ptr[buf->size++] = c;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_putcn(git_buf *buf, char c, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	size_t new_size;
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
Packit Service 20376f
	ENSURE_SIZE(buf, new_size);
Packit Service 20376f
	memset(buf->ptr + buf->size, c, len);
Packit Service 20376f
	buf->size += len;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_put(git_buf *buf, const char *data, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	if (len) {
Packit Service 20376f
		size_t new_size;
Packit Service 20376f
Packit Service 20376f
		assert(data);
Packit Service 20376f
		
Packit Service 20376f
		GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
Packit Service 20376f
		GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
Packit Service 20376f
		ENSURE_SIZE(buf, new_size);
Packit Service 20376f
		memmove(buf->ptr + buf->size, data, len);
Packit Service 20376f
		buf->size += len;
Packit Service 20376f
		buf->ptr[buf->size] = '\0';
Packit Service 20376f
	}
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_puts(git_buf *buf, const char *string)
Packit Service 20376f
{
Packit Service 20376f
	assert(string);
Packit Service 20376f
	return git_buf_put(buf, string, strlen(string));
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static const char base64_encode[] =
Packit Service 20376f
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Packit Service 20376f
Packit Service 20376f
int git_buf_encode_base64(git_buf *buf, const char *data, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	size_t extra = len % 3;
Packit Service 20376f
	uint8_t *write, a, b, c;
Packit Service 20376f
	const uint8_t *read = (const uint8_t *)data;
Packit Service 20376f
	size_t blocks = (len / 3) + !!extra, alloclen;
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&blocks, blocks, 1);
Packit Service 20376f
	GITERR_CHECK_ALLOC_MULTIPLY(&alloclen, blocks, 4);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, buf->size);
Packit Service 20376f
Packit Service 20376f
	ENSURE_SIZE(buf, alloclen);
Packit Service 20376f
	write = (uint8_t *)&buf->ptr[buf->size];
Packit Service 20376f
Packit Service 20376f
	/* convert each run of 3 bytes into 4 output bytes */
Packit Service 20376f
	for (len -= extra; len > 0; len -= 3) {
Packit Service 20376f
		a = *read++;
Packit Service 20376f
		b = *read++;
Packit Service 20376f
		c = *read++;
Packit Service 20376f
Packit Service 20376f
		*write++ = base64_encode[a >> 2];
Packit Service 20376f
		*write++ = base64_encode[(a & 0x03) << 4 | b >> 4];
Packit Service 20376f
		*write++ = base64_encode[(b & 0x0f) << 2 | c >> 6];
Packit Service 20376f
		*write++ = base64_encode[c & 0x3f];
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (extra > 0) {
Packit Service 20376f
		a = *read++;
Packit Service 20376f
		b = (extra > 1) ? *read++ : 0;
Packit Service 20376f
Packit Service 20376f
		*write++ = base64_encode[a >> 2];
Packit Service 20376f
		*write++ = base64_encode[(a & 0x03) << 4 | b >> 4];
Packit Service 20376f
		*write++ = (extra > 1) ? base64_encode[(b & 0x0f) << 2] : '=';
Packit Service 20376f
		*write++ = '=';
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	buf->size = ((char *)write) - buf->ptr;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* The inverse of base64_encode */
Packit Service 20376f
static const int8_t base64_decode[] = {
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
Packit Service 20376f
	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1,  0, -1, -1,
Packit Service 20376f
	-1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
Packit Service 20376f
	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
Packit Service 20376f
	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
int git_buf_decode_base64(git_buf *buf, const char *base64, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	size_t i;
Packit Service 20376f
	int8_t a, b, c, d;
Packit Service 20376f
	size_t orig_size = buf->size, new_size;
Packit Service 20376f
Packit Service 20376f
	if (len % 4) {
Packit Service 20376f
		giterr_set(GITERR_INVALID, "invalid base64 input");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	assert(len % 4 == 0);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, (len / 4 * 3), buf->size);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
Packit Service 20376f
	ENSURE_SIZE(buf, new_size);
Packit Service 20376f
Packit Service 20376f
	for (i = 0; i < len; i += 4) {
Packit Service 20376f
		if ((a = base64_decode[(unsigned char)base64[i]]) < 0 ||
Packit Service 20376f
			(b = base64_decode[(unsigned char)base64[i+1]]) < 0 ||
Packit Service 20376f
			(c = base64_decode[(unsigned char)base64[i+2]]) < 0 ||
Packit Service 20376f
			(d = base64_decode[(unsigned char)base64[i+3]]) < 0) {
Packit Service 20376f
			buf->size = orig_size;
Packit Service 20376f
			buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
			giterr_set(GITERR_INVALID, "invalid base64 input");
Packit Service 20376f
			return -1;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		buf->ptr[buf->size++] = ((a << 2) | (b & 0x30) >> 4);
Packit Service 20376f
		buf->ptr[buf->size++] = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
Packit Service 20376f
		buf->ptr[buf->size++] = (c & 0x03) << 6 | (d & 0x3f);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static const char base85_encode[] =
Packit Service 20376f
	"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
Packit Service 20376f
Packit Service 20376f
int git_buf_encode_base85(git_buf *buf, const char *data, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	size_t blocks = (len / 4) + !!(len % 4), alloclen;
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_MULTIPLY(&alloclen, blocks, 5);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, buf->size);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
Packit Service 20376f
Packit Service 20376f
	ENSURE_SIZE(buf, alloclen);
Packit Service 20376f
Packit Service 20376f
	while (len) {
Packit Service 20376f
		uint32_t acc = 0;
Packit Service 20376f
		char b85[5];
Packit Service 20376f
		int i;
Packit Service 20376f
Packit Service 20376f
		for (i = 24; i >= 0; i -= 8) {
Packit Service 20376f
			uint8_t ch = *data++;
Packit Service 20376f
			acc |= ch << i;
Packit Service 20376f
Packit Service 20376f
			if (--len == 0)
Packit Service 20376f
				break;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		for (i = 4; i >= 0; i--) {
Packit Service 20376f
			int val = acc % 85;
Packit Service 20376f
			acc /= 85;
Packit Service 20376f
Packit Service 20376f
			b85[i] = base85_encode[val];
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		for (i = 0; i < 5; i++)
Packit Service 20376f
			buf->ptr[buf->size++] = b85[i];
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* The inverse of base85_encode */
Packit Service 20376f
static const int8_t base85_decode[] = {
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, 63, -1, 64, 65, 66, 67, -1, 68, 69, 70, 71, -1, 72, -1, -1,
Packit Service 20376f
	 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, -1, 73, 74, 75, 76, 77,
Packit Service 20376f
	78, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
Packit Service 20376f
	26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, 79, 80,
Packit Service 20376f
	81, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
Packit Service 20376f
	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 82, 83, 84, 85, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Packit Service 20376f
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
int git_buf_decode_base85(
Packit Service 20376f
	git_buf *buf,
Packit Service 20376f
	const char *base85,
Packit Service 20376f
	size_t base85_len,
Packit Service 20376f
	size_t output_len)
Packit Service 20376f
{
Packit Service 20376f
	size_t orig_size = buf->size, new_size;
Packit Service 20376f
Packit Service 20376f
	if (base85_len % 5 ||
Packit Service 20376f
		output_len > base85_len * 4 / 5) {
Packit Service 20376f
		giterr_set(GITERR_INVALID, "invalid base85 input");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, output_len, buf->size);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
Packit Service 20376f
	ENSURE_SIZE(buf, new_size);
Packit Service 20376f
Packit Service 20376f
	while (output_len) {
Packit Service 20376f
		unsigned acc = 0;
Packit Service 20376f
		int de, cnt = 4;
Packit Service 20376f
		unsigned char ch;
Packit Service 20376f
		do {
Packit Service 20376f
			ch = *base85++;
Packit Service 20376f
			de = base85_decode[ch];
Packit Service 20376f
			if (--de < 0)
Packit Service 20376f
				goto on_error;
Packit Service 20376f
Packit Service 20376f
			acc = acc * 85 + de;
Packit Service 20376f
		} while (--cnt);
Packit Service 20376f
		ch = *base85++;
Packit Service 20376f
		de = base85_decode[ch];
Packit Service 20376f
		if (--de < 0)
Packit Service 20376f
			goto on_error;
Packit Service 20376f
Packit Service 20376f
		/* Detect overflow. */
Packit Service 20376f
		if (0xffffffff / 85 < acc ||
Packit Service 20376f
			0xffffffff - de < (acc *= 85))
Packit Service 20376f
			goto on_error;
Packit Service 20376f
Packit Service 20376f
		acc += de;
Packit Service 20376f
Packit Service 20376f
		cnt = (output_len < 4) ? output_len : 4;
Packit Service 20376f
		output_len -= cnt;
Packit Service 20376f
		do {
Packit Service 20376f
			acc = (acc << 8) | (acc >> 24);
Packit Service 20376f
			buf->ptr[buf->size++] = acc;
Packit Service 20376f
		} while (--cnt);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	buf->ptr[buf->size] = 0;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
Packit Service 20376f
on_error:
Packit Service 20376f
	buf->size = orig_size;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	giterr_set(GITERR_INVALID, "invalid base85 input");
Packit Service 20376f
	return -1;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
Packit Service 20376f
{
Packit Service 20376f
	size_t expected_size, new_size;
Packit Service 20376f
	int len;
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_MULTIPLY(&expected_size, strlen(format), 2);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&expected_size, expected_size, buf->size);
Packit Service 20376f
	ENSURE_SIZE(buf, expected_size);
Packit Service 20376f
Packit Service 20376f
	while (1) {
Packit Service 20376f
		va_list args;
Packit Service 20376f
		va_copy(args, ap);
Packit Service 20376f
Packit Service 20376f
		len = p_vsnprintf(
Packit Service 20376f
			buf->ptr + buf->size,
Packit Service 20376f
			buf->asize - buf->size,
Packit Service 20376f
			format, args
Packit Service 20376f
		);
Packit Service 20376f
Packit Service 20376f
		va_end(args);
Packit Service 20376f
Packit Service 20376f
		if (len < 0) {
Packit Service 20376f
			git__free(buf->ptr);
Packit Service 20376f
			buf->ptr = git_buf__oom;
Packit Service 20376f
			return -1;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if ((size_t)len + 1 <= buf->asize - buf->size) {
Packit Service 20376f
			buf->size += len;
Packit Service 20376f
			break;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
Packit Service 20376f
		GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
Packit Service 20376f
		ENSURE_SIZE(buf, new_size);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_printf(git_buf *buf, const char *format, ...)
Packit Service 20376f
{
Packit Service 20376f
	int r;
Packit Service 20376f
	va_list ap;
Packit Service 20376f
Packit Service 20376f
	va_start(ap, format);
Packit Service 20376f
	r = git_buf_vprintf(buf, format, ap);
Packit Service 20376f
	va_end(ap);
Packit Service 20376f
Packit Service 20376f
	return r;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	size_t copylen;
Packit Service 20376f
Packit Service 20376f
	assert(data && datasize && buf);
Packit Service 20376f
Packit Service 20376f
	data[0] = '\0';
Packit Service 20376f
Packit Service 20376f
	if (buf->size == 0 || buf->asize <= 0)
Packit Service 20376f
		return;
Packit Service 20376f
Packit Service 20376f
	copylen = buf->size;
Packit Service 20376f
	if (copylen > datasize - 1)
Packit Service 20376f
		copylen = datasize - 1;
Packit Service 20376f
	memmove(data, buf->ptr, copylen);
Packit Service 20376f
	data[copylen] = '\0';
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_consume(git_buf *buf, const char *end)
Packit Service 20376f
{
Packit Service 20376f
	if (end > buf->ptr && end <= buf->ptr + buf->size) {
Packit Service 20376f
		size_t consumed = end - buf->ptr;
Packit Service 20376f
		memmove(buf->ptr, end, buf->size - consumed);
Packit Service 20376f
		buf->size -= consumed;
Packit Service 20376f
		buf->ptr[buf->size] = '\0';
Packit Service 20376f
	}
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_truncate(git_buf *buf, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	if (len >= buf->size)
Packit Service 20376f
		return;
Packit Service 20376f
Packit Service 20376f
	buf->size = len;
Packit Service 20376f
	if (buf->size < buf->asize)
Packit Service 20376f
		buf->ptr[buf->size] = '\0';
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_shorten(git_buf *buf, size_t amount)
Packit Service 20376f
{
Packit Service 20376f
	if (buf->size > amount)
Packit Service 20376f
		git_buf_truncate(buf, buf->size - amount);
Packit Service 20376f
	else
Packit Service 20376f
		git_buf_clear(buf);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_rtruncate_at_char(git_buf *buf, char separator)
Packit Service 20376f
{
Packit Service 20376f
	ssize_t idx = git_buf_rfind_next(buf, separator);
Packit Service 20376f
	git_buf_truncate(buf, idx < 0 ? 0 : (size_t)idx);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
Packit Service 20376f
{
Packit Service 20376f
	git_buf t = *buf_a;
Packit Service 20376f
	*buf_a = *buf_b;
Packit Service 20376f
	*buf_b = t;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
char *git_buf_detach(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	char *data = buf->ptr;
Packit Service 20376f
Packit Service 20376f
	if (buf->asize == 0 || buf->ptr == git_buf__oom)
Packit Service 20376f
		return NULL;
Packit Service 20376f
Packit Service 20376f
	git_buf_init(buf, 0);
Packit Service 20376f
Packit Service 20376f
	return data;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_attach(git_buf *buf, char *ptr, size_t asize)
Packit Service 20376f
{
Packit Service 20376f
	git_buf_free(buf);
Packit Service 20376f
Packit Service 20376f
	if (ptr) {
Packit Service 20376f
		buf->ptr = ptr;
Packit Service 20376f
		buf->size = strlen(ptr);
Packit Service 20376f
		if (asize)
Packit Service 20376f
			buf->asize = (asize < buf->size) ? buf->size + 1 : asize;
Packit Service 20376f
		else /* pass 0 to fall back on strlen + 1 */
Packit Service 20376f
			buf->asize = buf->size + 1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	ENSURE_SIZE(buf, asize);
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_attach_notowned(git_buf *buf, const char *ptr, size_t size)
Packit Service 20376f
{
Packit Service 20376f
	if (git_buf_is_allocated(buf))
Packit Service 20376f
		git_buf_free(buf);
Packit Service 20376f
Packit Service 20376f
	if (!size) {
Packit Service 20376f
		git_buf_init(buf, 0);
Packit Service 20376f
	} else {
Packit Service 20376f
		buf->ptr = (char *)ptr;
Packit Service 20376f
		buf->asize = 0;
Packit Service 20376f
		buf->size = size;
Packit Service 20376f
	}
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
Packit Service 20376f
{
Packit Service 20376f
	va_list ap;
Packit Service 20376f
	int i;
Packit Service 20376f
	size_t total_size = 0, original_size = buf->size;
Packit Service 20376f
	char *out, *original = buf->ptr;
Packit Service 20376f
Packit Service 20376f
	if (buf->size > 0 && buf->ptr[buf->size - 1] != separator)
Packit Service 20376f
		++total_size; /* space for initial separator */
Packit Service 20376f
Packit Service 20376f
	/* Make two passes to avoid multiple reallocation */
Packit Service 20376f
Packit Service 20376f
	va_start(ap, nbuf);
Packit Service 20376f
	for (i = 0; i < nbuf; ++i) {
Packit Service 20376f
		const char* segment;
Packit Service 20376f
		size_t segment_len;
Packit Service 20376f
Packit Service 20376f
		segment = va_arg(ap, const char *);
Packit Service 20376f
		if (!segment)
Packit Service 20376f
			continue;
Packit Service 20376f
Packit Service 20376f
		segment_len = strlen(segment);
Packit Service 20376f
Packit Service 20376f
		GITERR_CHECK_ALLOC_ADD(&total_size, total_size, segment_len);
Packit Service 20376f
Packit Service 20376f
		if (segment_len == 0 || segment[segment_len - 1] != separator)
Packit Service 20376f
			GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1);
Packit Service 20376f
	}
Packit Service 20376f
	va_end(ap);
Packit Service 20376f
Packit Service 20376f
	/* expand buffer if needed */
Packit Service 20376f
	if (total_size == 0)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1);
Packit Service 20376f
	if (git_buf_grow_by(buf, total_size) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	out = buf->ptr + buf->size;
Packit Service 20376f
Packit Service 20376f
	/* append separator to existing buf if needed */
Packit Service 20376f
	if (buf->size > 0 && out[-1] != separator)
Packit Service 20376f
		*out++ = separator;
Packit Service 20376f
Packit Service 20376f
	va_start(ap, nbuf);
Packit Service 20376f
	for (i = 0; i < nbuf; ++i) {
Packit Service 20376f
		const char* segment;
Packit Service 20376f
		size_t segment_len;
Packit Service 20376f
Packit Service 20376f
		segment = va_arg(ap, const char *);
Packit Service 20376f
		if (!segment)
Packit Service 20376f
			continue;
Packit Service 20376f
Packit Service 20376f
		/* deal with join that references buffer's original content */
Packit Service 20376f
		if (segment >= original && segment < original + original_size) {
Packit Service 20376f
			size_t offset = (segment - original);
Packit Service 20376f
			segment = buf->ptr + offset;
Packit Service 20376f
			segment_len = original_size - offset;
Packit Service 20376f
		} else {
Packit Service 20376f
			segment_len = strlen(segment);
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		/* skip leading separators */
Packit Service 20376f
		if (out > buf->ptr && out[-1] == separator)
Packit Service 20376f
			while (segment_len > 0 && *segment == separator) {
Packit Service 20376f
				segment++;
Packit Service 20376f
				segment_len--;
Packit Service 20376f
			}
Packit Service 20376f
Packit Service 20376f
		/* copy over next buffer */
Packit Service 20376f
		if (segment_len > 0) {
Packit Service 20376f
			memmove(out, segment, segment_len);
Packit Service 20376f
			out += segment_len;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		/* append trailing separator (except for last item) */
Packit Service 20376f
		if (i < nbuf - 1 && out > buf->ptr && out[-1] != separator)
Packit Service 20376f
			*out++ = separator;
Packit Service 20376f
	}
Packit Service 20376f
	va_end(ap);
Packit Service 20376f
Packit Service 20376f
	/* set size based on num characters actually written */
Packit Service 20376f
	buf->size = out - buf->ptr;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_join(
Packit Service 20376f
	git_buf *buf,
Packit Service 20376f
	char separator,
Packit Service 20376f
	const char *str_a,
Packit Service 20376f
	const char *str_b)
Packit Service 20376f
{
Packit Service 20376f
	size_t strlen_a = str_a ? strlen(str_a) : 0;
Packit Service 20376f
	size_t strlen_b = strlen(str_b);
Packit Service 20376f
	size_t alloc_len;
Packit Service 20376f
	int need_sep = 0;
Packit Service 20376f
	ssize_t offset_a = -1;
Packit Service 20376f
Packit Service 20376f
	/* not safe to have str_b point internally to the buffer */
Packit Service 20376f
	assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
Packit Service 20376f
Packit Service 20376f
	/* figure out if we need to insert a separator */
Packit Service 20376f
	if (separator && strlen_a) {
Packit Service 20376f
		while (*str_b == separator) { str_b++; strlen_b--; }
Packit Service 20376f
		if (str_a[strlen_a - 1] != separator)
Packit Service 20376f
			need_sep = 1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/* str_a could be part of the buffer */
Packit Service 20376f
	if (str_a >= buf->ptr && str_a < buf->ptr + buf->size)
Packit Service 20376f
		offset_a = str_a - buf->ptr;
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, strlen_a, strlen_b);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, need_sep);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
Packit Service 20376f
	ENSURE_SIZE(buf, alloc_len);
Packit Service 20376f
Packit Service 20376f
	/* fix up internal pointers */
Packit Service 20376f
	if (offset_a >= 0)
Packit Service 20376f
		str_a = buf->ptr + offset_a;
Packit Service 20376f
Packit Service 20376f
	/* do the actual copying */
Packit Service 20376f
	if (offset_a != 0 && str_a)
Packit Service 20376f
		memmove(buf->ptr, str_a, strlen_a);
Packit Service 20376f
	if (need_sep)
Packit Service 20376f
		buf->ptr[strlen_a] = separator;
Packit Service 20376f
	memcpy(buf->ptr + strlen_a + need_sep, str_b, strlen_b);
Packit Service 20376f
Packit Service 20376f
	buf->size = strlen_a + strlen_b + need_sep;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_join3(
Packit Service 20376f
	git_buf *buf,
Packit Service 20376f
	char separator,
Packit Service 20376f
	const char *str_a,
Packit Service 20376f
	const char *str_b,
Packit Service 20376f
	const char *str_c)
Packit Service 20376f
{
Packit Service 20376f
	size_t len_a = strlen(str_a),
Packit Service 20376f
		len_b = strlen(str_b),
Packit Service 20376f
		len_c = strlen(str_c),
Packit Service 20376f
		len_total;
Packit Service 20376f
	int sep_a = 0, sep_b = 0;
Packit Service 20376f
	char *tgt;
Packit Service 20376f
Packit Service 20376f
	/* for this function, disallow pointers into the existing buffer */
Packit Service 20376f
	assert(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
Packit Service 20376f
	assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
Packit Service 20376f
	assert(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
Packit Service 20376f
Packit Service 20376f
	if (separator) {
Packit Service 20376f
		if (len_a > 0) {
Packit Service 20376f
			while (*str_b == separator) { str_b++; len_b--; }
Packit Service 20376f
			sep_a = (str_a[len_a - 1] != separator);
Packit Service 20376f
		}
Packit Service 20376f
		if (len_a > 0 || len_b > 0)
Packit Service 20376f
			while (*str_c == separator) { str_c++; len_c--; }
Packit Service 20376f
		if (len_b > 0)
Packit Service 20376f
			sep_b = (str_b[len_b - 1] != separator);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&len_total, len_a, sep_a);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&len_total, len_total, len_b);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&len_total, len_total, sep_b);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&len_total, len_total, len_c);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&len_total, len_total, 1);
Packit Service 20376f
	ENSURE_SIZE(buf, len_total);
Packit Service 20376f
Packit Service 20376f
	tgt = buf->ptr;
Packit Service 20376f
Packit Service 20376f
	if (len_a) {
Packit Service 20376f
		memcpy(tgt, str_a, len_a);
Packit Service 20376f
		tgt += len_a;
Packit Service 20376f
	}
Packit Service 20376f
	if (sep_a)
Packit Service 20376f
		*tgt++ = separator;
Packit Service 20376f
	if (len_b) {
Packit Service 20376f
		memcpy(tgt, str_b, len_b);
Packit Service 20376f
		tgt += len_b;
Packit Service 20376f
	}
Packit Service 20376f
	if (sep_b)
Packit Service 20376f
		*tgt++ = separator;
Packit Service 20376f
	if (len_c)
Packit Service 20376f
		memcpy(tgt, str_c, len_c);
Packit Service 20376f
Packit Service 20376f
	buf->size = len_a + sep_a + len_b + sep_b + len_c;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_buf_rtrim(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	while (buf->size > 0) {
Packit Service 20376f
		if (!git__isspace(buf->ptr[buf->size - 1]))
Packit Service 20376f
			break;
Packit Service 20376f
Packit Service 20376f
		buf->size--;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (buf->asize > buf->size)
Packit Service 20376f
		buf->ptr[buf->size] = '\0';
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_cmp(const git_buf *a, const git_buf *b)
Packit Service 20376f
{
Packit Service 20376f
	int result = memcmp(a->ptr, b->ptr, min(a->size, b->size));
Packit Service 20376f
	return (result != 0) ? result :
Packit Service 20376f
		(a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_buf_splice(
Packit Service 20376f
	git_buf *buf,
Packit Service 20376f
	size_t where,
Packit Service 20376f
	size_t nb_to_remove,
Packit Service 20376f
	const char *data,
Packit Service 20376f
	size_t nb_to_insert)
Packit Service 20376f
{
Packit Service 20376f
	char *splice_loc;
Packit Service 20376f
	size_t new_size, alloc_size;
Packit Service 20376f
Packit Service 20376f
	assert(buf && where <= buf->size && nb_to_remove <= buf->size - where);
Packit Service 20376f
Packit Service 20376f
	splice_loc = buf->ptr + where;
Packit Service 20376f
Packit Service 20376f
	/* Ported from git.git
Packit Service 20376f
	 * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
Packit Service 20376f
	 */
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&new_size, (buf->size - nb_to_remove), nb_to_insert);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_size, new_size, 1);
Packit Service 20376f
	ENSURE_SIZE(buf, alloc_size);
Packit Service 20376f
Packit Service 20376f
	memmove(splice_loc + nb_to_insert,
Packit Service 20376f
		splice_loc + nb_to_remove,
Packit Service 20376f
		buf->size - where - nb_to_remove);
Packit Service 20376f
Packit Service 20376f
	memcpy(splice_loc, data, nb_to_insert);
Packit Service 20376f
Packit Service 20376f
	buf->size = new_size;
Packit Service 20376f
	buf->ptr[buf->size] = '\0';
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* Quote per http://marc.info/?l=git&m=112927316408690&w=2 */
Packit Service 20376f
int git_buf_quote(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	const char whitespace[] = { 'a', 'b', 't', 'n', 'v', 'f', 'r' };
Packit Service 20376f
	git_buf quoted = GIT_BUF_INIT;
Packit Service 20376f
	size_t i = 0;
Packit Service 20376f
	bool quote = false;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	/* walk to the first char that needs quoting */
Packit Service 20376f
	if (buf->size && buf->ptr[0] == '!')
Packit Service 20376f
		quote = true;
Packit Service 20376f
Packit Service 20376f
	for (i = 0; !quote && i < buf->size; i++) {
Packit Service 20376f
		if (buf->ptr[i] == '"' || buf->ptr[i] == '\\' ||
Packit Service 20376f
			buf->ptr[i] < ' ' || buf->ptr[i] > '~') {
Packit Service 20376f
			quote = true;
Packit Service 20376f
			break;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (!quote)
Packit Service 20376f
		goto done;
Packit Service 20376f
Packit Service 20376f
	git_buf_putc(&quoted, '"');
Packit Service 20376f
	git_buf_put(&quoted, buf->ptr, i);
Packit Service 20376f
Packit Service 20376f
	for (; i < buf->size; i++) {
Packit Service 20376f
		/* whitespace - use the map above, which is ordered by ascii value */
Packit Service 20376f
		if (buf->ptr[i] >= '\a' && buf->ptr[i] <= '\r') {
Packit Service 20376f
			git_buf_putc(&quoted, '\\');
Packit Service 20376f
			git_buf_putc(&quoted, whitespace[buf->ptr[i] - '\a']);
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		/* double quote and backslash must be escaped */
Packit Service 20376f
		else if (buf->ptr[i] == '"' || buf->ptr[i] == '\\') {
Packit Service 20376f
			git_buf_putc(&quoted, '\\');
Packit Service 20376f
			git_buf_putc(&quoted, buf->ptr[i]);
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		/* escape anything unprintable as octal */
Packit Service 20376f
		else if (buf->ptr[i] != ' ' &&
Packit Service 20376f
				(buf->ptr[i] < '!' || buf->ptr[i] > '~')) {
Packit Service 20376f
			git_buf_printf(&quoted, "\\%03o", (unsigned char)buf->ptr[i]);
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		/* yay, printable! */
Packit Service 20376f
		else {
Packit Service 20376f
			git_buf_putc(&quoted, buf->ptr[i]);
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_buf_putc(&quoted, '"');
Packit Service 20376f
Packit Service 20376f
	if (git_buf_oom(&quoted)) {
Packit Service 20376f
		error = -1;
Packit Service 20376f
		goto done;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_buf_swap(&quoted, buf);
Packit Service 20376f
Packit Service 20376f
done:
Packit Service 20376f
	git_buf_free(&quoted);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* Unquote per http://marc.info/?l=git&m=112927316408690&w=2 */
Packit Service 20376f
int git_buf_unquote(git_buf *buf)
Packit Service 20376f
{
Packit Service 20376f
	size_t i, j;
Packit Service 20376f
	char ch;
Packit Service 20376f
Packit Service 20376f
	git_buf_rtrim(buf);
Packit Service 20376f
Packit Service 20376f
	if (buf->size < 2 || buf->ptr[0] != '"' || buf->ptr[buf->size-1] != '"')
Packit Service 20376f
		goto invalid;
Packit Service 20376f
Packit Service 20376f
	for (i = 0, j = 1; j < buf->size-1; i++, j++) {
Packit Service 20376f
		ch = buf->ptr[j];
Packit Service 20376f
Packit Service 20376f
		if (ch == '\\') {
Packit Service 20376f
			if (j == buf->size-2)
Packit Service 20376f
				goto invalid;
Packit Service 20376f
Packit Service 20376f
			ch = buf->ptr[++j];
Packit Service 20376f
Packit Service 20376f
			switch (ch) {
Packit Service 20376f
			/* \" or \\ simply copy the char in */
Packit Service 20376f
			case '"': case '\\':
Packit Service 20376f
				break;
Packit Service 20376f
Packit Service 20376f
			/* add the appropriate escaped char */
Packit Service 20376f
			case 'a': ch = '\a'; break;
Packit Service 20376f
			case 'b': ch = '\b'; break;
Packit Service 20376f
			case 'f': ch = '\f'; break;
Packit Service 20376f
			case 'n': ch = '\n'; break;
Packit Service 20376f
			case 'r': ch = '\r'; break;
Packit Service 20376f
			case 't': ch = '\t'; break;
Packit Service 20376f
			case 'v': ch = '\v'; break;
Packit Service 20376f
Packit Service 20376f
			/* \xyz digits convert to the char*/
Packit Service 20376f
			case '0': case '1': case '2': case '3':
Packit Service 20376f
				if (j == buf->size-3) {
Packit Service 20376f
					giterr_set(GITERR_INVALID,
Packit Service 20376f
						"truncated quoted character \\%c", ch);
Packit Service 20376f
					return -1;
Packit Service 20376f
				}
Packit Service 20376f
Packit Service 20376f
				if (buf->ptr[j+1] < '0' || buf->ptr[j+1] > '7' ||
Packit Service 20376f
					buf->ptr[j+2] < '0' || buf->ptr[j+2] > '7') {
Packit Service 20376f
					giterr_set(GITERR_INVALID,
Packit Service 20376f
						"truncated quoted character \\%c%c%c",
Packit Service 20376f
						buf->ptr[j], buf->ptr[j+1], buf->ptr[j+2]);
Packit Service 20376f
					return -1;
Packit Service 20376f
				}
Packit Service 20376f
Packit Service 20376f
				ch = ((buf->ptr[j] - '0') << 6) |
Packit Service 20376f
					((buf->ptr[j+1] - '0') << 3) |
Packit Service 20376f
					(buf->ptr[j+2] - '0');
Packit Service 20376f
				j += 2;
Packit Service 20376f
				break;
Packit Service 20376f
Packit Service 20376f
			default:
Packit Service 20376f
				giterr_set(GITERR_INVALID, "invalid quoted character \\%c", ch);
Packit Service 20376f
				return -1;
Packit Service 20376f
			}
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		buf->ptr[i] = ch;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	buf->ptr[i] = '\0';
Packit Service 20376f
	buf->size = i;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
Packit Service 20376f
invalid:
Packit Service 20376f
	giterr_set(GITERR_INVALID, "invalid quoted line");
Packit Service 20376f
	return -1;
Packit Service 20376f
}