Example
[apps/agl-service-can-low-level.git] / pb_decode.c
index e2888f2..2cde54c 100644 (file)
@@ -62,15 +62,15 @@ pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
  * Helper functions *
  ********************/
 
-bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
+static bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
 {
     uint64_t temp;
-    bool status = pb_decode_varint64(stream, &temp);
+    bool status = pb_decode_varint(stream, &temp);
     *dest = temp;
     return status;
 }
 
-bool pb_decode_varint64(pb_istream_t *stream, uint64_t *dest)
+bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
 {
     uint8_t byte;
     int bitpos = 0;
@@ -108,7 +108,7 @@ bool pb_skip_string(pb_istream_t *stream)
     return pb_read(stream, NULL, length);
 }
 
-/* Currently all wire type related stuff is kept hidden from
+/* Currently the wire type related stuff is kept hidden from
  * callbacks. They shouldn't need it. It's better for performance
  * to just assume the correct type and fail safely on corrupt message.
  */
@@ -185,13 +185,19 @@ static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, v
 {
     iter->start = iter->current = fields;
     iter->field_index = 0;
-    iter->pData = dest_struct;
+    iter->pData = dest_struct + iter->current->data_offset;
+    iter->pSize = (char*)iter->pData + iter->current->size_offset;
     iter->dest_struct = dest_struct;
 }
 
 static bool pb_field_next(pb_field_iterator_t *iter)
 {
     bool notwrapped = true;
+    size_t prev_size = iter->current->data_size;
+    
+    if (PB_HTYPE(iter->current->type) == PB_HTYPE_ARRAY)
+        prev_size *= iter->current->array_size;
+    
     iter->current++;
     iter->field_index++;
     if (iter->current->tag == 0)
@@ -199,10 +205,11 @@ static bool pb_field_next(pb_field_iterator_t *iter)
         iter->current = iter->start;
         iter->field_index = 0;
         iter->pData = iter->dest_struct;
+        prev_size = 0;
         notwrapped = false;
     }
     
-    iter->pData = (char*)iter->pData + iter->current->data_offset;
+    iter->pData = (char*)iter->pData + prev_size + iter->current->data_offset;
     iter->pSize = (char*)iter->pData + iter->current->size_offset;
     return notwrapped;
 }
@@ -224,7 +231,7 @@ static bool pb_field_find(pb_field_iterator_t *iter, int tag)
  * Decode a single field *
  *************************/
 
-bool decode_field(pb_istream_t *stream, int wire_type, pb_field_iterator_t *iter)
+static bool decode_field(pb_istream_t *stream, int wire_type, pb_field_iterator_t *iter)
 {
     pb_decoder_t func = PB_DECODERS[PB_LTYPE(iter->current->type)];
     
@@ -269,9 +276,14 @@ bool decode_field(pb_istream_t *stream, int wire_type, pb_field_iterator_t *iter
             }
         
         case PB_HTYPE_CALLBACK:
+        {
+            pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
+            
+            if (pCallback->funcs.decode == NULL)
+                return skip(stream, wire_type);
+            
             if (wire_type == PB_WT_STRING)
             {
-                pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
                 pb_istream_t substream;
                 
                 if (!make_string_substream(stream, &substream))
@@ -291,7 +303,6 @@ bool decode_field(pb_istream_t *stream, int wire_type, pb_field_iterator_t *iter
                  * which in turn allows to use same callback for packed and
                  * not-packed fields. */
                 pb_istream_t substream;
-                pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
                 uint8_t buffer[10];
                 size_t size = sizeof(buffer);
                 
@@ -301,7 +312,8 @@ bool decode_field(pb_istream_t *stream, int wire_type, pb_field_iterator_t *iter
                 
                 return pCallback->funcs.decode(&substream, iter->current, pCallback->arg);
             }
-            
+        }
+        
         default:
             return false;
     }
@@ -342,6 +354,10 @@ bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struc
         {
             *(size_t*)iter.pSize = 0;
         }
+        else if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED)
+        {
+            memset(iter.pData, 0, iter.current->data_size);
+        }
     } while (pb_field_next(&iter));
     
     while (stream->bytes_left)
@@ -349,7 +365,15 @@ bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struc
         uint32_t temp;
         int tag, wire_type;
         if (!pb_decode_varint32(stream, &temp))
-            return stream->bytes_left == 0; /* Was it EOF? */
+        {
+            if (stream->bytes_left == 0)
+                break; /* It was EOF */
+            else
+                return false; /* It was error */
+        }
+        
+        if (temp == 0)
+            break; /* Special feature: allow 0-terminated messages. */
         
         tag = temp >> 3;
         wire_type = temp & 7;
@@ -399,7 +423,7 @@ static void endian_copy(void *dest, void *src, size_t destsize, size_t srcsize)
 bool pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
 {
     uint64_t temp;
-    bool status = pb_decode_varint64(stream, &temp);
+    bool status = pb_decode_varint(stream, &temp);
     endian_copy(dest, &temp, field->data_size, sizeof(temp));
     return status;
 }
@@ -407,7 +431,7 @@ bool pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
 bool pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
 {
     uint64_t temp;
-    bool status = pb_decode_varint64(stream, &temp);
+    bool status = pb_decode_varint(stream, &temp);
     temp = (temp >> 1) ^ -(int64_t)(temp & 1);
     endian_copy(dest, &temp, field->data_size, sizeof(temp));
     return status;