提交 af034d37 编写于 作者: H hjchen2

Merge branch 'dev-latest' of https://github.com/hjchen2/paddle-mobile into dev-latest

...@@ -13,8 +13,8 @@ See the License for the specific language governing permissions and ...@@ -13,8 +13,8 @@ See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#include "io/executor.h" #include "io/executor.h"
#include <operators/math/gemm.h>
#include <algorithm> #include <algorithm>
#include <utility>
#include <vector> #include <vector>
#include "common/enforce.h" #include "common/enforce.h"
#include "common/log.h" #include "common/log.h"
...@@ -26,7 +26,7 @@ limitations under the License. */ ...@@ -26,7 +26,7 @@ limitations under the License. */
#include "framework/program/var_desc.h" #include "framework/program/var_desc.h"
#include "framework/scope.h" #include "framework/scope.h"
#include "framework/tensor.h" #include "framework/tensor.h"
#include "operators/math/gemm.h"
namespace paddle_mobile { namespace paddle_mobile {
...@@ -34,9 +34,8 @@ using framework::Variable; ...@@ -34,9 +34,8 @@ using framework::Variable;
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
Executor<Dtype, P>::Executor(const framework::Program<Dtype> p, Executor<Dtype, P>::Executor(const framework::Program<Dtype> p,
const bool use_optimize, const bool use_optimize, const bool loddable)
const bool loddable) : program_(p), use_optimize_(use_optimize), loddable_(loddable) {
: program_(p), use_optimize_(use_optimize), loddable_(loddable) {
Variable *variable_ptr = program_.scope->Var("batch_size"); Variable *variable_ptr = program_.scope->Var("batch_size");
variable_ptr->SetValue<int>(1); variable_ptr->SetValue<int>(1);
to_predict_program_ = to_predict_program_ =
...@@ -77,20 +76,20 @@ Executor<Dtype, P>::Executor(const framework::Program<Dtype> p, ...@@ -77,20 +76,20 @@ Executor<Dtype, P>::Executor(const framework::Program<Dtype> p,
} }
} }
template<typename Dtype> template <typename Dtype>
void LoadMemInternal(void **data, framework::LoDTensor *tensor) { void LoadMemInternal(void **data, framework::LoDTensor *tensor) {
char **data_buf = reinterpret_cast<char **>(data); char **data_buf = reinterpret_cast<char **>(data);
int64_t size = tensor->numel(); int64_t size = tensor->numel();
Dtype* tensor_data = tensor->mutable_data<Dtype>(); Dtype *tensor_data = tensor->mutable_data<Dtype>();
if (0) { if (0) {
// TODO should be moved into operator init function // TODO(hjchen2) should be moved into operator init function
float min_value; float min_value;
float max_value; float max_value;
memcpy(&min_value, data_buf, sizeof(float)); memcpy(&min_value, data_buf, sizeof(float));
memcpy(&max_value, data_buf + sizeof(float), sizeof(float)); memcpy(&max_value, data_buf + sizeof(float), sizeof(float));
data_buf += 2 * sizeof(float); data_buf += 2 * sizeof(float);
const float factor = (max_value - min_value) / 255.0; const float factor = (max_value - min_value) / 255.0;
const uint8_t *uint8_data = reinterpret_cast<uint8_t*>(data_buf); const uint8_t *uint8_data = reinterpret_cast<uint8_t *>(data_buf);
for (int k = 0; k < size; ++k) { for (int k = 0; k < size; ++k) {
tensor_data[k] = uint8_data[k] * factor + min_value; tensor_data[k] = uint8_data[k] * factor + min_value;
} }
...@@ -103,21 +102,20 @@ void LoadMemInternal(void **data, framework::LoDTensor *tensor) { ...@@ -103,21 +102,20 @@ void LoadMemInternal(void **data, framework::LoDTensor *tensor) {
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
void Executor<Dtype, P>::LoadMemory( void Executor<Dtype, P>::LoadMemory(
void **data, void **data, const std::shared_ptr<framework::VarDesc> var_desc,
const std::shared_ptr<framework::VarDesc> var_desc, framework::LoDTensor *tensor) {
framework::LoDTensor *tensor) { char **data_buf = reinterpret_cast<char **>(data);
char **data_buf = reinterpret_cast<char**>(data);
// version // version
uint32_t version = *(reinterpret_cast<uint32_t*>(*data_buf)); uint32_t version = *(reinterpret_cast<uint32_t *>(*data_buf));
*data_buf += sizeof(uint32_t); *data_buf += sizeof(uint32_t);
// lod information // lod information
uint64_t lod_level = *(reinterpret_cast<uint64_t*>(*data_buf)); uint64_t lod_level = *(reinterpret_cast<uint64_t *>(*data_buf));
*data_buf += sizeof(uint64_t); *data_buf += sizeof(uint64_t);
auto *lod = tensor->mutable_lod(); auto *lod = tensor->mutable_lod();
lod->resize(lod_level); lod->resize(lod_level);
for (uint64_t i = 0; i < lod_level; ++i) { for (uint64_t i = 0; i < lod_level; ++i) {
uint64_t size = *(reinterpret_cast<uint64_t*>(*data_buf)); uint64_t size = *(reinterpret_cast<uint64_t *>(*data_buf));
*data_buf += sizeof(uint64_t); *data_buf += sizeof(uint64_t);
std::vector<size_t> tmp_dim(size / sizeof(size_t)); std::vector<size_t> tmp_dim(size / sizeof(size_t));
memcpy(tmp_dim.data(), *data_buf, size); memcpy(tmp_dim.data(), *data_buf, size);
...@@ -125,10 +123,10 @@ void Executor<Dtype, P>::LoadMemory( ...@@ -125,10 +123,10 @@ void Executor<Dtype, P>::LoadMemory(
*data_buf += size; *data_buf += size;
} }
// tensor version // tensor version
uint32_t tensor_version = *(reinterpret_cast<uint32_t*>(*data_buf)); uint32_t tensor_version = *(reinterpret_cast<uint32_t *>(*data_buf));
*data_buf += sizeof(uint32_t); *data_buf += sizeof(uint32_t);
// tensor desc size // tensor desc size
int32_t tensor_desc_size = *(reinterpret_cast<int32_t*>(*data_buf)); int32_t tensor_desc_size = *(reinterpret_cast<int32_t *>(*data_buf));
*data_buf += sizeof(int32_t); *data_buf += sizeof(int32_t);
// skip tensor desc // skip tensor desc
*data_buf += tensor_desc_size; *data_buf += tensor_desc_size;
...@@ -138,13 +136,13 @@ void Executor<Dtype, P>::LoadMemory( ...@@ -138,13 +136,13 @@ void Executor<Dtype, P>::LoadMemory(
// parse tensor from stream // parse tensor from stream
switch (tensor_desc.DataType()) { switch (tensor_desc.DataType()) {
case framework::VARTYPE_TYPE_FP32: case framework::VARTYPE_TYPE_FP32:
LoadMemInternal<float>((void**)data_buf, tensor); LoadMemInternal<float>(reinterpret_cast<void **>(data_buf), tensor);
break; break;
case framework::VARTYPE_TYPE_INT8: case framework::VARTYPE_TYPE_INT8:
LoadMemInternal<int8_t>((void**)data_buf, tensor); LoadMemInternal<int8_t>(reinterpret_cast<void **>(data_buf), tensor);
break; break;
case framework::VARTYPE_TYPE_INT32: case framework::VARTYPE_TYPE_INT32:
LoadMemInternal<int>((void**)data_buf, tensor); LoadMemInternal<int>(reinterpret_cast<void **>(data_buf), tensor);
break; break;
default: default:
LOG(kLOG_ERROR) << "data type is not supported"; LOG(kLOG_ERROR) << "data type is not supported";
...@@ -164,8 +162,8 @@ void Executor<Dtype, P>::InitMemory() { ...@@ -164,8 +162,8 @@ void Executor<Dtype, P>::InitMemory() {
char *origin_data = char *origin_data =
ReadFileToBuff(program_.model_path + "/" + var_desc->Name()); ReadFileToBuff(program_.model_path + "/" + var_desc->Name());
char *data = origin_data; char *data = origin_data;
LoadMemory((void**)&data, var_desc, tensor); LoadMemory(reinterpret_cast<void **>(&data), var_desc, tensor);
delete [] origin_data; delete[] origin_data;
} else { } else {
if (var_desc->Type() == framework::VARTYPE_TYPE_LOD_TENSOR) { if (var_desc->Type() == framework::VARTYPE_TYPE_LOD_TENSOR) {
varInputMemory(var_desc, var, tensor); varInputMemory(var_desc, var, tensor);
...@@ -180,7 +178,8 @@ void Executor<Dtype, P>::InitCombineMemory() { ...@@ -180,7 +178,8 @@ void Executor<Dtype, P>::InitCombineMemory() {
char *origin_data = nullptr; char *origin_data = nullptr;
bool self_alloc = false; bool self_alloc = false;
if (program_.combined_params_buf && program_.combined_params_len) { if (program_.combined_params_buf && program_.combined_params_len) {
origin_data = (char *)program_.combined_params_buf; origin_data = reinterpret_cast<char *>(
const_cast<uint8_t *>(program_.combined_params_buf));
} else { } else {
self_alloc = true; self_alloc = true;
origin_data = ReadFileToBuff(program_.para_path); origin_data = ReadFileToBuff(program_.para_path);
...@@ -195,7 +194,7 @@ void Executor<Dtype, P>::InitCombineMemory() { ...@@ -195,7 +194,7 @@ void Executor<Dtype, P>::InitCombineMemory() {
if (var_desc->Name() == "feed" || var_desc->Name() == "fetch") { if (var_desc->Name() == "feed" || var_desc->Name() == "fetch") {
continue; continue;
} }
LoadMemory((void**)&data, var_desc, tensor); LoadMemory(reinterpret_cast<void **>(&data), var_desc, tensor);
} else { } else {
if (var_desc->Type() == framework::VARTYPE_TYPE_LOD_TENSOR) { if (var_desc->Type() == framework::VARTYPE_TYPE_LOD_TENSOR) {
varInputMemory(var_desc, var, tensor); varInputMemory(var_desc, var, tensor);
...@@ -204,7 +203,7 @@ void Executor<Dtype, P>::InitCombineMemory() { ...@@ -204,7 +203,7 @@ void Executor<Dtype, P>::InitCombineMemory() {
} }
} }
if (self_alloc) { if (self_alloc) {
delete [] origin_data; delete[] origin_data;
} }
LOG(kLOG_INFO) << "init combine memory finish"; LOG(kLOG_INFO) << "init combine memory finish";
} }
...@@ -231,9 +230,9 @@ bool Executor<Dtype, P>::varInputMemory( ...@@ -231,9 +230,9 @@ bool Executor<Dtype, P>::varInputMemory(
break; break;
} }
bool is_mute_match = (type == framework::VARTYPE_TYPE_FP32) || bool is_mute_match = (type == framework::VARTYPE_TYPE_FP32) ||
(type == framework::VARTYPE_TYPE_INT8) || (type == framework::VARTYPE_TYPE_INT8) ||
(type == framework::VARTYPE_TYPE_INT32) || (type == framework::VARTYPE_TYPE_INT32) ||
(type == framework::VARTYPE_TYPE_INT64); (type == framework::VARTYPE_TYPE_INT64);
PADDLE_MOBILE_ENFORCE(is_mute_match, "got unhandled data type : %d", type); PADDLE_MOBILE_ENFORCE(is_mute_match, "got unhandled data type : %d", type);
return is_mute_match; return is_mute_match;
} }
...@@ -402,12 +401,12 @@ void Executor<Dtype, P>::InjectVariable(const framework::Tensor &t, ...@@ -402,12 +401,12 @@ void Executor<Dtype, P>::InjectVariable(const framework::Tensor &t,
g_feed_value->GetMutable<framework::LoDTensor>(); g_feed_value->GetMutable<framework::LoDTensor>();
feed_tensor->Resize(t.dims()); feed_tensor->Resize(t.dims());
feed_tensor->ShareDataWith(t); feed_tensor->ShareDataWith(t);
}; }
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
void Executor<Dtype, P>::FeedData(const framework::Tensor &t) { void Executor<Dtype, P>::FeedData(const framework::Tensor &t) {
InjectVariable(t, "feed"); InjectVariable(t, "feed");
}; }
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
std::shared_ptr<framework::Tensor> Executor<Dtype, P>::FetchResult(int id) { std::shared_ptr<framework::Tensor> Executor<Dtype, P>::FetchResult(int id) {
...@@ -423,14 +422,14 @@ std::shared_ptr<framework::Tensor> Executor<Dtype, P>::FetchResult(int id) { ...@@ -423,14 +422,14 @@ std::shared_ptr<framework::Tensor> Executor<Dtype, P>::FetchResult(int id) {
auto *output_tensor = framework::GetVarValue<framework::LoDTensor>( auto *output_tensor = framework::GetVarValue<framework::LoDTensor>(
out_keys[0], output_map, *(program_.scope)); out_keys[0], output_map, *(program_.scope));
return std::make_shared<framework::Tensor>(framework::Tensor(*output_tensor)); return std::make_shared<framework::Tensor>(framework::Tensor(*output_tensor));
}; }
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
void Executor<Dtype, P>::Predict_From_To(int start, int end) { void Executor<Dtype, P>::Predict_From_To(int start, int end) {
std::shared_ptr<framework::BlockDesc> to_predict_block = std::shared_ptr<framework::BlockDesc> to_predict_block =
to_predict_program_->Block(0); to_predict_program_->Block(0);
auto &ops = ops_of_block_[*to_predict_block.get()]; auto &ops = ops_of_block_[*to_predict_block.get()];
end = end < 0 ? (int)ops.size() : end; end = end < 0 ? static_cast<int>(ops.size()) : end;
PADDLE_MOBILE_ENFORCE(start >= 0 && start < end && end <= ops.size(), PADDLE_MOBILE_ENFORCE(start >= 0 && start < end && end <= ops.size(),
"start or end parameter is wrong"); "start or end parameter is wrong");
...@@ -451,17 +450,17 @@ void Executor<Dtype, P>::Predict_From_To(int start, int end) { ...@@ -451,17 +450,17 @@ void Executor<Dtype, P>::Predict_From_To(int start, int end) {
profile[i].runEnd = (uint64_t)ts.tv_sec * 1e9 + ts.tv_nsec; profile[i].runEnd = (uint64_t)ts.tv_sec * 1e9 + ts.tv_nsec;
#endif #endif
} }
}; }
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
void Executor<Dtype, P>::Predict_From(int start) { void Executor<Dtype, P>::Predict_From(int start) {
Predict_From_To(start); Predict_From_To(start);
}; }
template <typename Dtype, Precision P> template <typename Dtype, Precision P>
void Executor<Dtype, P>::Predict_To(int end) { void Executor<Dtype, P>::Predict_To(int end) {
Predict_From_To(0, end); Predict_From_To(0, end);
}; }
#endif #endif
template class Executor<CPU, Precision::FP32>; template class Executor<CPU, Precision::FP32>;
......
...@@ -14,16 +14,16 @@ limitations under the License. */ ...@@ -14,16 +14,16 @@ limitations under the License. */
#pragma once #pragma once
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "common/types.h" #include "common/types.h"
#include "common/util.h" #include "common/util.h"
#include "framework/lod_tensor.h" #include "framework/lod_tensor.h"
#include "framework/operator.h" #include "framework/operator.h"
#include "framework/program/program.h" #include "framework/program/program.h"
#include "framework/tensor.h" #include "framework/tensor.h"
#include <memory>
#include <string>
#include <vector>
#include <map>
namespace paddle_mobile { namespace paddle_mobile {
...@@ -36,8 +36,7 @@ class Executor { ...@@ -36,8 +36,7 @@ class Executor {
// @param use_optimize bool whether use operator fusion to speed up or not // @param use_optimize bool whether use operator fusion to speed up or not
// @param loddable bool // @param loddable bool
Executor(const framework::Program<Dtype> program, Executor(const framework::Program<Dtype> program,
const bool use_optimize = true, const bool use_optimize = true, const bool loddable = false);
const bool loddable = false);
// predict with tensor input // predict with tensor input
// @param t input tensor to do prediction // @param t input tensor to do prediction
...@@ -68,8 +67,8 @@ class Executor { ...@@ -68,8 +67,8 @@ class Executor {
framework::LoDTensor *tensor) const; framework::LoDTensor *tensor) const;
void InitMemory(); void InitMemory();
void InitCombineMemory(); void InitCombineMemory();
void LoadMemory(void** data, void LoadMemory(void **data,
const std::shared_ptr<framework::VarDesc> var_desc, const std::shared_ptr<framework::VarDesc> var_desc,
framework::LoDTensor *tensor); framework::LoDTensor *tensor);
framework::Program<Dtype> program_; framework::Program<Dtype> program_;
......
...@@ -30,4 +30,3 @@ namespace ops = paddle_mobile::operators; ...@@ -30,4 +30,3 @@ namespace ops = paddle_mobile::operators;
#ifdef PADDLE_MOBILE_CPU #ifdef PADDLE_MOBILE_CPU
REGISTER_OPERATOR_CPU(dequantize, ops::DequantizeOp); REGISTER_OPERATOR_CPU(dequantize, ops::DequantizeOp);
#endif #endif
...@@ -12,8 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ...@@ -12,8 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#include "feed_op.h" #include "operators/feed_op.h"
namespace ops = paddle_mobile::operators; namespace ops = paddle_mobile::operators;
...@@ -26,4 +25,3 @@ REGISTER_OPERATOR_MALI_GPU(feed, ops::FeedOp); ...@@ -26,4 +25,3 @@ REGISTER_OPERATOR_MALI_GPU(feed, ops::FeedOp);
#ifdef PADDLE_MOBILE_FPGA #ifdef PADDLE_MOBILE_FPGA
REGISTER_OPERATOR_FPGA(feed, ops::FeedOp); REGISTER_OPERATOR_FPGA(feed, ops::FeedOp);
#endif #endif
...@@ -44,7 +44,7 @@ class FeedOp : public framework::OperatorBase<DeviceType> { ...@@ -44,7 +44,7 @@ class FeedOp : public framework::OperatorBase<DeviceType> {
} }
void RunImpl() const { void RunImpl() const {
auto input = (Tensor *)const_cast<LoDTensor *>(param_.InputX()); auto input = reinterpret_cast<Tensor *>(param_.InputX());
fpga::format_image(input); fpga::format_image(input);
auto input_ptr = input->data<float>(); auto input_ptr = input->data<float>();
Tensor *output = param_.Out(); Tensor *output = param_.Out();
...@@ -53,7 +53,7 @@ class FeedOp : public framework::OperatorBase<DeviceType> { ...@@ -53,7 +53,7 @@ class FeedOp : public framework::OperatorBase<DeviceType> {
fpga::BypassArgs args; fpga::BypassArgs args;
args.convert_type = fpga::DATA_FP32_TO_FP16; args.convert_type = fpga::DATA_FP32_TO_FP16;
args.layout_type = fpga::LAYOUT_NO_CONVERT; args.layout_type = fpga::LAYOUT_NO_CONVERT;
args.image.address = (void *)input_ptr; args.image.address = input_ptr;
args.image.channels = input->dims()[1]; args.image.channels = input->dims()[1];
args.image.height = input->dims()[2]; args.image.height = input->dims()[2];
args.image.width = input->dims()[3]; args.image.width = input->dims()[3];
...@@ -78,4 +78,3 @@ class FeedOp : public framework::OperatorBase<DeviceType> { ...@@ -78,4 +78,3 @@ class FeedOp : public framework::OperatorBase<DeviceType> {
} // namespace operators } // namespace operators
} // namespace paddle_mobile } // namespace paddle_mobile
...@@ -12,10 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ...@@ -12,10 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#include "fetch_op.h" #include "operators/fetch_op.h"
namespace paddle_mobile {
namespace operators {}
} // namespace paddle_mobile
namespace ops = paddle_mobile::operators; namespace ops = paddle_mobile::operators;
#ifdef PADDLE_MOBILE_CPU #ifdef PADDLE_MOBILE_CPU
...@@ -27,4 +24,3 @@ REGISTER_OPERATOR_MALI_GPU(fetch, ops::FetchOp); ...@@ -27,4 +24,3 @@ REGISTER_OPERATOR_MALI_GPU(fetch, ops::FetchOp);
#ifdef PADDLE_MOBILE_FPGA #ifdef PADDLE_MOBILE_FPGA
REGISTER_OPERATOR_FPGA(fetch, ops::FetchOp); REGISTER_OPERATOR_FPGA(fetch, ops::FetchOp);
#endif #endif
...@@ -46,4 +46,3 @@ class FetchOp : public framework::OperatorBase<DeviceType> { ...@@ -46,4 +46,3 @@ class FetchOp : public framework::OperatorBase<DeviceType> {
} // namespace operators } // namespace operators
} // namespace paddle_mobile } // namespace paddle_mobile
...@@ -23,16 +23,16 @@ limitations under the License. */ ...@@ -23,16 +23,16 @@ limitations under the License. */
namespace paddle_mobile { namespace paddle_mobile {
namespace operators { namespace operators {
template<> template <>
bool DequantizeKernel<CPU, float>::Init(DequantizeParam<CPU> *param) { bool DequantizeKernel<CPU, float>::Init(DequantizeParam<CPU> *param) {
return true; return true;
} }
template<> template <>
void DequantizeKernel<CPU, float>::Compute( void DequantizeKernel<CPU, float>::Compute(
const DequantizeParam<CPU> &param) const { const DequantizeParam<CPU> &param) const {
const Tensor *input = param.input_; const Tensor *input = param.input_;
Tensor *output = param.out_; Tensor *output = param.out_;
float activation_scale = param.activation_scale_->data<float>()[0]; float activation_scale = param.activation_scale_->data<float>()[0];
float weight_scale = param.weight_scale_; float weight_scale = param.weight_scale_;
const int32_t *x = input->data<const int32_t>(); const int32_t *x = input->data<const int32_t>();
...@@ -70,7 +70,7 @@ void DequantizeKernel<CPU, float>::Compute( ...@@ -70,7 +70,7 @@ void DequantizeKernel<CPU, float>::Compute(
} }
} }
} // namespace paddle_mobile
} // namespace operators } // namespace operators
} // namespace paddle_mobile
#endif #endif
...@@ -28,14 +28,12 @@ float32_t vmaxvq_f32(float32x4_t r) { ...@@ -28,14 +28,12 @@ float32_t vmaxvq_f32(float32x4_t r) {
} }
#endif #endif
int32x4_t vrnd_towards_zero(float32x4_t r) { int32x4_t vrnd_towards_zero(float32x4_t r) { return vcvtq_s32_f32(r); }
return vcvtq_s32_f32(r);
}
int32x4_t vrnd_away_zero(float32x4_t r) { int32x4_t vrnd_away_zero(float32x4_t r) {
float32x4_t plus = vdupq_n_f32(0.5); float32x4_t plus = vdupq_n_f32(0.5);
float32x4_t minus = vdupq_n_f32(-0.5); float32x4_t minus = vdupq_n_f32(-0.5);
float32x4_t zero = vdupq_n_f32(0); float32x4_t zero = vdupq_n_f32(0);
uint32x4_t more_than_zero = vcgtq_f32(r, zero); uint32x4_t more_than_zero = vcgtq_f32(r, zero);
float32x4_t temp = vbslq_f32(more_than_zero, plus, minus); float32x4_t temp = vbslq_f32(more_than_zero, plus, minus);
temp = vaddq_f32(r, temp); temp = vaddq_f32(r, temp);
...@@ -62,7 +60,7 @@ int32x4_t vrnd_to_even(float32x4_t r) { ...@@ -62,7 +60,7 @@ int32x4_t vrnd_to_even(float32x4_t r) {
} }
} }
return ret; return ret;
#else #else
float32x4_t point5 = vdupq_n_f32(0.5); float32x4_t point5 = vdupq_n_f32(0.5);
int32x4_t one = vdupq_n_s32(1); int32x4_t one = vdupq_n_s32(1);
int32x4_t zero = vdupq_n_s32(0); int32x4_t zero = vdupq_n_s32(0);
...@@ -83,9 +81,9 @@ int32x4_t vrnd_to_even(float32x4_t r) { ...@@ -83,9 +81,9 @@ int32x4_t vrnd_to_even(float32x4_t r) {
mask = vaddq_u32(more_than_zero, mask); mask = vaddq_u32(more_than_zero, mask);
int32x4_t smask = vreinterpretq_s32_u32(mask); int32x4_t smask = vreinterpretq_s32_u32(mask);
smask = vsubq_s32(smask, one); smask = vsubq_s32(smask, one);
rnd = vaddq_s32(rnd, smask); rnd = vaddq_s32(rnd, smask);
return rnd; return rnd;
#endif #endif
} }
#endif #endif
...@@ -93,7 +91,7 @@ namespace paddle_mobile { ...@@ -93,7 +91,7 @@ namespace paddle_mobile {
namespace operators { namespace operators {
static float find_abs_max(const Tensor *input) { static float find_abs_max(const Tensor *input) {
float max_abs = float(0); float max_abs = 0.f;
const float *x = input->data<const float>(); const float *x = input->data<const float>();
size_t size = input->numel(); size_t size = input->numel();
#if defined(__ARM_NEON__) || defined(__ARM_NEON) #if defined(__ARM_NEON__) || defined(__ARM_NEON)
...@@ -130,8 +128,7 @@ static float find_abs_max(const Tensor *input) { ...@@ -130,8 +128,7 @@ static float find_abs_max(const Tensor *input) {
return max_abs; return max_abs;
} }
static void quantize_round_to_even(const Tensor *input, static void quantize_round_to_even(const Tensor *input, const float scale,
const float scale,
Tensor *output) { Tensor *output) {
const float *x = input->data<const float>(); const float *x = input->data<const float>();
int8_t *y = output->data<int8_t>(); int8_t *y = output->data<int8_t>();
...@@ -183,9 +180,8 @@ static void quantize_round_to_even(const Tensor *input, ...@@ -183,9 +180,8 @@ static void quantize_round_to_even(const Tensor *input,
} }
} }
static void quantize_round_to_zero(const Tensor *input, static void quantize_round_to_zero(const Tensor *input, const float scale,
const float scale, Tensor *output) {
Tensor *output) {
const float *x = input->data<const float>(); const float *x = input->data<const float>();
int8_t *y = output->data<int8_t>(); int8_t *y = output->data<int8_t>();
size_t size = input->numel(); size_t size = input->numel();
...@@ -225,9 +221,8 @@ static void quantize_round_to_zero(const Tensor *input, ...@@ -225,9 +221,8 @@ static void quantize_round_to_zero(const Tensor *input,
} }
} }
static void quantize_round_to_nearest(const Tensor *input, static void quantize_round_to_nearest(const Tensor *input, const float scale,
const float scale, Tensor *output) {
Tensor *output) {
const float *x = input->data<const float>(); const float *x = input->data<const float>();
int8_t *y = output->data<int8_t>(); int8_t *y = output->data<int8_t>();
size_t size = input->numel(); size_t size = input->numel();
...@@ -267,15 +262,14 @@ static void quantize_round_to_nearest(const Tensor *input, ...@@ -267,15 +262,14 @@ static void quantize_round_to_nearest(const Tensor *input,
} }
} }
template<> template <>
bool QuantizeKernel<CPU, float>::Init(QuantizeParam<CPU> *param) { bool QuantizeKernel<CPU, float>::Init(QuantizeParam<CPU> *param) {
return true; return true;
} }
template<> template <>
void QuantizeKernel<CPU, float>::Compute( void QuantizeKernel<CPU, float>::Compute(
const QuantizeParam<CPU> &param) const { const QuantizeParam<CPU> &param) const {
// TODO
float max_abs = 0.f; float max_abs = 0.f;
const Tensor *input = param.input_; const Tensor *input = param.input_;
Tensor *output = param.out_; Tensor *output = param.out_;
...@@ -306,7 +300,7 @@ void QuantizeKernel<CPU, float>::Compute( ...@@ -306,7 +300,7 @@ void QuantizeKernel<CPU, float>::Compute(
} }
} }
} // namespace paddle_mobile
} // namespace operators } // namespace operators
} // namespace paddle_mobile
#endif #endif
...@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and ...@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#include "operators/quantize_op.h" #include "operators/quantize_op.h"
#include <vector>
namespace paddle_mobile { namespace paddle_mobile {
namespace operators { namespace operators {
...@@ -32,4 +33,3 @@ namespace ops = paddle_mobile::operators; ...@@ -32,4 +33,3 @@ namespace ops = paddle_mobile::operators;
#ifdef PADDLE_MOBILE_CPU #ifdef PADDLE_MOBILE_CPU
REGISTER_OPERATOR_CPU(quantize, ops::QuantizeOp); REGISTER_OPERATOR_CPU(quantize, ops::QuantizeOp);
#endif #endif
...@@ -45,19 +45,19 @@ ...@@ -45,19 +45,19 @@
* \todo Use size_t consistently. * \todo Use size_t consistently.
*/ */
#include <stdlib.h> /* for malloc, free */ #include <stdlib.h> /* for malloc, free */
#include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */ #include <string.h> /* for strcmp, strlen, memcpy, memmove, memset */
#include "protobuf-c.h" #include "protobuf-c.h"
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) #define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0)
/* Workaround for Microsoft compilers. */ /* Workaround for Microsoft compilers. */
#ifdef _MSC_VER #ifdef _MSC_VER
# define inline __inline #define inline __inline
#endif #endif
/** /**
...@@ -78,10 +78,10 @@ ...@@ -78,10 +78,10 @@
*/ */
/** The maximum length of a 64-bit integer in varint encoding. */ /** The maximum length of a 64-bit integer in varint encoding. */
#define MAX_UINT64_ENCODED_SIZE 10 #define MAX_UINT64_ENCODED_SIZE 10
#ifndef PROTOBUF_C_UNPACK_ERROR #ifndef PROTOBUF_C_UNPACK_ERROR
# define PROTOBUF_C_UNPACK_ERROR(...) #define PROTOBUF_C_UNPACK_ERROR(...)
#endif #endif
const char protobuf_c_empty_string[] = ""; const char protobuf_c_empty_string[] = "";
...@@ -93,7 +93,7 @@ const char protobuf_c_empty_string[] = ""; ...@@ -93,7 +93,7 @@ const char protobuf_c_empty_string[] = "";
* STRUCT_MEMBER_PTR(). * STRUCT_MEMBER_PTR().
*/ */
#define STRUCT_MEMBER_P(struct_p, struct_offset) \ #define STRUCT_MEMBER_P(struct_p, struct_offset) \
((void *) ((uint8_t *) (struct_p) + (struct_offset))) ((void *)((uint8_t *)(struct_p) + (struct_offset)))
/** /**
* Return field in a `ProtobufCMessage` based on offset. * Return field in a `ProtobufCMessage` based on offset.
...@@ -102,7 +102,7 @@ const char protobuf_c_empty_string[] = ""; ...@@ -102,7 +102,7 @@ const char protobuf_c_empty_string[] = "";
* Cast it to the passed type. * Cast it to the passed type.
*/ */
#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ #define STRUCT_MEMBER(member_type, struct_p, struct_offset) \
(*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) (*(member_type *)STRUCT_MEMBER_P((struct_p), (struct_offset)))
/** /**
* Return field in a `ProtobufCMessage` based on offset. * Return field in a `ProtobufCMessage` based on offset.
...@@ -111,63 +111,44 @@ const char protobuf_c_empty_string[] = ""; ...@@ -111,63 +111,44 @@ const char protobuf_c_empty_string[] = "";
* it to a pointer to the passed type. * it to a pointer to the passed type.
*/ */
#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ #define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \
((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) ((member_type *)STRUCT_MEMBER_P((struct_p), (struct_offset)))
/* Assertions for magic numbers. */ /* Assertions for magic numbers. */
#define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ #define ASSERT_IS_ENUM_DESCRIPTOR(desc) \
assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC) assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC)
#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ #define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \
assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC)
#define ASSERT_IS_MESSAGE(message) \ #define ASSERT_IS_MESSAGE(message) \
ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor) ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor)
#define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ #define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \
assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC) assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC)
/**@}*/ /**@}*/
/* --- version --- */ /* --- version --- */
const char * const char *protobuf_c_version(void) { return PROTOBUF_C_VERSION; }
protobuf_c_version(void)
{
return PROTOBUF_C_VERSION;
}
uint32_t uint32_t protobuf_c_version_number(void) { return PROTOBUF_C_VERSION_NUMBER; }
protobuf_c_version_number(void)
{
return PROTOBUF_C_VERSION_NUMBER;
}
/* --- allocator --- */ /* --- allocator --- */
static void * static void *system_alloc(void *allocator_data, size_t size) {
system_alloc(void *allocator_data, size_t size) return malloc(size);
{
return malloc(size);
} }
static void static void system_free(void *allocator_data, void *data) { free(data); }
system_free(void *allocator_data, void *data)
{
free(data);
}
static inline void * static inline void *do_alloc(ProtobufCAllocator *allocator, size_t size) {
do_alloc(ProtobufCAllocator *allocator, size_t size) return allocator->alloc(allocator->allocator_data, size);
{
return allocator->alloc(allocator->allocator_data, size);
} }
static inline void static inline void do_free(ProtobufCAllocator *allocator, void *data) {
do_free(ProtobufCAllocator *allocator, void *data) if (data != NULL) allocator->free(allocator->allocator_data, data);
{
if (data != NULL)
allocator->free(allocator->allocator_data, data);
} }
/* /*
...@@ -176,42 +157,37 @@ do_free(ProtobufCAllocator *allocator, void *data) ...@@ -176,42 +157,37 @@ do_free(ProtobufCAllocator *allocator, void *data)
* function. * function.
*/ */
static ProtobufCAllocator protobuf_c__allocator = { static ProtobufCAllocator protobuf_c__allocator = {
.alloc = &system_alloc, .alloc = &system_alloc,
.free = &system_free, .free = &system_free,
.allocator_data = NULL, .allocator_data = NULL,
}; };
/* === buffer-simple === */ /* === buffer-simple === */
void void protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, size_t len,
protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, const uint8_t *data) {
size_t len, const uint8_t *data) ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *)buffer;
{ size_t new_len = simp->len + len;
ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) buffer;
size_t new_len = simp->len + len; if (new_len > simp->alloced) {
ProtobufCAllocator *allocator = simp->allocator;
if (new_len > simp->alloced) { size_t new_alloced = simp->alloced * 2;
ProtobufCAllocator *allocator = simp->allocator; uint8_t *new_data;
size_t new_alloced = simp->alloced * 2;
uint8_t *new_data; if (allocator == NULL) allocator = &protobuf_c__allocator;
while (new_alloced < new_len) new_alloced += new_alloced;
if (allocator == NULL) new_data = do_alloc(allocator, new_alloced);
allocator = &protobuf_c__allocator; if (!new_data) return;
while (new_alloced < new_len) memcpy(new_data, simp->data, simp->len);
new_alloced += new_alloced; if (simp->must_free_data)
new_data = do_alloc(allocator, new_alloced); do_free(allocator, simp->data);
if (!new_data) else
return; simp->must_free_data = TRUE;
memcpy(new_data, simp->data, simp->len); simp->data = new_data;
if (simp->must_free_data) simp->alloced = new_alloced;
do_free(allocator, simp->data); }
else memcpy(simp->data + simp->len, data, len);
simp->must_free_data = TRUE; simp->len = new_len;
simp->data = new_data;
simp->alloced = new_alloced;
}
memcpy(simp->data + simp->len, data, len);
simp->len = new_len;
} }
/** /**
...@@ -232,20 +208,18 @@ protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, ...@@ -232,20 +208,18 @@ protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t get_tag_size(uint32_t number) {
get_tag_size(uint32_t number) if (number < (1UL << 4)) {
{ return 1;
if (number < (1UL << 4)) { } else if (number < (1UL << 11)) {
return 1; return 2;
} else if (number < (1UL << 11)) { } else if (number < (1UL << 18)) {
return 2; return 3;
} else if (number < (1UL << 18)) { } else if (number < (1UL << 25)) {
return 3; return 4;
} else if (number < (1UL << 25)) { } else {
return 4; return 5;
} else { }
return 5;
}
} }
/** /**
...@@ -257,20 +231,18 @@ get_tag_size(uint32_t number) ...@@ -257,20 +231,18 @@ get_tag_size(uint32_t number)
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t uint32_size(uint32_t v) {
uint32_size(uint32_t v) if (v < (1UL << 7)) {
{ return 1;
if (v < (1UL << 7)) { } else if (v < (1UL << 14)) {
return 1; return 2;
} else if (v < (1UL << 14)) { } else if (v < (1UL << 21)) {
return 2; return 3;
} else if (v < (1UL << 21)) { } else if (v < (1UL << 28)) {
return 3; return 4;
} else if (v < (1UL << 28)) { } else {
return 4; return 5;
} else { }
return 5;
}
} }
/** /**
...@@ -282,22 +254,20 @@ uint32_size(uint32_t v) ...@@ -282,22 +254,20 @@ uint32_size(uint32_t v)
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t int32_size(int32_t v) {
int32_size(int32_t v) if (v < 0) {
{ return 10;
if (v < 0) { } else if (v < (1L << 7)) {
return 10; return 1;
} else if (v < (1L << 7)) { } else if (v < (1L << 14)) {
return 1; return 2;
} else if (v < (1L << 14)) { } else if (v < (1L << 21)) {
return 2; return 3;
} else if (v < (1L << 21)) { } else if (v < (1L << 28)) {
return 3; return 4;
} else if (v < (1L << 28)) { } else {
return 4; return 5;
} else { }
return 5;
}
} }
/** /**
...@@ -309,13 +279,11 @@ int32_size(int32_t v) ...@@ -309,13 +279,11 @@ int32_size(int32_t v)
* \return * \return
* ZigZag encoded integer. * ZigZag encoded integer.
*/ */
static inline uint32_t static inline uint32_t zigzag32(int32_t v) {
zigzag32(int32_t v) if (v < 0)
{ return (-(uint32_t)v) * 2 - 1;
if (v < 0) else
return (-(uint32_t)v) * 2 - 1; return (uint32_t)(v)*2;
else
return (uint32_t)(v) * 2;
} }
/** /**
...@@ -328,11 +296,7 @@ zigzag32(int32_t v) ...@@ -328,11 +296,7 @@ zigzag32(int32_t v)
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t sint32_size(int32_t v) { return uint32_size(zigzag32(v)); }
sint32_size(int32_t v)
{
return uint32_size(zigzag32(v));
}
/** /**
* Return the number of bytes required to store a 64-bit unsigned integer in * Return the number of bytes required to store a 64-bit unsigned integer in
...@@ -343,26 +307,24 @@ sint32_size(int32_t v) ...@@ -343,26 +307,24 @@ sint32_size(int32_t v)
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t uint64_size(uint64_t v) {
uint64_size(uint64_t v) uint32_t upper_v = (uint32_t)(v >> 32);
{
uint32_t upper_v = (uint32_t) (v >> 32); if (upper_v == 0) {
return uint32_size((uint32_t)v);
if (upper_v == 0) { } else if (upper_v < (1UL << 3)) {
return uint32_size((uint32_t) v); return 5;
} else if (upper_v < (1UL << 3)) { } else if (upper_v < (1UL << 10)) {
return 5; return 6;
} else if (upper_v < (1UL << 10)) { } else if (upper_v < (1UL << 17)) {
return 6; return 7;
} else if (upper_v < (1UL << 17)) { } else if (upper_v < (1UL << 24)) {
return 7; return 8;
} else if (upper_v < (1UL << 24)) { } else if (upper_v < (1UL << 31)) {
return 8; return 9;
} else if (upper_v < (1UL << 31)) { } else {
return 9; return 10;
} else { }
return 10;
}
} }
/** /**
...@@ -374,13 +336,11 @@ uint64_size(uint64_t v) ...@@ -374,13 +336,11 @@ uint64_size(uint64_t v)
* \return * \return
* ZigZag encoded integer. * ZigZag encoded integer.
*/ */
static inline uint64_t static inline uint64_t zigzag64(int64_t v) {
zigzag64(int64_t v) if (v < 0)
{ return (-(uint64_t)v) * 2 - 1;
if (v < 0) else
return (-(uint64_t)v) * 2 - 1; return (uint64_t)(v)*2;
else
return (uint64_t)(v) * 2;
} }
/** /**
...@@ -393,11 +353,7 @@ zigzag64(int64_t v) ...@@ -393,11 +353,7 @@ zigzag64(int64_t v)
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t sint64_size(int64_t v) { return uint64_size(zigzag64(v)); }
sint64_size(int64_t v)
{
return uint64_size(zigzag64(v));
}
/** /**
* Calculate the serialized size of a single required message field, including * Calculate the serialized size of a single required message field, including
...@@ -410,54 +366,52 @@ sint64_size(int64_t v) ...@@ -410,54 +366,52 @@ sint64_size(int64_t v)
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static size_t static size_t required_field_get_packed_size(
required_field_get_packed_size(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, const void *member) {
const void *member) size_t rv = get_tag_size(field->id);
{
size_t rv = get_tag_size(field->id); switch (field->type) {
case PROTOBUF_C_TYPE_SINT32:
switch (field->type) { return rv + sint32_size(*(const int32_t *)member);
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_ENUM:
return rv + sint32_size(*(const int32_t *) member); case PROTOBUF_C_TYPE_INT32:
case PROTOBUF_C_TYPE_ENUM: return rv + int32_size(*(const int32_t *)member);
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_UINT32:
return rv + int32_size(*(const int32_t *) member); return rv + uint32_size(*(const uint32_t *)member);
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_SINT64:
return rv + uint32_size(*(const uint32_t *) member); return rv + sint64_size(*(const int64_t *)member);
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_INT64:
return rv + sint64_size(*(const int64_t *) member); case PROTOBUF_C_TYPE_UINT64:
case PROTOBUF_C_TYPE_INT64: return rv + uint64_size(*(const uint64_t *)member);
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_SFIXED32:
return rv + uint64_size(*(const uint64_t *) member); case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SFIXED32: return rv + 4;
case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_SFIXED64:
return rv + 4; case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_SFIXED64: return rv + 8;
case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_BOOL:
return rv + 8; return rv + 1;
case PROTOBUF_C_TYPE_BOOL: case PROTOBUF_C_TYPE_FLOAT:
return rv + 1; return rv + 4;
case PROTOBUF_C_TYPE_FLOAT: case PROTOBUF_C_TYPE_DOUBLE:
return rv + 4; return rv + 8;
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_STRING: {
return rv + 8; const char *str = *(char *const *)member;
case PROTOBUF_C_TYPE_STRING: { size_t len = str ? strlen(str) : 0;
const char *str = *(char * const *) member; return rv + uint32_size(len) + len;
size_t len = str ? strlen(str) : 0; }
return rv + uint32_size(len) + len; case PROTOBUF_C_TYPE_BYTES: {
} size_t len = ((const ProtobufCBinaryData *)member)->len;
case PROTOBUF_C_TYPE_BYTES: { return rv + uint32_size(len) + len;
size_t len = ((const ProtobufCBinaryData *) member)->len; }
return rv + uint32_size(len) + len; case PROTOBUF_C_TYPE_MESSAGE: {
} const ProtobufCMessage *msg = *(ProtobufCMessage *const *)member;
case PROTOBUF_C_TYPE_MESSAGE: { size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0;
const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; return rv + uint32_size(subrv) + subrv;
size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0; }
return rv + uint32_size(subrv) + subrv; }
} PROTOBUF_C__ASSERT_NOT_REACHED();
} return 0;
PROTOBUF_C__ASSERT_NOT_REACHED();
return 0;
} }
/** /**
...@@ -474,22 +428,18 @@ required_field_get_packed_size(const ProtobufCFieldDescriptor *field, ...@@ -474,22 +428,18 @@ required_field_get_packed_size(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static size_t static size_t oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field,
oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field, uint32_t oneof_case,
uint32_t oneof_case, const void *member) {
const void *member) if (oneof_case != field->id) {
{ return 0;
if (oneof_case != field->id) { }
return 0; if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
} field->type == PROTOBUF_C_TYPE_STRING) {
if (field->type == PROTOBUF_C_TYPE_MESSAGE || const void *ptr = *(const void *const *)member;
field->type == PROTOBUF_C_TYPE_STRING) if (ptr == NULL || ptr == field->default_value) return 0;
{ }
const void *ptr = *(const void * const *) member; return required_field_get_packed_size(field, member);
if (ptr == NULL || ptr == field->default_value)
return 0;
}
return required_field_get_packed_size(field, member);
} }
/** /**
...@@ -506,69 +456,62 @@ oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field, ...@@ -506,69 +456,62 @@ oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static size_t static size_t optional_field_get_packed_size(
optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, const protobuf_c_boolean has,
const protobuf_c_boolean has, const void *member) {
const void *member) if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
{ field->type == PROTOBUF_C_TYPE_STRING) {
if (field->type == PROTOBUF_C_TYPE_MESSAGE || const void *ptr = *(const void *const *)member;
field->type == PROTOBUF_C_TYPE_STRING) if (ptr == NULL || ptr == field->default_value) return 0;
{ } else {
const void *ptr = *(const void * const *) member; if (!has) return 0;
if (ptr == NULL || ptr == field->default_value) }
return 0; return required_field_get_packed_size(field, member);
} else { }
if (!has)
return 0; static protobuf_c_boolean field_is_zeroish(
} const ProtobufCFieldDescriptor *field, const void *member) {
return required_field_get_packed_size(field, member); protobuf_c_boolean ret = FALSE;
}
switch (field->type) {
static protobuf_c_boolean case PROTOBUF_C_TYPE_BOOL:
field_is_zeroish(const ProtobufCFieldDescriptor *field, ret = (0 == *(const protobuf_c_boolean *)member);
const void *member) break;
{ case PROTOBUF_C_TYPE_ENUM:
protobuf_c_boolean ret = FALSE; case PROTOBUF_C_TYPE_SINT32:
case PROTOBUF_C_TYPE_INT32:
switch (field->type) { case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_BOOL: case PROTOBUF_C_TYPE_SFIXED32:
ret = (0 == *(const protobuf_c_boolean *) member); case PROTOBUF_C_TYPE_FIXED32:
break; ret = (0 == *(const uint32_t *)member);
case PROTOBUF_C_TYPE_ENUM: break;
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_SINT64:
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_UINT64:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FIXED64:
ret = (0 == *(const uint32_t *) member); ret = (0 == *(const uint64_t *)member);
break; break;
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_INT64: ret = (0 == *(const float *)member);
case PROTOBUF_C_TYPE_UINT64: break;
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_FIXED64: ret = (0 == *(const double *)member);
ret = (0 == *(const uint64_t *) member); break;
break; case PROTOBUF_C_TYPE_STRING:
case PROTOBUF_C_TYPE_FLOAT: ret = (NULL == *(const char *const *)member) ||
ret = (0 == *(const float *) member); ('\0' == **(const char *const *)member);
break; break;
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_BYTES:
ret = (0 == *(const double *) member); case PROTOBUF_C_TYPE_MESSAGE:
break; ret = (NULL == *(const void *const *)member);
case PROTOBUF_C_TYPE_STRING: break;
ret = (NULL == *(const char * const *) member) || default:
('\0' == **(const char * const *) member); ret = TRUE;
break; break;
case PROTOBUF_C_TYPE_BYTES: }
case PROTOBUF_C_TYPE_MESSAGE:
ret = (NULL == *(const void * const *) member); return ret;
break;
default:
ret = TRUE;
break;
}
return ret;
} }
/** /**
...@@ -584,13 +527,10 @@ field_is_zeroish(const ProtobufCFieldDescriptor *field, ...@@ -584,13 +527,10 @@ field_is_zeroish(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static size_t static size_t unlabeled_field_get_packed_size(
unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, const void *member) {
const void *member) if (field_is_zeroish(field, member)) return 0;
{ return required_field_get_packed_size(field, member);
if (field_is_zeroish(field, member))
return 0;
return required_field_get_packed_size(field, member);
} }
/** /**
...@@ -607,81 +547,72 @@ unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field, ...@@ -607,81 +547,72 @@ unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static size_t static size_t repeated_field_get_packed_size(
repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, size_t count, const void *member) {
size_t count, const void *member) size_t header_size;
{ size_t rv = 0;
size_t header_size; unsigned i;
size_t rv = 0; void *array = *(void *const *)member;
unsigned i;
void *array = *(void * const *) member; if (count == 0) return 0;
header_size = get_tag_size(field->id);
if (count == 0) if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) header_size *= count;
return 0;
header_size = get_tag_size(field->id); switch (field->type) {
if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) case PROTOBUF_C_TYPE_SINT32:
header_size *= count; for (i = 0; i < count; i++) rv += sint32_size(((int32_t *)array)[i]);
break;
switch (field->type) { case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_INT32:
for (i = 0; i < count; i++) for (i = 0; i < count; i++) rv += int32_size(((int32_t *)array)[i]);
rv += sint32_size(((int32_t *) array)[i]); break;
break; case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_ENUM: for (i = 0; i < count; i++) rv += uint32_size(((uint32_t *)array)[i]);
case PROTOBUF_C_TYPE_INT32: break;
for (i = 0; i < count; i++) case PROTOBUF_C_TYPE_SINT64:
rv += int32_size(((int32_t *) array)[i]); for (i = 0; i < count; i++) rv += sint64_size(((int64_t *)array)[i]);
break; break;
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_INT64:
for (i = 0; i < count; i++) case PROTOBUF_C_TYPE_UINT64:
rv += uint32_size(((uint32_t *) array)[i]); for (i = 0; i < count; i++) rv += uint64_size(((uint64_t *)array)[i]);
break; break;
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_SFIXED32:
for (i = 0; i < count; i++) case PROTOBUF_C_TYPE_FIXED32:
rv += sint64_size(((int64_t *) array)[i]); case PROTOBUF_C_TYPE_FLOAT:
break; rv += 4 * count;
case PROTOBUF_C_TYPE_INT64: break;
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_SFIXED64:
for (i = 0; i < count; i++) case PROTOBUF_C_TYPE_FIXED64:
rv += uint64_size(((uint64_t *) array)[i]); case PROTOBUF_C_TYPE_DOUBLE:
break; rv += 8 * count;
case PROTOBUF_C_TYPE_SFIXED32: break;
case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_BOOL:
case PROTOBUF_C_TYPE_FLOAT: rv += count;
rv += 4 * count; break;
break; case PROTOBUF_C_TYPE_STRING:
case PROTOBUF_C_TYPE_SFIXED64: for (i = 0; i < count; i++) {
case PROTOBUF_C_TYPE_FIXED64: size_t len = strlen(((char **)array)[i]);
case PROTOBUF_C_TYPE_DOUBLE: rv += uint32_size(len) + len;
rv += 8 * count; }
break; break;
case PROTOBUF_C_TYPE_BOOL: case PROTOBUF_C_TYPE_BYTES:
rv += count; for (i = 0; i < count; i++) {
break; size_t len = ((ProtobufCBinaryData *)array)[i].len;
case PROTOBUF_C_TYPE_STRING: rv += uint32_size(len) + len;
for (i = 0; i < count; i++) { }
size_t len = strlen(((char **) array)[i]); break;
rv += uint32_size(len) + len; case PROTOBUF_C_TYPE_MESSAGE:
} for (i = 0; i < count; i++) {
break; size_t len =
case PROTOBUF_C_TYPE_BYTES: protobuf_c_message_get_packed_size(((ProtobufCMessage **)array)[i]);
for (i = 0; i < count; i++) { rv += uint32_size(len) + len;
size_t len = ((ProtobufCBinaryData *) array)[i].len; }
rv += uint32_size(len) + len; break;
} }
break;
case PROTOBUF_C_TYPE_MESSAGE: if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED))
for (i = 0; i < count; i++) { header_size += uint32_size(rv);
size_t len = protobuf_c_message_get_packed_size( return header_size + rv;
((ProtobufCMessage **) array)[i]);
rv += uint32_size(len) + len;
}
break;
}
if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED))
header_size += uint32_size(rv);
return header_size + rv;
} }
/** /**
...@@ -694,10 +625,9 @@ repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, ...@@ -694,10 +625,9 @@ repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static inline size_t static inline size_t unknown_field_get_packed_size(
unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) const ProtobufCMessageUnknownField *field) {
{ return get_tag_size(field->tag) + field->len;
return get_tag_size(field->tag) + field->len;
} }
/**@}*/ /**@}*/
...@@ -705,52 +635,36 @@ unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) ...@@ -705,52 +635,36 @@ unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field)
/* /*
* Calculate the serialized size of the message. * Calculate the serialized size of the message.
*/ */
size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) {
{ unsigned i;
unsigned i; size_t rv = 0;
size_t rv = 0;
ASSERT_IS_MESSAGE(message);
ASSERT_IS_MESSAGE(message); for (i = 0; i < message->descriptor->n_fields; i++) {
for (i = 0; i < message->descriptor->n_fields; i++) { const ProtobufCFieldDescriptor *field = message->descriptor->fields + i;
const ProtobufCFieldDescriptor *field = const void *member = ((const char *)message) + field->offset;
message->descriptor->fields + i; const void *qmember = ((const char *)message) + field->quantifier_offset;
const void *member =
((const char *) message) + field->offset; if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
const void *qmember = rv += required_field_get_packed_size(field, member);
((const char *) message) + field->quantifier_offset; } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL ||
field->label == PROTOBUF_C_LABEL_NONE) &&
if (field->label == PROTOBUF_C_LABEL_REQUIRED) { (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) {
rv += required_field_get_packed_size(field, member); rv += oneof_field_get_packed_size(field, *(const uint32_t *)qmember,
} else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || member);
field->label == PROTOBUF_C_LABEL_NONE) && } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) {
(0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { rv += optional_field_get_packed_size(
rv += oneof_field_get_packed_size( field, *(protobuf_c_boolean *)qmember, member);
field, } else if (field->label == PROTOBUF_C_LABEL_NONE) {
*(const uint32_t *) qmember, rv += unlabeled_field_get_packed_size(field, member);
member } else {
); rv += repeated_field_get_packed_size(field, *(const size_t *)qmember,
} else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { member);
rv += optional_field_get_packed_size( }
field, }
*(protobuf_c_boolean *) qmember, for (i = 0; i < message->n_unknown_fields; i++)
member rv += unknown_field_get_packed_size(&message->unknown_fields[i]);
); return rv;
} else if (field->label == PROTOBUF_C_LABEL_NONE) {
rv += unlabeled_field_get_packed_size(
field,
member
);
} else {
rv += repeated_field_get_packed_size(
field,
*(const size_t *) qmember,
member
);
}
}
for (i = 0; i < message->n_unknown_fields; i++)
rv += unknown_field_get_packed_size(&message->unknown_fields[i]);
return rv;
} }
/** /**
...@@ -773,30 +687,28 @@ size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) ...@@ -773,30 +687,28 @@ size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t uint32_pack(uint32_t value, uint8_t *out) {
uint32_pack(uint32_t value, uint8_t *out) unsigned rv = 0;
{
unsigned rv = 0; if (value >= 0x80) {
out[rv++] = value | 0x80;
if (value >= 0x80) { value >>= 7;
out[rv++] = value | 0x80; if (value >= 0x80) {
value >>= 7; out[rv++] = value | 0x80;
if (value >= 0x80) { value >>= 7;
out[rv++] = value | 0x80; if (value >= 0x80) {
value >>= 7; out[rv++] = value | 0x80;
if (value >= 0x80) { value >>= 7;
out[rv++] = value | 0x80; if (value >= 0x80) {
value >>= 7; out[rv++] = value | 0x80;
if (value >= 0x80) { value >>= 7;
out[rv++] = value | 0x80; }
value >>= 7; }
} }
} }
} /* assert: value<128 */
} out[rv++] = value;
/* assert: value<128 */ return rv;
out[rv++] = value;
return rv;
} }
/** /**
...@@ -810,21 +722,19 @@ uint32_pack(uint32_t value, uint8_t *out) ...@@ -810,21 +722,19 @@ uint32_pack(uint32_t value, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t int32_pack(int32_t value, uint8_t *out) {
int32_pack(int32_t value, uint8_t *out) if (value < 0) {
{ out[0] = value | 0x80;
if (value < 0) { out[1] = (value >> 7) | 0x80;
out[0] = value | 0x80; out[2] = (value >> 14) | 0x80;
out[1] = (value >> 7) | 0x80; out[3] = (value >> 21) | 0x80;
out[2] = (value >> 14) | 0x80; out[4] = (value >> 28) | 0x80;
out[3] = (value >> 21) | 0x80; out[5] = out[6] = out[7] = out[8] = 0xff;
out[4] = (value >> 28) | 0x80; out[9] = 0x01;
out[5] = out[6] = out[7] = out[8] = 0xff; return 10;
out[9] = 0x01; } else {
return 10; return uint32_pack(value, out);
} else { }
return uint32_pack(value, out);
}
} }
/** /**
...@@ -838,10 +748,8 @@ int32_pack(int32_t value, uint8_t *out) ...@@ -838,10 +748,8 @@ int32_pack(int32_t value, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t sint32_pack(int32_t value, uint8_t *out) {
sint32_pack(int32_t value, uint8_t *out) return uint32_pack(zigzag32(value), out);
{
return uint32_pack(zigzag32(value), out);
} }
/** /**
...@@ -855,33 +763,30 @@ sint32_pack(int32_t value, uint8_t *out) ...@@ -855,33 +763,30 @@ sint32_pack(int32_t value, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static size_t static size_t uint64_pack(uint64_t value, uint8_t *out) {
uint64_pack(uint64_t value, uint8_t *out) uint32_t hi = (uint32_t)(value >> 32);
{ uint32_t lo = (uint32_t)value;
uint32_t hi = (uint32_t) (value >> 32); unsigned rv;
uint32_t lo = (uint32_t) value;
unsigned rv; if (hi == 0) return uint32_pack((uint32_t)lo, out);
out[0] = (lo) | 0x80;
if (hi == 0) out[1] = (lo >> 7) | 0x80;
return uint32_pack((uint32_t) lo, out); out[2] = (lo >> 14) | 0x80;
out[0] = (lo) | 0x80; out[3] = (lo >> 21) | 0x80;
out[1] = (lo >> 7) | 0x80; if (hi < 8) {
out[2] = (lo >> 14) | 0x80; out[4] = (hi << 4) | (lo >> 28);
out[3] = (lo >> 21) | 0x80; return 5;
if (hi < 8) { } else {
out[4] = (hi << 4) | (lo >> 28); out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80;
return 5; hi >>= 3;
} else { }
out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; rv = 5;
hi >>= 3; while (hi >= 128) {
} out[rv++] = hi | 0x80;
rv = 5; hi >>= 7;
while (hi >= 128) { }
out[rv++] = hi | 0x80; out[rv++] = hi;
hi >>= 7; return rv;
}
out[rv++] = hi;
return rv;
} }
/** /**
...@@ -895,10 +800,8 @@ uint64_pack(uint64_t value, uint8_t *out) ...@@ -895,10 +800,8 @@ uint64_pack(uint64_t value, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t sint64_pack(int64_t value, uint8_t *out) {
sint64_pack(int64_t value, uint8_t *out) return uint64_pack(zigzag64(value), out);
{
return uint64_pack(zigzag64(value), out);
} }
/** /**
...@@ -912,20 +815,18 @@ sint64_pack(int64_t value, uint8_t *out) ...@@ -912,20 +815,18 @@ sint64_pack(int64_t value, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t fixed32_pack(uint32_t value, void *out) {
fixed32_pack(uint32_t value, void *out)
{
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
memcpy(out, &value, 4); memcpy(out, &value, 4);
#else #else
uint8_t *buf = out; uint8_t *buf = out;
buf[0] = value; buf[0] = value;
buf[1] = value >> 8; buf[1] = value >> 8;
buf[2] = value >> 16; buf[2] = value >> 16;
buf[3] = value >> 24; buf[3] = value >> 24;
#endif #endif
return 4; return 4;
} }
/** /**
...@@ -943,16 +844,14 @@ fixed32_pack(uint32_t value, void *out) ...@@ -943,16 +844,14 @@ fixed32_pack(uint32_t value, void *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t fixed64_pack(uint64_t value, void *out) {
fixed64_pack(uint64_t value, void *out)
{
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
memcpy(out, &value, 8); memcpy(out, &value, 8);
#else #else
fixed32_pack(value, out); fixed32_pack(value, out);
fixed32_pack(value >> 32, ((char *) out) + 4); fixed32_pack(value >> 32, ((char *)out) + 4);
#endif #endif
return 8; return 8;
} }
/** /**
...@@ -968,11 +867,9 @@ fixed64_pack(uint64_t value, void *out) ...@@ -968,11 +867,9 @@ fixed64_pack(uint64_t value, void *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t boolean_pack(protobuf_c_boolean value, uint8_t *out) {
boolean_pack(protobuf_c_boolean value, uint8_t *out) *out = value ? TRUE : FALSE;
{ return 1;
*out = value ? TRUE : FALSE;
return 1;
} }
/** /**
...@@ -990,18 +887,16 @@ boolean_pack(protobuf_c_boolean value, uint8_t *out) ...@@ -990,18 +887,16 @@ boolean_pack(protobuf_c_boolean value, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t string_pack(const char *str, uint8_t *out) {
string_pack(const char *str, uint8_t *out) if (str == NULL) {
{ out[0] = 0;
if (str == NULL) { return 1;
out[0] = 0; } else {
return 1; size_t len = strlen(str);
} else { size_t rv = uint32_pack(len, out);
size_t len = strlen(str); memcpy(out + rv, str, len);
size_t rv = uint32_pack(len, out); return rv + len;
memcpy(out + rv, str, len); }
return rv + len;
}
} }
/** /**
...@@ -1015,13 +910,12 @@ string_pack(const char *str, uint8_t *out) ...@@ -1015,13 +910,12 @@ string_pack(const char *str, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t binary_data_pack(const ProtobufCBinaryData *bd,
binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) uint8_t *out) {
{ size_t len = bd->len;
size_t len = bd->len; size_t rv = uint32_pack(len, out);
size_t rv = uint32_pack(len, out); memcpy(out + rv, bd->data, len);
memcpy(out + rv, bd->data, len); return rv + len;
return rv + len;
} }
/** /**
...@@ -1035,19 +929,17 @@ binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) ...@@ -1035,19 +929,17 @@ binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static inline size_t static inline size_t prefixed_message_pack(const ProtobufCMessage *message,
prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) uint8_t *out) {
{ if (message == NULL) {
if (message == NULL) { out[0] = 0;
out[0] = 0; return 1;
return 1; } else {
} else { size_t rv = protobuf_c_message_pack(message, out + 1);
size_t rv = protobuf_c_message_pack(message, out + 1); uint32_t rv_packed_size = uint32_size(rv);
uint32_t rv_packed_size = uint32_size(rv); if (rv_packed_size != 1) memmove(out + rv_packed_size, out + 1, rv);
if (rv_packed_size != 1) return uint32_pack(rv, out) + rv;
memmove(out + rv_packed_size, out + 1, rv); }
return uint32_pack(rv, out) + rv;
}
} }
/** /**
...@@ -1064,13 +956,11 @@ prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) ...@@ -1064,13 +956,11 @@ prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static size_t static size_t tag_pack(uint32_t id, uint8_t *out) {
tag_pack(uint32_t id, uint8_t *out) if (id < (1UL << (32 - 3)))
{ return uint32_pack(id << 3, out);
if (id < (1UL << (32 - 3))) else
return uint32_pack(id << 3, out); return uint64_pack(((uint64_t)id) << 3, out);
else
return uint64_pack(((uint64_t) id) << 3, out);
} }
/** /**
...@@ -1085,55 +975,55 @@ tag_pack(uint32_t id, uint8_t *out) ...@@ -1085,55 +975,55 @@ tag_pack(uint32_t id, uint8_t *out)
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static size_t static size_t required_field_pack(const ProtobufCFieldDescriptor *field,
required_field_pack(const ProtobufCFieldDescriptor *field, const void *member, uint8_t *out) {
const void *member, uint8_t *out) size_t rv = tag_pack(field->id, out);
{
size_t rv = tag_pack(field->id, out); switch (field->type) {
case PROTOBUF_C_TYPE_SINT32:
switch (field->type) { out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
case PROTOBUF_C_TYPE_SINT32: return rv + sint32_pack(*(const int32_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; case PROTOBUF_C_TYPE_ENUM:
return rv + sint32_pack(*(const int32_t *) member, out + rv); case PROTOBUF_C_TYPE_INT32:
case PROTOBUF_C_TYPE_ENUM: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
case PROTOBUF_C_TYPE_INT32: return rv + int32_pack(*(const int32_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; case PROTOBUF_C_TYPE_UINT32:
return rv + int32_pack(*(const int32_t *) member, out + rv); out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
case PROTOBUF_C_TYPE_UINT32: return rv + uint32_pack(*(const uint32_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; case PROTOBUF_C_TYPE_SINT64:
return rv + uint32_pack(*(const uint32_t *) member, out + rv); out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
case PROTOBUF_C_TYPE_SINT64: return rv + sint64_pack(*(const int64_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; case PROTOBUF_C_TYPE_INT64:
return rv + sint64_pack(*(const int64_t *) member, out + rv); case PROTOBUF_C_TYPE_UINT64:
case PROTOBUF_C_TYPE_INT64: out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
case PROTOBUF_C_TYPE_UINT64: return rv + uint64_pack(*(const uint64_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; case PROTOBUF_C_TYPE_SFIXED32:
return rv + uint64_pack(*(const uint64_t *) member, out + rv); case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FIXED32: out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT;
case PROTOBUF_C_TYPE_FLOAT: return rv + fixed32_pack(*(const uint32_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; case PROTOBUF_C_TYPE_SFIXED64:
return rv + fixed32_pack(*(const uint32_t *) member, out + rv); case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_FIXED64: out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT;
case PROTOBUF_C_TYPE_DOUBLE: return rv + fixed64_pack(*(const uint64_t *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; case PROTOBUF_C_TYPE_BOOL:
return rv + fixed64_pack(*(const uint64_t *) member, out + rv); out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
case PROTOBUF_C_TYPE_BOOL: return rv + boolean_pack(*(const protobuf_c_boolean *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; case PROTOBUF_C_TYPE_STRING:
return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
case PROTOBUF_C_TYPE_STRING: return rv + string_pack(*(char *const *)member, out + rv);
out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; case PROTOBUF_C_TYPE_BYTES:
return rv + string_pack(*(char *const *) member, out + rv); out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
case PROTOBUF_C_TYPE_BYTES: return rv +
out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; binary_data_pack((const ProtobufCBinaryData *)member, out + rv);
return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv); case PROTOBUF_C_TYPE_MESSAGE:
case PROTOBUF_C_TYPE_MESSAGE: out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; return rv + prefixed_message_pack(*(ProtobufCMessage *const *)member,
return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); out + rv);
} }
PROTOBUF_C__ASSERT_NOT_REACHED(); PROTOBUF_C__ASSERT_NOT_REACHED();
return 0; return 0;
} }
/** /**
...@@ -1151,22 +1041,18 @@ required_field_pack(const ProtobufCFieldDescriptor *field, ...@@ -1151,22 +1041,18 @@ required_field_pack(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static size_t static size_t oneof_field_pack(const ProtobufCFieldDescriptor *field,
oneof_field_pack(const ProtobufCFieldDescriptor *field, uint32_t oneof_case, const void *member,
uint32_t oneof_case, uint8_t *out) {
const void *member, uint8_t *out) if (oneof_case != field->id) {
{ return 0;
if (oneof_case != field->id) { }
return 0; if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
} field->type == PROTOBUF_C_TYPE_STRING) {
if (field->type == PROTOBUF_C_TYPE_MESSAGE || const void *ptr = *(const void *const *)member;
field->type == PROTOBUF_C_TYPE_STRING) if (ptr == NULL || ptr == field->default_value) return 0;
{ }
const void *ptr = *(const void * const *) member; return required_field_pack(field, member, out);
if (ptr == NULL || ptr == field->default_value)
return 0;
}
return required_field_pack(field, member, out);
} }
/** /**
...@@ -1183,22 +1069,17 @@ oneof_field_pack(const ProtobufCFieldDescriptor *field, ...@@ -1183,22 +1069,17 @@ oneof_field_pack(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static size_t static size_t optional_field_pack(const ProtobufCFieldDescriptor *field,
optional_field_pack(const ProtobufCFieldDescriptor *field, const protobuf_c_boolean has,
const protobuf_c_boolean has, const void *member, uint8_t *out) {
const void *member, uint8_t *out) if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
{ field->type == PROTOBUF_C_TYPE_STRING) {
if (field->type == PROTOBUF_C_TYPE_MESSAGE || const void *ptr = *(const void *const *)member;
field->type == PROTOBUF_C_TYPE_STRING) if (ptr == NULL || ptr == field->default_value) return 0;
{ } else {
const void *ptr = *(const void * const *) member; if (!has) return 0;
if (ptr == NULL || ptr == field->default_value) }
return 0; return required_field_pack(field, member, out);
} else {
if (!has)
return 0;
}
return required_field_pack(field, member, out);
} }
/** /**
...@@ -1213,13 +1094,10 @@ optional_field_pack(const ProtobufCFieldDescriptor *field, ...@@ -1213,13 +1094,10 @@ optional_field_pack(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes written to `out`. * Number of bytes written to `out`.
*/ */
static size_t static size_t unlabeled_field_pack(const ProtobufCFieldDescriptor *field,
unlabeled_field_pack(const ProtobufCFieldDescriptor *field, const void *member, uint8_t *out) {
const void *member, uint8_t *out) if (field_is_zeroish(field, member)) return 0;
{ return required_field_pack(field, member, out);
if (field_is_zeroish(field, member))
return 0;
return required_field_pack(field, member, out);
} }
/** /**
...@@ -1232,35 +1110,33 @@ unlabeled_field_pack(const ProtobufCFieldDescriptor *field, ...@@ -1232,35 +1110,33 @@ unlabeled_field_pack(const ProtobufCFieldDescriptor *field,
* \return * \return
* Size of the field. * Size of the field.
*/ */
static inline size_t static inline size_t sizeof_elt_in_repeated_array(ProtobufCType type) {
sizeof_elt_in_repeated_array(ProtobufCType type) switch (type) {
{ case PROTOBUF_C_TYPE_SINT32:
switch (type) { case PROTOBUF_C_TYPE_INT32:
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_SFIXED32:
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_FLOAT: return 4;
case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_SINT64:
return 4; case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_UINT64:
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_FIXED64: return 8;
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_BOOL:
return 8; return sizeof(protobuf_c_boolean);
case PROTOBUF_C_TYPE_BOOL: case PROTOBUF_C_TYPE_STRING:
return sizeof(protobuf_c_boolean); case PROTOBUF_C_TYPE_MESSAGE:
case PROTOBUF_C_TYPE_STRING: return sizeof(void *);
case PROTOBUF_C_TYPE_MESSAGE: case PROTOBUF_C_TYPE_BYTES:
return sizeof(void *); return sizeof(ProtobufCBinaryData);
case PROTOBUF_C_TYPE_BYTES: }
return sizeof(ProtobufCBinaryData); PROTOBUF_C__ASSERT_NOT_REACHED();
} return 0;
PROTOBUF_C__ASSERT_NOT_REACHED();
return 0;
} }
/** /**
...@@ -1273,16 +1149,14 @@ sizeof_elt_in_repeated_array(ProtobufCType type) ...@@ -1273,16 +1149,14 @@ sizeof_elt_in_repeated_array(ProtobufCType type)
* \param[in] n * \param[in] n
* Number of elements in the source array. * Number of elements in the source array.
*/ */
static void static void copy_to_little_endian_32(void *out, const void *in,
copy_to_little_endian_32(void *out, const void *in, const unsigned n) const unsigned n) {
{
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
memcpy(out, in, n * 4); memcpy(out, in, n * 4);
#else #else
unsigned i; unsigned i;
const uint32_t *ini = in; const uint32_t *ini = in;
for (i = 0; i < n; i++) for (i = 0; i < n; i++) fixed32_pack(ini[i], (uint32_t *)out + i);
fixed32_pack(ini[i], (uint32_t *) out + i);
#endif #endif
} }
...@@ -1296,16 +1170,14 @@ copy_to_little_endian_32(void *out, const void *in, const unsigned n) ...@@ -1296,16 +1170,14 @@ copy_to_little_endian_32(void *out, const void *in, const unsigned n)
* \param[in] n * \param[in] n
* Number of elements in the source array. * Number of elements in the source array.
*/ */
static void static void copy_to_little_endian_64(void *out, const void *in,
copy_to_little_endian_64(void *out, const void *in, const unsigned n) const unsigned n) {
{
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
memcpy(out, in, n * 8); memcpy(out, in, n * 8);
#else #else
unsigned i; unsigned i;
const uint64_t *ini = in; const uint64_t *ini = in;
for (i = 0; i < n; i++) for (i = 0; i < n; i++) fixed64_pack(ini[i], (uint64_t *)out + i);
fixed64_pack(ini[i], (uint64_t *) out + i);
#endif #endif
} }
...@@ -1318,22 +1190,16 @@ copy_to_little_endian_64(void *out, const void *in, const unsigned n) ...@@ -1318,22 +1190,16 @@ copy_to_little_endian_64(void *out, const void *in, const unsigned n)
* \return * \return
* Number of bytes. * Number of bytes.
*/ */
static unsigned static unsigned get_type_min_size(ProtobufCType type) {
get_type_min_size(ProtobufCType type) if (type == PROTOBUF_C_TYPE_SFIXED32 || type == PROTOBUF_C_TYPE_FIXED32 ||
{ type == PROTOBUF_C_TYPE_FLOAT) {
if (type == PROTOBUF_C_TYPE_SFIXED32 || return 4;
type == PROTOBUF_C_TYPE_FIXED32 || }
type == PROTOBUF_C_TYPE_FLOAT) if (type == PROTOBUF_C_TYPE_SFIXED64 || type == PROTOBUF_C_TYPE_FIXED64 ||
{ type == PROTOBUF_C_TYPE_DOUBLE) {
return 4; return 8;
} }
if (type == PROTOBUF_C_TYPE_SFIXED64 || return 1;
type == PROTOBUF_C_TYPE_FIXED64 ||
type == PROTOBUF_C_TYPE_DOUBLE)
{
return 8;
}
return 1;
} }
/** /**
...@@ -1351,174 +1217,159 @@ get_type_min_size(ProtobufCType type) ...@@ -1351,174 +1217,159 @@ get_type_min_size(ProtobufCType type)
* \return * \return
* Number of bytes serialised to `out`. * Number of bytes serialised to `out`.
*/ */
static size_t static size_t repeated_field_pack(const ProtobufCFieldDescriptor *field,
repeated_field_pack(const ProtobufCFieldDescriptor *field, size_t count, const void *member,
size_t count, const void *member, uint8_t *out) uint8_t *out) {
{ void *array = *(void *const *)member;
void *array = *(void * const *) member; unsigned i;
unsigned i;
if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) {
if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { unsigned header_len;
unsigned header_len; unsigned len_start;
unsigned len_start; unsigned min_length;
unsigned min_length; unsigned payload_len;
unsigned payload_len; unsigned length_size_min;
unsigned length_size_min; unsigned actual_length_size;
unsigned actual_length_size; uint8_t *payload_at;
uint8_t *payload_at;
if (count == 0) return 0;
if (count == 0) header_len = tag_pack(field->id, out);
return 0; out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
header_len = tag_pack(field->id, out); len_start = header_len;
out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; min_length = get_type_min_size(field->type) * count;
len_start = header_len; length_size_min = uint32_size(min_length);
min_length = get_type_min_size(field->type) * count; header_len += length_size_min;
length_size_min = uint32_size(min_length); payload_at = out + header_len;
header_len += length_size_min;
payload_at = out + header_len; switch (field->type) {
case PROTOBUF_C_TYPE_SFIXED32:
switch (field->type) { case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FIXED32: copy_to_little_endian_32(payload_at, array, count);
case PROTOBUF_C_TYPE_FLOAT: payload_at += count * 4;
copy_to_little_endian_32(payload_at, array, count); break;
payload_at += count * 4; case PROTOBUF_C_TYPE_SFIXED64:
break; case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_FIXED64: copy_to_little_endian_64(payload_at, array, count);
case PROTOBUF_C_TYPE_DOUBLE: payload_at += count * 8;
copy_to_little_endian_64(payload_at, array, count); break;
payload_at += count * 8; case PROTOBUF_C_TYPE_ENUM:
break; case PROTOBUF_C_TYPE_INT32: {
case PROTOBUF_C_TYPE_ENUM: const int32_t *arr = (const int32_t *)array;
case PROTOBUF_C_TYPE_INT32: { for (i = 0; i < count; i++)
const int32_t *arr = (const int32_t *) array; payload_at += int32_pack(arr[i], payload_at);
for (i = 0; i < count; i++) break;
payload_at += int32_pack(arr[i], payload_at); }
break; case PROTOBUF_C_TYPE_SINT32: {
} const int32_t *arr = (const int32_t *)array;
case PROTOBUF_C_TYPE_SINT32: { for (i = 0; i < count; i++)
const int32_t *arr = (const int32_t *) array; payload_at += sint32_pack(arr[i], payload_at);
for (i = 0; i < count; i++) break;
payload_at += sint32_pack(arr[i], payload_at); }
break; case PROTOBUF_C_TYPE_SINT64: {
} const int64_t *arr = (const int64_t *)array;
case PROTOBUF_C_TYPE_SINT64: { for (i = 0; i < count; i++)
const int64_t *arr = (const int64_t *) array; payload_at += sint64_pack(arr[i], payload_at);
for (i = 0; i < count; i++) break;
payload_at += sint64_pack(arr[i], payload_at); }
break; case PROTOBUF_C_TYPE_UINT32: {
} const uint32_t *arr = (const uint32_t *)array;
case PROTOBUF_C_TYPE_UINT32: { for (i = 0; i < count; i++)
const uint32_t *arr = (const uint32_t *) array; payload_at += uint32_pack(arr[i], payload_at);
for (i = 0; i < count; i++) break;
payload_at += uint32_pack(arr[i], payload_at); }
break; case PROTOBUF_C_TYPE_INT64:
} case PROTOBUF_C_TYPE_UINT64: {
case PROTOBUF_C_TYPE_INT64: const uint64_t *arr = (const uint64_t *)array;
case PROTOBUF_C_TYPE_UINT64: { for (i = 0; i < count; i++)
const uint64_t *arr = (const uint64_t *) array; payload_at += uint64_pack(arr[i], payload_at);
for (i = 0; i < count; i++) break;
payload_at += uint64_pack(arr[i], payload_at); }
break; case PROTOBUF_C_TYPE_BOOL: {
} const protobuf_c_boolean *arr = (const protobuf_c_boolean *)array;
case PROTOBUF_C_TYPE_BOOL: { for (i = 0; i < count; i++)
const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; payload_at += boolean_pack(arr[i], payload_at);
for (i = 0; i < count; i++) break;
payload_at += boolean_pack(arr[i], payload_at); }
break; default:
} PROTOBUF_C__ASSERT_NOT_REACHED();
default: }
PROTOBUF_C__ASSERT_NOT_REACHED();
} payload_len = payload_at - (out + header_len);
actual_length_size = uint32_size(payload_len);
payload_len = payload_at - (out + header_len); if (length_size_min != actual_length_size) {
actual_length_size = uint32_size(payload_len); assert(actual_length_size == length_size_min + 1);
if (length_size_min != actual_length_size) { memmove(out + header_len + 1, out + header_len, payload_len);
assert(actual_length_size == length_size_min + 1); header_len++;
memmove(out + header_len + 1, out + header_len, }
payload_len); uint32_pack(payload_len, out + len_start);
header_len++; return header_len + payload_len;
} } else {
uint32_pack(payload_len, out + len_start); /* not "packed" cased */
return header_len + payload_len; /* CONSIDER: optimize this case a bit (by putting the loop inside the
} else { * switch) */
/* not "packed" cased */ size_t rv = 0;
/* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ unsigned siz = sizeof_elt_in_repeated_array(field->type);
size_t rv = 0;
unsigned siz = sizeof_elt_in_repeated_array(field->type); for (i = 0; i < count; i++) {
rv += required_field_pack(field, array, out + rv);
for (i = 0; i < count; i++) { array = (char *)array + siz;
rv += required_field_pack(field, array, out + rv); }
array = (char *)array + siz; return rv;
} }
return rv; }
}
} static size_t unknown_field_pack(const ProtobufCMessageUnknownField *field,
uint8_t *out) {
static size_t size_t rv = tag_pack(field->tag, out);
unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) out[0] |= field->wire_type;
{ memcpy(out + rv, field->data, field->len);
size_t rv = tag_pack(field->tag, out); return rv + field->len;
out[0] |= field->wire_type;
memcpy(out + rv, field->data, field->len);
return rv + field->len;
} }
/**@}*/ /**@}*/
size_t size_t protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) {
protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) unsigned i;
{ size_t rv = 0;
unsigned i;
size_t rv = 0; ASSERT_IS_MESSAGE(message);
for (i = 0; i < message->descriptor->n_fields; i++) {
ASSERT_IS_MESSAGE(message); const ProtobufCFieldDescriptor *field = message->descriptor->fields + i;
for (i = 0; i < message->descriptor->n_fields; i++) { const void *member = ((const char *)message) + field->offset;
const ProtobufCFieldDescriptor *field =
message->descriptor->fields + i; /*
const void *member = ((const char *) 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:
* It doesn't hurt to compute qmember (a pointer to the * - a repeated field, or
* quantifier field of the structure), but the pointer is only * - a field that is part of a oneof
* valid if the field is: * - an optional field that isn't a pointer type
* - a repeated field, or * (Meaning: not a message or a string).
* - a field that is part of a oneof */
* - an optional field that isn't a pointer type const void *qmember = ((const char *)message) + field->quantifier_offset;
* (Meaning: not a message or a string).
*/ if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
const void *qmember = rv += required_field_pack(field, member, out + rv);
((const char *) message) + field->quantifier_offset; } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL ||
field->label == PROTOBUF_C_LABEL_NONE) &&
if (field->label == PROTOBUF_C_LABEL_REQUIRED) { (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) {
rv += required_field_pack(field, member, out + rv); rv +=
} else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || oneof_field_pack(field, *(const uint32_t *)qmember, member, out + rv);
field->label == PROTOBUF_C_LABEL_NONE) && } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) {
(0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { rv += optional_field_pack(field, *(const protobuf_c_boolean *)qmember,
rv += oneof_field_pack( member, out + rv);
field, } else if (field->label == PROTOBUF_C_LABEL_NONE) {
*(const uint32_t *) qmember, rv += unlabeled_field_pack(field, member, out + rv);
member, } else {
out + rv rv += repeated_field_pack(field, *(const size_t *)qmember, member,
); out + rv);
} else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { }
rv += optional_field_pack( }
field, for (i = 0; i < message->n_unknown_fields; i++)
*(const protobuf_c_boolean *) qmember, rv += unknown_field_pack(&message->unknown_fields[i], out + rv);
member, return rv;
out + rv
);
} else if (field->label == PROTOBUF_C_LABEL_NONE) {
rv += unlabeled_field_pack(field, member, out + rv);
} else {
rv += repeated_field_pack(field, *(const size_t *) qmember,
member, out + rv);
}
}
for (i = 0; i < message->n_unknown_fields; i++)
rv += unknown_field_pack(&message->unknown_fields[i], out + rv);
return rv;
} }
/** /**
...@@ -1542,110 +1393,110 @@ protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) ...@@ -1542,110 +1393,110 @@ protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out)
* \return * \return
* Number of bytes packed. * Number of bytes packed.
*/ */
static size_t static size_t required_field_pack_to_buffer(
required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, const void *member,
const void *member, ProtobufCBuffer *buffer) ProtobufCBuffer *buffer) {
{ size_t rv;
size_t rv; uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2];
uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2];
rv = tag_pack(field->id, scratch);
rv = tag_pack(field->id, scratch); switch (field->type) {
switch (field->type) { case PROTOBUF_C_TYPE_SINT32:
case PROTOBUF_C_TYPE_SINT32: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += sint32_pack(*(const int32_t *)member, scratch + rv);
rv += sint32_pack(*(const int32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_INT32:
case PROTOBUF_C_TYPE_INT32: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += int32_pack(*(const int32_t *)member, scratch + rv);
rv += int32_pack(*(const int32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_UINT32: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += uint32_pack(*(const uint32_t *)member, scratch + rv);
rv += uint32_pack(*(const uint32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_SINT64:
case PROTOBUF_C_TYPE_SINT64: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += sint64_pack(*(const int64_t *)member, scratch + rv);
rv += sint64_pack(*(const int64_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT64:
case PROTOBUF_C_TYPE_UINT64: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += uint64_pack(*(const uint64_t *)member, scratch + rv);
rv += uint64_pack(*(const uint64_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_SFIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FLOAT: scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; rv += fixed32_pack(*(const uint32_t *)member, scratch + rv);
rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_DOUBLE: scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; rv += fixed64_pack(*(const uint64_t *)member, scratch + rv);
rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_BOOL:
case PROTOBUF_C_TYPE_BOOL: scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; rv += boolean_pack(*(const protobuf_c_boolean *)member, scratch + rv);
rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); break;
break; case PROTOBUF_C_TYPE_STRING: {
case PROTOBUF_C_TYPE_STRING: { const char *str = *(char *const *)member;
const char *str = *(char *const *) member; size_t sublen = str ? strlen(str) : 0;
size_t sublen = str ? strlen(str) : 0;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; rv += uint32_pack(sublen, scratch + rv);
rv += uint32_pack(sublen, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); buffer->append(buffer, sublen, (const uint8_t *)str);
buffer->append(buffer, sublen, (const uint8_t *) str); rv += sublen;
rv += sublen; break;
break; }
} case PROTOBUF_C_TYPE_BYTES: {
case PROTOBUF_C_TYPE_BYTES: { const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *)member);
const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); size_t sublen = bd->len;
size_t sublen = bd->len;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; rv += uint32_pack(sublen, scratch + rv);
rv += uint32_pack(sublen, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); buffer->append(buffer, sublen, bd->data);
buffer->append(buffer, sublen, bd->data); rv += sublen;
rv += sublen; break;
break; }
} case PROTOBUF_C_TYPE_MESSAGE: {
case PROTOBUF_C_TYPE_MESSAGE: { uint8_t simple_buffer_scratch[256];
uint8_t simple_buffer_scratch[256]; size_t sublen;
size_t sublen; const ProtobufCMessage *msg = *(ProtobufCMessage *const *)member;
const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; ProtobufCBufferSimple simple_buffer =
ProtobufCBufferSimple simple_buffer = PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch);
PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch);
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; if (msg == NULL)
if (msg == NULL) sublen = 0;
sublen = 0; else
else sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base);
sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); rv += uint32_pack(sublen, scratch + rv);
rv += uint32_pack(sublen, scratch + rv); buffer->append(buffer, rv, scratch);
buffer->append(buffer, rv, scratch); buffer->append(buffer, sublen, simple_buffer.data);
buffer->append(buffer, sublen, simple_buffer.data); rv += sublen;
rv += sublen; PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer);
PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); break;
break; }
} default:
default: PROTOBUF_C__ASSERT_NOT_REACHED();
PROTOBUF_C__ASSERT_NOT_REACHED(); }
} return rv;
return rv;
} }
/** /**
* Pack a oneof field to a buffer. Only packs the field that is selected by the case enum. * Pack a oneof field to a buffer. Only packs the field that is selected by the
* case enum.
* *
* \param field * \param field
* Field descriptor. * Field descriptor.
...@@ -1658,22 +1509,19 @@ required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, ...@@ -1658,22 +1509,19 @@ required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes serialised to `buffer`. * Number of bytes serialised to `buffer`.
*/ */
static size_t static size_t oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, uint32_t oneof_case,
uint32_t oneof_case, const void *member,
const void *member, ProtobufCBuffer *buffer) ProtobufCBuffer *buffer) {
{ if (oneof_case != field->id) {
if (oneof_case != field->id) { return 0;
return 0; }
} if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
if (field->type == PROTOBUF_C_TYPE_MESSAGE || field->type == PROTOBUF_C_TYPE_STRING) {
field->type == PROTOBUF_C_TYPE_STRING) const void *ptr = *(const void *const *)member;
{ if (ptr == NULL || ptr == field->default_value) return 0;
const void *ptr = *(const void *const *) member; }
if (ptr == NULL || ptr == field->default_value) return required_field_pack_to_buffer(field, member, buffer);
return 0;
}
return required_field_pack_to_buffer(field, member, buffer);
} }
/** /**
...@@ -1690,22 +1538,17 @@ oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, ...@@ -1690,22 +1538,17 @@ oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes serialised to `buffer`. * Number of bytes serialised to `buffer`.
*/ */
static size_t static size_t optional_field_pack_to_buffer(
optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, const protobuf_c_boolean has,
const protobuf_c_boolean has, const void *member, ProtobufCBuffer *buffer) {
const void *member, ProtobufCBuffer *buffer) if (field->type == PROTOBUF_C_TYPE_MESSAGE ||
{ field->type == PROTOBUF_C_TYPE_STRING) {
if (field->type == PROTOBUF_C_TYPE_MESSAGE || const void *ptr = *(const void *const *)member;
field->type == PROTOBUF_C_TYPE_STRING) if (ptr == NULL || ptr == field->default_value) return 0;
{ } else {
const void *ptr = *(const void *const *) member; if (!has) return 0;
if (ptr == NULL || ptr == field->default_value) }
return 0; return required_field_pack_to_buffer(field, member, buffer);
} else {
if (!has)
return 0;
}
return required_field_pack_to_buffer(field, member, buffer);
} }
/** /**
...@@ -1720,13 +1563,11 @@ optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, ...@@ -1720,13 +1563,11 @@ optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes serialised to `buffer`. * Number of bytes serialised to `buffer`.
*/ */
static size_t static size_t unlabeled_field_pack_to_buffer(
unlabeled_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, const void *member,
const void *member, ProtobufCBuffer *buffer) ProtobufCBuffer *buffer) {
{ if (field_is_zeroish(field, member)) return 0;
if (field_is_zeroish(field, member)) return required_field_pack_to_buffer(field, member, buffer);
return 0;
return required_field_pack_to_buffer(field, member, buffer);
} }
/** /**
...@@ -1741,60 +1582,53 @@ unlabeled_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, ...@@ -1741,60 +1582,53 @@ unlabeled_field_pack_to_buffer(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes required. * Number of bytes required.
*/ */
static size_t static size_t get_packed_payload_length(const ProtobufCFieldDescriptor *field,
get_packed_payload_length(const ProtobufCFieldDescriptor *field, unsigned count, const void *array) {
unsigned count, const void *array) unsigned rv = 0;
{ unsigned i;
unsigned rv = 0;
unsigned i; switch (field->type) {
case PROTOBUF_C_TYPE_SFIXED32:
switch (field->type) { case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FIXED32: return count * 4;
case PROTOBUF_C_TYPE_FLOAT: case PROTOBUF_C_TYPE_SFIXED64:
return count * 4; case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_FIXED64: return count * 8;
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_ENUM:
return count * 8; case PROTOBUF_C_TYPE_INT32: {
case PROTOBUF_C_TYPE_ENUM: const int32_t *arr = (const int32_t *)array;
case PROTOBUF_C_TYPE_INT32: { for (i = 0; i < count; i++) rv += int32_size(arr[i]);
const int32_t *arr = (const int32_t *) array; break;
for (i = 0; i < count; i++) }
rv += int32_size(arr[i]); case PROTOBUF_C_TYPE_SINT32: {
break; const int32_t *arr = (const int32_t *)array;
} for (i = 0; i < count; i++) rv += sint32_size(arr[i]);
case PROTOBUF_C_TYPE_SINT32: { break;
const int32_t *arr = (const int32_t *) array; }
for (i = 0; i < count; i++) case PROTOBUF_C_TYPE_UINT32: {
rv += sint32_size(arr[i]); const uint32_t *arr = (const uint32_t *)array;
break; for (i = 0; i < count; i++) rv += uint32_size(arr[i]);
} break;
case PROTOBUF_C_TYPE_UINT32: { }
const uint32_t *arr = (const uint32_t *) array; case PROTOBUF_C_TYPE_SINT64: {
for (i = 0; i < count; i++) const int64_t *arr = (const int64_t *)array;
rv += uint32_size(arr[i]); for (i = 0; i < count; i++) rv += sint64_size(arr[i]);
break; break;
} }
case PROTOBUF_C_TYPE_SINT64: { case PROTOBUF_C_TYPE_INT64:
const int64_t *arr = (const int64_t *) array; case PROTOBUF_C_TYPE_UINT64: {
for (i = 0; i < count; i++) const uint64_t *arr = (const uint64_t *)array;
rv += sint64_size(arr[i]); for (i = 0; i < count; i++) rv += uint64_size(arr[i]);
break; break;
} }
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_BOOL:
case PROTOBUF_C_TYPE_UINT64: { return count;
const uint64_t *arr = (const uint64_t *) array; default:
for (i = 0; i < count; i++) PROTOBUF_C__ASSERT_NOT_REACHED();
rv += uint64_size(arr[i]); }
break; return rv;
}
case PROTOBUF_C_TYPE_BOOL:
return count;
default:
PROTOBUF_C__ASSERT_NOT_REACHED();
}
return rv;
} }
/** /**
...@@ -1811,204 +1645,177 @@ get_packed_payload_length(const ProtobufCFieldDescriptor *field, ...@@ -1811,204 +1645,177 @@ get_packed_payload_length(const ProtobufCFieldDescriptor *field,
* \return * \return
* Number of bytes packed. * Number of bytes packed.
*/ */
static size_t static size_t pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field,
pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, unsigned count, const void *array,
unsigned count, const void *array, ProtobufCBuffer *buffer) {
ProtobufCBuffer *buffer) uint8_t scratch[16];
{ size_t rv = 0;
uint8_t scratch[16]; unsigned i;
size_t rv = 0;
unsigned i; switch (field->type) {
case PROTOBUF_C_TYPE_SFIXED32:
switch (field->type) { case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_FLOAT:
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
rv = count * 4; rv = count * 4;
goto no_packing_needed; goto no_packing_needed;
#else #else
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); unsigned len = fixed32_pack(((uint32_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
#endif #endif
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_DOUBLE:
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
rv = count * 8; rv = count * 8;
goto no_packing_needed; goto no_packing_needed;
#else #else
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); unsigned len = fixed64_pack(((uint64_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
#endif #endif
case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_INT32:
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = int32_pack(((int32_t *) array)[i], scratch); unsigned len = int32_pack(((int32_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_SINT32:
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = sint32_pack(((int32_t *) array)[i], scratch); unsigned len = sint32_pack(((int32_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_UINT32:
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); unsigned len = uint32_pack(((uint32_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_SINT64:
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = sint64_pack(((int64_t *) array)[i], scratch); unsigned len = sint64_pack(((int64_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_UINT64:
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); unsigned len = uint64_pack(((uint64_t *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
break; break;
case PROTOBUF_C_TYPE_BOOL: case PROTOBUF_C_TYPE_BOOL:
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); unsigned len = boolean_pack(((protobuf_c_boolean *)array)[i], scratch);
buffer->append(buffer, len, scratch); buffer->append(buffer, len, scratch);
rv += len; rv += len;
} }
return count; return count;
default: default:
PROTOBUF_C__ASSERT_NOT_REACHED(); PROTOBUF_C__ASSERT_NOT_REACHED();
} }
return rv; return rv;
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
no_packing_needed: no_packing_needed:
buffer->append(buffer, rv, array); buffer->append(buffer, rv, array);
return rv; return rv;
#endif #endif
} }
static size_t static size_t repeated_field_pack_to_buffer(
repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, const ProtobufCFieldDescriptor *field, unsigned count, const void *member,
unsigned count, const void *member, ProtobufCBuffer *buffer) {
ProtobufCBuffer *buffer) char *array = *(char *const *)member;
{
char *array = *(char * const *) member; if (count == 0) return 0;
if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) {
if (count == 0) uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2];
return 0; size_t rv = tag_pack(field->id, scratch);
if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { size_t payload_len = get_packed_payload_length(field, count, array);
uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; size_t tmp;
size_t rv = tag_pack(field->id, scratch);
size_t payload_len = get_packed_payload_length(field, count, array); scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED;
size_t tmp; rv += uint32_pack(payload_len, scratch + rv);
buffer->append(buffer, rv, scratch);
scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; tmp = pack_buffer_packed_payload(field, count, array, buffer);
rv += uint32_pack(payload_len, scratch + rv); assert(tmp == payload_len);
buffer->append(buffer, rv, scratch); return rv + payload_len;
tmp = pack_buffer_packed_payload(field, count, array, buffer); } else {
assert(tmp == payload_len); size_t siz;
return rv + payload_len; unsigned i;
} else { /* CONSIDER: optimize this case a bit (by putting the loop inside the
size_t siz; * switch) */
unsigned i; unsigned rv = 0;
/* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */
unsigned rv = 0; siz = sizeof_elt_in_repeated_array(field->type);
for (i = 0; i < count; i++) {
siz = sizeof_elt_in_repeated_array(field->type); rv += required_field_pack_to_buffer(field, array, buffer);
for (i = 0; i < count; i++) { array += siz;
rv += required_field_pack_to_buffer(field, array, buffer); }
array += siz; return rv;
} }
return rv; }
}
} static size_t unknown_field_pack_to_buffer(
const ProtobufCMessageUnknownField *field, ProtobufCBuffer *buffer) {
static size_t uint8_t header[MAX_UINT64_ENCODED_SIZE];
unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, size_t rv = tag_pack(field->tag, header);
ProtobufCBuffer *buffer)
{ header[0] |= field->wire_type;
uint8_t header[MAX_UINT64_ENCODED_SIZE]; buffer->append(buffer, rv, header);
size_t rv = tag_pack(field->tag, header); buffer->append(buffer, field->len, field->data);
return rv + field->len;
header[0] |= field->wire_type;
buffer->append(buffer, rv, header);
buffer->append(buffer, field->len, field->data);
return rv + field->len;
} }
/**@}*/ /**@}*/
size_t size_t protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message,
protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, ProtobufCBuffer *buffer) {
ProtobufCBuffer *buffer) unsigned i;
{ size_t rv = 0;
unsigned i;
size_t rv = 0; ASSERT_IS_MESSAGE(message);
for (i = 0; i < message->descriptor->n_fields; i++) {
ASSERT_IS_MESSAGE(message); const ProtobufCFieldDescriptor *field = message->descriptor->fields + i;
for (i = 0; i < message->descriptor->n_fields; i++) { const void *member = ((const char *)message) + field->offset;
const ProtobufCFieldDescriptor *field = const void *qmember = ((const char *)message) + field->quantifier_offset;
message->descriptor->fields + i;
const void *member = if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
((const char *) message) + field->offset; rv += required_field_pack_to_buffer(field, member, buffer);
const void *qmember = } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL ||
((const char *) message) + field->quantifier_offset; field->label == PROTOBUF_C_LABEL_NONE) &&
(0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) {
if (field->label == PROTOBUF_C_LABEL_REQUIRED) { rv += oneof_field_pack_to_buffer(field, *(const uint32_t *)qmember,
rv += required_field_pack_to_buffer(field, member, buffer); member, buffer);
} else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) {
field->label == PROTOBUF_C_LABEL_NONE) && rv += optional_field_pack_to_buffer(
(0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { field, *(const protobuf_c_boolean *)qmember, member, buffer);
rv += oneof_field_pack_to_buffer( } else if (field->label == PROTOBUF_C_LABEL_NONE) {
field, rv += unlabeled_field_pack_to_buffer(field, member, buffer);
*(const uint32_t *) qmember, } else {
member, rv += repeated_field_pack_to_buffer(field, *(const size_t *)qmember,
buffer member, buffer);
); }
} else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { }
rv += optional_field_pack_to_buffer( for (i = 0; i < message->n_unknown_fields; i++)
field, rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer);
*(const protobuf_c_boolean *) qmember,
member, return rv;
buffer
);
} else if (field->label == PROTOBUF_C_LABEL_NONE) {
rv += unlabeled_field_pack_to_buffer(
field,
member,
buffer
);
} else {
rv += repeated_field_pack_to_buffer(
field,
*(const size_t *) qmember,
member,
buffer
);
}
}
for (i = 0; i < message->n_unknown_fields; i++)
rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer);
return rv;
} }
/** /**
...@@ -2020,74 +1827,64 @@ protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, ...@@ -2020,74 +1827,64 @@ protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message,
* @{ * @{
*/ */
static inline int static inline int int_range_lookup(unsigned n_ranges,
int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value) const ProtobufCIntRange *ranges, int value) {
{ unsigned n;
unsigned n; unsigned start;
unsigned start;
if (n_ranges == 0) return -1;
if (n_ranges == 0) start = 0;
return -1; n = n_ranges;
start = 0; while (n > 1) {
n = n_ranges; unsigned mid = start + n / 2;
while (n > 1) {
unsigned mid = start + n / 2; if (value < ranges[mid].start_value) {
n = mid - start;
if (value < ranges[mid].start_value) { } else if (value >=
n = mid - start; ranges[mid].start_value +
} else if (value >= ranges[mid].start_value + (int)(ranges[mid + 1].orig_index - ranges[mid].orig_index)) {
(int) (ranges[mid + 1].orig_index - unsigned new_start = mid + 1;
ranges[mid].orig_index)) n = start + n - new_start;
{ start = new_start;
unsigned new_start = mid + 1; } else
n = start + n - new_start; return (value - ranges[mid].start_value) + ranges[mid].orig_index;
start = new_start; }
} else if (n > 0) {
return (value - ranges[mid].start_value) + unsigned start_orig_index = ranges[start].orig_index;
ranges[mid].orig_index; unsigned range_size = ranges[start + 1].orig_index - start_orig_index;
}
if (n > 0) { if (ranges[start].start_value <= value &&
unsigned start_orig_index = ranges[start].orig_index; value < (int)(ranges[start].start_value + range_size)) {
unsigned range_size = return (value - ranges[start].start_value) + start_orig_index;
ranges[start + 1].orig_index - start_orig_index; }
}
if (ranges[start].start_value <= value && return -1;
value < (int) (ranges[start].start_value + range_size)) }
{
return (value - ranges[start].start_value) + static size_t parse_tag_and_wiretype(size_t len, const uint8_t *data,
start_orig_index; uint32_t *tag_out,
} ProtobufCWireType *wiretype_out) {
} unsigned max_rv = len > 5 ? 5 : len;
return -1; uint32_t tag = (data[0] & 0x7f) >> 3;
} unsigned shift = 4;
unsigned rv;
static size_t
parse_tag_and_wiretype(size_t len, *wiretype_out = data[0] & 7;
const uint8_t *data, if ((data[0] & 0x80) == 0) {
uint32_t *tag_out, *tag_out = tag;
ProtobufCWireType *wiretype_out) return 1;
{ }
unsigned max_rv = len > 5 ? 5 : len; for (rv = 1; rv < max_rv; rv++) {
uint32_t tag = (data[0] & 0x7f) >> 3; if (data[rv] & 0x80) {
unsigned shift = 4; tag |= (data[rv] & 0x7f) << shift;
unsigned rv; shift += 7;
} else {
*wiretype_out = data[0] & 7; tag |= data[rv] << shift;
if ((data[0] & 0x80) == 0) { *tag_out = tag;
*tag_out = tag; return rv + 1;
return 1; }
} }
for (rv = 1; rv < max_rv; rv++) { return 0; /* error: bad header */
if (data[rv] & 0x80) {
tag |= (data[rv] & 0x7f) << shift;
shift += 7;
} else {
tag |= data[rv] << shift;
*tag_out = tag;
return rv + 1;
}
}
return 0; /* error: bad header */
} }
/* sizeof(ScannedMember) must be <= (1UL<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */ /* sizeof(ScannedMember) must be <= (1UL<<BOUND_SIZEOF_SCANNED_MEMBER_LOG2) */
...@@ -2095,51 +1892,46 @@ parse_tag_and_wiretype(size_t len, ...@@ -2095,51 +1892,46 @@ parse_tag_and_wiretype(size_t len,
typedef struct _ScannedMember ScannedMember; typedef struct _ScannedMember ScannedMember;
/** Field as it's being read. */ /** Field as it's being read. */
struct _ScannedMember { struct _ScannedMember {
uint32_t tag; /**< Field tag. */ uint32_t tag; /**< Field tag. */
uint8_t wire_type; /**< Field type. */ uint8_t wire_type; /**< Field type. */
uint8_t length_prefix_len; /**< Prefix length. */ uint8_t length_prefix_len; /**< Prefix length. */
const ProtobufCFieldDescriptor *field; /**< Field descriptor. */ const ProtobufCFieldDescriptor *field; /**< Field descriptor. */
size_t len; /**< Field length. */ size_t len; /**< Field length. */
const uint8_t *data; /**< Pointer to field data. */ const uint8_t *data; /**< Pointer to field data. */
}; };
static inline uint32_t static inline uint32_t scan_length_prefixed_data(size_t len,
scan_length_prefixed_data(size_t len, const uint8_t *data, const uint8_t *data,
size_t *prefix_len_out) size_t *prefix_len_out) {
{ unsigned hdr_max = len < 5 ? len : 5;
unsigned hdr_max = len < 5 ? len : 5; unsigned hdr_len;
unsigned hdr_len; uint32_t val = 0;
uint32_t val = 0; unsigned i;
unsigned i; unsigned shift = 0;
unsigned shift = 0;
for (i = 0; i < hdr_max; i++) {
for (i = 0; i < hdr_max; i++) { val |= (data[i] & 0x7f) << shift;
val |= (data[i] & 0x7f) << shift; shift += 7;
shift += 7; if ((data[i] & 0x80) == 0) break;
if ((data[i] & 0x80) == 0) }
break; if (i == hdr_max) {
} PROTOBUF_C_UNPACK_ERROR("error parsing length for length-prefixed data");
if (i == hdr_max) { return 0;
PROTOBUF_C_UNPACK_ERROR("error parsing length for length-prefixed data"); }
return 0; hdr_len = i + 1;
} *prefix_len_out = hdr_len;
hdr_len = i + 1; if (hdr_len + val > len) {
*prefix_len_out = hdr_len; PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val);
if (hdr_len + val > len) { return 0;
PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); }
return 0; return hdr_len + val;
} }
return hdr_len + val;
} static size_t max_b128_numbers(size_t len, const uint8_t *data) {
size_t rv = 0;
static size_t while (len--)
max_b128_numbers(size_t len, const uint8_t *data) if ((*data++ & 0x80) == 0) ++rv;
{ return rv;
size_t rv = 0;
while (len--)
if ((*data++ & 0x80) == 0)
++rv;
return rv;
} }
/**@}*/ /**@}*/
...@@ -2158,178 +1950,145 @@ max_b128_numbers(size_t len, const uint8_t *data) ...@@ -2158,178 +1950,145 @@ max_b128_numbers(size_t len, const uint8_t *data)
* some of its fields may have been reused and changed to their default * some of its fields may have been reused and changed to their default
* values during the merge. * values during the merge.
*/ */
static protobuf_c_boolean static protobuf_c_boolean merge_messages(ProtobufCMessage *earlier_msg,
merge_messages(ProtobufCMessage *earlier_msg, ProtobufCMessage *latter_msg,
ProtobufCMessage *latter_msg, ProtobufCAllocator *allocator) {
ProtobufCAllocator *allocator) unsigned i;
{ const ProtobufCFieldDescriptor *fields = latter_msg->descriptor->fields;
unsigned i; for (i = 0; i < latter_msg->descriptor->n_fields; i++) {
const ProtobufCFieldDescriptor *fields = if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) {
latter_msg->descriptor->fields; size_t *n_earlier =
for (i = 0; i < latter_msg->descriptor->n_fields; i++) { STRUCT_MEMBER_PTR(size_t, earlier_msg, fields[i].quantifier_offset);
if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { uint8_t **p_earlier =
size_t *n_earlier = STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, fields[i].offset);
STRUCT_MEMBER_PTR(size_t, earlier_msg, size_t *n_latter =
fields[i].quantifier_offset); STRUCT_MEMBER_PTR(size_t, latter_msg, fields[i].quantifier_offset);
uint8_t **p_earlier = uint8_t **p_latter =
STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, STRUCT_MEMBER_PTR(uint8_t *, latter_msg, fields[i].offset);
fields[i].offset);
size_t *n_latter = if (*n_earlier > 0) {
STRUCT_MEMBER_PTR(size_t, latter_msg, if (*n_latter > 0) {
fields[i].quantifier_offset); /* Concatenate the repeated field */
uint8_t **p_latter = size_t el_size = sizeof_elt_in_repeated_array(fields[i].type);
STRUCT_MEMBER_PTR(uint8_t *, latter_msg, uint8_t *new_field;
fields[i].offset);
new_field = do_alloc(allocator, (*n_earlier + *n_latter) * el_size);
if (*n_earlier > 0) { if (!new_field) return FALSE;
if (*n_latter > 0) {
/* Concatenate the repeated field */ memcpy(new_field, *p_earlier, *n_earlier * el_size);
size_t el_size = memcpy(new_field + *n_earlier * el_size, *p_latter,
sizeof_elt_in_repeated_array(fields[i].type); *n_latter * el_size);
uint8_t *new_field;
do_free(allocator, *p_latter);
new_field = do_alloc(allocator, do_free(allocator, *p_earlier);
(*n_earlier + *n_latter) * el_size); *p_latter = new_field;
if (!new_field) *n_latter = *n_earlier + *n_latter;
return FALSE; } else {
/* Zero copy the repeated field from the earlier message */
memcpy(new_field, *p_earlier, *n_latter = *n_earlier;
*n_earlier * el_size); *p_latter = *p_earlier;
memcpy(new_field + }
*n_earlier * el_size, /* Make sure the field does not get double freed */
*p_latter, *n_earlier = 0;
*n_latter * el_size); *p_earlier = 0;
}
do_free(allocator, *p_latter); } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL ||
do_free(allocator, *p_earlier); fields[i].label == PROTOBUF_C_LABEL_NONE) {
*p_latter = new_field; const ProtobufCFieldDescriptor *field;
*n_latter = *n_earlier + *n_latter; uint32_t *earlier_case_p =
} else { STRUCT_MEMBER_PTR(uint32_t, earlier_msg, fields[i].quantifier_offset);
/* Zero copy the repeated field from the earlier message */ uint32_t *latter_case_p =
*n_latter = *n_earlier; STRUCT_MEMBER_PTR(uint32_t, latter_msg, fields[i].quantifier_offset);
*p_latter = *p_earlier; protobuf_c_boolean need_to_merge = FALSE;
} void *earlier_elem;
/* Make sure the field does not get double freed */ void *latter_elem;
*n_earlier = 0; const void *def_val;
*p_earlier = 0;
} if (fields[i].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) {
} else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL || if (*latter_case_p == 0) {
fields[i].label == PROTOBUF_C_LABEL_NONE) { /* lookup correct oneof field */
const ProtobufCFieldDescriptor *field; int field_index = int_range_lookup(
uint32_t *earlier_case_p = STRUCT_MEMBER_PTR(uint32_t, latter_msg->descriptor->n_field_ranges,
earlier_msg, latter_msg->descriptor->field_ranges, *earlier_case_p);
fields[i]. if (field_index < 0) return FALSE;
quantifier_offset); field = latter_msg->descriptor->fields + field_index;
uint32_t *latter_case_p = STRUCT_MEMBER_PTR(uint32_t, } else {
latter_msg, /* Oneof is present in the latter message, move on */
fields[i]. continue;
quantifier_offset); }
protobuf_c_boolean need_to_merge = FALSE; } else {
void *earlier_elem; field = &fields[i];
void *latter_elem; }
const void *def_val;
earlier_elem = STRUCT_MEMBER_P(earlier_msg, field->offset);
if (fields[i].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) { latter_elem = STRUCT_MEMBER_P(latter_msg, field->offset);
if (*latter_case_p == 0) { def_val = field->default_value;
/* lookup correct oneof field */
int field_index = switch (field->type) {
int_range_lookup( case PROTOBUF_C_TYPE_MESSAGE: {
latter_msg->descriptor ProtobufCMessage *em = *(ProtobufCMessage **)earlier_elem;
->n_field_ranges, ProtobufCMessage *lm = *(ProtobufCMessage **)latter_elem;
latter_msg->descriptor if (em != NULL) {
->field_ranges, if (lm != NULL) {
*earlier_case_p); if (!merge_messages(em, lm, allocator)) return FALSE;
if (field_index < 0) /* Already merged */
return FALSE; need_to_merge = FALSE;
field = latter_msg->descriptor->fields + } else {
field_index; /* Zero copy the message */
} else { need_to_merge = TRUE;
/* Oneof is present in the latter message, move on */ }
continue; }
} break;
} else { }
field = &fields[i]; case PROTOBUF_C_TYPE_BYTES: {
} uint8_t *e_data = ((ProtobufCBinaryData *)earlier_elem)->data;
uint8_t *l_data = ((ProtobufCBinaryData *)latter_elem)->data;
earlier_elem = STRUCT_MEMBER_P(earlier_msg, field->offset); const ProtobufCBinaryData *d_bd = (ProtobufCBinaryData *)def_val;
latter_elem = STRUCT_MEMBER_P(latter_msg, field->offset);
def_val = field->default_value; need_to_merge =
(e_data != NULL && (d_bd == NULL || e_data != d_bd->data)) &&
switch (field->type) { (l_data == NULL || (d_bd != NULL && l_data == d_bd->data));
case PROTOBUF_C_TYPE_MESSAGE: { break;
ProtobufCMessage *em = *(ProtobufCMessage **) earlier_elem; }
ProtobufCMessage *lm = *(ProtobufCMessage **) latter_elem; case PROTOBUF_C_TYPE_STRING: {
if (em != NULL) { char *e_str = *(char **)earlier_elem;
if (lm != NULL) { char *l_str = *(char **)latter_elem;
if (!merge_messages(em, lm, allocator)) const char *d_str = def_val;
return FALSE;
/* Already merged */ need_to_merge = e_str != d_str && l_str == d_str;
need_to_merge = FALSE; break;
} else { }
/* Zero copy the message */ default: {
need_to_merge = TRUE; /* Could be has field or case enum, the logic is
} * equivalent, since 0 (FALSE) means not set for
} * oneof */
break; need_to_merge = (*earlier_case_p != 0) && (*latter_case_p == 0);
} break;
case PROTOBUF_C_TYPE_BYTES: { }
uint8_t *e_data = }
((ProtobufCBinaryData *) earlier_elem)->data;
uint8_t *l_data = if (need_to_merge) {
((ProtobufCBinaryData *) latter_elem)->data; size_t el_size = sizeof_elt_in_repeated_array(field->type);
const ProtobufCBinaryData *d_bd = memcpy(latter_elem, earlier_elem, el_size);
(ProtobufCBinaryData *) def_val; /*
* Reset the element from the old message to 0
need_to_merge = * to make sure earlier message deallocation
(e_data != NULL && * doesn't corrupt zero-copied data in the new
(d_bd == NULL || * message, earlier message will be freed after
e_data != d_bd->data)) && * this function is called anyway
(l_data == NULL || */
(d_bd != NULL && memset(earlier_elem, 0, el_size);
l_data == d_bd->data));
break; if (field->quantifier_offset != 0) {
} /* Set the has field or the case enum,
case PROTOBUF_C_TYPE_STRING: { * if applicable */
char *e_str = *(char **) earlier_elem; *latter_case_p = *earlier_case_p;
char *l_str = *(char **) latter_elem; *earlier_case_p = 0;
const char *d_str = def_val; }
}
need_to_merge = e_str != d_str && l_str == d_str; }
break; }
} return TRUE;
default: {
/* Could be has field or case enum, the logic is
* equivalent, since 0 (FALSE) means not set for
* oneof */
need_to_merge = (*earlier_case_p != 0) &&
(*latter_case_p == 0);
break;
}
}
if (need_to_merge) {
size_t el_size =
sizeof_elt_in_repeated_array(field->type);
memcpy(latter_elem, earlier_elem, el_size);
/*
* Reset the element from the old message to 0
* to make sure earlier message deallocation
* doesn't corrupt zero-copied data in the new
* message, earlier message will be freed after
* this function is called anyway
*/
memset(earlier_elem, 0, el_size);
if (field->quantifier_offset != 0) {
/* Set the has field or the case enum,
* if applicable */
*latter_case_p = *earlier_case_p;
*earlier_case_p = 0;
}
}
}
}
return TRUE;
} }
/** /**
...@@ -2340,582 +2099,502 @@ merge_messages(ProtobufCMessage *earlier_msg, ...@@ -2340,582 +2099,502 @@ merge_messages(ProtobufCMessage *earlier_msg,
* others; the remaining error checking is done by * others; the remaining error checking is done by
* parse_packed_repeated_member(). * parse_packed_repeated_member().
*/ */
static protobuf_c_boolean static protobuf_c_boolean count_packed_elements(ProtobufCType type, size_t len,
count_packed_elements(ProtobufCType type, const uint8_t *data,
size_t len, const uint8_t *data, size_t *count_out) size_t *count_out) {
{ switch (type) {
switch (type) { case PROTOBUF_C_TYPE_SFIXED32:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_FIXED32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_FLOAT: if (len % 4 != 0) {
if (len % 4 != 0) { PROTOBUF_C_UNPACK_ERROR(
PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); "length must be a multiple of 4 for fixed-length 32-bit types");
return FALSE; return FALSE;
} }
*count_out = len / 4; *count_out = len / 4;
return TRUE; return TRUE;
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_DOUBLE:
if (len % 8 != 0) { if (len % 8 != 0) {
PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); PROTOBUF_C_UNPACK_ERROR(
return FALSE; "length must be a multiple of 8 for fixed-length 64-bit types");
} return FALSE;
*count_out = len / 8; }
return TRUE; *count_out = len / 8;
case PROTOBUF_C_TYPE_ENUM: return TRUE;
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_INT32:
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_SINT32:
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_SINT64:
*count_out = max_b128_numbers(len, data); case PROTOBUF_C_TYPE_UINT64:
return TRUE; *count_out = max_b128_numbers(len, data);
case PROTOBUF_C_TYPE_BOOL: return TRUE;
*count_out = len; case PROTOBUF_C_TYPE_BOOL:
return TRUE; *count_out = len;
case PROTOBUF_C_TYPE_STRING: return TRUE;
case PROTOBUF_C_TYPE_BYTES: case PROTOBUF_C_TYPE_STRING:
case PROTOBUF_C_TYPE_MESSAGE: case PROTOBUF_C_TYPE_BYTES:
default: case PROTOBUF_C_TYPE_MESSAGE:
PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); default:
return FALSE; PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated",
} type);
} return FALSE;
}
static inline uint32_t }
parse_uint32(unsigned len, const uint8_t *data)
{ static inline uint32_t parse_uint32(unsigned len, const uint8_t *data) {
uint32_t rv = data[0] & 0x7f; uint32_t rv = data[0] & 0x7f;
if (len > 1) { if (len > 1) {
rv |= ((uint32_t) (data[1] & 0x7f) << 7); rv |= ((uint32_t)(data[1] & 0x7f) << 7);
if (len > 2) { if (len > 2) {
rv |= ((uint32_t) (data[2] & 0x7f) << 14); rv |= ((uint32_t)(data[2] & 0x7f) << 14);
if (len > 3) { if (len > 3) {
rv |= ((uint32_t) (data[3] & 0x7f) << 21); rv |= ((uint32_t)(data[3] & 0x7f) << 21);
if (len > 4) if (len > 4) rv |= ((uint32_t)(data[4]) << 28);
rv |= ((uint32_t) (data[4]) << 28); }
} }
} }
} return rv;
return rv; }
}
static inline uint32_t parse_int32(unsigned len, const uint8_t *data) {
static inline uint32_t return parse_uint32(len, data);
parse_int32(unsigned len, const uint8_t *data) }
{
return parse_uint32(len, data); static inline int32_t unzigzag32(uint32_t v) {
} if (v & 1)
return -(v >> 1) - 1;
static inline int32_t else
unzigzag32(uint32_t v) return v >> 1;
{ }
if (v & 1)
return -(v >> 1) - 1; static inline uint32_t parse_fixed_uint32(const uint8_t *data) {
else
return v >> 1;
}
static inline uint32_t
parse_fixed_uint32(const uint8_t *data)
{
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
uint32_t t; uint32_t t;
memcpy(&t, data, 4); memcpy(&t, data, 4);
return t; return t;
#else #else
return data[0] | return data[0] | ((uint32_t)(data[1]) << 8) | ((uint32_t)(data[2]) << 16) |
((uint32_t) (data[1]) << 8) | ((uint32_t)(data[3]) << 24);
((uint32_t) (data[2]) << 16) |
((uint32_t) (data[3]) << 24);
#endif #endif
} }
static uint64_t static uint64_t parse_uint64(unsigned len, const uint8_t *data) {
parse_uint64(unsigned len, const uint8_t *data) unsigned shift, i;
{ uint64_t rv;
unsigned shift, i;
uint64_t rv; if (len < 5) return parse_uint32(len, data);
rv = ((uint64_t)(data[0] & 0x7f)) | ((uint64_t)(data[1] & 0x7f) << 7) |
if (len < 5) ((uint64_t)(data[2] & 0x7f) << 14) | ((uint64_t)(data[3] & 0x7f) << 21);
return parse_uint32(len, data); shift = 28;
rv = ((uint64_t) (data[0] & 0x7f)) | for (i = 4; i < len; i++) {
((uint64_t) (data[1] & 0x7f) << 7) | rv |= (((uint64_t)(data[i] & 0x7f)) << shift);
((uint64_t) (data[2] & 0x7f) << 14) | shift += 7;
((uint64_t) (data[3] & 0x7f) << 21); }
shift = 28; return rv;
for (i = 4; i < len; i++) { }
rv |= (((uint64_t) (data[i] & 0x7f)) << shift);
shift += 7; static inline int64_t unzigzag64(uint64_t v) {
} if (v & 1)
return rv; return -(v >> 1) - 1;
} else
return v >> 1;
static inline int64_t }
unzigzag64(uint64_t v)
{ static inline uint64_t parse_fixed_uint64(const uint8_t *data) {
if (v & 1)
return -(v >> 1) - 1;
else
return v >> 1;
}
static inline uint64_t
parse_fixed_uint64(const uint8_t *data)
{
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
uint64_t t; uint64_t t;
memcpy(&t, data, 8); memcpy(&t, data, 8);
return t; return t;
#else #else
return (uint64_t) parse_fixed_uint32(data) | return (uint64_t)parse_fixed_uint32(data) |
(((uint64_t) parse_fixed_uint32(data + 4)) << 32); (((uint64_t)parse_fixed_uint32(data + 4)) << 32);
#endif #endif
} }
static protobuf_c_boolean static protobuf_c_boolean parse_boolean(unsigned len, const uint8_t *data) {
parse_boolean(unsigned len, const uint8_t *data) unsigned i;
{ for (i = 0; i < len; i++)
unsigned i; if (data[i] & 0x7f) return TRUE;
for (i = 0; i < len; i++) return FALSE;
if (data[i] & 0x7f) }
return TRUE;
return FALSE; static protobuf_c_boolean parse_required_member(
} ScannedMember *scanned_member, void *member, ProtobufCAllocator *allocator,
protobuf_c_boolean maybe_clear) {
static protobuf_c_boolean unsigned len = scanned_member->len;
parse_required_member(ScannedMember *scanned_member, const uint8_t *data = scanned_member->data;
void *member, ProtobufCWireType wire_type = scanned_member->wire_type;
ProtobufCAllocator *allocator,
protobuf_c_boolean maybe_clear) switch (scanned_member->field->type) {
{ case PROTOBUF_C_TYPE_ENUM:
unsigned len = scanned_member->len; case PROTOBUF_C_TYPE_INT32:
const uint8_t *data = scanned_member->data; if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE;
ProtobufCWireType wire_type = scanned_member->wire_type; *(int32_t *)member = parse_int32(len, data);
return TRUE;
switch (scanned_member->field->type) { case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_ENUM: if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE;
case PROTOBUF_C_TYPE_INT32: *(uint32_t *)member = parse_uint32(len, data);
if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return TRUE;
return FALSE; case PROTOBUF_C_TYPE_SINT32:
*(int32_t *) member = parse_int32(len, data); if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE;
return TRUE; *(int32_t *)member = unzigzag32(parse_uint32(len, data));
case PROTOBUF_C_TYPE_UINT32: return TRUE;
if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) case PROTOBUF_C_TYPE_SFIXED32:
return FALSE; case PROTOBUF_C_TYPE_FIXED32:
*(uint32_t *) member = parse_uint32(len, data); case PROTOBUF_C_TYPE_FLOAT:
return TRUE; if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) return FALSE;
case PROTOBUF_C_TYPE_SINT32: *(uint32_t *)member = parse_fixed_uint32(data);
if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return TRUE;
return FALSE; case PROTOBUF_C_TYPE_INT64:
*(int32_t *) member = unzigzag32(parse_uint32(len, data)); case PROTOBUF_C_TYPE_UINT64:
return TRUE; if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE;
case PROTOBUF_C_TYPE_SFIXED32: *(uint64_t *)member = parse_uint64(len, data);
case PROTOBUF_C_TYPE_FIXED32: return TRUE;
case PROTOBUF_C_TYPE_FLOAT: case PROTOBUF_C_TYPE_SINT64:
if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return FALSE;
return FALSE; *(int64_t *)member = unzigzag64(parse_uint64(len, data));
*(uint32_t *) member = parse_fixed_uint32(data); return TRUE;
return TRUE; case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_DOUBLE:
if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) return FALSE;
return FALSE; *(uint64_t *)member = parse_fixed_uint64(data);
*(uint64_t *) member = parse_uint64(len, data); return TRUE;
return TRUE; case PROTOBUF_C_TYPE_BOOL:
case PROTOBUF_C_TYPE_SINT64: *(protobuf_c_boolean *)member = parse_boolean(len, data);
if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) return TRUE;
return FALSE; case PROTOBUF_C_TYPE_STRING: {
*(int64_t *) member = unzigzag64(parse_uint64(len, data)); char **pstr = member;
return TRUE; unsigned pref_len = scanned_member->length_prefix_len;
case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_FIXED64: if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) return FALSE;
case PROTOBUF_C_TYPE_DOUBLE:
if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) if (maybe_clear && *pstr != NULL) {
return FALSE; const char *def = scanned_member->field->default_value;
*(uint64_t *) member = parse_fixed_uint64(data); if (*pstr != NULL && *pstr != def) do_free(allocator, *pstr);
return TRUE; }
case PROTOBUF_C_TYPE_BOOL: *pstr = do_alloc(allocator, len - pref_len + 1);
*(protobuf_c_boolean *) member = parse_boolean(len, data); if (*pstr == NULL) return FALSE;
return TRUE; memcpy(*pstr, data + pref_len, len - pref_len);
case PROTOBUF_C_TYPE_STRING: { (*pstr)[len - pref_len] = 0;
char **pstr = member; return TRUE;
unsigned pref_len = scanned_member->length_prefix_len; }
case PROTOBUF_C_TYPE_BYTES: {
if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) ProtobufCBinaryData *bd = member;
return FALSE; const ProtobufCBinaryData *def_bd;
unsigned pref_len = scanned_member->length_prefix_len;
if (maybe_clear && *pstr != NULL) {
const char *def = scanned_member->field->default_value; if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) return FALSE;
if (*pstr != NULL && *pstr != def)
do_free(allocator, *pstr); def_bd = scanned_member->field->default_value;
} if (maybe_clear && bd->data != NULL &&
*pstr = do_alloc(allocator, len - pref_len + 1); (def_bd == NULL || bd->data != def_bd->data)) {
if (*pstr == NULL) do_free(allocator, bd->data);
return FALSE; }
memcpy(*pstr, data + pref_len, len - pref_len); if (len - pref_len > 0) {
(*pstr)[len - pref_len] = 0; bd->data = do_alloc(allocator, len - pref_len);
return TRUE; if (bd->data == NULL) return FALSE;
} memcpy(bd->data, data + pref_len, len - pref_len);
case PROTOBUF_C_TYPE_BYTES: { } else {
ProtobufCBinaryData *bd = member; bd->data = NULL;
const ProtobufCBinaryData *def_bd; }
unsigned pref_len = scanned_member->length_prefix_len; bd->len = len - pref_len;
return TRUE;
if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) }
return FALSE; case PROTOBUF_C_TYPE_MESSAGE: {
ProtobufCMessage **pmessage = member;
def_bd = scanned_member->field->default_value; ProtobufCMessage *subm;
if (maybe_clear && const ProtobufCMessage *def_mess;
bd->data != NULL && protobuf_c_boolean merge_successful = TRUE;
(def_bd == NULL || bd->data != def_bd->data)) unsigned pref_len = scanned_member->length_prefix_len;
{
do_free(allocator, bd->data); if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) return FALSE;
}
if (len - pref_len > 0) { def_mess = scanned_member->field->default_value;
bd->data = do_alloc(allocator, len - pref_len); subm =
if (bd->data == NULL) protobuf_c_message_unpack(scanned_member->field->descriptor,
return FALSE; allocator, len - pref_len, data + pref_len);
memcpy(bd->data, data + pref_len, len - pref_len);
} else { if (maybe_clear && *pmessage != NULL && *pmessage != def_mess) {
bd->data = NULL; if (subm != NULL)
} merge_successful = merge_messages(*pmessage, subm, allocator);
bd->len = len - pref_len; /* Delete the previous message */
return TRUE; protobuf_c_message_free_unpacked(*pmessage, allocator);
} }
case PROTOBUF_C_TYPE_MESSAGE: { *pmessage = subm;
ProtobufCMessage **pmessage = member; if (subm == NULL || !merge_successful) return FALSE;
ProtobufCMessage *subm; return TRUE;
const ProtobufCMessage *def_mess; }
protobuf_c_boolean merge_successful = TRUE; }
unsigned pref_len = scanned_member->length_prefix_len; return FALSE;
}
if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED)
return FALSE; static protobuf_c_boolean parse_oneof_member(ScannedMember *scanned_member,
void *member,
def_mess = scanned_member->field->default_value; ProtobufCMessage *message,
subm = protobuf_c_message_unpack(scanned_member->field->descriptor, ProtobufCAllocator *allocator) {
allocator, uint32_t *oneof_case = STRUCT_MEMBER_PTR(
len - pref_len, uint32_t, message, scanned_member->field->quantifier_offset);
data + pref_len);
/* If we have already parsed a member of this oneof, free it. */
if (maybe_clear && if (*oneof_case != 0) {
*pmessage != NULL && /* lookup field */
*pmessage != def_mess) int field_index =
{ int_range_lookup(message->descriptor->n_field_ranges,
if (subm != NULL) message->descriptor->field_ranges, *oneof_case);
merge_successful = merge_messages(*pmessage, subm, allocator); if (field_index < 0) return FALSE;
/* Delete the previous message */ const ProtobufCFieldDescriptor *old_field =
protobuf_c_message_free_unpacked(*pmessage, allocator); message->descriptor->fields + field_index;
} size_t el_size = sizeof_elt_in_repeated_array(old_field->type);
*pmessage = subm;
if (subm == NULL || !merge_successful) switch (old_field->type) {
return FALSE; case PROTOBUF_C_TYPE_STRING: {
return TRUE; char **pstr = member;
} const char *def = old_field->default_value;
} if (*pstr != NULL && *pstr != def) do_free(allocator, *pstr);
return FALSE; break;
} }
case PROTOBUF_C_TYPE_BYTES: {
static protobuf_c_boolean ProtobufCBinaryData *bd = member;
parse_oneof_member (ScannedMember *scanned_member, const ProtobufCBinaryData *def_bd = old_field->default_value;
void *member, if (bd->data != NULL && (def_bd == NULL || bd->data != def_bd->data)) {
ProtobufCMessage *message, do_free(allocator, bd->data);
ProtobufCAllocator *allocator) }
{ break;
uint32_t *oneof_case = STRUCT_MEMBER_PTR(uint32_t, message, }
scanned_member->field->quantifier_offset); case PROTOBUF_C_TYPE_MESSAGE: {
ProtobufCMessage **pmessage = member;
/* If we have already parsed a member of this oneof, free it. */ const ProtobufCMessage *def_mess = old_field->default_value;
if (*oneof_case != 0) { if (*pmessage != NULL && *pmessage != def_mess)
/* lookup field */ protobuf_c_message_free_unpacked(*pmessage, allocator);
int field_index = break;
int_range_lookup(message->descriptor->n_field_ranges, }
message->descriptor->field_ranges, default:
*oneof_case); break;
if (field_index < 0) }
return FALSE;
const ProtobufCFieldDescriptor *old_field = memset(member, 0, el_size);
message->descriptor->fields + field_index; }
size_t el_size = sizeof_elt_in_repeated_array(old_field->type); if (!parse_required_member(scanned_member, member, allocator, TRUE))
return FALSE;
switch (old_field->type) {
case PROTOBUF_C_TYPE_STRING: { *oneof_case = scanned_member->tag;
char **pstr = member; return TRUE;
const char *def = old_field->default_value; }
if (*pstr != NULL && *pstr != def)
do_free(allocator, *pstr); static protobuf_c_boolean parse_optional_member(ScannedMember *scanned_member,
break; void *member,
} ProtobufCMessage *message,
case PROTOBUF_C_TYPE_BYTES: { ProtobufCAllocator *allocator) {
ProtobufCBinaryData *bd = member; if (!parse_required_member(scanned_member, member, allocator, TRUE))
const ProtobufCBinaryData *def_bd = old_field->default_value; return FALSE;
if (bd->data != NULL && if (scanned_member->field->quantifier_offset != 0)
(def_bd == NULL || bd->data != def_bd->data)) STRUCT_MEMBER(protobuf_c_boolean, message,
{ scanned_member->field->quantifier_offset) = TRUE;
do_free(allocator, bd->data); return TRUE;
} }
break;
} static protobuf_c_boolean parse_repeated_member(ScannedMember *scanned_member,
case PROTOBUF_C_TYPE_MESSAGE: { void *member,
ProtobufCMessage **pmessage = member; ProtobufCMessage *message,
const ProtobufCMessage *def_mess = old_field->default_value; ProtobufCAllocator *allocator) {
if (*pmessage != NULL && *pmessage != def_mess) const ProtobufCFieldDescriptor *field = scanned_member->field;
protobuf_c_message_free_unpacked(*pmessage, allocator); size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset);
break; size_t siz = sizeof_elt_in_repeated_array(field->type);
} char *array = *(char **)member;
default:
break; if (!parse_required_member(scanned_member, array + siz * (*p_n), allocator,
} FALSE)) {
return FALSE;
memset (member, 0, el_size); }
} *p_n += 1;
if (!parse_required_member (scanned_member, member, allocator, TRUE)) return TRUE;
return FALSE; }
*oneof_case = scanned_member->tag; static unsigned scan_varint(unsigned len, const uint8_t *data) {
return TRUE; unsigned i;
} if (len > 10) len = 10;
for (i = 0; i < len; i++)
if ((data[i] & 0x80) == 0) break;
static protobuf_c_boolean if (i == len) return 0;
parse_optional_member(ScannedMember *scanned_member, return i + 1;
void *member, }
ProtobufCMessage *message,
ProtobufCAllocator *allocator) static protobuf_c_boolean parse_packed_repeated_member(
{ ScannedMember *scanned_member, void *member, ProtobufCMessage *message) {
if (!parse_required_member(scanned_member, member, allocator, TRUE)) const ProtobufCFieldDescriptor *field = scanned_member->field;
return FALSE; size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset);
if (scanned_member->field->quantifier_offset != 0) size_t siz = sizeof_elt_in_repeated_array(field->type);
STRUCT_MEMBER(protobuf_c_boolean, void *array = *(char **)member + siz * (*p_n);
message, const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len;
scanned_member->field->quantifier_offset) = TRUE; size_t rem = scanned_member->len - scanned_member->length_prefix_len;
return TRUE; size_t count = 0;
} unsigned i;
static protobuf_c_boolean switch (field->type) {
parse_repeated_member(ScannedMember *scanned_member, case PROTOBUF_C_TYPE_SFIXED32:
void *member, case PROTOBUF_C_TYPE_FIXED32:
ProtobufCMessage *message, case PROTOBUF_C_TYPE_FLOAT:
ProtobufCAllocator *allocator) count = (scanned_member->len - scanned_member->length_prefix_len) / 4;
{
const ProtobufCFieldDescriptor *field = scanned_member->field;
size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset);
size_t siz = sizeof_elt_in_repeated_array(field->type);
char *array = *(char **) member;
if (!parse_required_member(scanned_member, array + siz * (*p_n),
allocator, FALSE))
{
return FALSE;
}
*p_n += 1;
return TRUE;
}
static unsigned
scan_varint(unsigned len, const uint8_t *data)
{
unsigned i;
if (len > 10)
len = 10;
for (i = 0; i < len; i++)
if ((data[i] & 0x80) == 0)
break;
if (i == len)
return 0;
return i + 1;
}
static protobuf_c_boolean
parse_packed_repeated_member(ScannedMember *scanned_member,
void *member,
ProtobufCMessage *message)
{
const ProtobufCFieldDescriptor *field = scanned_member->field;
size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset);
size_t siz = sizeof_elt_in_repeated_array(field->type);
void *array = *(char **) member + siz * (*p_n);
const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len;
size_t rem = scanned_member->len - scanned_member->length_prefix_len;
size_t count = 0;
unsigned i;
switch (field->type) {
case PROTOBUF_C_TYPE_SFIXED32:
case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_FLOAT:
count = (scanned_member->len - scanned_member->length_prefix_len) / 4;
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
goto no_unpacking_needed; goto no_unpacking_needed;
#else #else
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
((uint32_t *) array)[i] = parse_fixed_uint32(at); ((uint32_t *)array)[i] = parse_fixed_uint32(at);
at += 4; at += 4;
} }
break; break;
#endif #endif
case PROTOBUF_C_TYPE_SFIXED64: case PROTOBUF_C_TYPE_SFIXED64:
case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_DOUBLE: case PROTOBUF_C_TYPE_DOUBLE:
count = (scanned_member->len - scanned_member->length_prefix_len) / 8; count = (scanned_member->len - scanned_member->length_prefix_len) / 8;
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
goto no_unpacking_needed; goto no_unpacking_needed;
#else #else
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
((uint64_t *) array)[i] = parse_fixed_uint64(at); ((uint64_t *)array)[i] = parse_fixed_uint64(at);
at += 8; at += 8;
} }
break; break;
#endif #endif
case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_INT32:
while (rem > 0) { while (rem > 0) {
unsigned s = scan_varint(rem, at); unsigned s = scan_varint(rem, at);
if (s == 0) { if (s == 0) {
PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value");
return FALSE; return FALSE;
} }
((int32_t *) array)[count++] = parse_int32(s, at); ((int32_t *)array)[count++] = parse_int32(s, at);
at += s; at += s;
rem -= s; rem -= s;
} }
break; break;
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_SINT32:
while (rem > 0) { while (rem > 0) {
unsigned s = scan_varint(rem, at); unsigned s = scan_varint(rem, at);
if (s == 0) { if (s == 0) {
PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value");
return FALSE; return FALSE;
} }
((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); ((int32_t *)array)[count++] = unzigzag32(parse_uint32(s, at));
at += s; at += s;
rem -= s; rem -= s;
} }
break; break;
case PROTOBUF_C_TYPE_UINT32: case PROTOBUF_C_TYPE_UINT32:
while (rem > 0) { while (rem > 0) {
unsigned s = scan_varint(rem, at); unsigned s = scan_varint(rem, at);
if (s == 0) { if (s == 0) {
PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value");
return FALSE; return FALSE;
} }
((uint32_t *) array)[count++] = parse_uint32(s, at); ((uint32_t *)array)[count++] = parse_uint32(s, at);
at += s; at += s;
rem -= s; rem -= s;
} }
break; break;
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_SINT64:
while (rem > 0) { while (rem > 0) {
unsigned s = scan_varint(rem, at); unsigned s = scan_varint(rem, at);
if (s == 0) { if (s == 0) {
PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value");
return FALSE; return FALSE;
} }
((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); ((int64_t *)array)[count++] = unzigzag64(parse_uint64(s, at));
at += s; at += s;
rem -= s; rem -= s;
} }
break; break;
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_UINT64: case PROTOBUF_C_TYPE_UINT64:
while (rem > 0) { while (rem > 0) {
unsigned s = scan_varint(rem, at); unsigned s = scan_varint(rem, at);
if (s == 0) { if (s == 0) {
PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value");
return FALSE; return FALSE;
} }
((int64_t *) array)[count++] = parse_uint64(s, at); ((int64_t *)array)[count++] = parse_uint64(s, at);
at += s; at += s;
rem -= s; rem -= s;
} }
break; break;
case PROTOBUF_C_TYPE_BOOL: case PROTOBUF_C_TYPE_BOOL:
count = rem; count = rem;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (at[i] > 1) { if (at[i] > 1) {
PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value");
return FALSE; return FALSE;
} }
((protobuf_c_boolean *) array)[i] = at[i]; ((protobuf_c_boolean *)array)[i] = at[i];
} }
break; break;
default: default:
PROTOBUF_C__ASSERT_NOT_REACHED(); PROTOBUF_C__ASSERT_NOT_REACHED();
} }
*p_n += count; *p_n += count;
return TRUE; return TRUE;
#if !defined(WORDS_BIGENDIAN) #if !defined(WORDS_BIGENDIAN)
no_unpacking_needed: no_unpacking_needed:
memcpy(array, at, count * siz); memcpy(array, at, count * siz);
*p_n += count; *p_n += count;
return TRUE; return TRUE;
#endif #endif
} }
static protobuf_c_boolean static protobuf_c_boolean is_packable_type(ProtobufCType type) {
is_packable_type(ProtobufCType type) return type != PROTOBUF_C_TYPE_STRING && type != PROTOBUF_C_TYPE_BYTES &&
{ type != PROTOBUF_C_TYPE_MESSAGE;
return }
type != PROTOBUF_C_TYPE_STRING &&
type != PROTOBUF_C_TYPE_BYTES && static protobuf_c_boolean parse_member(ScannedMember *scanned_member,
type != PROTOBUF_C_TYPE_MESSAGE; ProtobufCMessage *message,
} ProtobufCAllocator *allocator) {
const ProtobufCFieldDescriptor *field = scanned_member->field;
static protobuf_c_boolean void *member;
parse_member(ScannedMember *scanned_member,
ProtobufCMessage *message, if (field == NULL) {
ProtobufCAllocator *allocator) ProtobufCMessageUnknownField *ufield =
{ message->unknown_fields + (message->n_unknown_fields++);
const ProtobufCFieldDescriptor *field = scanned_member->field; ufield->tag = scanned_member->tag;
void *member; ufield->wire_type = scanned_member->wire_type;
ufield->len = scanned_member->len;
if (field == NULL) { ufield->data = do_alloc(allocator, scanned_member->len);
ProtobufCMessageUnknownField *ufield = if (ufield->data == NULL) return FALSE;
message->unknown_fields + memcpy(ufield->data, scanned_member->data, ufield->len);
(message->n_unknown_fields++); return TRUE;
ufield->tag = scanned_member->tag; }
ufield->wire_type = scanned_member->wire_type; member = (char *)message + field->offset;
ufield->len = scanned_member->len; switch (field->label) {
ufield->data = do_alloc(allocator, scanned_member->len); case PROTOBUF_C_LABEL_REQUIRED:
if (ufield->data == NULL) return parse_required_member(scanned_member, member, allocator, TRUE);
return FALSE; case PROTOBUF_C_LABEL_OPTIONAL:
memcpy(ufield->data, scanned_member->data, ufield->len); case PROTOBUF_C_LABEL_NONE:
return TRUE; if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) {
} return parse_oneof_member(scanned_member, member, message, allocator);
member = (char *) message + field->offset; } else {
switch (field->label) { return parse_optional_member(scanned_member, member, message,
case PROTOBUF_C_LABEL_REQUIRED: allocator);
return parse_required_member(scanned_member, member, }
allocator, TRUE); case PROTOBUF_C_LABEL_REPEATED:
case PROTOBUF_C_LABEL_OPTIONAL: if (scanned_member->wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED &&
case PROTOBUF_C_LABEL_NONE: (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) ||
if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) { is_packable_type(field->type))) {
return parse_oneof_member(scanned_member, member, return parse_packed_repeated_member(scanned_member, member, message);
message, allocator); } else {
} else { return parse_repeated_member(scanned_member, member, message,
return parse_optional_member(scanned_member, member, allocator);
message, allocator); }
} }
case PROTOBUF_C_LABEL_REPEATED: PROTOBUF_C__ASSERT_NOT_REACHED();
if (scanned_member->wire_type == return 0;
PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED &&
(0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) ||
is_packable_type(field->type)))
{
return parse_packed_repeated_member(scanned_member,
member, message);
} else {
return parse_repeated_member(scanned_member,
member, message,
allocator);
}
}
PROTOBUF_C__ASSERT_NOT_REACHED();
return 0;
} }
/** /**
...@@ -2925,58 +2604,54 @@ parse_member(ScannedMember *scanned_member, ...@@ -2925,58 +2604,54 @@ parse_member(ScannedMember *scanned_member,
* for old code, and which would be useful to support allocating * for old code, and which would be useful to support allocating
* descriptors dynamically). * descriptors dynamically).
*/ */
static void static void message_init_generic(const ProtobufCMessageDescriptor *desc,
message_init_generic(const ProtobufCMessageDescriptor *desc, ProtobufCMessage *message) {
ProtobufCMessage *message) unsigned i;
{
unsigned i; memset(message, 0, desc->sizeof_message);
message->descriptor = desc;
memset(message, 0, desc->sizeof_message); for (i = 0; i < desc->n_fields; i++) {
message->descriptor = desc; if (desc->fields[i].default_value != NULL &&
for (i = 0; i < desc->n_fields; i++) { desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) {
if (desc->fields[i].default_value != NULL && void *field = STRUCT_MEMBER_P(message, desc->fields[i].offset);
desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) const void *dv = desc->fields[i].default_value;
{
void *field = switch (desc->fields[i].type) {
STRUCT_MEMBER_P(message, desc->fields[i].offset); case PROTOBUF_C_TYPE_INT32:
const void *dv = desc->fields[i].default_value; case PROTOBUF_C_TYPE_SINT32:
case PROTOBUF_C_TYPE_SFIXED32:
switch (desc->fields[i].type) { case PROTOBUF_C_TYPE_UINT32:
case PROTOBUF_C_TYPE_INT32: case PROTOBUF_C_TYPE_FIXED32:
case PROTOBUF_C_TYPE_SINT32: case PROTOBUF_C_TYPE_FLOAT:
case PROTOBUF_C_TYPE_SFIXED32: case PROTOBUF_C_TYPE_ENUM:
case PROTOBUF_C_TYPE_UINT32: memcpy(field, dv, 4);
case PROTOBUF_C_TYPE_FIXED32: break;
case PROTOBUF_C_TYPE_FLOAT: case PROTOBUF_C_TYPE_INT64:
case PROTOBUF_C_TYPE_ENUM: case PROTOBUF_C_TYPE_SINT64:
memcpy(field, dv, 4); case PROTOBUF_C_TYPE_SFIXED64:
break; case PROTOBUF_C_TYPE_UINT64:
case PROTOBUF_C_TYPE_INT64: case PROTOBUF_C_TYPE_FIXED64:
case PROTOBUF_C_TYPE_SINT64: case PROTOBUF_C_TYPE_DOUBLE:
case PROTOBUF_C_TYPE_SFIXED64: memcpy(field, dv, 8);
case PROTOBUF_C_TYPE_UINT64: break;
case PROTOBUF_C_TYPE_FIXED64: case PROTOBUF_C_TYPE_BOOL:
case PROTOBUF_C_TYPE_DOUBLE: memcpy(field, dv, sizeof(protobuf_c_boolean));
memcpy(field, dv, 8); break;
break; case PROTOBUF_C_TYPE_BYTES:
case PROTOBUF_C_TYPE_BOOL: memcpy(field, dv, sizeof(ProtobufCBinaryData));
memcpy(field, dv, sizeof(protobuf_c_boolean)); break;
break;
case PROTOBUF_C_TYPE_BYTES: case PROTOBUF_C_TYPE_STRING:
memcpy(field, dv, sizeof(ProtobufCBinaryData)); case PROTOBUF_C_TYPE_MESSAGE:
break; /*
* The next line essentially implements a cast
case PROTOBUF_C_TYPE_STRING: * from const, which is totally unavoidable.
case PROTOBUF_C_TYPE_MESSAGE: */
/* *(const void **)field = dv;
* The next line essentially implements a cast break;
* from const, which is totally unavoidable. }
*/ }
*(const void **) field = dv; }
break;
}
}
}
} }
/**@}*/ /**@}*/
...@@ -2997,650 +2672,573 @@ message_init_generic(const ProtobufCMessageDescriptor *desc, ...@@ -2997,650 +2672,573 @@ message_init_generic(const ProtobufCMessageDescriptor *desc,
* The number of slabs, including the stack-allocated ones; choose the number so * 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. * that we would overflow if we needed a slab larger than provided.
*/ */
#define MAX_SCANNED_MEMBER_SLAB \ #define MAX_SCANNED_MEMBER_SLAB \
(sizeof(unsigned int)*8 - 1 \ (sizeof(unsigned int) * 8 - 1 - BOUND_SIZEOF_SCANNED_MEMBER_LOG2 - \
- BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2)
- FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2)
#define REQUIRED_FIELD_BITMAP_SET(index) \
#define REQUIRED_FIELD_BITMAP_SET(index) \ (required_fields_bitmap[(index) / 8] |= (1UL << ((index) % 8)))
(required_fields_bitmap[(index)/8] |= (1UL<<((index)%8)))
#define REQUIRED_FIELD_BITMAP_IS_SET(index) \
#define REQUIRED_FIELD_BITMAP_IS_SET(index) \ (required_fields_bitmap[(index) / 8] & (1UL << ((index) % 8)))
(required_fields_bitmap[(index)/8] & (1UL<<((index)%8)))
ProtobufCMessage *protobuf_c_message_unpack(
ProtobufCMessage * const ProtobufCMessageDescriptor *desc, ProtobufCAllocator *allocator,
protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, size_t len, const uint8_t *data) {
ProtobufCAllocator *allocator, ProtobufCMessage *rv;
size_t len, const uint8_t *data) size_t rem = len;
{ const uint8_t *at = data;
ProtobufCMessage *rv; const ProtobufCFieldDescriptor *last_field = desc->fields + 0;
size_t rem = len; ScannedMember first_member_slab[1UL << FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2];
const uint8_t *at = data;
const ProtobufCFieldDescriptor *last_field = desc->fields + 0; /*
ScannedMember first_member_slab[1UL << * scanned_member_slabs[i] is an array of arrays of ScannedMember.
FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; * 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.
* scanned_member_slabs[i] is an array of arrays of ScannedMember. */
* The first slab (scanned_member_slabs[0] is just a pointer to ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1];
* first_member_slab), above. All subsequent slabs will be allocated unsigned which_slab = 0; /* the slab we are currently populating */
* using the allocator. unsigned in_slab_index = 0; /* number of members in the slab */
*/ size_t n_unknown = 0;
ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; unsigned f;
unsigned which_slab = 0; /* the slab we are currently populating */ unsigned j;
unsigned in_slab_index = 0; /* number of members in the slab */ unsigned i_slab;
size_t n_unknown = 0; unsigned last_field_index = 0;
unsigned f; unsigned required_fields_bitmap_len;
unsigned j; unsigned char required_fields_bitmap_stack[16];
unsigned i_slab; unsigned char *required_fields_bitmap = required_fields_bitmap_stack;
unsigned last_field_index = 0; protobuf_c_boolean required_fields_bitmap_alloced = FALSE;
unsigned required_fields_bitmap_len;
unsigned char required_fields_bitmap_stack[16]; ASSERT_IS_MESSAGE_DESCRIPTOR(desc);
unsigned char *required_fields_bitmap = required_fields_bitmap_stack;
protobuf_c_boolean required_fields_bitmap_alloced = FALSE; if (allocator == NULL) allocator = &protobuf_c__allocator;
ASSERT_IS_MESSAGE_DESCRIPTOR(desc); rv = do_alloc(allocator, desc->sizeof_message);
if (!rv) return (NULL);
if (allocator == NULL) scanned_member_slabs[0] = first_member_slab;
allocator = &protobuf_c__allocator;
required_fields_bitmap_len = (desc->n_fields + 7) / 8;
rv = do_alloc(allocator, desc->sizeof_message); if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) {
if (!rv) required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len);
return (NULL); if (!required_fields_bitmap) {
scanned_member_slabs[0] = first_member_slab; do_free(allocator, rv);
return (NULL);
required_fields_bitmap_len = (desc->n_fields + 7) / 8; }
if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) { required_fields_bitmap_alloced = TRUE;
required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len); }
if (!required_fields_bitmap) { memset(required_fields_bitmap, 0, required_fields_bitmap_len);
do_free(allocator, rv);
return (NULL); /*
} * Generated code always defines "message_init". However, we provide a
required_fields_bitmap_alloced = TRUE; * fallback for (1) users of old protobuf-c generated-code that do not
} * provide the function, and (2) descriptors constructed from some other
memset(required_fields_bitmap, 0, required_fields_bitmap_len); * source (most likely, direct construction from the .proto file).
*/
/* if (desc->message_init != NULL)
* Generated code always defines "message_init". However, we provide a protobuf_c_message_init(desc, rv);
* fallback for (1) users of old protobuf-c generated-code that do not else
* provide the function, and (2) descriptors constructed from some other message_init_generic(desc, rv);
* source (most likely, direct construction from the .proto file).
*/ while (rem > 0) {
if (desc->message_init != NULL) uint32_t tag;
protobuf_c_message_init(desc, rv); ProtobufCWireType wire_type;
else size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type);
message_init_generic(desc, rv); const ProtobufCFieldDescriptor *field;
ScannedMember tmp;
while (rem > 0) {
uint32_t tag; if (used == 0) {
ProtobufCWireType wire_type; PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u",
size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); (unsigned)(at - data));
const ProtobufCFieldDescriptor *field; goto error_cleanup_during_scan;
ScannedMember tmp; }
/*
if (used == 0) { * \todo Consider optimizing for field[1].id == tag, if field[1]
PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", * exists!
(unsigned) (at - data)); */
goto error_cleanup_during_scan; if (last_field == NULL || last_field->id != tag) {
} /* lookup field */
/* int field_index =
* \todo Consider optimizing for field[1].id == tag, if field[1] int_range_lookup(desc->n_field_ranges, desc->field_ranges, tag);
* exists! if (field_index < 0) {
*/ field = NULL;
if (last_field == NULL || last_field->id != tag) { n_unknown++;
/* lookup field */ } else {
int field_index = field = desc->fields + field_index;
int_range_lookup(desc->n_field_ranges, last_field = field;
desc->field_ranges, last_field_index = field_index;
tag); }
if (field_index < 0) { } else {
field = NULL; field = last_field;
n_unknown++; }
} else {
field = desc->fields + field_index; if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED)
last_field = field; REQUIRED_FIELD_BITMAP_SET(last_field_index);
last_field_index = field_index;
} at += used;
} else { rem -= used;
field = last_field; tmp.tag = tag;
} tmp.wire_type = wire_type;
tmp.field = field;
if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) tmp.data = at;
REQUIRED_FIELD_BITMAP_SET(last_field_index); tmp.length_prefix_len = 0;
at += used; switch (wire_type) {
rem -= used; case PROTOBUF_C_WIRE_TYPE_VARINT: {
tmp.tag = tag; unsigned max_len = rem < 10 ? rem : 10;
tmp.wire_type = wire_type; unsigned i;
tmp.field = field;
tmp.data = at; for (i = 0; i < max_len; i++)
tmp.length_prefix_len = 0; if ((at[i] & 0x80) == 0) break;
if (i == max_len) {
switch (wire_type) { PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u",
case PROTOBUF_C_WIRE_TYPE_VARINT: { (unsigned)(at - data));
unsigned max_len = rem < 10 ? rem : 10; goto error_cleanup_during_scan;
unsigned i; }
tmp.len = i + 1;
for (i = 0; i < max_len; i++) break;
if ((at[i] & 0x80) == 0) }
break; case PROTOBUF_C_WIRE_TYPE_64BIT:
if (i == max_len) { if (rem < 8) {
PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u",
(unsigned) (at - data)); (unsigned)(at - data));
goto error_cleanup_during_scan; goto error_cleanup_during_scan;
} }
tmp.len = i + 1; tmp.len = 8;
break; break;
} case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: {
case PROTOBUF_C_WIRE_TYPE_64BIT: size_t pref_len;
if (rem < 8) {
PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", tmp.len = scan_length_prefixed_data(rem, at, &pref_len);
(unsigned) (at - data)); if (tmp.len == 0) {
goto error_cleanup_during_scan; /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */
} goto error_cleanup_during_scan;
tmp.len = 8; }
break; tmp.length_prefix_len = pref_len;
case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { break;
size_t pref_len; }
case PROTOBUF_C_WIRE_TYPE_32BIT:
tmp.len = scan_length_prefixed_data(rem, at, &pref_len); if (rem < 4) {
if (tmp.len == 0) { PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u",
/* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ (unsigned)(at - data));
goto error_cleanup_during_scan; goto error_cleanup_during_scan;
} }
tmp.length_prefix_len = pref_len; tmp.len = 4;
break; break;
} default:
case PROTOBUF_C_WIRE_TYPE_32BIT: PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", wire_type,
if (rem < 4) { (unsigned)(at - data));
PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", goto error_cleanup_during_scan;
(unsigned) (at - data)); }
goto error_cleanup_during_scan;
} if (in_slab_index ==
tmp.len = 4; (1UL << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) {
break; size_t size;
default:
PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", in_slab_index = 0;
wire_type, (unsigned) (at - data)); if (which_slab == MAX_SCANNED_MEMBER_SLAB) {
goto error_cleanup_during_scan; PROTOBUF_C_UNPACK_ERROR("too many fields");
} goto error_cleanup_during_scan;
}
if (in_slab_index == (1UL << which_slab++;
(which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) size = sizeof(ScannedMember)
{ << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2);
size_t size; scanned_member_slabs[which_slab] = do_alloc(allocator, size);
if (scanned_member_slabs[which_slab] == NULL)
in_slab_index = 0; goto error_cleanup_during_scan;
if (which_slab == MAX_SCANNED_MEMBER_SLAB) { }
PROTOBUF_C_UNPACK_ERROR("too many fields"); scanned_member_slabs[which_slab][in_slab_index++] = tmp;
goto error_cleanup_during_scan;
} if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) {
which_slab++; size_t *n = STRUCT_MEMBER_PTR(size_t, rv, field->quantifier_offset);
size = sizeof(ScannedMember) if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED &&
<< (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) ||
scanned_member_slabs[which_slab] = do_alloc(allocator, size); is_packable_type(field->type))) {
if (scanned_member_slabs[which_slab] == NULL) size_t count;
goto error_cleanup_during_scan; if (!count_packed_elements(field->type, tmp.len - tmp.length_prefix_len,
} tmp.data + tmp.length_prefix_len, &count)) {
scanned_member_slabs[which_slab][in_slab_index++] = tmp; PROTOBUF_C_UNPACK_ERROR("counting packed elements");
goto error_cleanup_during_scan;
if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { }
size_t *n = STRUCT_MEMBER_PTR(size_t, rv, *n += count;
field->quantifier_offset); } else {
if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && *n += 1;
(0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || }
is_packable_type(field->type))) }
{
size_t count; at += tmp.len;
if (!count_packed_elements(field->type, rem -= tmp.len;
tmp.len - }
tmp.length_prefix_len,
tmp.data + /* allocate space for repeated fields, also check that all required fields
tmp.length_prefix_len, * have been set */
&count)) for (f = 0; f < desc->n_fields; f++) {
{ const ProtobufCFieldDescriptor *field = desc->fields + f;
PROTOBUF_C_UNPACK_ERROR("counting packed elements"); if (field->label == PROTOBUF_C_LABEL_REPEATED) {
goto error_cleanup_during_scan; size_t siz = sizeof_elt_in_repeated_array(field->type);
} size_t *n_ptr = STRUCT_MEMBER_PTR(size_t, rv, field->quantifier_offset);
*n += count; if (*n_ptr != 0) {
} else { unsigned n = *n_ptr;
*n += 1; void *a;
} *n_ptr = 0;
} assert(rv->descriptor != NULL);
#define CLEAR_REMAINING_N_PTRS() \
at += tmp.len; for (f++; f < desc->n_fields; f++) { \
rem -= tmp.len; field = desc->fields + f; \
} if (field->label == PROTOBUF_C_LABEL_REPEATED) \
STRUCT_MEMBER(size_t, rv, field->quantifier_offset) = 0; \
/* allocate space for repeated fields, also check that all required fields have been set */ }
for (f = 0; f < desc->n_fields; f++) { a = do_alloc(allocator, siz * n);
const ProtobufCFieldDescriptor *field = desc->fields + f; if (!a) {
if (field->label == PROTOBUF_C_LABEL_REPEATED) { CLEAR_REMAINING_N_PTRS();
size_t siz = goto error_cleanup;
sizeof_elt_in_repeated_array(field->type); }
size_t *n_ptr = STRUCT_MEMBER(void *, rv, field->offset) = a;
STRUCT_MEMBER_PTR(size_t, rv, }
field->quantifier_offset); } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
if (*n_ptr != 0) { if (field->default_value == NULL && !REQUIRED_FIELD_BITMAP_IS_SET(f)) {
unsigned n = *n_ptr; CLEAR_REMAINING_N_PTRS();
void *a; PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'",
*n_ptr = 0; desc->name, field->name);
assert(rv->descriptor != NULL); goto error_cleanup;
#define CLEAR_REMAINING_N_PTRS() \ }
for(f++;f < desc->n_fields; f++) \ }
{ \ }
field = desc->fields + f; \
if (field->label == PROTOBUF_C_LABEL_REPEATED) \
STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \
}
a = do_alloc(allocator, siz * n);
if (!a) {
CLEAR_REMAINING_N_PTRS();
goto error_cleanup;
}
STRUCT_MEMBER(void *, rv, field->offset) = a;
}
} else if (field->label == PROTOBUF_C_LABEL_REQUIRED) {
if (field->default_value == NULL &&
!REQUIRED_FIELD_BITMAP_IS_SET(f))
{
CLEAR_REMAINING_N_PTRS();
PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'",
desc->name, field->name);
goto error_cleanup;
}
}
}
#undef CLEAR_REMAINING_N_PTRS #undef CLEAR_REMAINING_N_PTRS
/* allocate space for unknown fields */ /* allocate space for unknown fields */
if (n_unknown) { if (n_unknown) {
rv->unknown_fields = do_alloc(allocator, rv->unknown_fields =
n_unknown * sizeof(ProtobufCMessageUnknownField)); do_alloc(allocator, n_unknown * sizeof(ProtobufCMessageUnknownField));
if (rv->unknown_fields == NULL) if (rv->unknown_fields == NULL) goto error_cleanup;
goto error_cleanup; }
}
/* do real parsing */
/* do real parsing */ for (i_slab = 0; i_slab <= which_slab; i_slab++) {
for (i_slab = 0; i_slab <= which_slab; i_slab++) { unsigned max =
unsigned max = (i_slab == which_slab) ? (i_slab == which_slab) ? in_slab_index : (1UL << (i_slab + 4));
in_slab_index : (1UL << (i_slab + 4)); ScannedMember *slab = scanned_member_slabs[i_slab];
ScannedMember *slab = scanned_member_slabs[i_slab];
for (j = 0; j < max; j++) {
for (j = 0; j < max; j++) { if (!parse_member(slab + j, rv, allocator)) {
if (!parse_member(slab + j, rv, allocator)) { PROTOBUF_C_UNPACK_ERROR(
PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", "error parsing member %s of %s",
slab->field ? slab->field->name : "*unknown-field*", slab->field ? slab->field->name : "*unknown-field*", desc->name);
desc->name); goto error_cleanup;
goto error_cleanup; }
} }
} }
}
/* cleanup */
/* cleanup */ for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]);
for (j = 1; j <= which_slab; j++) if (required_fields_bitmap_alloced)
do_free(allocator, scanned_member_slabs[j]); do_free(allocator, required_fields_bitmap);
if (required_fields_bitmap_alloced) return rv;
do_free(allocator, required_fields_bitmap);
return rv;
error_cleanup: error_cleanup:
protobuf_c_message_free_unpacked(rv, allocator); protobuf_c_message_free_unpacked(rv, allocator);
for (j = 1; j <= which_slab; j++) for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]);
do_free(allocator, scanned_member_slabs[j]); if (required_fields_bitmap_alloced)
if (required_fields_bitmap_alloced) do_free(allocator, required_fields_bitmap);
do_free(allocator, required_fields_bitmap); return NULL;
return NULL;
error_cleanup_during_scan: error_cleanup_during_scan:
do_free(allocator, rv); do_free(allocator, rv);
for (j = 1; j <= which_slab; j++) for (j = 1; j <= which_slab; j++) do_free(allocator, scanned_member_slabs[j]);
do_free(allocator, scanned_member_slabs[j]); if (required_fields_bitmap_alloced)
if (required_fields_bitmap_alloced) do_free(allocator, required_fields_bitmap);
do_free(allocator, required_fields_bitmap); return NULL;
return NULL; }
}
void protobuf_c_message_free_unpacked(ProtobufCMessage *message,
void ProtobufCAllocator *allocator) {
protobuf_c_message_free_unpacked(ProtobufCMessage *message, const ProtobufCMessageDescriptor *desc;
ProtobufCAllocator *allocator) unsigned f;
{
const ProtobufCMessageDescriptor *desc; if (message == NULL) return;
unsigned f;
desc = message->descriptor;
if (message == NULL)
return; ASSERT_IS_MESSAGE(message);
desc = message->descriptor; if (allocator == NULL) allocator = &protobuf_c__allocator;
message->descriptor = NULL;
ASSERT_IS_MESSAGE(message); for (f = 0; f < desc->n_fields; f++) {
if (0 != (desc->fields[f].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) &&
if (allocator == NULL) desc->fields[f].id !=
allocator = &protobuf_c__allocator; STRUCT_MEMBER(uint32_t, message,
message->descriptor = NULL; desc->fields[f].quantifier_offset)) {
for (f = 0; f < desc->n_fields; f++) { /* This is not the selected oneof, skip it */
if (0 != (desc->fields[f].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) && continue;
desc->fields[f].id != }
STRUCT_MEMBER(uint32_t, message, desc->fields[f].quantifier_offset))
{ if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) {
/* This is not the selected oneof, skip it */ size_t n =
continue; STRUCT_MEMBER(size_t, message, desc->fields[f].quantifier_offset);
} void *arr = STRUCT_MEMBER(void *, message, desc->fields[f].offset);
if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { if (arr != NULL) {
size_t n = STRUCT_MEMBER(size_t, if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) {
message, unsigned i;
desc->fields[f].quantifier_offset); for (i = 0; i < n; i++) do_free(allocator, ((char **)arr)[i]);
void *arr = STRUCT_MEMBER(void *, } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) {
message, unsigned i;
desc->fields[f].offset); for (i = 0; i < n; i++)
do_free(allocator, ((ProtobufCBinaryData *)arr)[i].data);
if (arr != NULL) { } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) {
if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { unsigned i;
unsigned i; for (i = 0; i < n; i++)
for (i = 0; i < n; i++) protobuf_c_message_free_unpacked(((ProtobufCMessage **)arr)[i],
do_free(allocator, ((char **) arr)[i]); allocator);
} else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { }
unsigned i; do_free(allocator, arr);
for (i = 0; i < n; i++) }
do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) {
} else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { char *str = STRUCT_MEMBER(char *, message, desc->fields[f].offset);
unsigned i;
for (i = 0; i < n; i++) if (str && str != desc->fields[f].default_value) do_free(allocator, str);
protobuf_c_message_free_unpacked( } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) {
((ProtobufCMessage **) arr)[i], void *data =
allocator STRUCT_MEMBER(ProtobufCBinaryData, message, desc->fields[f].offset)
); .data;
} const ProtobufCBinaryData *default_bd;
do_free(allocator, arr);
} default_bd = desc->fields[f].default_value;
} else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { if (data != NULL && (default_bd == NULL || default_bd->data != data)) {
char *str = STRUCT_MEMBER(char *, message, do_free(allocator, data);
desc->fields[f].offset); }
} else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) {
if (str && str != desc->fields[f].default_value) ProtobufCMessage *sm;
do_free(allocator, str);
} else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { sm = STRUCT_MEMBER(ProtobufCMessage *, message, desc->fields[f].offset);
void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, if (sm && sm != desc->fields[f].default_value)
desc->fields[f].offset).data; protobuf_c_message_free_unpacked(sm, allocator);
const ProtobufCBinaryData *default_bd; }
}
default_bd = desc->fields[f].default_value;
if (data != NULL && for (f = 0; f < message->n_unknown_fields; f++)
(default_bd == NULL || do_free(allocator, message->unknown_fields[f].data);
default_bd->data != data)) if (message->unknown_fields != NULL)
{ do_free(allocator, message->unknown_fields);
do_free(allocator, data);
} do_free(allocator, message);
} else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { }
ProtobufCMessage *sm;
void protobuf_c_message_init(const ProtobufCMessageDescriptor *descriptor,
sm = STRUCT_MEMBER(ProtobufCMessage *, message, void *message) {
desc->fields[f].offset); descriptor->message_init((ProtobufCMessage *)(message));
if (sm && sm != desc->fields[f].default_value) }
protobuf_c_message_free_unpacked(sm, allocator);
} protobuf_c_boolean protobuf_c_message_check(const ProtobufCMessage *message) {
} unsigned i;
for (f = 0; f < message->n_unknown_fields; f++) if (!message || !message->descriptor ||
do_free(allocator, message->unknown_fields[f].data); message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) {
if (message->unknown_fields != NULL) return FALSE;
do_free(allocator, message->unknown_fields); }
do_free(allocator, message); for (i = 0; i < message->descriptor->n_fields; i++) {
} const ProtobufCFieldDescriptor *f = message->descriptor->fields + i;
ProtobufCType type = f->type;
void ProtobufCLabel label = f->label;
protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, void *field = STRUCT_MEMBER_P(message, f->offset);
void *message)
{ if (label == PROTOBUF_C_LABEL_REPEATED) {
descriptor->message_init((ProtobufCMessage *) (message)); size_t *quantity = STRUCT_MEMBER_P(message, f->quantifier_offset);
}
if (*quantity > 0 && *(void **)field == NULL) {
protobuf_c_boolean return FALSE;
protobuf_c_message_check(const ProtobufCMessage *message) }
{
unsigned i; if (type == PROTOBUF_C_TYPE_MESSAGE) {
ProtobufCMessage **submessage = *(ProtobufCMessage ***)field;
if (!message || unsigned j;
!message->descriptor || for (j = 0; j < *quantity; j++) {
message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) if (!protobuf_c_message_check(submessage[j])) return FALSE;
{ }
return FALSE; } else if (type == PROTOBUF_C_TYPE_STRING) {
} char **string = *(char ***)field;
unsigned j;
for (i = 0; i < message->descriptor->n_fields; i++) { for (j = 0; j < *quantity; j++) {
const ProtobufCFieldDescriptor *f = message->descriptor->fields + i; if (!string[j]) return FALSE;
ProtobufCType type = f->type; }
ProtobufCLabel label = f->label; } else if (type == PROTOBUF_C_TYPE_BYTES) {
void *field = STRUCT_MEMBER_P (message, f->offset); ProtobufCBinaryData *bd = *(ProtobufCBinaryData **)field;
unsigned j;
if (label == PROTOBUF_C_LABEL_REPEATED) { for (j = 0; j < *quantity; j++) {
size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset); if (bd[j].len > 0 && bd[j].data == NULL) return FALSE;
}
if (*quantity > 0 && *(void **) field == NULL) { }
return FALSE;
} } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */
if (type == PROTOBUF_C_TYPE_MESSAGE) { if (type == PROTOBUF_C_TYPE_MESSAGE) {
ProtobufCMessage **submessage = *(ProtobufCMessage ***) field; ProtobufCMessage *submessage = *(ProtobufCMessage **)field;
unsigned j; if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) {
for (j = 0; j < *quantity; j++) { if (!protobuf_c_message_check(submessage)) return FALSE;
if (!protobuf_c_message_check(submessage[j])) }
return FALSE; } else if (type == PROTOBUF_C_TYPE_STRING) {
} char *string = *(char **)field;
} else if (type == PROTOBUF_C_TYPE_STRING) { if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL) return FALSE;
char **string = *(char ***) field; } else if (type == PROTOBUF_C_TYPE_BYTES) {
unsigned j; protobuf_c_boolean *has =
for (j = 0; j < *quantity; j++) { STRUCT_MEMBER_P(message, f->quantifier_offset);
if (!string[j]) ProtobufCBinaryData *bd = field;
return FALSE; if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) {
} if (bd->len > 0 && bd->data == NULL) return FALSE;
} else if (type == PROTOBUF_C_TYPE_BYTES) { }
ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field; }
unsigned j; }
for (j = 0; j < *quantity; j++) { }
if (bd[j].len > 0 && bd[j].data == NULL)
return FALSE; return TRUE;
}
}
} else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */
if (type == PROTOBUF_C_TYPE_MESSAGE) {
ProtobufCMessage *submessage = *(ProtobufCMessage **) field;
if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) {
if (!protobuf_c_message_check(submessage))
return FALSE;
}
} else if (type == PROTOBUF_C_TYPE_STRING) {
char *string = *(char **) field;
if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL)
return FALSE;
} else if (type == PROTOBUF_C_TYPE_BYTES) {
protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset);
ProtobufCBinaryData *bd = field;
if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) {
if (bd->len > 0 && bd->data == NULL)
return FALSE;
}
}
}
}
return TRUE;
} }
/* === services === */ /* === services === */
typedef void (*GenericHandler) (void *service, typedef void (*GenericHandler)(void *service, const ProtobufCMessage *input,
const ProtobufCMessage *input, ProtobufCClosure closure, void *closure_data);
ProtobufCClosure closure, void protobuf_c_service_invoke_internal(ProtobufCService *service,
void *closure_data); unsigned method_index,
void const ProtobufCMessage *input,
protobuf_c_service_invoke_internal(ProtobufCService *service, ProtobufCClosure closure,
unsigned method_index, void *closure_data) {
const ProtobufCMessage *input, GenericHandler *handlers;
ProtobufCClosure closure, GenericHandler handler;
void *closure_data)
{ /*
GenericHandler *handlers; * Verify that method_index is within range. If this fails, you are
GenericHandler handler; * likely invoking a newly added method on an old service. (Although
* other memory corruption bugs can cause this assertion too.)
/* */
* Verify that method_index is within range. If this fails, you are assert(method_index < service->descriptor->n_methods);
* likely invoking a newly added method on an old service. (Although
* other memory corruption bugs can cause this assertion too.) /*
*/ * Get the array of virtual methods (which are enumerated by the
assert(method_index < service->descriptor->n_methods); * generated code).
*/
/* handlers = (GenericHandler *)(service + 1);
* Get the array of virtual methods (which are enumerated by the
* generated code). /*
*/ * Get our method and invoke it.
handlers = (GenericHandler *) (service + 1); * \todo Seems like handler == NULL is a situation that needs handling.
*/
/* handler = handlers[method_index];
* Get our method and invoke it. (*handler)(service, input, closure, closure_data);
* \todo Seems like handler == NULL is a situation that needs handling. }
*/
handler = handlers[method_index]; void protobuf_c_service_generated_init(
(*handler)(service, input, closure, closure_data); ProtobufCService *service, const ProtobufCServiceDescriptor *descriptor,
} ProtobufCServiceDestroy destroy) {
ASSERT_IS_SERVICE_DESCRIPTOR(descriptor);
void service->descriptor = descriptor;
protobuf_c_service_generated_init(ProtobufCService *service, service->destroy = destroy;
const ProtobufCServiceDescriptor *descriptor, service->invoke = protobuf_c_service_invoke_internal;
ProtobufCServiceDestroy destroy) memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler));
{ }
ASSERT_IS_SERVICE_DESCRIPTOR(descriptor);
service->descriptor = descriptor; void protobuf_c_service_destroy(ProtobufCService *service) {
service->destroy = destroy; service->destroy(service);
service->invoke = protobuf_c_service_invoke_internal;
memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler));
}
void protobuf_c_service_destroy(ProtobufCService *service)
{
service->destroy(service);
} }
/* --- querying the descriptors --- */ /* --- querying the descriptors --- */
const ProtobufCEnumValue * const ProtobufCEnumValue *protobuf_c_enum_descriptor_get_value_by_name(
protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, const ProtobufCEnumDescriptor *desc, const char *name) {
const char *name) unsigned start = 0;
{ unsigned count;
unsigned start = 0;
unsigned count; if (desc == NULL || desc->values_by_name == NULL) return NULL;
if (desc == NULL || desc->values_by_name == NULL) count = desc->n_value_names;
return NULL;
while (count > 1) {
count = desc->n_value_names; unsigned mid = start + count / 2;
int rv = strcmp(desc->values_by_name[mid].name, name);
while (count > 1) { if (rv == 0)
unsigned mid = start + count / 2; return desc->values + desc->values_by_name[mid].index;
int rv = strcmp(desc->values_by_name[mid].name, name); else if (rv < 0) {
if (rv == 0) count = start + count - (mid + 1);
return desc->values + desc->values_by_name[mid].index; start = mid + 1;
else if (rv < 0) { } else
count = start + count - (mid + 1); count = mid - start;
start = mid + 1; }
} else if (count == 0) return NULL;
count = mid - start; if (strcmp(desc->values_by_name[start].name, name) == 0)
} return desc->values + desc->values_by_name[start].index;
if (count == 0) return NULL;
return NULL; }
if (strcmp(desc->values_by_name[start].name, name) == 0)
return desc->values + desc->values_by_name[start].index; const ProtobufCEnumValue *protobuf_c_enum_descriptor_get_value(
return NULL; const ProtobufCEnumDescriptor *desc, int value) {
} int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value);
if (rv < 0) return NULL;
const ProtobufCEnumValue * return desc->values + rv;
protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, }
int value)
{ const ProtobufCFieldDescriptor *protobuf_c_message_descriptor_get_field_by_name(
int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); const ProtobufCMessageDescriptor *desc, const char *name) {
if (rv < 0) unsigned start = 0;
return NULL; unsigned count;
return desc->values + rv; const ProtobufCFieldDescriptor *field;
}
if (desc == NULL || desc->fields_sorted_by_name == NULL) return NULL;
const ProtobufCFieldDescriptor *
protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, count = desc->n_fields;
const char *name)
{ while (count > 1) {
unsigned start = 0; unsigned mid = start + count / 2;
unsigned count; int rv;
const ProtobufCFieldDescriptor *field; field = desc->fields + desc->fields_sorted_by_name[mid];
rv = strcmp(field->name, name);
if (desc == NULL || desc->fields_sorted_by_name == NULL) if (rv == 0)
return NULL; return field;
else if (rv < 0) {
count = desc->n_fields; count = start + count - (mid + 1);
start = mid + 1;
while (count > 1) { } else
unsigned mid = start + count / 2; count = mid - start;
int rv; }
field = desc->fields + desc->fields_sorted_by_name[mid]; if (count == 0) return NULL;
rv = strcmp(field->name, name); field = desc->fields + desc->fields_sorted_by_name[start];
if (rv == 0) if (strcmp(field->name, name) == 0) return field;
return field; return NULL;
else if (rv < 0) { }
count = start + count - (mid + 1);
start = mid + 1; const ProtobufCFieldDescriptor *protobuf_c_message_descriptor_get_field(
} else const ProtobufCMessageDescriptor *desc, unsigned value) {
count = mid - start; int rv = int_range_lookup(desc->n_field_ranges, desc->field_ranges, value);
} if (rv < 0) return NULL;
if (count == 0) return desc->fields + rv;
return NULL;
field = desc->fields + desc->fields_sorted_by_name[start];
if (strcmp(field->name, name) == 0)
return field;
return NULL;
}
const ProtobufCFieldDescriptor *
protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc,
unsigned value)
{
int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value);
if (rv < 0)
return NULL;
return desc->fields + rv;
} }
const ProtobufCMethodDescriptor * const ProtobufCMethodDescriptor *
protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, protobuf_c_service_descriptor_get_method_by_name(
const char *name) const ProtobufCServiceDescriptor *desc, const char *name) {
{ unsigned start = 0;
unsigned start = 0; unsigned count;
unsigned count;
if (desc == NULL || desc->method_indices_by_name == NULL) return NULL;
if (desc == NULL || desc->method_indices_by_name == NULL)
return NULL; count = desc->n_methods;
count = desc->n_methods; while (count > 1) {
unsigned mid = start + count / 2;
while (count > 1) { unsigned mid_index = desc->method_indices_by_name[mid];
unsigned mid = start + count / 2; const char *mid_name = desc->methods[mid_index].name;
unsigned mid_index = desc->method_indices_by_name[mid]; int rv = strcmp(mid_name, name);
const char *mid_name = desc->methods[mid_index].name;
int rv = strcmp(mid_name, name); if (rv == 0) return desc->methods + desc->method_indices_by_name[mid];
if (rv < 0) {
if (rv == 0) count = start + count - (mid + 1);
return desc->methods + desc->method_indices_by_name[mid]; start = mid + 1;
if (rv < 0) { } else {
count = start + count - (mid + 1); count = mid - start;
start = mid + 1; }
} else { }
count = mid - start; if (count == 0) return NULL;
} if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) ==
} 0)
if (count == 0) return desc->methods + desc->method_indices_by_name[start];
return NULL; return NULL;
if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0)
return desc->methods + desc->method_indices_by_name[start];
return NULL;
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
TOTAL_ERRORS=0 TOTAL_ERRORS=0
# The trick to remove deleted files: https://stackoverflow.com/a/2413151 # The trick to remove deleted files: https://stackoverflow.com/a/2413151
for file in $(git diff --cached --name-status | awk '$1 != "D" {print $2}' | grep -v ".pb.cpp" | grep -v ".pb.h"); do for file in $(git diff --cached --name-status | awk '$1 != "D" {print $2}' | grep -v ".pb.cpp" | grep -v ".pb.h" | grep -v "protobuf-c.*"); do
cpplint $file; cpplint $file;
TOTAL_ERRORS=$(expr $TOTAL_ERRORS + $?); TOTAL_ERRORS=$(expr $TOTAL_ERRORS + $?);
done done
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册