protobuf-c infelizmente não é compatível com a diretiva extend , como:
message extendingmsg {
required string name = 1;
extend msg {
optional extendingmsg msg_ext = 1000;
};
};
Mas há uma solução alternativa, ou seja, o membro base.unknown_fields da mensagem base. O campo desconhecido para uma mensagem é um campo delimitado por comprimento , então ele começa com o comprimento da carga útil codificado na codificação varint seguido pela própria carga útil – a mensagem de extensão.
Assim, você faz isso:
– descompacte o protobuf como o tipo de mensagem base (‘msg’ no exemplo acima)
– a mensagem de extensão (‘extendingmsg’ acima) será (provavelmente) o primeiro e único campo desconhecido.
– decodifique o varint de msg-> base.unknown_fields [0] , certifique-se de manter o controle do tamanho do varint em si (daí a var -parte de varint )
– agora pule o varint e decodifique a carga restante conforme sua tipo de mensagem (‘extendingmsg’ acima).
Ou em código:
int handle_protobuf_extendingmsg (unsigned char *buf, int len) {
msg *m;
extendingmsg *em;
int vlen;
uint64_t plen;
/* Unpack containign msg message. */
if (!(m = msg__unpack(NULL, len, buf)))
return -1;
if (m->base.n_unknown_fields < 1) {
msg__free_unpacked(m, NULL);
return -1;
}
/* The message starts past the varint-encoded length. */
plen = rd_varint_decode_u64(
m->base.unknown_fields[0].data,
m->base.unknown_fields[0].len, &vlen);
if (vlen <= 0) {
/* varint decode failed */
msg__free_unpacked(m, NULL);
return -1;
}
/* Unpack the extendingmsg past the varint */
if (!(em =
extendingmsg__unpack(NULL,
m->base.unknown_fields[0].len-vlen,
m->base.unknown_fields[0].data+vlen))) {
msg__free_unpacked(m, NULL);
return -1;
}
/* em and e are now unpacked and ready to use
* as two separeate protobuf messages. */
printf("name: %sn", em->name);
extendingmsg__free_unpacked(em, NULL);
msg__free_unpacked(m, NULL);
return 0;
}
O código acima utiliza o decodificador varint do librd, que pode ser encontrado aqui:
https://github.com/edenhill/librd