protobuf_c_unpack_message():  
Insist that required fields be represented in the packed message.


git-svn-id: http://protobuf-c.googlecode.com/svn/trunk@242 00440858-1255-0410-a3e6-75ea37f81c3a
diff --git a/ChangeLog b/ChangeLog
index f4b29ed..7824285 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,7 +5,9 @@
       - bug in dsk_dispatch_close_fd(), which usually only
         showed up in later function calls.
       - support for deprecated fields -- enable a GCC warning
-        if a field has the "deprecated" option enabled. (Andrey Nigmatulin)
+        if a field has the "deprecated" option enabled. (Andrei Nigmatulin)
+      - fix for protobuf_c_message_unpack() to issue error if any "required" field
+        is missing in input stream. (Andrei Nigmatulin)
 
 0.13:
       - Fix for when the number of connections gets too great in RPC.
diff --git a/src/google/protobuf-c/protobuf-c.c b/src/google/protobuf-c/protobuf-c.c
index 0b050b8..4e4094f 100644
--- a/src/google/protobuf-c/protobuf-c.c
+++ b/src/google/protobuf-c/protobuf-c.c
@@ -2103,11 +2103,20 @@
   size_t n_unknown = 0;
   unsigned f;
   unsigned i_slab;
+  unsigned last_field_index = 0;
+  unsigned long *required_fields_bitmap;
+  unsigned required_fields_bitmap_len;
+  static const unsigned word_bits = sizeof(long) * 8;
 
   ASSERT_IS_MESSAGE_DESCRIPTOR (desc);
 
   if (allocator == NULL)
     allocator = &protobuf_c_default_allocator;
+
+  required_fields_bitmap_len = (desc->n_fields + word_bits - 1) / word_bits;
+  required_fields_bitmap = alloca(required_fields_bitmap_len * sizeof(long));
+  memset(required_fields_bitmap, 0, required_fields_bitmap_len * sizeof(long));
+
   DO_ALLOC (rv, allocator, desc->sizeof_message, return NULL);
   scanned_member_slabs[0] = first_member_slab;
 
@@ -2150,11 +2159,15 @@
             {
               field = desc->fields + field_index;
               last_field = field;
+              last_field_index = field_index;
             }
         }
       else
         field = last_field;
 
+      if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED)
+        required_fields_bitmap[last_field_index / word_bits] |= (1UL << (last_field_index % word_bits));
+
       at += used;
       rem -= used;
       tmp.tag = tag;
@@ -2258,11 +2271,12 @@
       rem -= tmp.len;
     }
 
-  /* allocate space for repeated fields */
+  /* allocate space for repeated fields, also check that all required fields have been set */
   for (f = 0; f < desc->n_fields; f++)
-    if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED)
-      {
-        const ProtobufCFieldDescriptor *field = desc->fields + f;
+  {
+    const ProtobufCFieldDescriptor *field = desc->fields + f;
+    if (field->label == PROTOBUF_C_LABEL_REPEATED)
+    {
         size_t siz = sizeof_elt_in_repeated_array (field->type);
         size_t *n_ptr = STRUCT_MEMBER_PTR (size_t, rv, field->quantifier_offset);
         if (*n_ptr != 0)
@@ -2282,7 +2296,16 @@
                       CLEAR_REMAINING_N_PTRS (); goto error_cleanup);
 #undef CLEAR_REMAINING_N_PTRS
           }
+    }
+    else if (field->label == PROTOBUF_C_LABEL_REQUIRED)
+    {
+      if (field->default_value == NULL && 0 == (required_fields_bitmap[f / word_bits] & (1UL << (f % word_bits))))
+      {
+        UNPACK_ERROR (("message '%s': missing required field '%s'", desc->name, field->name));
+        goto error_cleanup;
       }
+    }
+  }
 
   /* allocate space for unknown fields */
   if (n_unknown)