-
Notifications
You must be signed in to change notification settings - Fork 8
/
protobuf.c
154 lines (133 loc) · 4.91 KB
/
protobuf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/***
* Helper to derived protobuf objects
*/
#include <stdint.h>
#include <string.h>
#include "varint.h"
#include "protobuf.h"
int protobuf_encode_length_delimited(int field_number, enum WireType field_type, const char* incoming, size_t incoming_length,
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 = 0;
*bytes_written = 0;
// field type & number
varint_encode(field, buffer, max_buffer_length, &bytes_processed);
*bytes_written += bytes_processed;
// field size
varint_encode(incoming_length, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_processed);
*bytes_written += bytes_processed;
// field value
if (incoming_length > 0) {
memcpy(&buffer[*bytes_written], incoming, incoming_length);
*bytes_written += incoming_length;
}
return 1;
}
int protobuf_decode_length_delimited(const unsigned char* buffer, size_t buffer_length, char** results, size_t *results_length, size_t* bytes_read) {
size_t pos = 0;
*bytes_read = 0;
// grab the field size
size_t field_size = varint_decode(&buffer[pos], buffer_length - pos, bytes_read);
pos += *bytes_read;
// allocate memory
*results = malloc(sizeof(char) * field_size);
if ((*results) == NULL)
return 0;
memset(*results, 0, field_size);
// copy the bytes
memcpy( *results, &buffer[pos], field_size);
pos += field_size;
// set return values
*bytes_read = pos;
*results_length = field_size;
return 1;
}
/***
* 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) {
return protobuf_encode_length_delimited(field_number, field_type, incoming, strlen(incoming), buffer, max_buffer_length, bytes_written);
}
/***
* 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) {
*bytes_written = 0;
// 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;
}
int protobuf_decode_varint(const unsigned char* buffer, size_t buffer_length, unsigned long long* results, size_t* bytes_read) {
*results = varint_decode(buffer, buffer_length, bytes_read);
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;
*bytes_read = 0;
// grab the field size
int length = varint_decode(&buffer[pos], buffer_length - pos, bytes_read);
pos += *bytes_read;
*bytes_read += length;
// allocate memory (if neccesary)
if (length > 0) {
*results = malloc(sizeof(char) * length + 1);
if ((*results) == NULL)
return 0;
memset(*results, 0, length+1);
// copy the string
memcpy((*results), &buffer[pos], length);
// don't forget the null
(*results)[length] = 0;
}
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) {
*bytes_read = 0;
unsigned long long field = varint_decode(buffer, buffer_length, bytes_read);
*field_no = field >> 3;
*field_type = field - (*field_no << 3);
return 1;
}