Skip to content

Commit aeb5ee5

Browse files
dturner-twnovalis
authored andcommitted
varint: Add varint encoding/decoding
This code is ported from git.git Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: David Turner <dturner@twopensource.com>
1 parent 26a8617 commit aeb5ee5

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

src/varint.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 "common.h"
9+
#include "varint.h"
10+
11+
uintmax_t git_decode_varint(const unsigned char *bufp, size_t *varint_len)
12+
{
13+
const unsigned char *buf = bufp;
14+
unsigned char c = *buf++;
15+
uintmax_t val = c & 127;
16+
while (c & 128) {
17+
val += 1;
18+
if (!val || MSB(val, 7)) {
19+
/* This is not a valid varint_len, so it signals
20+
the error */
21+
*varint_len = 0;
22+
return 0; /* overflow */
23+
}
24+
c = *buf++;
25+
val = (val << 7) + (c & 127);
26+
}
27+
*varint_len = buf - bufp;
28+
return val;
29+
}
30+
31+
int git_encode_varint(unsigned char *buf, size_t bufsize, uintmax_t value)
32+
{
33+
unsigned char varint[16];
34+
unsigned pos = sizeof(varint) - 1;
35+
varint[pos] = value & 127;
36+
while (value >>= 7)
37+
varint[--pos] = 128 | (--value & 127);
38+
if (buf) {
39+
if (bufsize < pos)
40+
return -1;
41+
memcpy(buf, varint + pos, sizeof(varint) - pos);
42+
}
43+
return sizeof(varint) - pos;
44+
}

src/varint.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
#ifndef INCLUDE_varint_h__
8+
#define INCLUDE_varint_h__
9+
10+
#include <stdint.h>
11+
12+
extern int git_encode_varint(unsigned char *, size_t, uintmax_t);
13+
extern uintmax_t git_decode_varint(const unsigned char *, size_t *);
14+
15+
#endif

tests/core/encoding.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "clar_libgit2.h"
2+
#include "varint.h"
3+
4+
void test_core_encoding__decode(void)
5+
{
6+
const unsigned char *buf = (unsigned char *)"AB";
7+
size_t size;
8+
9+
cl_assert(git_decode_varint(buf, &size) == 65);
10+
cl_assert(size == 1);
11+
12+
buf = (unsigned char *)"\xfe\xdc\xbaXY";
13+
cl_assert(git_decode_varint(buf, &size) == 267869656);
14+
cl_assert(size == 4);
15+
16+
buf = (unsigned char *)"\xaa\xaa\xfe\xdc\xbaXY";
17+
cl_assert(git_decode_varint(buf, &size) == 1489279344088ULL);
18+
cl_assert(size == 6);
19+
20+
buf = (unsigned char *)"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xfe\xdc\xbaXY";
21+
cl_assert(git_decode_varint(buf, &size) == 0);
22+
cl_assert(size == 0);
23+
24+
}
25+
26+
void test_core_encoding__encode(void)
27+
{
28+
unsigned char buf[100];
29+
cl_assert(git_encode_varint(buf, 100, 65) == 1);
30+
cl_assert(buf[0] == 'A');
31+
32+
cl_assert(git_encode_varint(buf, 100, 267869656) == 4);
33+
cl_assert(!memcmp(buf, "\xfe\xdc\xbaX", 4));
34+
35+
cl_assert(git_encode_varint(buf, 100, 1489279344088ULL) == 6);
36+
cl_assert(!memcmp(buf, "\xaa\xaa\xfe\xdc\xbaX", 6));
37+
38+
cl_assert(git_encode_varint(buf, 1, 1489279344088ULL) == -1);
39+
}

0 commit comments

Comments
 (0)