/* --- protobuf-c.c: public protobuf c runtime implementation --- *//* * Copyright (c) 2008-2011, Dave Benson. * * All rights reserved. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * Redistributions in binary form must reproduce * the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other * materials provided with the distribution. * * Neither the name * of "protobuf-c" nor the names of its contributors * may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *//* TODO items: * 64-BIT OPTIMIZATION: certain implementations use 32-bit math even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64) * get_packed_size and pack seem to use type-prefixed names, whereas parse uses type-suffixed names. pick one and stick with it. Decision: go with type-suffixed, since the type (or its instance) is typically the object of the verb. NOTE: perhaps the "parse" methods should be reanemd to "unpack" at the same time. (this only affects internal (static) functions) * use TRUE and FALSE instead of 1 and 0 as appropriate * use size_t consistently */#if HAVE_PROTOBUF_C_CONFIG_H#include"protobuf-c-config.h"#endif#include<stdio.h> /* for occasional printf()s */#include<stdlib.h> /* for abort(), malloc() etc */#include<string.h> /* for strlen(), memcpy(), memmove() */#if 0 /* we no longer use alloca. */#if HAVE_ALLOCA_H#include <alloca.h>#elif HAVE_MALLOC_H#include <malloc.h>#endif#endif#ifndef PRINT_UNPACK_ERRORS#define PRINT_UNPACK_ERRORS 1#endif#include"protobuf-c.h"unsignedprotobuf_c_major=PROTOBUF_C_MAJOR;unsignedprotobuf_c_minor=PROTOBUF_C_MINOR;#define MAX_UINT64_ENCODED_SIZE 10/* This should be roughly the biggest message you think you'll encounter. However, the only point of the hashing is to detect uninitialized required members. I doubt many messages have 128 REQUIRED fields, so hopefully this'll be fine. TODO: A better solution is to separately in the descriptor index the required fields, and use the allcoator if the required field count is too big. */#define MAX_MEMBERS_FOR_HASH_SIZE 128/* convenience macros */#define TMPALLOC(allocator, size) ((allocator)->tmp_alloc ((allocator)->allocator_data, (size)))#define FREE(allocator, ptr) \ do { if ((ptr) != NULL) ((allocator)->free ((allocator)->allocator_data, (ptr))); } while(0)#define UNALIGNED_ALLOC(allocator, size) ALLOC (allocator, size) /* placeholder */#define STRUCT_MEMBER_P(struct_p, struct_offset) \ ((void *) ((uint8_t*) (struct_p) + (struct_offset)))#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ (*(member_type*) STRUCT_MEMBER_P ((struct_p), (struct_offset)))#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ ((member_type*) STRUCT_MEMBER_P ((struct_p), (struct_offset)))#define TRUE 1#define FALSE 0staticvoidalloc_failed_warning(unsignedsize,constchar*filename,unsignedline){fprintf(stderr,"WARNING: out-of-memory allocating a block of size %u (%s:%u)\n",size,filename,line);}/* Try to allocate memory, running some special code if it fails. */#define DO_ALLOC(dst, allocator, size, fail_code) \{ size_t da__allocation_size = (size); \ if (da__allocation_size == 0) \ dst = NULL; \ else if ((dst=((allocator)->alloc ((allocator)->allocator_data, \ da__allocation_size))) == NULL) \ { \ alloc_failed_warning (da__allocation_size, __FILE__, __LINE__); \ fail_code; \ } \}#define DO_UNALIGNED_ALLOC DO_ALLOC /* placeholder */#define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ assert((desc)->magic == PROTOBUF_C_ENUM_DESCRIPTOR_MAGIC)#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ assert((desc)->magic == PROTOBUF_C_MESSAGE_DESCRIPTOR_MAGIC)#define ASSERT_IS_MESSAGE(message) \ ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor)#define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ assert((desc)->magic == PROTOBUF_C_SERVICE_DESCRIPTOR_MAGIC)/* --- allocator --- */staticvoidprotobuf_c_out_of_memory_default(void){fprintf(stderr,"Out Of Memory!!!\n");abort();}void(*protobuf_c_out_of_memory)(void)=protobuf_c_out_of_memory_default;staticvoid*system_alloc(void*allocator_data,size_tsize){void*rv;(void)allocator_data;if(size==0)returnNULL;rv=malloc(size);if(rv==NULL)protobuf_c_out_of_memory();returnrv;}staticvoidsystem_free(void*allocator_data,void*data){(void)allocator_data;if(data)free(data);}/* Some users may configure the default allocator; providing your own allocator to unpack() is prefered. this allocator is still used for packing nested messages. */ProtobufCAllocatorprotobuf_c_default_allocator={system_alloc,system_free,NULL,/* tmp_alloc */8192,/* max_alloca */NULL/* allocator_data */};/* Users should NOT modify this structure, but it's difficult to prevent. please modify protobuf_c_default_allocator instead. */ProtobufCAllocatorprotobuf_c_system_allocator={system_alloc,system_free,NULL,/* tmp_alloc */8192,/* max_alloca */NULL/* allocator_data */};/* === buffer-simple === */voidprotobuf_c_buffer_simple_append(ProtobufCBuffer*buffer,size_tlen,constuint8_t*data){ProtobufCBufferSimple*simp=(ProtobufCBufferSimple*)buffer;size_tnew_len=simp->len+len;if(new_len>simp->alloced){size_tnew_alloced=simp->alloced*2;uint8_t*new_data;while(new_alloced<new_len)new_alloced+=new_alloced;DO_ALLOC(new_data,&protobuf_c_default_allocator,new_alloced,return);memcpy(new_data,simp->data,simp->len);if(simp->must_free_data)FREE(&protobuf_c_default_allocator,simp->data);elsesimp->must_free_data=1;simp->data=new_data;simp->alloced=new_alloced;}memcpy(simp->data+simp->len,data,len);simp->len=new_len;}/* === get_packed_size() === *//* Return the number of bytes required to store the tag for the field (which includes 3 bits for the wire-type, and a single bit that denotes the end-of-tag. */staticinlinesize_tget_tag_size(unsignednumber){if(number<(1<<4))return1;elseif(number<(1<<11))return2;elseif(number<(1<<18))return3;elseif(number<(1<<25))return4;elsereturn5;}/* Return the number of bytes required to store a variable-length unsigned integer that fits in 32-bit uint in base-128 encoding. */staticinlinesize_tuint32_size(uint32_tv){if(v<(1<<7))return1;elseif(v<(1<<14))return2;elseif(v<(1<<21))return3;elseif(v<(1<<28))return4;elsereturn5;}/* Return the number of bytes required to store a variable-length signed integer that fits in 32-bit int in base-128 encoding. */staticinlinesize_tint32_size(int32_tv){if(v<0)return10;elseif(v<(1<<7))return1;elseif(v<(1<<14))return2;elseif(v<(1<<21))return3;elseif(v<(1<<28))return4;elsereturn5;}/* return the zigzag-encoded 32-bit unsigned int from a 32-bit signed int */staticinlineuint32_tzigzag32(int32_tv){if(v<0)return((uint32_t)(-v))*2-1;elsereturnv*2;}/* Return the number of bytes required to store a variable-length signed integer that fits in 32-bit int, converted to unsigned via the zig-zag algorithm, then packed using base-128 encoding. */staticinlinesize_tsint32_size(int32_tv){returnuint32_size(zigzag32(v));}/* Return the number of bytes required to store a variable-length unsigned integer that fits in 64-bit uint in base-128 encoding. */staticinlinesize_tuint64_size(uint64_tv){uint32_tupper_v=(uint32_t)(v>>32);if(upper_v==0)returnuint32_size((uint32_t)v);elseif(upper_v<(1<<3))return5;elseif(upper_v<(1<<10))return6;elseif(upper_v<(1<<17))return7;elseif(upper_v<(1<<24))return8;elseif(upper_v<(1U<<31))return9;elsereturn10;}/* return the zigzag-encoded 64-bit unsigned int from a 64-bit signed int */staticinlineuint64_tzigzag64(int64_tv){if(v<0)return((uint64_t)(-v))*2-1;elsereturnv*2;}/* Return the number of bytes required to store a variable-length signed integer that fits in 64-bit int, converted to unsigned via the zig-zag algorithm, then packed using base-128 encoding. */staticinlinesize_tsint64_size(int64_tv){returnuint64_size(zigzag64(v));}/* Get serialized size of a single field in the message, including the space needed by the identifying tag. */staticsize_trequired_field_get_packed_size(constProtobufCFieldDescriptor*field,constvoid*member){size_trv=get_tag_size(field->id);switch(field->type){casePROTOBUF_C_TYPE_SINT32:returnrv+sint32_size(*(constint32_t*)member);casePROTOBUF_C_TYPE_INT32:returnrv+int32_size(*(constuint32_t*)member);casePROTOBUF_C_TYPE_UINT32:returnrv+uint32_size(*(constuint32_t*)member);casePROTOBUF_C_TYPE_SINT64:returnrv+sint64_size(*(constint64_t*)member);casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:returnrv+uint64_size(*(constuint64_t*)member);casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:returnrv+4;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:returnrv+8;casePROTOBUF_C_TYPE_BOOL:returnrv+1;casePROTOBUF_C_TYPE_FLOAT:returnrv+4;casePROTOBUF_C_TYPE_DOUBLE:returnrv+8;casePROTOBUF_C_TYPE_ENUM:// TODO: is this correct for negative-valued enums?returnrv+uint32_size(*(constuint32_t*)member);casePROTOBUF_C_TYPE_STRING:{constchar*str=*(char*const*)member;size_tlen=str?strlen(str):0;returnrv+uint32_size(len)+len;}casePROTOBUF_C_TYPE_BYTES:{size_tlen=((constProtobufCBinaryData*)member)->len;returnrv+uint32_size(len)+len;}//case PROTOBUF_C_TYPE_GROUP:casePROTOBUF_C_TYPE_MESSAGE:{constProtobufCMessage*msg=*(ProtobufCMessage*const*)member;size_tsubrv=msg?protobuf_c_message_get_packed_size(msg):0;returnrv+uint32_size(subrv)+subrv;}}PROTOBUF_C_ASSERT_NOT_REACHED();return0;}/* Get serialized size of a single optional field in the message, including the space needed by the identifying tag. Returns 0 if the optional field isn't set. */staticsize_toptional_field_get_packed_size(constProtobufCFieldDescriptor*field,constprotobuf_c_boolean*has,constvoid*member){if(field->type==PROTOBUF_C_TYPE_MESSAGE||field->type==PROTOBUF_C_TYPE_STRING){constvoid*ptr=*(constvoid*const*)member;if(ptr==NULL||ptr==field->default_value)return0;}else{if(!*has)return0;}returnrequired_field_get_packed_size(field,member);}/* Get serialized size of a repeated field in the message, which may consist of any number of values (including 0). Includes the space needed by the identifying tags (as needed). */staticsize_trepeated_field_get_packed_size(constProtobufCFieldDescriptor*field,size_tcount,constvoid*member){size_theader_size;size_trv=0;unsignedi;void*array=*(void*const*)member;if(count==0)return0;header_size=get_tag_size(field->id);if(!field->packed)header_size*=count;switch(field->type){casePROTOBUF_C_TYPE_SINT32:for(i=0;i<count;i++)rv+=sint32_size(((int32_t*)array)[i]);break;casePROTOBUF_C_TYPE_INT32:for(i=0;i<count;i++)rv+=int32_size(((uint32_t*)array)[i]);break;casePROTOBUF_C_TYPE_UINT32:casePROTOBUF_C_TYPE_ENUM:for(i=0;i<count;i++)rv+=uint32_size(((uint32_t*)array)[i]);break;casePROTOBUF_C_TYPE_SINT64:for(i=0;i<count;i++)rv+=sint64_size(((int64_t*)array)[i]);break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:for(i=0;i<count;i++)rv+=uint64_size(((uint64_t*)array)[i]);break;casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:rv+=4*count;break;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:rv+=8*count;break;casePROTOBUF_C_TYPE_BOOL:rv+=count;break;casePROTOBUF_C_TYPE_STRING:for(i=0;i<count;i++){size_tlen=strlen(((char**)array)[i]);rv+=uint32_size(len)+len;}break;casePROTOBUF_C_TYPE_BYTES:for(i=0;i<count;i++){size_tlen=((ProtobufCBinaryData*)array)[i].len;rv+=uint32_size(len)+len;}break;casePROTOBUF_C_TYPE_MESSAGE:for(i=0;i<count;i++){size_tlen=protobuf_c_message_get_packed_size(((ProtobufCMessage**)array)[i]);rv+=uint32_size(len)+len;}break;//case PROTOBUF_C_TYPE_GROUP: // NOT SUPPORTED}if(field->packed)header_size+=uint32_size(rv);returnheader_size+rv;}/* Get the packed size of a unknown field (meaning one that is passed through mostly uninterpreted... this is done for forward compatibilty with the addition of new fields). */staticinlinesize_tunknown_field_get_packed_size(constProtobufCMessageUnknownField*field){returnget_tag_size(field->tag)+field->len;}/* Get the number of bytes that the message will occupy once serialized. */size_tprotobuf_c_message_get_packed_size(constProtobufCMessage*message){unsignedi;size_trv=0;ASSERT_IS_MESSAGE(message);for(i=0;i<message->descriptor->n_fields;i++){constProtobufCFieldDescriptor*field=message->descriptor->fields+i;constvoid*member=((constchar*)message)+field->offset;constvoid*qmember=((constchar*)message)+field->quantifier_offset;if(field->label==PROTOBUF_C_LABEL_REQUIRED)rv+=required_field_get_packed_size(field,member);elseif(field->label==PROTOBUF_C_LABEL_OPTIONAL)rv+=optional_field_get_packed_size(field,qmember,member);elserv+=repeated_field_get_packed_size(field,*(constsize_t*)qmember,member);}for(i=0;i<message->n_unknown_fields;i++)rv+=unknown_field_get_packed_size(&message->unknown_fields[i]);returnrv;}/* === pack() === *//* Pack an unsigned 32-bit integer in base-128 encoding, and return the number of bytes needed: this will be 5 or less. */staticinlinesize_tuint32_pack(uint32_tvalue,uint8_t*out){unsignedrv=0;if(value>=0x80){out[rv++]=value|0x80;value>>=7;if(value>=0x80){out[rv++]=value|0x80;value>>=7;if(value>=0x80){out[rv++]=value|0x80;value>>=7;if(value>=0x80){out[rv++]=value|0x80;value>>=7;}}}}/* assert: value<128 */out[rv++]=value;returnrv;}/* Pack a 32-bit signed integer, returning the number of bytes needed. Negative numbers are packed as twos-complement 64-bit integers. */staticinlinesize_tint32_pack(int32_tvalue,uint8_t*out){if(value<0){out[0]=value|0x80;out[1]=(value>>7)|0x80;out[2]=(value>>14)|0x80;out[3]=(value>>21)|0x80;out[4]=(value>>28)|0x80;out[5]=out[6]=out[7]=out[8]=0xff;out[9]=0x01;return10;}elsereturnuint32_pack(value,out);}/* Pack a 32-bit integer in zigzag encoding. */staticinlinesize_tsint32_pack(int32_tvalue,uint8_t*out){returnuint32_pack(zigzag32(value),out);}/* Pack a 64-bit unsigned integer that fits in a 64-bit uint, using base-128 encoding. */staticsize_tuint64_pack(uint64_tvalue,uint8_t*out){uint32_thi=(uint32_t)(value>>32);uint32_tlo=(uint32_t)value;unsignedrv;if(hi==0)returnuint32_pack((uint32_t)lo,out);out[0]=(lo)|0x80;out[1]=(lo>>7)|0x80;out[2]=(lo>>14)|0x80;out[3]=(lo>>21)|0x80;if(hi<8){out[4]=(hi<<4)|(lo>>28);return5;}else{out[4]=((hi&7)<<4)|(lo>>28)|0x80;hi>>=3;}rv=5;while(hi>=128){out[rv++]=hi|0x80;hi>>=7;}out[rv++]=hi;returnrv;}/* Pack a 64-bit signed integer in zigzan encoding, return the size of the packed output. (Max returned value is 10) */staticinlinesize_tsint64_pack(int64_tvalue,uint8_t*out){returnuint64_pack(zigzag64(value),out);}/* Pack a 32-bit value, little-endian. Used for fixed32, sfixed32, float) */staticinlinesize_tfixed32_pack(uint32_tvalue,void*out){#if IS_LITTLE_ENDIANmemcpy(out,&value,4);#elseuint8_t*buf=out;buf[0]=value;buf[1]=value>>8;buf[2]=value>>16;buf[3]=value>>24;#endifreturn4;}/* Pack a 64-bit fixed-length value. (Used for fixed64, sfixed64, double) *//* XXX: the big-endian impl is really only good for 32-bit machines, a 64-bit version would be appreciated, plus a way to decide to use 64-bit math where convenient. */staticinlinesize_tfixed64_pack(uint64_tvalue,void*out){#if IS_LITTLE_ENDIANmemcpy(out,&value,8);#elsefixed32_pack(value,out);fixed32_pack(value>>32,((char*)out)+4);#endifreturn8;}/* Pack a boolean as 0 or 1, even though the protobuf_c_boolean can really assume any integer value. *//* XXX: perhaps on some platforms "*out = !!value" would be a better impl, b/c that is idiotmatic c++ in some stl impls. */staticinlinesize_tboolean_pack(protobuf_c_booleanvalue,uint8_t*out){*out=value?1:0;return1;}/* Pack a length-prefixed string. The input string is NUL-terminated. The NULL pointer is treated as an empty string. This isn't really necessary, but it allows people to leave required strings blank. (See Issue 13 in the bug tracker for a little more explanation). */staticinlinesize_tstring_pack(constchar*str,uint8_t*out){if(str==NULL){out[0]=0;return1;}else{size_tlen=strlen(str);size_trv=uint32_pack(len,out);memcpy(out+rv,str,len);returnrv+len;}}staticinlinesize_tbinary_data_pack(constProtobufCBinaryData*bd,uint8_t*out){size_tlen=bd->len;size_trv=uint32_pack(len,out);memcpy(out+rv,bd->data,len);returnrv+len;}staticinlinesize_tprefixed_message_pack(constProtobufCMessage*message,uint8_t*out){if(message==NULL){out[0]=0;return1;}else{size_trv=protobuf_c_message_pack(message,out+1);uint32_trv_packed_size=uint32_size(rv);if(rv_packed_size!=1)memmove(out+rv_packed_size,out+1,rv);returnuint32_pack(rv,out)+rv;}}/* wire-type will be added in required_field_pack() *//* XXX: just call uint64_pack on 64-bit platforms. */staticsize_ttag_pack(uint32_tid,uint8_t*out){if(id<(1<<(32-3)))returnuint32_pack(id<<3,out);elsereturnuint64_pack(((uint64_t)id)<<3,out);}staticsize_trequired_field_pack(constProtobufCFieldDescriptor*field,constvoid*member,uint8_t*out){size_trv=tag_pack(field->id,out);switch(field->type){casePROTOBUF_C_TYPE_SINT32:out[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;returnrv+sint32_pack(*(constint32_t*)member,out+rv);casePROTOBUF_C_TYPE_INT32:out[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;returnrv+int32_pack(*(constuint32_t*)member,out+rv);casePROTOBUF_C_TYPE_UINT32:casePROTOBUF_C_TYPE_ENUM:out[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;returnrv+uint32_pack(*(constuint32_t*)member,out+rv);casePROTOBUF_C_TYPE_SINT64:out[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;returnrv+sint64_pack(*(constint64_t*)member,out+rv);casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:out[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;returnrv+uint64_pack(*(constuint64_t*)member,out+rv);casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:out[0]|=PROTOBUF_C_WIRE_TYPE_32BIT;returnrv+fixed32_pack(*(constuint32_t*)member,out+rv);casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:out[0]|=PROTOBUF_C_WIRE_TYPE_64BIT;returnrv+fixed64_pack(*(constuint64_t*)member,out+rv);casePROTOBUF_C_TYPE_BOOL:out[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;returnrv+boolean_pack(*(constprotobuf_c_boolean*)member,out+rv);casePROTOBUF_C_TYPE_STRING:{out[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;returnrv+string_pack(*(char*const*)member,out+rv);}casePROTOBUF_C_TYPE_BYTES:{constProtobufCBinaryData*bd=((constProtobufCBinaryData*)member);out[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;returnrv+binary_data_pack(bd,out+rv);}//case PROTOBUF_C_TYPE_GROUP: // NOT SUPPORTEDcasePROTOBUF_C_TYPE_MESSAGE:{out[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;returnrv+prefixed_message_pack(*(ProtobufCMessage*const*)member,out+rv);}}PROTOBUF_C_ASSERT_NOT_REACHED();return0;}staticsize_toptional_field_pack(constProtobufCFieldDescriptor*field,constprotobuf_c_boolean*has,constvoid*member,uint8_t*out){if(field->type==PROTOBUF_C_TYPE_MESSAGE||field->type==PROTOBUF_C_TYPE_STRING){constvoid*ptr=*(constvoid*const*)member;if(ptr==NULL||ptr==field->default_value)return0;}else{if(!*has)return0;}returnrequired_field_pack(field,member,out);}/* TODO: implement as a table lookup */staticinlinesize_tsizeof_elt_in_repeated_array(ProtobufCTypetype){switch(type){casePROTOBUF_C_TYPE_SINT32:casePROTOBUF_C_TYPE_INT32:casePROTOBUF_C_TYPE_UINT32:casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:casePROTOBUF_C_TYPE_ENUM:return4;casePROTOBUF_C_TYPE_SINT64:casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:return8;casePROTOBUF_C_TYPE_BOOL:returnsizeof(protobuf_c_boolean);casePROTOBUF_C_TYPE_STRING:casePROTOBUF_C_TYPE_MESSAGE:returnsizeof(void*);casePROTOBUF_C_TYPE_BYTES:returnsizeof(ProtobufCBinaryData);}PROTOBUF_C_ASSERT_NOT_REACHED();return0;}staticvoidcopy_to_little_endian_32(void*out,constvoid*in,unsignedN){#if IS_LITTLE_ENDIANmemcpy(out,in,N*4);#elseunsignedi;constuint32_t*ini=in;for(i=0;i<N;i++)fixed32_pack(ini[i],(uint32_t*)out+i);#endif}staticvoidcopy_to_little_endian_64(void*out,constvoid*in,unsignedN){#if IS_LITTLE_ENDIANmemcpy(out,in,N*8);#elseunsignedi;constuint64_t*ini=in;for(i=0;i<N;i++)fixed64_pack(ini[i],(uint64_t*)out+i);#endif}staticunsignedget_type_min_size(ProtobufCTypetype){if(type==PROTOBUF_C_TYPE_SFIXED32||type==PROTOBUF_C_TYPE_FIXED32||type==PROTOBUF_C_TYPE_FLOAT)return4;if(type==PROTOBUF_C_TYPE_SFIXED64||type==PROTOBUF_C_TYPE_FIXED64||type==PROTOBUF_C_TYPE_DOUBLE)return8;return1;}staticsize_trepeated_field_pack(constProtobufCFieldDescriptor*field,size_tcount,constvoid*member,uint8_t*out){char*array=*(char*const*)member;unsignedi;if(field->packed){unsignedheader_len;unsignedlen_start;unsignedmin_length;unsignedpayload_len;unsignedlength_size_min;unsignedactual_length_size;uint8_t*payload_at;if(count==0)return0;header_len=tag_pack(field->id,out);out[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;len_start=header_len;min_length=get_type_min_size(field->type)*count;length_size_min=uint32_size(min_length);header_len+=length_size_min;payload_at=out+header_len;switch(field->type){casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:copy_to_little_endian_32(payload_at,array,count);payload_at+=count*4;break;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:copy_to_little_endian_64(payload_at,array,count);payload_at+=count*8;break;casePROTOBUF_C_TYPE_INT32:{constint32_t*arr=(constint32_t*)array;for(i=0;i<count;i++)payload_at+=int32_pack(arr[i],payload_at);}break;casePROTOBUF_C_TYPE_SINT32:{constint32_t*arr=(constint32_t*)array;for(i=0;i<count;i++)payload_at+=sint32_pack(arr[i],payload_at);}break;casePROTOBUF_C_TYPE_SINT64:{constint64_t*arr=(constint64_t*)array;for(i=0;i<count;i++)payload_at+=sint64_pack(arr[i],payload_at);}break;casePROTOBUF_C_TYPE_ENUM:casePROTOBUF_C_TYPE_UINT32:{constuint32_t*arr=(constuint32_t*)array;for(i=0;i<count;i++)payload_at+=uint32_pack(arr[i],payload_at);}break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:{constuint64_t*arr=(constuint64_t*)array;for(i=0;i<count;i++)payload_at+=uint64_pack(arr[i],payload_at);}break;casePROTOBUF_C_TYPE_BOOL:{constprotobuf_c_boolean*arr=(constprotobuf_c_boolean*)array;for(i=0;i<count;i++)payload_at+=boolean_pack(arr[i],payload_at);}break;default:assert(0);}payload_len=payload_at-(out+header_len);actual_length_size=uint32_size(payload_len);if(length_size_min!=actual_length_size){assert(actual_length_size==length_size_min+1);memmove(out+header_len+1,out+header_len,payload_len);header_len++;}uint32_pack(payload_len,out+len_start);returnheader_len+payload_len;}else{/* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */size_trv=0;unsignedsiz=sizeof_elt_in_repeated_array(field->type);for(i=0;i<count;i++){rv+=required_field_pack(field,array,out+rv);array+=siz;}returnrv;}}staticsize_tunknown_field_pack(constProtobufCMessageUnknownField*field,uint8_t*out){size_trv=tag_pack(field->tag,out);out[0]|=field->wire_type;memcpy(out+rv,field->data,field->len);returnrv+field->len;}size_tprotobuf_c_message_pack(constProtobufCMessage*message,uint8_t*out){unsignedi;size_trv=0;ASSERT_IS_MESSAGE(message);for(i=0;i<message->descriptor->n_fields;i++){constProtobufCFieldDescriptor*field=message->descriptor->fields+i;constvoid*member=((constchar*)message)+field->offset;/* it doesn't hurt to compute qmember (a pointer to the quantifier field of the structure), but the pointer is only valid if the field is one of: - a repeated field - an optional field that isn't a pointer type (meaning: not a message or a string) */constvoid*qmember=((constchar*)message)+field->quantifier_offset;if(field->label==PROTOBUF_C_LABEL_REQUIRED)rv+=required_field_pack(field,member,out+rv);elseif(field->label==PROTOBUF_C_LABEL_OPTIONAL)/* note that qmember is bogus for strings and messages, but it isn't used */rv+=optional_field_pack(field,qmember,member,out+rv);elserv+=repeated_field_pack(field,*(constsize_t*)qmember,member,out+rv);}for(i=0;i<message->n_unknown_fields;i++)rv+=unknown_field_pack(&message->unknown_fields[i],out+rv);returnrv;}/* === pack_to_buffer() === */staticsize_trequired_field_pack_to_buffer(constProtobufCFieldDescriptor*field,constvoid*member,ProtobufCBuffer*buffer){size_trv;uint8_tscratch[MAX_UINT64_ENCODED_SIZE*2];rv=tag_pack(field->id,scratch);switch(field->type){casePROTOBUF_C_TYPE_SINT32:scratch[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;rv+=sint32_pack(*(constint32_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_INT32:scratch[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;rv+=int32_pack(*(constuint32_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_UINT32:casePROTOBUF_C_TYPE_ENUM:scratch[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;rv+=uint32_pack(*(constuint32_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_SINT64:scratch[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;rv+=sint64_pack(*(constint64_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:scratch[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;rv+=uint64_pack(*(constuint64_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:scratch[0]|=PROTOBUF_C_WIRE_TYPE_32BIT;rv+=fixed32_pack(*(constuint32_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:scratch[0]|=PROTOBUF_C_WIRE_TYPE_64BIT;rv+=fixed64_pack(*(constuint64_t*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_BOOL:scratch[0]|=PROTOBUF_C_WIRE_TYPE_VARINT;rv+=boolean_pack(*(constprotobuf_c_boolean*)member,scratch+rv);buffer->append(buffer,rv,scratch);break;casePROTOBUF_C_TYPE_STRING:{constchar*str=*(char*const*)member;size_tsublen=str?strlen(str):0;scratch[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;rv+=uint32_pack(sublen,scratch+rv);buffer->append(buffer,rv,scratch);buffer->append(buffer,sublen,(constuint8_t*)str);rv+=sublen;break;}casePROTOBUF_C_TYPE_BYTES:{constProtobufCBinaryData*bd=((constProtobufCBinaryData*)member);size_tsublen=bd->len;scratch[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;rv+=uint32_pack(sublen,scratch+rv);buffer->append(buffer,rv,scratch);buffer->append(buffer,sublen,bd->data);rv+=sublen;break;}//PROTOBUF_C_TYPE_GROUP, // NOT SUPPORTEDcasePROTOBUF_C_TYPE_MESSAGE:{uint8_tsimple_buffer_scratch[256];size_tsublen;ProtobufCBufferSimplesimple_buffer=PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch);constProtobufCMessage*msg=*(ProtobufCMessage*const*)member;scratch[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;if(msg==NULL)sublen=0;elsesublen=protobuf_c_message_pack_to_buffer(msg,&simple_buffer.base);rv+=uint32_pack(sublen,scratch+rv);buffer->append(buffer,rv,scratch);buffer->append(buffer,sublen,simple_buffer.data);rv+=sublen;PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer);break;}default:PROTOBUF_C_ASSERT_NOT_REACHED();}returnrv;}staticsize_toptional_field_pack_to_buffer(constProtobufCFieldDescriptor*field,constprotobuf_c_boolean*has,constvoid*member,ProtobufCBuffer*buffer){if(field->type==PROTOBUF_C_TYPE_MESSAGE||field->type==PROTOBUF_C_TYPE_STRING){constvoid*ptr=*(constvoid*const*)member;if(ptr==NULL||ptr==field->default_value)return0;}else{if(!*has)return0;}returnrequired_field_pack_to_buffer(field,member,buffer);}staticsize_tget_packed_payload_length(constProtobufCFieldDescriptor*field,unsignedcount,constvoid*array){unsignedrv=0;unsignedi;switch(field->type){casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:returncount*4;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:returncount*8;casePROTOBUF_C_TYPE_INT32:{constint32_t*arr=(constint32_t*)array;for(i=0;i<count;i++)rv+=int32_size(arr[i]);}break;casePROTOBUF_C_TYPE_SINT32:{constint32_t*arr=(constint32_t*)array;for(i=0;i<count;i++)rv+=sint32_size(arr[i]);}break;casePROTOBUF_C_TYPE_ENUM:casePROTOBUF_C_TYPE_UINT32:{constuint32_t*arr=(constuint32_t*)array;for(i=0;i<count;i++)rv+=uint32_size(arr[i]);}break;casePROTOBUF_C_TYPE_SINT64:{constint64_t*arr=(constint64_t*)array;for(i=0;i<count;i++)rv+=sint64_size(arr[i]);}break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:{constuint64_t*arr=(constuint64_t*)array;for(i=0;i<count;i++)rv+=uint64_size(arr[i]);}break;casePROTOBUF_C_TYPE_BOOL:returncount;default:assert(0);}returnrv;}staticsize_tpack_buffer_packed_payload(constProtobufCFieldDescriptor*field,unsignedcount,constvoid*array,ProtobufCBuffer*buffer){uint8_tscratch[16];size_trv=0;unsignedi;switch(field->type){casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:#if IS_LITTLE_ENDIANrv=count*4;gotono_packing_needed;#elsefor(i=0;i<count;i++){unsignedlen=fixed32_pack(((uint32_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}#endifbreak;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:#if IS_LITTLE_ENDIANrv=count*8;gotono_packing_needed;#elsefor(i=0;i<count;i++){unsignedlen=fixed64_pack(((uint64_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}break;#endifcasePROTOBUF_C_TYPE_INT32:for(i=0;i<count;i++){unsignedlen=int32_pack(((int32_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}break;casePROTOBUF_C_TYPE_SINT32:for(i=0;i<count;i++){unsignedlen=sint32_pack(((int32_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}break;casePROTOBUF_C_TYPE_ENUM:casePROTOBUF_C_TYPE_UINT32:for(i=0;i<count;i++){unsignedlen=uint32_pack(((uint32_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}break;casePROTOBUF_C_TYPE_SINT64:for(i=0;i<count;i++){unsignedlen=sint64_pack(((int64_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:for(i=0;i<count;i++){unsignedlen=uint64_pack(((uint64_t*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}break;casePROTOBUF_C_TYPE_BOOL:for(i=0;i<count;i++){unsignedlen=boolean_pack(((protobuf_c_boolean*)array)[i],scratch);buffer->append(buffer,len,scratch);rv+=len;}returncount;default:assert(0);}returnrv;no_packing_needed:buffer->append(buffer,rv,array);returnrv;}staticsize_trepeated_field_pack_to_buffer(constProtobufCFieldDescriptor*field,unsignedcount,constvoid*member,ProtobufCBuffer*buffer){char*array=*(char*const*)member;if(count==0)return0;if(field->packed){uint8_tscratch[MAX_UINT64_ENCODED_SIZE*2];size_trv=tag_pack(field->id,scratch);size_tpayload_len=get_packed_payload_length(field,count,array);size_ttmp;scratch[0]|=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;rv+=uint32_pack(payload_len,scratch+rv);buffer->append(buffer,rv,scratch);tmp=pack_buffer_packed_payload(field,count,array,buffer);assert(tmp==payload_len);returnrv+payload_len;}else{size_tsiz;unsignedi;/* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */unsignedrv=0;siz=sizeof_elt_in_repeated_array(field->type);for(i=0;i<count;i++){rv+=required_field_pack_to_buffer(field,array,buffer);array+=siz;}returnrv;}}staticsize_tunknown_field_pack_to_buffer(constProtobufCMessageUnknownField*field,ProtobufCBuffer*buffer){uint8_theader[MAX_UINT64_ENCODED_SIZE];size_trv=tag_pack(field->tag,header);header[0]|=field->wire_type;buffer->append(buffer,rv,header);buffer->append(buffer,field->len,field->data);returnrv+field->len;}size_tprotobuf_c_message_pack_to_buffer(constProtobufCMessage*message,ProtobufCBuffer*buffer){unsignedi;size_trv=0;ASSERT_IS_MESSAGE(message);for(i=0;i<message->descriptor->n_fields;i++){constProtobufCFieldDescriptor*field=message->descriptor->fields+i;constvoid*member=((constchar*)message)+field->offset;constvoid*qmember=((constchar*)message)+field->quantifier_offset;if(field->label==PROTOBUF_C_LABEL_REQUIRED)rv+=required_field_pack_to_buffer(field,member,buffer);elseif(field->label==PROTOBUF_C_LABEL_OPTIONAL)rv+=optional_field_pack_to_buffer(field,qmember,member,buffer);elserv+=repeated_field_pack_to_buffer(field,*(constsize_t*)qmember,member,buffer);}for(i=0;i<message->n_unknown_fields;i++)rv+=unknown_field_pack_to_buffer(&message->unknown_fields[i],buffer);returnrv;}/* === unpacking === */#if PRINT_UNPACK_ERRORS# define UNPACK_ERROR(args) do { printf args;printf("\n"); }while(0)#else# define UNPACK_ERROR(args) do { } while (0)#endifstaticinlineintint_range_lookup(unsignedn_ranges,constProtobufCIntRange*ranges,intvalue){unsignedstart,n;if(n_ranges==0)return-1;start=0;n=n_ranges;while(n>1){unsignedmid=start+n/2;if(value<ranges[mid].start_value){n=mid-start;}elseif(value>=ranges[mid].start_value+(int)(ranges[mid+1].orig_index-ranges[mid].orig_index)){unsignednew_start=mid+1;n=start+n-new_start;start=new_start;}elsereturn(value-ranges[mid].start_value)+ranges[mid].orig_index;}if(n>0){unsignedstart_orig_index=ranges[start].orig_index;unsignedrange_size=ranges[start+1].orig_index-start_orig_index;if(ranges[start].start_value<=value&&value<(int)(ranges[start].start_value+range_size))return(value-ranges[start].start_value)+start_orig_index;}return-1;}staticsize_tparse_tag_and_wiretype(size_tlen,constuint8_t*data,uint32_t*tag_out,ProtobufCWireType*wiretype_out){unsignedmax_rv=len>5?5:len;uint32_ttag=(data[0]&0x7f)>>3;unsignedshift=4;unsignedrv;*wiretype_out=data[0]&7;if((data[0]&0x80)==0){*tag_out=tag;return1;}for(rv=1;rv<max_rv;rv++)if(data[rv]&0x80){tag|=(data[rv]&0x7f)<<shift;shift+=7;}else{tag|=data[rv]<<shift;*tag_out=tag;returnrv+1;}return0;/* error: bad header */}/* sizeof(ScannedMember) must be <= (1<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */#define BOUND_SIZEOF_SCANNED_MEMBER_LOG2 5typedefstruct_ScannedMemberScannedMember;struct_ScannedMember{uint32_ttag;uint8_twire_type;uint8_tlength_prefix_len;constProtobufCFieldDescriptor*field;size_tlen;constuint8_t*data;};staticinlineuint32_tscan_length_prefixed_data(size_tlen,constuint8_t*data,size_t*prefix_len_out){unsignedhdr_max=len<5?len:5;unsignedhdr_len;uint32_tval=0;unsignedi;unsignedshift=0;for(i=0;i<hdr_max;i++){val|=(data[i]&0x7f)<<shift;shift+=7;if((data[i]&0x80)==0)break;}if(i==hdr_max){UNPACK_ERROR(("error parsing length for length-prefixed data"));return0;}hdr_len=i+1;*prefix_len_out=hdr_len;if(hdr_len+val>len){UNPACK_ERROR(("data too short after length-prefix of %u",val));return0;}returnhdr_len+val;}staticsize_tmax_b128_numbers(size_tlen,constuint8_t*data){size_trv=0;while(len--)if((*data++&0x80)==0)++rv;returnrv;}/* Given a raw slab of packed-repeated values, determine the number of elements. This function detects certain kinds of errors but not others; the remaining error checking is done by parse_packed_repeated_member() */staticprotobuf_c_booleancount_packed_elements(ProtobufCTypetype,size_tlen,constuint8_t*data,size_t*count_out){switch(type){casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:if(len%4!=0){UNPACK_ERROR(("length must be a multiple of 4 for fixed-length 32-bit types"));returnFALSE;}*count_out=len/4;returnTRUE;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:if(len%8!=0){UNPACK_ERROR(("length must be a multiple of 8 for fixed-length 64-bit types"));returnFALSE;}*count_out=len/8;returnTRUE;casePROTOBUF_C_TYPE_INT32:casePROTOBUF_C_TYPE_SINT32:casePROTOBUF_C_TYPE_ENUM:casePROTOBUF_C_TYPE_UINT32:casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_SINT64:casePROTOBUF_C_TYPE_UINT64:*count_out=max_b128_numbers(len,data);returnTRUE;casePROTOBUF_C_TYPE_BOOL:*count_out=len;returnTRUE;casePROTOBUF_C_TYPE_STRING:casePROTOBUF_C_TYPE_BYTES:casePROTOBUF_C_TYPE_MESSAGE:default:UNPACK_ERROR(("bad protobuf-c type %u for packed-repeated",type));returnFALSE;}}staticinlineuint32_tparse_uint32(unsignedlen,constuint8_t*data){unsignedrv=data[0]&0x7f;if(len>1){rv|=((data[1]&0x7f)<<7);if(len>2){rv|=((data[2]&0x7f)<<14);if(len>3){rv|=((data[3]&0x7f)<<21);if(len>4)rv|=(data[4]<<28);}}}returnrv;}staticinlineuint32_tparse_int32(unsignedlen,constuint8_t*data){returnparse_uint32(len,data);}staticinlineint32_tunzigzag32(uint32_tv){if(v&1)return-(v>>1)-1;elsereturnv>>1;}staticinlineuint32_tparse_fixed_uint32(constuint8_t*data){#if IS_LITTLE_ENDIANuint32_tt;memcpy(&t,data,4);returnt;#elsereturndata[0]|(data[1]<<8)|(data[2]<<16)|(data[3]<<24);#endif}staticuint64_tparse_uint64(unsignedlen,constuint8_t*data){unsignedshift,i;uint64_trv;if(len<5)returnparse_uint32(len,data);rv=((data[0]&0x7f))|((data[1]&0x7f)<<7)|((data[2]&0x7f)<<14)|((data[3]&0x7f)<<21);shift=28;for(i=4;i<len;i++){rv|=(((uint64_t)(data[i]&0x7f))<<shift);shift+=7;}returnrv;}staticinlineint64_tunzigzag64(uint64_tv){if(v&1)return-(v>>1)-1;elsereturnv>>1;}staticinlineuint64_tparse_fixed_uint64(constuint8_t*data){#if IS_LITTLE_ENDIANuint64_tt;memcpy(&t,data,8);returnt;#elsereturn(uint64_t)parse_fixed_uint32(data)|(((uint64_t)parse_fixed_uint32(data+4))<<32);#endif}staticprotobuf_c_booleanparse_boolean(unsignedlen,constuint8_t*data){unsignedi;for(i=0;i<len;i++)if(data[i]&0x7f)return1;return0;}staticprotobuf_c_booleanparse_required_member(ScannedMember*scanned_member,void*member,ProtobufCAllocator*allocator,protobuf_c_booleanmaybe_clear){unsignedlen=scanned_member->len;constuint8_t*data=scanned_member->data;ProtobufCWireTypewire_type=scanned_member->wire_type;switch(scanned_member->field->type){casePROTOBUF_C_TYPE_INT32:if(wire_type!=PROTOBUF_C_WIRE_TYPE_VARINT)return0;*(uint32_t*)member=parse_int32(len,data);return1;casePROTOBUF_C_TYPE_UINT32:if(wire_type!=PROTOBUF_C_WIRE_TYPE_VARINT)return0;*(uint32_t*)member=parse_uint32(len,data);return1;casePROTOBUF_C_TYPE_SINT32:if(wire_type!=PROTOBUF_C_WIRE_TYPE_VARINT)return0;*(int32_t*)member=unzigzag32(parse_uint32(len,data));return1;casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:if(wire_type!=PROTOBUF_C_WIRE_TYPE_32BIT)return0;*(uint32_t*)member=parse_fixed_uint32(data);return1;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:if(wire_type!=PROTOBUF_C_WIRE_TYPE_VARINT)return0;*(uint64_t*)member=parse_uint64(len,data);return1;casePROTOBUF_C_TYPE_SINT64:if(wire_type!=PROTOBUF_C_WIRE_TYPE_VARINT)return0;*(int64_t*)member=unzigzag64(parse_uint64(len,data));return1;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:if(wire_type!=PROTOBUF_C_WIRE_TYPE_64BIT)return0;*(uint64_t*)member=parse_fixed_uint64(data);return1;casePROTOBUF_C_TYPE_BOOL:*(protobuf_c_boolean*)member=parse_boolean(len,data);return1;casePROTOBUF_C_TYPE_ENUM:if(wire_type!=PROTOBUF_C_WIRE_TYPE_VARINT)return0;*(uint32_t*)member=parse_uint32(len,data);return1;casePROTOBUF_C_TYPE_STRING:if(wire_type!=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)return0;{char**pstr=member;unsignedpref_len=scanned_member->length_prefix_len;if(maybe_clear&&*pstr!=NULL){constchar*def=scanned_member->field->default_value;if(*pstr!=NULL&&*pstr!=def)FREE(allocator,*pstr);}DO_ALLOC(*pstr,allocator,len-pref_len+1,return0);memcpy(*pstr,data+pref_len,len-pref_len);(*pstr)[len-pref_len]=0;return1;}casePROTOBUF_C_TYPE_BYTES:if(wire_type!=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)return0;{ProtobufCBinaryData*bd=member;constProtobufCBinaryData*def_bd;unsignedpref_len=scanned_member->length_prefix_len;def_bd=scanned_member->field->default_value;if(maybe_clear&&bd->data!=NULL&&(def_bd==NULL||bd->data!=def_bd->data))FREE(allocator,bd->data);DO_ALLOC(bd->data,allocator,len-pref_len,return0);memcpy(bd->data,data+pref_len,len-pref_len);bd->len=len-pref_len;return1;}//case PROTOBUF_C_TYPE_GROUP, // NOT SUPPORTEDcasePROTOBUF_C_TYPE_MESSAGE:if(wire_type!=PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)return0;{ProtobufCMessage**pmessage=member;ProtobufCMessage*subm;constProtobufCMessage*def_mess;unsignedpref_len=scanned_member->length_prefix_len;def_mess=scanned_member->field->default_value;if(maybe_clear&&*pmessage!=NULL&&*pmessage!=def_mess)protobuf_c_message_free_unpacked(*pmessage,allocator);subm=protobuf_c_message_unpack(scanned_member->field->descriptor,allocator,len-pref_len,data+pref_len);*pmessage=subm;/* since we freed the message we must clear the field, even if NULL */if(subm==NULL)return0;return1;}}return0;}staticprotobuf_c_booleanparse_optional_member(ScannedMember*scanned_member,void*member,ProtobufCMessage*message,ProtobufCAllocator*allocator){if(!parse_required_member(scanned_member,member,allocator,TRUE))return0;if(scanned_member->field->quantifier_offset!=0)STRUCT_MEMBER(protobuf_c_boolean,message,scanned_member->field->quantifier_offset)=1;return1;}staticprotobuf_c_booleanparse_repeated_member(ScannedMember*scanned_member,void*member,ProtobufCMessage*message,ProtobufCAllocator*allocator){constProtobufCFieldDescriptor*field=scanned_member->field;size_t*p_n=STRUCT_MEMBER_PTR(size_t,message,field->quantifier_offset);size_tsiz=sizeof_elt_in_repeated_array(field->type);char*array=*(char**)member;if(!parse_required_member(scanned_member,array+siz*(*p_n),allocator,FALSE))return0;*p_n+=1;return1;}staticunsignedscan_varint(unsignedlen,constuint8_t*data){unsignedi;if(len>10)len=10;for(i=0;i<len;i++)if((data[i]&0x80)==0)break;if(i==len)return0;returni+1;}staticprotobuf_c_booleanparse_packed_repeated_member(ScannedMember*scanned_member,void*member,ProtobufCMessage*message){constProtobufCFieldDescriptor*field=scanned_member->field;size_t*p_n=STRUCT_MEMBER_PTR(size_t,message,field->quantifier_offset);size_tsiz=sizeof_elt_in_repeated_array(field->type);char*array=*(char**)member+siz*(*p_n);constuint8_t*at=scanned_member->data+scanned_member->length_prefix_len;size_trem=scanned_member->len-scanned_member->length_prefix_len;size_tcount=0;unsignedi;switch(field->type){casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:count=(scanned_member->len-scanned_member->length_prefix_len)/4;#if IS_LITTLE_ENDIANgotono_unpacking_needed;#elsefor(i=0;i<count;i++){((uint32_t*)array)[i]=parse_fixed_uint32(at);at+=4;}#endifbreak;casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:count=(scanned_member->len-scanned_member->length_prefix_len)/8;#if IS_LITTLE_ENDIANgotono_unpacking_needed;#elsefor(i=0;i<count;i++){((uint64_t*)array)[i]=parse_fixed_uint64(at);at+=8;}break;#endifcasePROTOBUF_C_TYPE_INT32:while(rem>0){unsigneds=scan_varint(rem,at);if(s==0){UNPACK_ERROR(("bad packed-repeated int32 value"));returnFALSE;}((int32_t*)array)[count++]=parse_int32(s,at);at+=s;rem-=s;}break;casePROTOBUF_C_TYPE_SINT32:while(rem>0){unsigneds=scan_varint(rem,at);if(s==0){UNPACK_ERROR(("bad packed-repeated sint32 value"));returnFALSE;}((int32_t*)array)[count++]=unzigzag32(parse_uint32(s,at));at+=s;rem-=s;}break;casePROTOBUF_C_TYPE_ENUM:casePROTOBUF_C_TYPE_UINT32:while(rem>0){unsigneds=scan_varint(rem,at);if(s==0){UNPACK_ERROR(("bad packed-repeated enum or uint32 value"));returnFALSE;}((uint32_t*)array)[count++]=parse_uint32(s,at);at+=s;rem-=s;}break;casePROTOBUF_C_TYPE_SINT64:while(rem>0){unsigneds=scan_varint(rem,at);if(s==0){UNPACK_ERROR(("bad packed-repeated sint64 value"));returnFALSE;}((int64_t*)array)[count++]=unzigzag64(parse_uint64(s,at));at+=s;rem-=s;}break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_UINT64:while(rem>0){unsigneds=scan_varint(rem,at);if(s==0){UNPACK_ERROR(("bad packed-repeated int64/uint64 value"));returnFALSE;}((int64_t*)array)[count++]=parse_uint64(s,at);at+=s;rem-=s;}break;casePROTOBUF_C_TYPE_BOOL:count=rem;for(i=0;i<count;i++){if(at[i]>1){UNPACK_ERROR(("bad packed-repeated boolean value"));returnFALSE;}((protobuf_c_boolean*)array)[i]=at[i];}break;default:assert(0);}*p_n+=count;returnTRUE;no_unpacking_needed:memcpy(array,at,count*siz);*p_n+=count;returnTRUE;}staticprotobuf_c_booleanis_packable_type(ProtobufCTypetype){returntype!=PROTOBUF_C_TYPE_STRING&&type!=PROTOBUF_C_TYPE_BYTES&&type!=PROTOBUF_C_TYPE_MESSAGE;}staticprotobuf_c_booleanparse_member(ScannedMember*scanned_member,ProtobufCMessage*message,ProtobufCAllocator*allocator){constProtobufCFieldDescriptor*field=scanned_member->field;void*member;if(field==NULL){ProtobufCMessageUnknownField*ufield=message->unknown_fields+(message->n_unknown_fields++);ufield->tag=scanned_member->tag;ufield->wire_type=scanned_member->wire_type;ufield->len=scanned_member->len;DO_UNALIGNED_ALLOC(ufield->data,allocator,scanned_member->len,return0);memcpy(ufield->data,scanned_member->data,ufield->len);return1;}member=(char*)message+field->offset;switch(field->label){casePROTOBUF_C_LABEL_REQUIRED:returnparse_required_member(scanned_member,member,allocator,TRUE);casePROTOBUF_C_LABEL_OPTIONAL:returnparse_optional_member(scanned_member,member,message,allocator);casePROTOBUF_C_LABEL_REPEATED:if(scanned_member->wire_type==PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED&&(field->packed||is_packable_type(field->type)))returnparse_packed_repeated_member(scanned_member,member,message);elsereturnparse_repeated_member(scanned_member,member,message,allocator);}PROTOBUF_C_ASSERT_NOT_REACHED();return0;}/* TODO: expose/use this function if desc->message_init==NULL (which occurs for old code, and may be useful for certain programatic techniques for generating descriptors). */voidprotobuf_c_message_init_generic(constProtobufCMessageDescriptor*desc,ProtobufCMessage*message){unsignedi;memset(message,0,desc->sizeof_message);message->descriptor=desc;for(i=0;i<desc->n_fields;i++)if(desc->fields[i].default_value!=NULL&&desc->fields[i].label!=PROTOBUF_C_LABEL_REPEATED){void*field=STRUCT_MEMBER_P(message,desc->fields[i].offset);constvoid*dv=desc->fields[i].default_value;switch(desc->fields[i].type){casePROTOBUF_C_TYPE_INT32:casePROTOBUF_C_TYPE_SINT32:casePROTOBUF_C_TYPE_SFIXED32:casePROTOBUF_C_TYPE_UINT32:casePROTOBUF_C_TYPE_FIXED32:casePROTOBUF_C_TYPE_FLOAT:casePROTOBUF_C_TYPE_ENUM:memcpy(field,dv,4);break;casePROTOBUF_C_TYPE_INT64:casePROTOBUF_C_TYPE_SINT64:casePROTOBUF_C_TYPE_SFIXED64:casePROTOBUF_C_TYPE_UINT64:casePROTOBUF_C_TYPE_FIXED64:casePROTOBUF_C_TYPE_DOUBLE:memcpy(field,dv,8);break;casePROTOBUF_C_TYPE_BOOL:memcpy(field,dv,sizeof(protobuf_c_boolean));break;casePROTOBUF_C_TYPE_BYTES:memcpy(field,dv,sizeof(ProtobufCBinaryData));break;casePROTOBUF_C_TYPE_STRING:casePROTOBUF_C_TYPE_MESSAGE:/* the next line essentially implements a cast from const, which is totally unavoidable. */*(constvoid**)field=dv;break;}}}/* ScannedMember slabs (an unpacking implementation detail). Before doing real unpacking, we first scan through the elements to see how many there are (for repeated fields), and which field to use (for non-repeated fields given twice). * In order to avoid allocations for small messages, we keep a stack-allocated slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we fill that up, we allocate each slab twice as large as the previous one. */#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4/* The number of slabs, including the stack-allocated ones; choose the number so that we would overflow if we needed a slab larger than provided. */#define MAX_SCANNED_MEMBER_SLAB \ (sizeof(void*)*8 - 1 \ - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2)ProtobufCMessage*protobuf_c_message_unpack(constProtobufCMessageDescriptor*desc,ProtobufCAllocator*allocator,size_tlen,constuint8_t*data){ProtobufCMessage*rv;size_trem=len;constuint8_t*at=data;constProtobufCFieldDescriptor*last_field=desc->fields+0;ScannedMemberfirst_member_slab[1<<FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2];/* scanned_member_slabs[i] is an array of arrays of ScannedMember. The first slab (scanned_member_slabs[0] is just a pointer to first_member_slab), above. All subsequent slabs will be allocated using the allocator. */ScannedMember*scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB+1];unsignedwhich_slab=0;/* the slab we are currently populating */unsignedin_slab_index=0;/* number of members in the slab */s