Add inline allocation of bytes fields
[apps/agl-service-can-low-level.git] / pb_decode.c
index b7a0093..7a4e29a 100644 (file)
@@ -65,7 +65,8 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
     &pb_dec_bytes,
     &pb_dec_string,
     &pb_dec_submessage,
-    NULL /* extensions */
+    NULL, /* extensions */
+    &pb_dec_bytes /* PB_LTYPE_FIXED_LENGTH_BYTES */
 };
 
 /*******************************
@@ -1035,6 +1036,12 @@ static void pb_release_single_field(const pb_field_iter_t *iter)
         if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
         {
             count = *(pb_size_t*)iter->pSize;
+
+            if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size)
+            {
+                /* Protect against corrupted _count fields */
+                count = iter->pos->array_size;
+            }
         }
         
         if (pItem)
@@ -1155,19 +1162,22 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *fi
      * not break decoding of such messages, we cast <=32 bit fields to
      * int32_t first to get the sign correct.
      */
-    if (field->data_size == 8)
+    if (field->data_size == sizeof(int64_t))
         svalue = (int64_t)value;
     else
         svalue = (int32_t)value;
 
-    switch (field->data_size)
-    {
-        case 1: clamped = *(int8_t*)dest = (int8_t)svalue; break;
-        case 2: clamped = *(int16_t*)dest = (int16_t)svalue; break;
-        case 4: clamped = *(int32_t*)dest = (int32_t)svalue; break;
-        case 8: clamped = *(int64_t*)dest = svalue; break;
-        default: PB_RETURN_ERROR(stream, "invalid data_size");
-    }
+    /* Cast to the proper field size, while checking for overflows */
+    if (field->data_size == sizeof(int64_t))
+        clamped = *(int64_t*)dest = svalue;
+    else if (field->data_size == sizeof(int32_t))
+        clamped = *(int32_t*)dest = (int32_t)svalue;
+    else if (field->data_size == sizeof(int_least16_t))
+        clamped = *(int_least16_t*)dest = (int_least16_t)svalue;
+    else if (field->data_size == sizeof(int_least8_t))
+        clamped = *(int_least8_t*)dest = (int_least8_t)svalue;
+    else
+        PB_RETURN_ERROR(stream, "invalid data_size");
 
     if (clamped != svalue)
         PB_RETURN_ERROR(stream, "integer too large");
@@ -1181,14 +1191,17 @@ static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *f
     if (!pb_decode_varint(stream, &value))
         return false;
     
-    switch (field->data_size)
-    {
-        case 1: clamped = *(uint_least8_t*)dest = (uint_least8_t)value; break;
-        case 2: clamped = *(uint_least16_t*)dest = (uint_least16_t)value; break;
-        case 4: clamped = *(uint32_t*)dest = (uint32_t)value; break;
-        case 8: clamped = *(uint64_t*)dest = value; break;
-        default: PB_RETURN_ERROR(stream, "invalid data_size");
-    }
+    /* Cast to the proper field size, while checking for overflows */
+    if (field->data_size == sizeof(uint64_t))
+        clamped = *(uint64_t*)dest = value;
+    else if (field->data_size == sizeof(uint32_t))
+        clamped = *(uint32_t*)dest = (uint32_t)value;
+    else if (field->data_size == sizeof(uint_least16_t))
+        clamped = *(uint_least16_t*)dest = (uint_least16_t)value;
+    else if (field->data_size == sizeof(uint_least8_t))
+        clamped = *(uint_least8_t*)dest = (uint_least8_t)value;
+    else
+        PB_RETURN_ERROR(stream, "invalid data_size");
     
     if (clamped != value)
         PB_RETURN_ERROR(stream, "integer too large");
@@ -1202,14 +1215,17 @@ static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *f
     if (!pb_decode_svarint(stream, &value))
         return false;
     
-    switch (field->data_size)
-    {
-        case 1: clamped = *(int_least8_t*)dest = (int_least8_t)value; break;
-        case 2: clamped = *(int_least16_t*)dest = (int_least16_t)value; break;
-        case 4: clamped = *(int32_t*)dest = (int32_t)value; break;
-        case 8: clamped = *(int64_t*)dest = value; break;
-        default: PB_RETURN_ERROR(stream, "invalid data_size");
-    }
+    /* Cast to the proper field size, while checking for overflows */
+    if (field->data_size == sizeof(int64_t))
+        clamped = *(int64_t*)dest = value;
+    else if (field->data_size == sizeof(int32_t))
+        clamped = *(int32_t*)dest = (int32_t)value;
+    else if (field->data_size == sizeof(int_least16_t))
+        clamped = *(int_least16_t*)dest = (int_least16_t)value;
+    else if (field->data_size == sizeof(int_least8_t))
+        clamped = *(int_least8_t*)dest = (int_least8_t)value;
+    else
+        PB_RETURN_ERROR(stream, "invalid data_size");
 
     if (clamped != value)
         PB_RETURN_ERROR(stream, "integer too large");
@@ -1257,6 +1273,12 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
     }
     else
     {
+        if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES) {
+            if (size != field->data_size)
+                PB_RETURN_ERROR(stream, "incorrect inline bytes size");
+            return pb_read(stream, (pb_byte_t*)dest, field->data_size);
+        }
+
         if (alloc_size > field->data_size)
             PB_RETURN_ERROR(stream, "bytes overflow");
         bdest = (pb_bytes_array_t*)dest;