+#ifdef PB_ENABLE_MALLOC
+void pb_release(const pb_field_t fields[], void *dest_struct)
+{
+ pb_field_iterator_t iter;
+ pb_field_init(&iter, fields, dest_struct);
+
+ do
+ {
+ pb_type_t type;
+ type = iter.pos->type;
+
+ /* Avoid crash on empty message types (zero fields) */
+ if (iter.pos->tag == 0)
+ continue;
+
+ if (PB_ATYPE(type) == PB_ATYPE_POINTER)
+ {
+ if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
+ (PB_LTYPE(type) == PB_LTYPE_STRING ||
+ PB_LTYPE(type) == PB_LTYPE_BYTES))
+ {
+ /* Release entries in repeated string or bytes array */
+ void **pItem = *(void***)iter.pData;
+ size_t count = *(size_t*)iter.pSize;
+ while (count--)
+ {
+ pb_free(*pItem);
+ *pItem++ = NULL;
+ }
+ }
+ else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+ {
+ /* Release fields in submessages */
+ void *pItem = *(void**)iter.pData;
+ size_t count = (pItem ? 1 : 0);
+
+ if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
+ {
+ count = *(size_t*)iter.pSize;
+ }
+
+ while (count--)
+ {
+ pb_release((const pb_field_t*)iter.pos->ptr, pItem);
+ pItem = (uint8_t*)pItem + iter.pos->data_size;
+ }
+ }
+
+ /* Release main item */
+ pb_free(*(void**)iter.pData);
+ *(void**)iter.pData = NULL;
+ }
+ } while (pb_field_next(&iter));
+}
+#endif
+