diff --git a/.cproject b/.cproject
new file mode 100644
index 0000000..40ef94d
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ make
+
+ all
+ true
+ false
+ true
+
+
+ make
+
+ clean
+ true
+ false
+ true
+
+
+ make
+
+ rebuild
+ true
+ false
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..46d242b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*
+
+!.gitignore
+!Makefile
+!**/
+
+*.o
+.settings/language.settings.xml
+test_protobuf
diff --git a/.project b/.project
new file mode 100644
index 0000000..3cd7414
--- /dev/null
+++ b/.project
@@ -0,0 +1,26 @@
+
+
+ protobuf-c
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a65253d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CC = gcc
+CFLAGS = -O0 -g3 -Wall
+LFLAGS =
+DEPS = protobuf.h
+OBJS = testit.o protobuf.o varint.o Test1_protobuf.o Test2_protobuf.o
+
+%.o: %.c $(DEPS)
+ $(CC) -c -o $@ $< $(CFLAGS)
+
+test_protobuf: $(OBJS)
+ $(CC) -o $@ $^ $(LFLAGS)
+
+all: test_protobuf
+
+clean:
+ rm -f *.o
+ rm -f test_protobuf
+
+rebuild: clean all
\ No newline at end of file
diff --git a/Test1_protobuf.c b/Test1_protobuf.c
new file mode 100644
index 0000000..ad083dc
--- /dev/null
+++ b/Test1_protobuf.c
@@ -0,0 +1,49 @@
+#include
+#include
+#include
+#include "protobuf.h"
+#include "varint.h"
+#include "Test1_protobuf.h"
+
+enum WireType Test1_message_fields[] = { WIRETYPE_VARINT };
+
+int Test1_new(struct Test1** test1) {
+ *test1 = (struct Test1*)malloc(sizeof(struct Test1));
+ if (*test1 == NULL)
+ return 0;
+ (*test1)->a = 0;
+ return 1;
+}
+
+int Test1_free(struct Test1* test1) {
+ free(test1);
+ return 1;
+}
+
+int Test1_protobuf_encode(struct Test1* incoming, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
+ protobuf_encode_varint(1, Test1_message_fields[0], incoming->a, buffer, max_buffer_length, bytes_written);
+ return 1;
+}
+
+int Test1_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Test1** output) {
+ int pos = 0;
+ if (Test1_new(output) == 0)
+ return 0;
+
+ while (pos < buffer_length) { // loop through buffer
+ size_t bytes_read = 0;
+ int field_no;
+ enum WireType field_type;
+ if (protobuf_decode_field_and_type(buffer, buffer_length, &field_no, &field_type, &bytes_read) == 0) {
+ Test1_free(*output);
+ return 0;
+ }
+ switch (field_no) {
+ case (1):
+ (*output)->a = varint_decode(&buffer[pos], buffer_length - pos, &bytes_read);
+ pos += (unsigned int)bytes_read;
+ break;
+ }
+ }
+ return 1;
+}
diff --git a/Test1_protobuf.h b/Test1_protobuf.h
new file mode 100644
index 0000000..f433638
--- /dev/null
+++ b/Test1_protobuf.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "protobuf.h"
+
+struct Test1 {
+ int a;
+};
+
+int Test1_new(struct Test1** test1);
+int Test1_free(struct Test1* test1);
+
+int Test1_protobuf_encode(struct Test1* incoming, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written);
+int Test1_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Test1** output);
diff --git a/Test2_protobuf.c b/Test2_protobuf.c
new file mode 100644
index 0000000..af60dfd
--- /dev/null
+++ b/Test2_protobuf.c
@@ -0,0 +1,79 @@
+#include
+#include
+#include
+#include "protobuf.h"
+#include "varint.h"
+#include "Test2_protobuf.h"
+
+enum WireType Test2_message_fields[] = { WIRETYPE_LENGTH_DELIMITED };
+
+/**
+ * Allocate resources for this structure
+ * @param test2 the structure
+ * @returns true(1) on success
+ */
+int Test2_new(struct Test2** test2) {
+ *test2 = (struct Test2*)malloc(sizeof(struct Test2));
+ if (*test2 == NULL)
+ return 0;
+ (*test2)->a = NULL;
+
+ return 1;
+}
+
+/**
+ * Free resources
+ * @param test2 the struct
+ * @returns true(1) on success
+ */
+int Test2_free(struct Test2* test2) {
+ if (test2->a != NULL)
+ free(test2->a);
+ free(test2);
+ return 1;
+}
+
+/***
+ * Encode struct into protobuf stream
+ * @param incoming the struct
+ * @param buffer the place to put the stream
+ * @param max_buffer_length the length of the buffer
+ * @param bytes_written the number of bytes used in encoding the stream
+ * @returns true(1) on success
+ */
+int Test2_protobuf_encode(struct Test2* incoming, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
+ if (protobuf_encode_string(1, Test2_message_fields[0], incoming->a, buffer, max_buffer_length, bytes_written) == 0)
+ return 0;
+ return 1;
+}
+
+/***
+ * Decode a buffer into a struct
+ * @param buffer the incoming buffer
+ * @param buffer_length the length of the buffer
+ * @param output the resultant struct
+ * @returns true(1) on success
+ */
+int Test2_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Test2** output) {
+ int pos = 0;
+ if (Test2_new(output) == 0)
+ return 0;
+
+ while (pos < buffer_length) { // loop through buffer
+ size_t bytes_read;
+ int field_no;
+ enum WireType field_type;
+ protobuf_decode_field_and_type(&buffer[pos], buffer_length - pos, &field_no, &field_type, &bytes_read);
+ pos += bytes_read;
+ bytes_read = 0;
+ switch(field_no) {
+ case 1:
+ protobuf_decode_string(&buffer[pos], buffer_length - pos, &((*output)->a), &bytes_read);
+ break;
+ }
+ pos += bytes_read;
+
+ }
+ return 1;
+}
+
diff --git a/Test2_protobuf.h b/Test2_protobuf.h
new file mode 100644
index 0000000..b08bf3e
--- /dev/null
+++ b/Test2_protobuf.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "protobuf.h"
+
+struct Test2 {
+ char* a;
+};
+
+int Test2_protobuf_encode(struct Test2* incoming, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written);
+int Test2_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Test2** output);
+int Test2_free(struct Test2* test2);
+int Test2_new(struct Test2** test2);
diff --git a/protobuf.c b/protobuf.c
new file mode 100644
index 0000000..5ad42ab
--- /dev/null
+++ b/protobuf.c
@@ -0,0 +1,107 @@
+/***
+ * Helper to derived protobuf objects
+ */
+#include
+#include
+
+#include "varint.h"
+#include "protobuf.h"
+
+/***
+ * encode a string into the buffer
+ * @param field_number the field number
+ * @param field_type the field type
+ * @param incoming the string value
+ * @param buffer the pointer to where to place the encoded value
+ * @param max_buffer_length the buffer length remaining
+ * @param bytes_written the number of bytes written
+ * @returns true(1) on success
+ */
+int protobuf_encode_string(int field_number, enum WireType field_type, const char* incoming, unsigned char* buffer,
+ size_t max_buffer_length, size_t* bytes_written) {
+ // push the field number and wire type together
+ unsigned int field_no = field_number << 3;
+ unsigned long long field = field_no | field_type;
+ size_t bytes_processed;
+ // field type & number
+ varint_encode(field, buffer, max_buffer_length, &bytes_processed);
+ *bytes_written += bytes_processed;
+ // field size
+ varint_encode(strlen(incoming), &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_processed);
+ *bytes_written += bytes_processed;
+ // field value
+ memcpy(&buffer[*bytes_written], incoming, strlen(incoming));
+ *bytes_written += strlen(incoming);
+ return 1;
+}
+
+/***
+ * encode a varint into the buffer
+ * @param field_number the field number
+ * @param field_type the field type
+ * @param incoming the value
+ * @param buffer the pointer to where to place the encoded value
+ * @param max_buffer_length the buffer length remaining
+ * @param bytes_written the number of bytes written
+ * @returns true(1) on success
+ */
+int protobuf_encode_varint(int field_number, enum WireType field_type, unsigned long long incoming, unsigned char* buffer,
+ size_t max_buffer_length, size_t* bytes_written) {
+ // push the field number and wire type together
+ unsigned int field_no = field_number << 3;
+ unsigned long long field = field_no | field_type;
+ size_t bytes_processed;
+ // field type & number
+ varint_encode(field, buffer, max_buffer_length, &bytes_processed);
+ *bytes_written += bytes_processed;
+ // field value
+ varint_encode(incoming, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_processed);
+ *bytes_written += bytes_processed;
+ return 1;
+
+}
+
+/**
+ * Pull a string from the protobuf buffer
+ * @param the buffer, positioned at the field size
+ * @param buffer_length the buffer length
+ * @param results the results (NOTE: will allocate memory)
+ * @param bytes_read the number of bytes read
+ * @returns true(1) on success
+ */
+int protobuf_decode_string(const unsigned char* buffer, size_t buffer_length, char** results, size_t* bytes_read) {
+ size_t pos = 0;
+ // grab the field size
+ int length = varint_decode(&buffer[pos], buffer_length - pos, bytes_read);
+ pos += *bytes_read;
+
+ // allocate memory
+ *results = malloc(sizeof(char) * length);
+ if ((*results) == NULL)
+ return 0;
+
+ // copy the string
+ memcpy((*results), &buffer[pos], length);
+ pos += length;
+ *bytes_read = pos;
+
+ return 1;
+}
+
+/***
+ * retrieve field number and field type from current buffer at position 0
+ * @param buffer the incoming buffer
+ * @param buffer_length the length of the buffer
+ * @param field_no the resultant field number
+ * @param field_type the field type
+ * @param bytes_read the number of bytes read from the buffer
+ */
+int protobuf_decode_field_and_type(const unsigned char* buffer, int buffer_length, int *field_no, enum WireType *field_type, size_t* bytes_read) {
+ unsigned long long field = varint_decode(buffer, buffer_length, bytes_read);
+ *field_no = field >> 3;
+ *field_type = field | *field_no;
+ return 1;
+}
+
+
+
diff --git a/protobuf.h b/protobuf.h
new file mode 100644
index 0000000..dee77e5
--- /dev/null
+++ b/protobuf.h
@@ -0,0 +1,69 @@
+/*
+ * protobuf.h
+ *
+ * Created on: Dec 7, 2016
+ * Author: JohnJones
+ */
+
+#ifndef __PROTOBUF_H__
+#define __PROTOBUF_H__
+
+#include
+#include
+
+enum WireType {
+ WIRETYPE_VARINT,
+ WIRETYPE_64BIT,
+ WIRETYPE_LENGTH_DELIMITED,
+ WIRETYPE_START_GROUP,
+ WIRETYPE_END_GROUP,
+ WIRETYPE_32BIT
+};
+
+/***
+ * encode a string into the buffer
+ * @param field_number the field number
+ * @param incoming the string value
+ * @param buffer the pointer to where to place the encoded value
+ * @param max_buffer_length the buffer length remaining
+ * @param bytes_written the number of bytes written
+ * @returns true(1) on success
+ */
+int protobuf_encode_string(int field_number, enum WireType wire_type, const char* incoming, unsigned char* buffer,
+ size_t max_buffer_length, size_t* bytes_written);
+
+/**
+ * Pull a string from the protobuf buffer
+ * @param the buffer, positioned at the field size
+ * @param buffer_length the buffer length
+ * @param results the results (NOTE: will allocate memory)
+ * @param bytes_read the number of bytes read
+ * @returns true(1) on success
+ */
+int protobuf_decode_string(const unsigned char* buffer, size_t buffer_length, char** results, size_t* bytes_read);
+
+/***
+ * encode a varint into the buffer
+ * @param field_number the field number
+ * @param field_type the field type
+ * @param incoming the value
+ * @param buffer the pointer to where to place the encoded value
+ * @param max_buffer_length the buffer length remaining
+ * @param bytes_written the number of bytes written
+ * @returns true(1) on success
+ */
+int protobuf_encode_varint(int field_number, enum WireType field_type, unsigned long long incoming, unsigned char* buffer,
+ size_t max_buffer_length, size_t* bytes_written);
+
+/***
+ * retrieve field number and field type from current buffer at position 0
+ * @param buffer the incoming buffer
+ * @param buffer_length the length of the buffer
+ * @param field_no the resultant field number
+ * @param field_type the field type
+ * @param bytes_read the number of bytes read from the buffer
+ */
+int protobuf_decode_field_and_type(const unsigned char* buffer, int buffer_length, int *field_no, enum WireType *field_type, size_t* bytes_read);
+
+
+#endif /* PROTOBUF_H_ */
diff --git a/test_protobuf.h b/test_protobuf.h
new file mode 100644
index 0000000..47bec42
--- /dev/null
+++ b/test_protobuf.h
@@ -0,0 +1,187 @@
+
+/***
+ * This...
+ *
+ * message Test1 {
+ * required int32 a = 1;
+ * }
+ *
+ * should generate Test1_protobuf.h and c that contains this...
+ *
+ * enum WireType Test1_message_fields[] = { WIRETYPE_VARINT }
+ *
+ * struct Test1 {
+ * int a;
+ * }
+ *
+ * int Test1_protobuf_encode(struct Test1* incoming, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written);
+ * int Test1_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Test1** output);
+ */
+
+#include "Test1_protobuf.h"
+#include "Test2_protobuf.h"
+
+int test_rightshift() {
+ struct Test1 test1;
+ test1.a = 0;
+
+ size_t buffer_size = 256;
+ unsigned char buffer[buffer_size];
+ memset(buffer, 0, 256);
+
+ int retVal = 0;
+ size_t bytes_written = 0;
+ retVal = Test1_protobuf_encode(&test1, buffer, buffer_size, &bytes_written);
+
+ if (retVal == 0) {
+ printf("Error encoding\n");
+ return 0;
+ }
+
+ if (bytes_written != 2) {
+ printf("Incorrect number of bytes written. Expected 2, but got %d\n", retVal);
+ return 0;
+ }
+
+ unsigned int pos0 = buffer[0];
+ unsigned int pos1 = buffer[1];
+
+ if (pos0 != 8) {
+ printf("Results at pos 0 not as expected\n");
+ return 0;
+ }
+
+ if (pos1 != 0) {
+ printf("Results at pos 1 not as expected\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+int test_write_simple() {
+ struct Test1 test1;
+ test1.a = 150;
+
+ size_t buffer_size = 256;
+ unsigned char buffer[buffer_size];
+ memset(buffer, 0, 256);
+
+ int retVal = 0;
+ size_t bytes_written = 0;
+ retVal = Test1_protobuf_encode(&test1, buffer, buffer_size, &bytes_written);
+
+ if (retVal == 0) {
+ printf("Error encoding\n");
+ return 0;
+ }
+
+ if (bytes_written != 3) {
+ printf("Incorrect number of bytes written. Expected 3, but got %d\n", retVal);
+ return 0;
+ }
+
+ unsigned int pos0 = buffer[0];
+ unsigned int pos1 = buffer[1];
+ unsigned int pos2 = buffer[2];
+
+ if (pos0 != 8 || pos1 != 150 || pos2 != 1) {
+ printf("Results not as expected\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+int test_write_negative() {
+ struct Test1 test1;
+ test1.a = -150;
+
+ size_t buffer_size = 256;
+ unsigned char buffer[buffer_size];
+ memset(buffer, 0, 256);
+
+ int retVal = 0;
+ size_t bytes_written = 0;
+ retVal = Test1_protobuf_encode(&test1, buffer, buffer_size, &bytes_written);
+
+ if (retVal == 0) {
+ printf("Error encoding\n");
+ return 0;
+ }
+
+ if (bytes_written != 11) {
+ printf("Incorrect number of bytes written. Expected 11, but got %d\n", retVal);
+ return 0;
+ }
+
+ unsigned int pos0 = buffer[0];
+ unsigned int pos1 = buffer[1];
+ unsigned int pos2 = buffer[2];
+ unsigned int pos3 = buffer[3];
+ unsigned int pos4 = buffer[4];
+ unsigned int pos5 = buffer[5];
+ unsigned int pos6 = buffer[6];
+ unsigned int pos7 = buffer[7];
+ unsigned int pos8 = buffer[8];
+ unsigned int pos9 = buffer[9];
+ unsigned int pos10 = buffer[10];
+
+ if (pos0 != 8 || pos1 != 234 || pos2 != 254
+ || pos3 != 255 || pos4 != 255 || pos5 != 255 || pos6 != 255
+ || pos7 != 255 || pos8 != 255 || pos9 != 255 || pos10 != 1
+ ) {
+ printf("Results not as expected\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+int test_write_string() {
+ struct Test2 test2;
+ test2.a = "testing";
+
+ size_t buffer_size = 256;
+ unsigned char buffer[buffer_size];
+ memset(buffer, 0, 256);
+
+ int retVal = 0;
+ size_t bytes_written = 0;
+
+ retVal = Test2_protobuf_encode(&test2, buffer, buffer_size, &bytes_written);
+
+ if (retVal == 0) {
+ printf("Error encoding\n");
+ return 0;
+ }
+
+ if (bytes_written != 9) {
+ printf("Incorrect number of bytes written. Expected 9, but got %d\n", retVal);
+ return 0;
+ }
+
+ unsigned char expected[] = { 10, 7, 't', 'e', 's', 't', 'i', 'n', 'g' };
+
+ int correct = 1;
+ for(int i = 0; i < 9; i++) {
+ if (expected[i] != buffer[i]) {
+ correct = 0;
+ printf("Incorrect value at position %d... Expected %02x but received %02x.\n", i, expected[i], buffer[i]);
+ }
+ }
+ if (!correct)
+ return 0;
+
+ struct Test2* test_results;
+ Test2_protobuf_decode(buffer, bytes_written, &test_results);
+ if (strcmp(test2.a, test_results->a) != 0) {
+ printf("Strings do not match. %s vs %s", test2.a, test_results->a);
+ Test2_free(test_results);
+ return 0;
+ }
+
+ Test2_free(test_results);
+
+ return 1;
+}
diff --git a/test_varint.h b/test_varint.h
new file mode 100644
index 0000000..42f2e53
--- /dev/null
+++ b/test_varint.h
@@ -0,0 +1,37 @@
+#include "varint.h"
+
+int test_varint() {
+
+ unsigned long long ull = 150;
+ size_t buffer_size = 256;
+ unsigned char buffer[buffer_size];
+
+ memset(buffer, 0, 256);
+
+ size_t results;
+ varint_encode(ull, buffer, buffer_size, &results);
+
+ unsigned int pos0 = (unsigned int)buffer[0];
+ unsigned int pos1 = (unsigned int)buffer[1];
+
+ if ( pos0 != 150) {
+ printf("Expected %d but got %d at position 0\n", 150, pos0);
+ return 0;
+ }
+
+ if (pos1 != 1) {
+ printf("Expected %d but got %d at position 1\n", 2, pos1);
+ return 0;
+ }
+
+ // now do the reverse
+
+ unsigned long long newVal = varint_decode(buffer, (int)results, &results);
+
+ if (newVal != ull) {
+ printf("Expected %llu but received %llu\n", ull, newVal);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/testit.c b/testit.c
new file mode 100644
index 0000000..a510f65
--- /dev/null
+++ b/testit.c
@@ -0,0 +1,74 @@
+#include
+#include
+
+#include "test_protobuf.h"
+#include "test_varint.h"
+
+int testit(const char* name, int (*func)(void)) {
+ printf("Testing %s...\n", name);
+ int retVal = func();
+ if (retVal)
+ printf("%s success!\n", name);
+ else
+ printf("** Uh oh! %s failed.**\n", name);
+ return retVal == 0;
+}
+
+const char* names[] = {
+ "test_write_simple",
+ "test_write_negative",
+ "test_write_string",
+ "test_rightshift",
+ "test_varint"
+};
+
+int (*funcs[])(void) = {
+ test_write_simple,
+ test_write_negative,
+ test_write_string,
+ test_rightshift,
+ test_varint
+};
+
+/**
+ * run 1 test or run all
+ */
+int main(int argc, char** argv) {
+ int counter = 0;
+ int tests_ran = 0;
+ char* test_wanted;
+ int only_one = 0;
+ if(argc > 1) {
+ only_one = 1;
+ if (argv[1][0] == '\'') { // some shells put quotes around arguments
+ argv[1][strlen(argv[1])-1] = 0;
+ test_wanted = &(argv[1][1]);
+ }
+ else
+ test_wanted = argv[1];
+ }
+ int array_length = sizeof(funcs) / sizeof(funcs[0]);
+ for (int i = 0; i < array_length; i++) {
+ if (only_one && strcmp(names[i], test_wanted) == 0) {
+ tests_ran++;
+ counter += testit(names[i], funcs[i]);
+ }
+ else
+ if (!only_one) {
+ tests_ran++;
+ counter += testit(names[i], funcs[i]);
+ }
+
+ }
+
+ if (tests_ran == 0)
+ printf("***** No tests found *****\n");
+ else {
+ if (counter > 0) {
+ printf("***** There were %d failed test(s) *****\n", counter);
+ } else {
+ printf("All %d tests passed\n", tests_ran);
+ }
+ }
+ return 1;
+}
diff --git a/varint.c b/varint.c
new file mode 100644
index 0000000..3294515
--- /dev/null
+++ b/varint.c
@@ -0,0 +1,80 @@
+#include
+#include "varint.h"
+
+static const char MSB = 0x80;
+static const char MSBALL = ~0x7F;
+
+static const unsigned long long N1 = 128; // 2 ^ 7
+static const unsigned long long N2 = 16384;
+static const unsigned long long N3 = 2097152;
+static const unsigned long long N4 = 268435456;
+static const unsigned long long N5 = 34359738368;
+static const unsigned long long N6 = 4398046511104;
+static const unsigned long long N7 = 562949953421312;
+static const unsigned long long N8 = 72057594037927936;
+static const unsigned long long N9 = 9223372036854775808U;
+
+int varint_encoding_length(unsigned long long n) {
+ return (
+ n < N1 ? 1
+ : n < N2 ? 2
+ : n < N3 ? 3
+ : n < N4 ? 4
+ : n < N5 ? 5
+ : n < N6 ? 6
+ : n < N7 ? 7
+ : n < N8 ? 8
+ : n < N9 ? 9
+ : 10
+ );
+}
+
+/**
+ * Encode an unsigned long long into a varint
+ * @param n the number to encode
+ * @param buf where to put the results
+ * @param len the length of buf
+ * @param bytes the length written
+ * @returns a pointer to the buf
+ */
+unsigned char* varint_encode(const unsigned long long n, unsigned char* buf, int len, size_t* bytes) {
+ unsigned char* ptr = buf;
+ unsigned long long copy = n;
+
+ while (copy & MSBALL) {
+ *(ptr++) = (copy & 0xFF) | MSB;
+ copy = copy >> 7;
+ assert((ptr - buf) < len);
+ }
+ *ptr = copy;
+ if (bytes != NULL) *bytes = ptr - buf + 1;
+
+ return buf;
+}
+
+/***
+ * decode a varint
+ * @param buf the buffer that contains the varint
+ * @param len the length of the buffer
+ * @param bytes number of bytes processed
+ * @returns the value decoded
+ */
+unsigned long long varint_decode(const unsigned char* buf, int len, size_t* bytes) {
+ unsigned long long result = 0;
+ int bits = 0;
+ const unsigned char* ptr = buf;
+ unsigned long long ll;
+ while (*ptr & MSB) {
+ ll = *ptr;
+ result += ((ll & 0x7F) << bits);
+ ptr++;
+ bits += 7;
+ assert((ptr - buf) < len);
+ }
+ ll = *ptr;
+ result += ((ll & 0x7F) << bits);
+
+ if (bytes != NULL) *bytes = ptr - buf + 1;
+
+ return result;
+}
diff --git a/varint.h b/varint.h
new file mode 100644
index 0000000..8d7d943
--- /dev/null
+++ b/varint.h
@@ -0,0 +1,32 @@
+/***
+ * handles varint
+ */
+#ifndef _VARINT_H_
+#define _VARINT_H_
+#include
+
+/**
+ * Encode an unsigned long long into a varint
+ * @param n the number to encode
+ * @param buf where to put the results
+ * @param len the length of buf
+ * @param bytes the length written
+ * @returns a pointer to the buf
+ */
+unsigned char* varint_encode(const unsigned long long n, unsigned char* buf, int len, size_t* bytes);
+
+/***
+ * decode a varint
+ * @param buf the buffer that contains the varint
+ * @param len the length of the buffer
+ * @param bytes number of bytes processed
+ * @returns the value decoded
+ */
+unsigned long long varint_decode(const unsigned char* buf, int len, size_t* bytes);
+
+/**
+ *
+ */
+int varint_encoding_length(unsigned long long n);
+
+#endif