95223cb67c775c65f3e2ae2dfdc562cdd29b225c
[apps/agl-service-can-low-level.git] / pb_encode.c
1 /* pb_encode.c -- encode a protobuf using minimal resources
2  *
3  * 2011 Petteri Aimonen <jpa@kapsi.fi>
4  */
5
6 #define NANOPB_INTERNALS
7 #include "pb.h"
8 #include "pb_encode.h"
9 #include <string.h>
10
11 /* The warn_unused_result attribute appeared first in gcc-3.4.0 */
12 #if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
13     #define checkreturn
14 #else
15     /* Verify that we remember to check all return values for proper error propagation */
16     #define checkreturn __attribute__((warn_unused_result))
17 #endif
18
19 typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
20
21 /* --- Function pointers to field encoders ---
22  * Order in the array must match pb_action_t LTYPE numbering.
23  */
24 static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
25     &pb_enc_varint,
26     &pb_enc_svarint,
27     &pb_enc_fixed32,
28     &pb_enc_fixed64,
29     
30     &pb_enc_bytes,
31     &pb_enc_string,
32     &pb_enc_submessage
33 };
34
35 /* pb_ostream_t implementation */
36
37 static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
38 {
39     uint8_t *dest = (uint8_t*)stream->state;
40     stream->state = dest + count;
41     
42     while (count--)
43         *dest++ = *buf++;
44     
45     return true;
46 }
47
48 pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
49 {
50     pb_ostream_t stream;
51     stream.callback = &buf_write;
52     stream.state = buf;
53     stream.max_size = bufsize;
54     stream.bytes_written = 0;
55     return stream;
56 }
57
58 bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
59 {
60     if (stream->callback != NULL)
61     {
62         if (stream->bytes_written + count > stream->max_size)
63             return false;
64         
65         if (!stream->callback(stream, buf, count))
66             return false;
67     }
68     
69     stream->bytes_written += count;
70     return true;
71 }
72
73 /* Main encoding stuff */
74
75 /* Callbacks don't need this function because they usually know the data type
76  * without examining the field structure.
77  * Therefore it is static for now.
78  */
79 static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
80                          const void *pData, size_t count, pb_encoder_t func)
81 {
82     size_t i;
83     const void *p;
84     size_t size;
85     
86     if (count == 0)
87         return true;
88     
89     if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
90     {
91         if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
92             return false;
93         
94         /* Determine the total size of packed array. */
95         if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
96         {
97             size = 4 * count;
98         }
99         else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
100         {
101             size = 8 * count;
102         }
103         else
104         {
105             pb_ostream_t sizestream = {0,0,0,0};
106             p = pData;
107             for (i = 0; i < count; i++)
108             {
109                 if (!func(&sizestream, field, p))
110                     return false;
111                 p = (const char*)p + field->data_size;
112             }
113             size = sizestream.bytes_written;
114         }
115         
116         if (!pb_encode_varint(stream, (uint64_t)size))
117             return false;
118         
119         if (stream->callback == NULL)
120             return pb_write(stream, NULL, size); /* Just sizing.. */
121         
122         /* Write the data */
123         p = pData;
124         for (i = 0; i < count; i++)
125         {
126             if (!func(stream, field, p))
127                 return false;
128             p = (const char*)p + field->data_size;
129         }
130     }
131     else
132     {
133         p = pData;
134         for (i = 0; i < count; i++)
135         {
136             if (!pb_encode_tag_for_field(stream, field))
137                 return false;
138             if (!func(stream, field, p))
139                 return false;
140             p = (const char*)p + field->data_size;
141         }
142     }
143     
144     return true;
145 }
146
147 bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
148 {
149     const pb_field_t *field = fields;
150     const void *pData = src_struct;
151     const void *pSize;
152     size_t prev_size = 0;
153     
154     while (field->tag != 0)
155     {
156         pb_encoder_t func = PB_ENCODERS[PB_LTYPE(field->type)];
157         pData = (const char*)pData + prev_size + field->data_offset;
158         pSize = (const char*)pData + field->size_offset;
159         
160         prev_size = field->data_size;
161         if (PB_HTYPE(field->type) == PB_HTYPE_ARRAY)
162             prev_size *= field->array_size;
163                 
164         switch (PB_HTYPE(field->type))
165         {
166             case PB_HTYPE_REQUIRED:
167                 if (!pb_encode_tag_for_field(stream, field))
168                     return false;
169                 if (!func(stream, field, pData))
170                     return false;
171                 break;
172             
173             case PB_HTYPE_OPTIONAL:
174                 if (*(const bool*)pSize)
175                 {
176                     if (!pb_encode_tag_for_field(stream, field))
177                         return false;
178                 
179                     if (!func(stream, field, pData))
180                         return false;
181                 }
182                 break;
183             
184             case PB_HTYPE_ARRAY:
185                 if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
186                     return false;
187                 break;
188             
189             case PB_HTYPE_CALLBACK:
190             {
191                 const pb_callback_t *callback = (const pb_callback_t*)pData;
192                 if (callback->funcs.encode != NULL)
193                 {
194                     if (!callback->funcs.encode(stream, field, callback->arg))
195                         return false;
196                 }
197                 break;
198             }
199         }
200     
201         field++;
202     }
203     
204     return true;
205 }
206
207 /* Helper functions */
208 bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
209 {
210     uint8_t buffer[10];
211     size_t i = 0;
212     
213     if (value == 0)
214         return pb_write(stream, (uint8_t*)&value, 1);
215     
216     while (value)
217     {
218         buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
219         value >>= 7;
220         i++;
221     }
222     buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
223     
224     return pb_write(stream, buffer, i);
225 }
226
227 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
228 {
229     uint64_t zigzagged;
230     if (value < 0)
231         zigzagged = (uint64_t)(~(value << 1));
232     else
233         zigzagged = (uint64_t)(value << 1);
234     
235     return pb_encode_varint(stream, zigzagged);
236 }
237
238 bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
239 {
240     #ifdef __BIG_ENDIAN__
241     const uint8_t *bytes = value;
242     uint8_t lebytes[4];
243     lebytes[0] = bytes[3];
244     lebytes[1] = bytes[2];
245     lebytes[2] = bytes[1];
246     lebytes[3] = bytes[0];
247     return pb_write(stream, lebytes, 4);
248     #else
249     return pb_write(stream, (const uint8_t*)value, 4);
250     #endif
251 }
252
253 bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
254 {
255     #ifdef __BIG_ENDIAN__
256     const uint8_t *bytes = value;
257     uint8_t lebytes[8];
258     lebytes[0] = bytes[7];
259     lebytes[1] = bytes[6];
260     lebytes[2] = bytes[5];
261     lebytes[3] = bytes[4];
262     lebytes[4] = bytes[3];
263     lebytes[5] = bytes[2];
264     lebytes[6] = bytes[1];
265     lebytes[7] = bytes[0];
266     return pb_write(stream, lebytes, 8);
267     #else
268     return pb_write(stream, (const uint8_t*)value, 8);
269     #endif
270 }
271
272 bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
273 {
274     uint64_t tag = wiretype | (field_number << 3);
275     return pb_encode_varint(stream, tag);
276 }
277
278 bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
279 {
280     pb_wire_type_t wiretype;
281     switch (PB_LTYPE(field->type))
282     {
283         case PB_LTYPE_VARINT:
284         case PB_LTYPE_SVARINT:
285             wiretype = PB_WT_VARINT;
286             break;
287         
288         case PB_LTYPE_FIXED32:
289             wiretype = PB_WT_32BIT;
290             break;
291         
292         case PB_LTYPE_FIXED64:
293             wiretype = PB_WT_64BIT;
294             break;
295         
296         case PB_LTYPE_BYTES:
297         case PB_LTYPE_STRING:
298         case PB_LTYPE_SUBMESSAGE:
299             wiretype = PB_WT_STRING;
300             break;
301         
302         default:
303             return false;
304     }
305     
306     return pb_encode_tag(stream, wiretype, field->tag);
307 }
308
309 bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
310 {
311     if (!pb_encode_varint(stream, (uint64_t)size))
312         return false;
313     
314     return pb_write(stream, buffer, size);
315 }
316
317 bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
318 {
319     /* First calculate the message size using a non-writing substream. */
320     pb_ostream_t substream = {0,0,0,0};
321     size_t size;
322     bool status;
323     
324     if (!pb_encode(&substream, fields, src_struct))
325         return false;
326     
327     size = substream.bytes_written;
328     
329     if (!pb_encode_varint(stream, (uint64_t)size))
330         return false;
331     
332     if (stream->callback == NULL)
333         return pb_write(stream, NULL, size); /* Just sizing */
334     
335     if (stream->bytes_written + size > stream->max_size)
336         return false;
337         
338     /* Use a substream to verify that a callback doesn't write more than
339      * what it did the first time. */
340     substream.callback = stream->callback;
341     substream.state = stream->state;
342     substream.max_size = size;
343     substream.bytes_written = 0;
344     
345     status = pb_encode(&substream, fields, src_struct);
346     
347     stream->bytes_written += substream.bytes_written;
348     stream->state = substream.state;
349     
350     if (substream.bytes_written != size)
351         return false;
352     
353     return status;
354 }
355
356 /* Field encoders */
357
358 bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
359 {
360     uint64_t value = 0;
361     
362     switch (field->data_size)
363     {
364         case 1: value = *(const uint8_t*)src; break;
365         case 2: value = *(const uint16_t*)src; break;
366         case 4: value = *(const uint32_t*)src; break;
367         case 8: value = *(const uint64_t*)src; break;
368         default: return false;
369     }
370     
371     return pb_encode_varint(stream, value);
372 }
373
374 bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
375 {
376     int64_t value = 0;
377     
378     switch (field->data_size)
379     {
380         case 4: value = *(const int32_t*)src; break;
381         case 8: value = *(const int64_t*)src; break;
382         default: return false;
383     }
384     
385     return pb_encode_svarint(stream, value);
386 }
387
388 bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
389 {
390     UNUSED(field);
391     return pb_encode_fixed64(stream, src);
392 }
393
394 bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
395 {
396     UNUSED(field);
397     return pb_encode_fixed32(stream, src);
398 }
399
400 bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
401 {
402     const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
403     UNUSED(field);
404     return pb_encode_string(stream, bytes->bytes, bytes->size);
405 }
406
407 bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
408 {
409     UNUSED(field);
410     return pb_encode_string(stream, (const uint8_t*)src, strlen((const char*)src));
411 }
412
413 bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
414 {
415     if (field->ptr == NULL)
416         return false;
417     
418     return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
419 }
420