connection_state_machine_loop (request_st * const r, connection * const con)
{
	request_state_t ostate;
	do {
		if (r->conf.log_state_handling) {
			log_error(r->conf.errh, __FILE__, __LINE__,
			  "state for fd:%d id:%d %s", con->fd, r->h2id,
			  connection_get_state(r->state));
		}

		switch ((ostate = r->state)) {
		case CON_STATE_REQUEST_START: /* transient */
			/*(should not be reached by HTTP/2 streams)*/
			r->start_hp.tv_sec = con->read_idle_ts = log_epoch_secs;
			if (r->conf.high_precision_timestamps)
				log_clock_gettime_realtime(&r->start_hp);

			con->request_count++;
			r->loops_per_request = 0;

			connection_set_state(r, CON_STATE_READ);
			__attribute_fallthrough__
		case CON_STATE_READ:
			/*(should not be reached by HTTP/2 streams)*/
			if (!connection_handle_read_state(con)) {
				if (r->http_version == HTTP_VERSION_2) {
					connection_transition_h2(r, con);
					connection_state_machine_h2(r, con);
					return;
				}
				break;
			}
			/*if (r->state != CON_STATE_REQUEST_END) break;*/
			__attribute_fallthrough__
		case CON_STATE_REQUEST_END: /* transient */
			ostate = (0 == r->reqbody_length)
			  ? CON_STATE_HANDLE_REQUEST
			  : CON_STATE_READ_POST;
			connection_set_state(r, ostate);
			__attribute_fallthrough__
		case CON_STATE_READ_POST:
		case CON_STATE_HANDLE_REQUEST:
			switch (http_response_handler(r)) {
			  case HANDLER_GO_ON:/*CON_STATE_RESPONSE_START occurred;transient*/
			  case HANDLER_FINISHED:
				break;
			  case HANDLER_WAIT_FOR_EVENT:
				return;
			  case HANDLER_COMEBACK:
				/* redo loop; will not match r->state */
				ostate = CON_STATE_CONNECT;
				continue;
			  case HANDLER_WAIT_FOR_FD:
		                connection_fdwaitqueue_append(con);
				return;
			  /*case HANDLER_ERROR:*/
			  default:
				connection_set_state_error(r, CON_STATE_ERROR);
				continue;
			}
			/*__attribute_fallthrough__*/
		/*case CON_STATE_RESPONSE_START:*//*occurred;transient*/
			if (r->http_version > HTTP_VERSION_1_1)
				h2_send_headers(r, con);
			else
				http_response_write_header(r);
			connection_set_state(r, CON_STATE_WRITE);
			__attribute_fallthrough__
		case CON_STATE_WRITE:
			if (connection_handle_write_state(r, con)
			    != CON_STATE_RESPONSE_END)
				break;
			__attribute_fallthrough__
		case CON_STATE_RESPONSE_END: /* transient */
		case CON_STATE_ERROR:        /* transient */
			if (r->http_version > HTTP_VERSION_1_1 && r != &con->request)
				return;
			connection_handle_response_end_state(r, con);
			break;
		case CON_STATE_CLOSE:
			/*(should not be reached by HTTP/2 streams)*/
			connection_handle_close_state(con);
			break;
		case CON_STATE_CONNECT:
			break;
		default:
			log_error(r->conf.errh, __FILE__, __LINE__,
			  "unknown state: %d %d", con->fd, r->state);
			break;
		}
	} while (ostate != (request_state_t)r->state);
}


static void connection_handle_response_end_state(request_st * const r, connection * const con) {
	if (r->http_version > HTTP_VERSION_1_1) {
		h2_retire_con(r, con);
		r->keep_alive = 0;
		/* set a status so that mod_accesslog, mod_rrdtool hooks are called
		 * in plugins_call_handle_request_done() (XXX: or set to 0 to omit) */
		r->http_status = 100; /* XXX: what if con->state == CON_STATE_ERROR? */
	}

	/* call request_done hook if http_status set (e.g. to log request) */
	/* (even if error, connection dropped, as long as http_status is set) */
	if (r->http_status) plugins_call_handle_request_done(r);

	if (r->state != CON_STATE_ERROR) ++con->srv->con_written;

	if (r->reqbody_length != r->reqbody_queue.bytes_in
	    || r->state == CON_STATE_ERROR) {
		/* request body may not have been read completely */
		r->keep_alive = 0;
		/* clean up failed partial write of 1xx intermediate responses*/
		if (&r->write_queue != con->write_queue) { /*(for HTTP/1.1)*/
			chunkqueue_free(con->write_queue);
			con->write_queue = &r->write_queue;
		}
	}

        if (r->keep_alive) {
		request_reset(r);
		config_reset_config(r);
		con->is_readable = 1; /* potentially trigger optimistic read */
		/*(accounting used by mod_accesslog for HTTP/1.0 and HTTP/1.1)*/
		r->bytes_read_ckpt = con->bytes_read;
		r->bytes_written_ckpt = con->bytes_written;
#if 0
		r->start_hp.tv_sec = con->read_idle_ts = log_epoch_secs;
#endif
		connection_set_state(r, CON_STATE_REQUEST_START);
	} else {
		connection_handle_shutdown(con);
	}
}

[core] fix merging large headers across mult reads (fixes #3059)

(thx mitd)

x-ref:
  "Connections stuck in Close_Wait causing 100% cpu usage"
  https://redmine.lighttpd.net/issues/3059

#define connection_set_state(r, n) ((r)->state = (n))

__attribute_cold__
static connection *connection_init(server *srv);

static void connection_reset(connection *con);

server * const srv = con->srv;

request_st * const r = &con->request;

static handler_t connection_handle_read_post_state(request_st * const r);

static void connection_state_machine_h2 (request_st *h2r, connection *con);


static int connection_read_cq_err(connection *con) {
    request_st * const r = &con->request;
  #if defined(__WIN32)
    int lastError = WSAGetLastError();
    switch (lastError) {
    case EAGAIN:
        return 0;
    case EINTR:
        /* we have been interrupted before we could read */
        con->is_readable = 1;
        return 0;
    case ECONNRESET:
        /* suppress logging for this error, expected for keep-alive */
        break;
    default:
        log_error(r->conf.errh, __FILE__, __LINE__,
          "connection closed - recv failed: %d", lastError);
        break;
    }
  #else /* __WIN32 */
    switch (errno) {
    case EAGAIN:
        return 0;
    case EINTR:
        /* we have been interrupted before we could read */
        con->is_readable = 1;
        return 0;
    case ECONNRESET:
        /* suppress logging for this error, expected for keep-alive */
        break;
    default:
        log_perror(r->conf.errh, __FILE__, __LINE__,
          "connection closed - read failed");
        break;
    }
  #endif /* __WIN32 */

    connection_set_state_error(r, CON_STATE_ERROR);
    return -1;
}

__attribute_cold__
static connection *connection_init(server *srv);

static void connection_reset(connection *con);

server * const srv = con->srv;

request_st * const r = &con->request;

static handler_t connection_handle_read_post_state(request_st * const r);

static void connection_state_machine_h2 (request_st *h2r, connection *con);


  void Compute(OpKernelContext* ctx) override {
    const Tensor& shape_tensor = ctx->input(0);
    const Tensor& means_tensor = ctx->input(1);
    const Tensor& stddevs_tensor = ctx->input(2);
    const Tensor& minvals_tensor = ctx->input(3);
    const Tensor& maxvals_tensor = ctx->input(4);

    OP_REQUIRES(
        ctx, TensorShapeUtils::IsVector(shape_tensor.shape()),
        errors::InvalidArgument("Input shape should be a vector, got shape: ",
                                shape_tensor.shape().DebugString()));
    OP_REQUIRES(ctx, shape_tensor.NumElements() > 0,
                errors::InvalidArgument("Shape tensor must not be empty, got ",
                                        shape_tensor.DebugString()));
    int32 num_batches = shape_tensor.flat<int32>()(0);

    int32 samples_per_batch = 1;
    const int32 num_dims = shape_tensor.dim_size(0);
    for (int32 i = 1; i < num_dims; i++) {
      samples_per_batch *= shape_tensor.flat<int32>()(i);
    }
    const int32 num_elements = num_batches * samples_per_batch;

    // Allocate the output before fudging num_batches and samples_per_batch.
    auto shape_vec = shape_tensor.flat<int32>();
    TensorShape tensor_shape;
    OP_REQUIRES_OK(ctx, TensorShapeUtils::MakeShape(
                            shape_vec.data(), shape_vec.size(), &tensor_shape));
    Tensor* samples_tensor;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, tensor_shape, &samples_tensor));

    // Parameters must be 0-d or 1-d.
    OP_REQUIRES(ctx, means_tensor.dims() <= 1,
                errors::InvalidArgument(
                    "Input means should be a scalar or vector, got shape: ",
                    means_tensor.shape().DebugString()));
    OP_REQUIRES(ctx, stddevs_tensor.dims() <= 1,
                errors::InvalidArgument(
                    "Input stddevs should be a scalar or vector, got shape: ",
                    stddevs_tensor.shape().DebugString()));
    OP_REQUIRES(ctx, minvals_tensor.dims() <= 1,
                errors::InvalidArgument(
                    "Input minvals should be a scalar or vector, got shape: ",
                    minvals_tensor.shape().DebugString()));
    OP_REQUIRES(ctx, maxvals_tensor.dims() <= 1,
                errors::InvalidArgument(
                    "Input maxvals should be a scalar or vector, got shape: ",
                    maxvals_tensor.shape().DebugString()));

    if ((means_tensor.dims() == 0 || means_tensor.dim_size(0) == 1) &&
        (stddevs_tensor.dims() == 0 || stddevs_tensor.dim_size(0) == 1) &&
        minvals_tensor.dims() == 0 && maxvals_tensor.dims() == 0) {
      // All batches have the same parameters, so we can update the batch size
      // to a reasonable value to improve parallelism (ensure enough batches,
      // and no very small batches which have high overhead).
      int32 size = num_batches * samples_per_batch;
      int32 adjusted_samples = kDesiredBatchSize;
      // Ensure adjusted_batches * adjusted_samples >= size.
      int32 adjusted_batches = Eigen::divup(size, adjusted_samples);
      num_batches = adjusted_batches;
      samples_per_batch = adjusted_samples;
    } else {
      // Parameters must be broadcastable to the shape [num_batches].
      OP_REQUIRES(
          ctx,
          TensorShapeUtils::IsScalar(means_tensor.shape()) ||
              means_tensor.dim_size(0) == 1 ||
              means_tensor.dim_size(0) == num_batches,
          errors::InvalidArgument(
              "Input means should have length 1 or shape[0], got shape: ",
              means_tensor.shape().DebugString()));
      OP_REQUIRES(
          ctx,
          TensorShapeUtils::IsScalar(stddevs_tensor.shape()) ||
              stddevs_tensor.dim_size(0) == 1 ||
              stddevs_tensor.dim_size(0) == num_batches,
          errors::InvalidArgument(
              "Input stddevs should have length 1 or shape[0], got shape: ",
              stddevs_tensor.shape().DebugString()));
      OP_REQUIRES(
          ctx,
          TensorShapeUtils::IsScalar(minvals_tensor.shape()) ||
              minvals_tensor.dim_size(0) == 1 ||
              minvals_tensor.dim_size(0) == num_batches,
          errors::InvalidArgument(
              "Input minvals should have length 1 or shape[0], got shape: ",
              minvals_tensor.shape().DebugString()));
      OP_REQUIRES(
          ctx,
          TensorShapeUtils::IsScalar(maxvals_tensor.shape()) ||
              maxvals_tensor.dim_size(0) == 1 ||
              maxvals_tensor.dim_size(0) == num_batches,
          errors::InvalidArgument(
              "Input maxvals should have length 1 or shape[0], got shape: ",
              maxvals_tensor.shape().DebugString()));
    }

    auto truncFunctor = functor::TruncatedNormalFunctor<Device, T>();
    // Each worker has the fudge factor for samples_per_batch, so use it here.
    random::PhiloxRandom rng =
        generator_.ReserveSamples128(num_batches * 2 * functor::kMaxIterations *
                                     (samples_per_batch + 3) / 4);
    truncFunctor(ctx, ctx->eigen_device<Device>(), num_batches,
                 samples_per_batch, num_elements, means_tensor.flat<T>(),
                 stddevs_tensor.flat<T>(), minvals_tensor.flat<T>(),
                 maxvals_tensor.flat<T>(), rng, samples_tensor->flat<T>());
  }

Fix breakage in parameterized_truncated_normal_op.cc

PiperOrigin-RevId: 372041718
Change-Id: Iff79e77a2bb27032423eefcb84211627b27dfe81


bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream)
{
    uint32_t size;
    if (!pb_decode_varint32(stream, &size))
        return false;

    *substream = *stream;
    if (substream->bytes_left < size)
        PB_RETURN_ERROR(stream, "parent stream too short");

    substream->bytes_left = size;
    stream->bytes_left -= size;
    return true;
}

Fix invalid free() after failed realloc() (GHSA-gcx3-7m76-287p)

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

#define pb_uint64_t uint32_t


static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
{
#ifdef PB_ENABLE_MALLOC
    /* When decoding an oneof field, check if there is old data that must be
     * released first. */
    if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF)
    {
        if (!pb_release_union_field(stream, iter))
            return false;
    }
#endif

    switch (PB_ATYPE(iter->pos->type))
    {
        case PB_ATYPE_STATIC:
            return decode_static_field(stream, wire_type, iter);

        case PB_ATYPE_POINTER:
            return decode_pointer_field(stream, wire_type, iter);

        case PB_ATYPE_CALLBACK:
            return decode_callback_field(stream, wire_type, iter);

        default:
            PB_RETURN_ERROR(stream, "invalid field type");
    }
}

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    bool status;
    pb_istream_t substream;
    const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr;

    if (!pb_make_string_substream(stream, &substream))
        return false;

    if (field->ptr == NULL)
        PB_RETURN_ERROR(stream, "invalid field descriptor");

    /* New array entries need to be initialized, while required and optional
     * submessages have already been initialized in the top-level pb_decode. */
    if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
        status = pb_decode(&substream, submsg_fields, dest);
    else
        status = pb_decode_noinit(&substream, submsg_fields, dest);

    if (!pb_close_string_substream(stream, &substream))
        return false;
    return status;
}


static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter)
{
    if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING ||
        PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES)
    {
        *(void**)pItem = NULL;
    }
    else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
    {
        /* We memset to zero so that any callbacks are set to NULL.
         * Then set any default values. */
        memset(pItem, 0, iter->pos->data_size);
        pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem);
    }
}

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    pb_uint64_t value, clamped;
    if (!pb_decode_varint(stream, &value))
        return false;

    /* Cast to the proper field size, while checking for overflows */
    if (field->data_size == sizeof(pb_uint64_t))
        clamped = *(pb_uint64_t*)dest = value;
    else if (field->data_size == sizeof(uint32_t))
        clamped = *(uint32_t*)dest = (uint32_t)value;
    else if (field->data_size == sizeof(uint_least16_t))
        clamped = *(uint_least16_t*)dest = (uint_least16_t)value;
    else if (field->data_size == sizeof(uint_least8_t))
        clamped = *(uint_least8_t*)dest = (uint_least8_t)value;
    else
        PB_RETURN_ERROR(stream, "invalid data_size");

    if (clamped != value)
        PB_RETURN_ERROR(stream, "integer too large");

    return true;
}

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

#define pb_uint64_t uint32_t

#define pb_uint64_t uint64_t

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
    bool status;
    pb_message_set_to_defaults(fields, dest_struct);
    status = pb_decode_noinit(stream, fields, dest_struct);

#ifdef PB_ENABLE_MALLOC
    if (!status)
        pb_release(fields, dest_struct);
#endif

    return status;
}


bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
    pb_istream_t substream;
    bool status;

    if (!pb_make_string_substream(stream, &substream))
        return false;

    status = pb_decode_noinit(&substream, fields, dest_struct);

    if (!pb_close_string_substream(stream, &substream))
        return false;
    return status;
}


static void pb_release_single_field(const pb_field_iter_t *iter)
{
    pb_type_t type;
    type = iter->pos->type;

    if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
    {
        if (*(pb_size_t*)iter->pSize != iter->pos->tag)
            return; /* This is not the current field in the union */
    }

    /* Release anything contained inside an extension or submsg.
     * This has to be done even if the submsg itself is statically
     * allocated. */
    if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
    {
        /* Release fields from all extensions in the linked list */
        pb_extension_t *ext = *(pb_extension_t**)iter->pData;
        while (ext != NULL)
        {
            pb_field_iter_t ext_iter;
            iter_from_extension(&ext_iter, ext);
            pb_release_single_field(&ext_iter);
            ext = ext->next;
        }
    }
    else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && PB_ATYPE(type) != PB_ATYPE_CALLBACK)
    {
        /* Release fields in submessage or submsg array */
        void *pItem = iter->pData;
        pb_size_t count = 1;

        if (PB_ATYPE(type) == PB_ATYPE_POINTER)
        {
            pItem = *(void**)iter->pData;
        }

        if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
        {
            if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) {
                /* No _count field so use size of the array */
                count = iter->pos->array_size;
            } else {
                count = *(pb_size_t*)iter->pSize;
            }

            if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size)
            {
                /* Protect against corrupted _count fields */
                count = iter->pos->array_size;
            }
        }

        if (pItem)
        {
            while (count--)
            {
                pb_release((const pb_field_t*)iter->pos->ptr, pItem);
                pItem = (char*)pItem + iter->pos->data_size;
            }
        }
    }

    if (PB_ATYPE(type) == PB_ATYPE_POINTER)
    {
        if (PB_HTYPE(type) == PB_HTYPE_REPEATED &&
            (PB_LTYPE(type) == PB_LTYPE_STRING ||
             PB_LTYPE(type) == PB_LTYPE_BYTES))
        {
            /* Release entries in repeated string or bytes array */
            void **pItem = *(void***)iter->pData;
            pb_size_t count = *(pb_size_t*)iter->pSize;
            while (count--)
            {
                pb_free(*pItem);
                *pItem++ = NULL;
            }
        }

        if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
        {
            /* We are going to release the array, so set the size to 0 */
            *(pb_size_t*)iter->pSize = 0;
        }

        /* Release main item */
        pb_free(*(void**)iter->pData);
        *(void**)iter->pData = NULL;
    }
}


bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
    pb_istream_t substream;
    bool status;

    if (!pb_make_string_substream(stream, &substream))
        return false;

    status = pb_decode(&substream, fields, dest_struct);

    if (!pb_close_string_substream(stream, &substream))
        return false;
    return status;
}


bool pb_decode_bool(pb_istream_t *stream, bool *dest)
{
    return pb_dec_bool(stream, NULL, (void*)dest);
}


bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof)
{
    uint32_t temp;
    *eof = false;
    *wire_type = (pb_wire_type_t) 0;
    *tag = 0;

    if (!pb_decode_varint32_eof(stream, &temp, eof))
    {
        return false;
    }

    if (temp == 0)
    {
        *eof = true; /* Special feature: allow 0-terminated messages. */
        return false;
    }

    *tag = temp >> 3;
    *wire_type = (pb_wire_type_t)(temp & 7);
    return true;
}


static void pb_field_set_to_default(pb_field_iter_t *iter)
{
    pb_type_t type;
    type = iter->pos->type;

    if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
    {
        pb_extension_t *ext = *(pb_extension_t* const *)iter->pData;
        while (ext != NULL)
        {
            pb_field_iter_t ext_iter;
            ext->found = false;
            iter_from_extension(&ext_iter, ext);
            pb_field_set_to_default(&ext_iter);
            ext = ext->next;
        }
    }
    else if (PB_ATYPE(type) == PB_ATYPE_STATIC)
    {
        bool init_data = true;
        if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData)
        {
            /* Set has_field to false. Still initialize the optional field
             * itself also. */
            *(bool*)iter->pSize = false;
        }
        else if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
                 PB_HTYPE(type) == PB_HTYPE_ONEOF)
        {
            /* REPEATED: Set array count to 0, no need to initialize contents.
               ONEOF: Set which_field to 0. */
            *(pb_size_t*)iter->pSize = 0;
            init_data = false;
        }

        if (init_data)
        {
            if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
            {
                /* Initialize submessage to defaults */
                pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData);
            }
            else if (iter->pos->ptr != NULL)
            {
                /* Initialize to default value */
                memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size);
            }
            else
            {
                /* Initialize to zeros */
                memset(iter->pData, 0, iter->pos->data_size);
            }
        }
    }
    else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
    {
        /* Initialize the pointer to NULL. */
        *(void**)iter->pData = NULL;

        /* Initialize array count to 0. */
        if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
            PB_HTYPE(type) == PB_HTYPE_ONEOF)
        {
            *(pb_size_t*)iter->pSize = 0;
        }
    }
    else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
    {
        /* Don't overwrite callback */
    }
}


void pb_release(const pb_field_t fields[], void *dest_struct)
{
    pb_field_iter_t iter;

    if (!dest_struct)
        return; /* Ignore NULL pointers, similar to free() */

    if (!pb_field_iter_begin(&iter, fields, dest_struct))
        return; /* Empty message type */

    do
    {
        pb_release_single_field(&iter);
    } while (pb_field_iter_next(&iter));
}

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
    uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0};
    const uint32_t allbits = ~(uint32_t)0;
    uint32_t extension_range_start = 0;
    pb_field_iter_t iter;

    /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed
     * count field. This can only handle _one_ repeated fixed count field that
     * is unpacked and unordered among other (non repeated fixed count) fields.
     */
    const pb_field_t *fixed_count_field = NULL;
    pb_size_t fixed_count_size = 0;

    /* Return value ignored, as empty message types will be correctly handled by
     * pb_field_iter_find() anyway. */
    (void)pb_field_iter_begin(&iter, fields, dest_struct);

    while (stream->bytes_left)
    {
        uint32_t tag;
        pb_wire_type_t wire_type;
        bool eof;

        if (!pb_decode_tag(stream, &wire_type, &tag, &eof))
        {
            if (eof)
                break;
            else
                return false;
        }

        if (!pb_field_iter_find(&iter, tag))
        {
            /* No match found, check if it matches an extension. */
            if (tag >= extension_range_start)
            {
                if (!find_extension_field(&iter))
                    extension_range_start = (uint32_t)-1;
                else
                    extension_range_start = iter.pos->tag;

                if (tag >= extension_range_start)
                {
                    size_t pos = stream->bytes_left;

                    if (!decode_extension(stream, tag, wire_type, &iter))
                        return false;

                    if (pos != stream->bytes_left)
                    {
                        /* The field was handled */
                        continue;
                    }
                }
            }

            /* No match found, skip data */
            if (!pb_skip_field(stream, wire_type))
                return false;
            continue;
        }

        /* If a repeated fixed count field was found, get size from
         * 'fixed_count_field' as there is no counter contained in the struct.
         */
        if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED
            && iter.pSize == iter.pData)
        {
            if (fixed_count_field != iter.pos) {
                /* If the new fixed count field does not match the previous one,
                 * check that the previous one is NULL or that it finished
                 * receiving all the expected data.
                 */
                if (fixed_count_field != NULL &&
                    fixed_count_size != fixed_count_field->array_size)
                {
                    PB_RETURN_ERROR(stream, "wrong size for fixed count field");
                }

                fixed_count_field = iter.pos;
                fixed_count_size = 0;
            }

            iter.pSize = &fixed_count_size;
        }

        if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED
            && iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
        {
            uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31));
            fields_seen[iter.required_field_index >> 5] |= tmp;
        }

        if (!decode_field(stream, wire_type, &iter))
            return false;
    }

    /* Check that all elements of the last decoded fixed count field were present. */
    if (fixed_count_field != NULL &&
        fixed_count_size != fixed_count_field->array_size)
    {
        PB_RETURN_ERROR(stream, "wrong size for fixed count field");
    }

    /* Check that all required fields were present. */
    {
        /* First figure out the number of required fields by
         * seeking to the end of the field array. Usually we
         * are already close to end after decoding.
         */
        unsigned req_field_count;
        pb_type_t last_type;
        unsigned i;
        do {
            req_field_count = iter.required_field_index;
            last_type = iter.pos->type;
        } while (pb_field_iter_next(&iter));

        /* Fixup if last field was also required. */
        if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
            req_field_count++;

        if (req_field_count > PB_MAX_REQUIRED_FIELDS)
            req_field_count = PB_MAX_REQUIRED_FIELDS;

        if (req_field_count > 0)
        {
            /* Check the whole words */
            for (i = 0; i < (req_field_count >> 5); i++)
            {
                if (fields_seen[i] != allbits)
                    PB_RETURN_ERROR(stream, "missing required field");
            }

            /* Check the remaining bits (if any) */
            if ((req_field_count & 31) != 0)
            {
                if (fields_seen[req_field_count >> 5] !=
                    (allbits >> (32 - (req_field_count & 31))))
                {
                    PB_RETURN_ERROR(stream, "missing required field");
                }
            }
        }
    }

    return true;
}

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

#define pb_uint64_t uint32_t

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof)
{
    pb_byte_t byte;
    uint32_t result;

    if (!pb_readbyte(stream, &byte))
    {
        if (stream->bytes_left == 0)
        {
            if (eof)
            {
                *eof = true;
            }
        }

        return false;
    }

    if ((byte & 0x80) == 0)
    {
        /* Quick case, 1 byte value */
        result = byte;
    }
    else
    {
        /* Multibyte case */
        uint_fast8_t bitpos = 7;
        result = byte & 0x7F;

        do
        {
            if (!pb_readbyte(stream, &byte))
                return false;

            if (bitpos >= 32)
            {
                /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */
                uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;

                if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension))
                {
                    PB_RETURN_ERROR(stream, "varint overflow");
                }
            }
            else
            {
                result |= (uint32_t)(byte & 0x7F) << bitpos;
            }
            bitpos = (uint_fast8_t)(bitpos + 7);
        } while (byte & 0x80);

        if (bitpos == 35 && (byte & 0x70) != 0)
        {
            /* The last byte was at bitpos=28, so only bottom 4 bits fit. */
            PB_RETURN_ERROR(stream, "varint overflow");
        }
   }

   *dest = result;
   return true;
}


static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
{
#ifndef PB_ENABLE_MALLOC
    PB_UNUSED(wire_type);
    PB_UNUSED(iter);
    PB_RETURN_ERROR(stream, "no malloc support");
#else
    pb_type_t type;
    pb_decoder_t func;

    type = iter->pos->type;
    func = PB_DECODERS[PB_LTYPE(type)];

    switch (PB_HTYPE(type))
    {
        case PB_HTYPE_REQUIRED:
        case PB_HTYPE_OPTIONAL:
        case PB_HTYPE_ONEOF:
            if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE &&
                *(void**)iter->pData != NULL)
            {
                /* Duplicate field, have to release the old allocation first. */
                pb_release_single_field(iter);
            }

            if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
            {
                *(pb_size_t*)iter->pSize = iter->pos->tag;
            }

            if (PB_LTYPE(type) == PB_LTYPE_STRING ||
                PB_LTYPE(type) == PB_LTYPE_BYTES)
            {
                return func(stream, iter->pos, iter->pData);
            }
            else
            {
                if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1))
                    return false;

                initialize_pointer_field(*(void**)iter->pData, iter);
                return func(stream, iter->pos, *(void**)iter->pData);
            }

        case PB_HTYPE_REPEATED:
            if (wire_type == PB_WT_STRING
                && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
            {
                /* Packed array, multiple items come in at once. */
                bool status = true;
                pb_size_t *size = (pb_size_t*)iter->pSize;
                size_t allocated_size = *size;
                void *pItem;
                pb_istream_t substream;

                if (!pb_make_string_substream(stream, &substream))
                    return false;

                while (substream.bytes_left)
                {
                    if ((size_t)*size + 1 > allocated_size)
                    {
                        /* Allocate more storage. This tries to guess the
                         * number of remaining entries. Round the division
                         * upwards. */
                        allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1;

                        if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size))
                        {
                            status = false;
                            break;
                        }
                    }

                    /* Decode the array entry */
                    pItem = *(char**)iter->pData + iter->pos->data_size * (*size);
                    initialize_pointer_field(pItem, iter);
                    if (!func(&substream, iter->pos, pItem))
                    {
                        status = false;
                        break;
                    }

                    if (*size == PB_SIZE_MAX)
                    {
#ifndef PB_NO_ERRMSG
                        stream->errmsg = "too many array entries";
#endif
                        status = false;
                        break;
                    }

                    (*size)++;
                }
                if (!pb_close_string_substream(stream, &substream))
                    return false;

                return status;
            }
            else
            {
                /* Normal repeated field, i.e. only one item at a time. */
                pb_size_t *size = (pb_size_t*)iter->pSize;
                void *pItem;

                if (*size == PB_SIZE_MAX)
                    PB_RETURN_ERROR(stream, "too many array entries");

                if (!allocate_field(stream, iter->pData, iter->pos->data_size, (size_t)(*size + 1)))
                    return false;

                pItem = *(char**)iter->pData + iter->pos->data_size * (*size);
                (*size)++;
                initialize_pointer_field(pItem, iter);
                return func(stream, iter->pos, pItem);
            }

        default:
            PB_RETURN_ERROR(stream, "invalid field type");
    }
#endif
}


static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    uint32_t size;
    size_t alloc_size;
    bool status;
    if (!pb_decode_varint32(stream, &size))
        return false;

    /* Space for null terminator */
    alloc_size = size + 1;

    if (alloc_size < size)
        PB_RETURN_ERROR(stream, "size too large");

    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
    {
#ifndef PB_ENABLE_MALLOC
        PB_RETURN_ERROR(stream, "no malloc support");
#else
        if (!allocate_field(stream, dest, alloc_size, 1))
            return false;
        dest = *(void**)dest;
#endif
    }
    else
    {
        if (alloc_size > field->data_size)
            PB_RETURN_ERROR(stream, "string overflow");
    }

    status = pb_read(stream, (pb_byte_t*)dest, size);
    *((pb_byte_t*)dest + size) = 0;
    return status;
}


static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    uint32_t size;

    if (!pb_decode_varint32(stream, &size))
        return false;

    if (size > PB_SIZE_MAX)
        PB_RETURN_ERROR(stream, "bytes overflow");

    if (size == 0)
    {
        /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */
        memset(dest, 0, field->data_size);
        return true;
    }

    if (size != field->data_size)
        PB_RETURN_ERROR(stream, "incorrect fixed length bytes size");

    return pb_read(stream, (pb_byte_t*)dest, field->data_size);
}


static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
{
    pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
#ifdef PB_OLD_CALLBACK_STYLE
    void *arg;
#else
    void **arg;
#endif

    if (pCallback == NULL || pCallback->funcs.decode == NULL)
        return pb_skip_field(stream, wire_type);

#ifdef PB_OLD_CALLBACK_STYLE
    arg = pCallback->arg;
#else
    arg = &(pCallback->arg);
#endif

    if (wire_type == PB_WT_STRING)
    {
        pb_istream_t substream;

        if (!pb_make_string_substream(stream, &substream))
            return false;

        do
        {
            if (!pCallback->funcs.decode(&substream, iter->pos, arg))
                PB_RETURN_ERROR(stream, "callback failed");
        } while (substream.bytes_left);

        if (!pb_close_string_substream(stream, &substream))
            return false;

        return true;
    }
    else
    {
        /* Copy the single scalar value to stack.
         * This is required so that we can limit the stream length,
         * which in turn allows to use same callback for packed and
         * not-packed fields. */
        pb_istream_t substream;
        pb_byte_t buffer[10];
        size_t size = sizeof(buffer);

        if (!read_raw_value(stream, wire_type, buffer, &size))
            return false;
        substream = pb_istream_from_buffer(buffer, size);

        return pCallback->funcs.decode(&substream, iter->pos, arg);
    }
}


bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
{
    pb_byte_t bytes[4];

    if (!pb_read(stream, bytes, 4))
        return false;

    *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) |
                       ((uint32_t)bytes[1] << 8) |
                       ((uint32_t)bytes[2] << 16) |
                       ((uint32_t)bytes[3] << 24);
    return true;
}

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

#define pb_uint64_t uint32_t


static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    PB_UNUSED(field);
    return pb_decode_fixed32(stream, dest);
}


bool checkreturn pb_skip_string(pb_istream_t *stream)
{
    uint32_t length;
    if (!pb_decode_varint32(stream, &length))
        return false;

    return pb_read(stream, NULL, length);
}

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

#define pb_uint64_t uint32_t

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    PB_UNUSED(field);
#ifndef PB_WITHOUT_64BIT
    return pb_decode_fixed64(stream, dest);
#else
    PB_UNUSED(dest);
    PB_RETURN_ERROR(stream, "no 64bit support");
#endif
}


static bool checkreturn find_extension_field(pb_field_iter_t *iter)
{
    const pb_field_t *start = iter->pos;

    do {
        if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION)
            return true;
        (void)pb_field_iter_next(iter);
    } while (iter->pos != start);

    return false;
}


static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size)
{
    size_t max_size = *size;
    switch (wire_type)
    {
        case PB_WT_VARINT:
            *size = 0;
            do
            {
                (*size)++;
                if (*size > max_size) return false;
                if (!pb_read(stream, buf, 1)) return false;
            } while (*buf++ & 0x80);
            return true;

        case PB_WT_64BIT:
            *size = 8;
            return pb_read(stream, buf, 8);

        case PB_WT_32BIT:
            *size = 4;
            return pb_read(stream, buf, 4);

        case PB_WT_STRING:
            /* Calling read_raw_value with a PB_WT_STRING is an error.
             * Explicitly handle this case and fallthrough to default to avoid
             * compiler warnings.
             */

        default: PB_RETURN_ERROR(stream, "invalid wire_type");
    }
}


static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension)
{
    /* Fake a field iterator for the extension field.
     * It is not actually safe to advance this iterator, but decode_field
     * will not even try to. */
    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
    (void)pb_field_iter_begin(iter, field, extension->dest);
    iter->pData = extension->dest;
    iter->pSize = &extension->found;

    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
    {
        /* For pointer extensions, the pointer is stored directly
         * in the extension structure. This avoids having an extra
         * indirection. */
        iter->pData = &extension->dest;
    }
}


bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
    /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */
    return pb_decode(stream, fields, dest_struct);
}


static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    uint32_t size;
    size_t alloc_size;
    pb_bytes_array_t *bdest;

    if (!pb_decode_varint32(stream, &size))
        return false;

    if (size > PB_SIZE_MAX)
        PB_RETURN_ERROR(stream, "bytes overflow");

    alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size);
    if (size > alloc_size)
        PB_RETURN_ERROR(stream, "size too large");

    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
    {
#ifndef PB_ENABLE_MALLOC
        PB_RETURN_ERROR(stream, "no malloc support");
#else
        if (!allocate_field(stream, dest, alloc_size, 1))
            return false;
        bdest = *(pb_bytes_array_t**)dest;
#endif
    }
    else
    {
        if (alloc_size > field->data_size)
            PB_RETURN_ERROR(stream, "bytes overflow");
        bdest = (pb_bytes_array_t*)dest;
    }

    bdest->size = (pb_size_t)size;
    return pb_read(stream, bdest->bytes, size);
}


static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter)
{
    pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */
    pb_size_t new_tag = iter->pos->tag; /* New which_ value */

    if (old_tag == 0)
        return true; /* Ok, no old data in union */

    if (old_tag == new_tag)
        return true; /* Ok, old data is of same type => merge */

    /* Release old data. The find can fail if the message struct contains
     * invalid data. */
    if (!pb_field_iter_find(iter, old_tag))
        PB_RETURN_ERROR(stream, "invalid union tag");

    pb_release_single_field(iter);

    /* Restore iterator to where it should be.
     * This shouldn't fail unless the pb_field_t structure is corrupted. */
    if (!pb_field_iter_find(iter, new_tag))
        PB_RETURN_ERROR(stream, "iterator error");

    return true;
}


static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct)
{
    pb_field_iter_t iter;

    if (!pb_field_iter_begin(&iter, fields, dest_struct))
        return; /* Empty message type */

    do
    {
        pb_field_set_to_default(&iter);
    } while (pb_field_iter_next(&iter));
}


static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    pb_uint64_t value;
    pb_int64_t svalue;
    pb_int64_t clamped;
    if (!pb_decode_varint(stream, &value))
        return false;

    /* See issue 97: Google's C++ protobuf allows negative varint values to
     * be cast as int32_t, instead of the int64_t that should be used when
     * encoding. Previous nanopb versions had a bug in encoding. In order to
     * not break decoding of such messages, we cast <=32 bit fields to
     * int32_t first to get the sign correct.
     */
    if (field->data_size == sizeof(pb_int64_t))
        svalue = (pb_int64_t)value;
    else
        svalue = (int32_t)value;

    /* Cast to the proper field size, while checking for overflows */
    if (field->data_size == sizeof(pb_int64_t))
        clamped = *(pb_int64_t*)dest = svalue;
    else if (field->data_size == sizeof(int32_t))
        clamped = *(int32_t*)dest = (int32_t)svalue;
    else if (field->data_size == sizeof(int_least16_t))
        clamped = *(int_least16_t*)dest = (int_least16_t)svalue;
    else if (field->data_size == sizeof(int_least8_t))
        clamped = *(int_least8_t*)dest = (int_least8_t)svalue;
    else
        PB_RETURN_ERROR(stream, "invalid data_size");

    if (clamped != svalue)
        PB_RETURN_ERROR(stream, "integer too large");

    return true;
}

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

#define pb_int64_t int32_t

#define pb_uint64_t uint32_t

#define pb_int64_t int64_t

#define pb_uint64_t uint64_t

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    uint32_t value;
    PB_UNUSED(field);
    if (!pb_decode_varint32(stream, &value))
        return false;

    *(bool*)dest = (value != 0);
    return true;
}


bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
{
    pb_byte_t bytes[8];

    if (!pb_read(stream, bytes, 8))
        return false;

    *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) |
                       ((uint64_t)bytes[1] << 8) |
                       ((uint64_t)bytes[2] << 16) |
                       ((uint64_t)bytes[3] << 24) |
                       ((uint64_t)bytes[4] << 32) |
                       ((uint64_t)bytes[5] << 40) |
                       ((uint64_t)bytes[6] << 48) |
                       ((uint64_t)bytes[7] << 56);

    return true;
}

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

#define pb_uint64_t uint64_t


static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
    pb_int64_t value, clamped;
    if (!pb_decode_svarint(stream, &value))
        return false;

    /* Cast to the proper field size, while checking for overflows */
    if (field->data_size == sizeof(pb_int64_t))
        clamped = *(pb_int64_t*)dest = value;
    else if (field->data_size == sizeof(int32_t))
        clamped = *(int32_t*)dest = (int32_t)value;
    else if (field->data_size == sizeof(int_least16_t))
        clamped = *(int_least16_t*)dest = (int_least16_t)value;
    else if (field->data_size == sizeof(int_least8_t))
        clamped = *(int_least8_t*)dest = (int_least8_t)value;
    else
        PB_RETURN_ERROR(stream, "invalid data_size");

    if (clamped != value)
        PB_RETURN_ERROR(stream, "integer too large");

    return true;
}

#define checkreturn

#define checkreturn __attribute__((warn_unused_result))

typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest)

static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);

static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);

static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);

static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);

static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);

static bool checkreturn

static void pb_field_set_to_default(pb_field_iter_t *iter);

static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);

static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);

static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);

static void pb_release_single_field(const pb_field_iter_t *iter);

#define pb_int64_t int32_t

#define pb_int64_t int64_t

static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
    &pb_dec_bool,
    &pb_dec_varint,
    &pb_dec_uvarint,
    &pb_dec_svarint,
    &pb_dec_fixed32,
    &pb_dec_fixed64,

    &pb_dec_bytes,
    &pb_dec_string,
    &pb_dec_submessage,
    NULL, /* extensions */
    &pb_dec_fixed_length_bytes
};


static bool checkreturn default_extension_decoder(pb_istream_t *stream,
    pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type)
{
    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
    pb_field_iter_t iter;

    if (field->tag != tag)
        return true;

    iter_from_extension(&iter, extension);
    extension->found = true;
    return decode_field(stream, wire_type, &iter);
}


  void Compute(OpKernelContext* context) override {
    // Here's the basic idea:
    // Batch and depth dimension are independent from row and col dimension. And
    // because FractionalAvgPool currently only support pooling along row and
    // col, we can basically think of this 4D tensor backpropagation as
    // operation of a series of 2D planes.
    //
    // For each element of a 'slice' (2D plane) of output_backprop, we need to
    // figure out its contributors when doing FractionalAvgPool operation. This
    // can be done based on row_pooling_sequence, col_pooling_seq and
    // overlapping.
    // Once we figure out the original contributors, we just need to evenly
    // divide the value of this element among these contributors.
    //
    // Internally, we divide the out_backprop tensor and store it in a temporary
    // tensor of double type. And cast it to the corresponding type.
    typedef Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>
        ConstEigenMatrixMap;
    typedef Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>>
        EigenDoubleMatrixMap;

    // Grab the inputs.
    const Tensor& orig_input_tensor_shape = context->input(0);
    OP_REQUIRES(context,
                orig_input_tensor_shape.dims() == 1 &&
                    orig_input_tensor_shape.NumElements() == 4,
                errors::InvalidArgument("original input tensor shape must be"
                                        "1-dimensional and 4 elements"));
    const Tensor& out_backprop = context->input(1);
    const Tensor& row_seq_tensor = context->input(2);
    const Tensor& col_seq_tensor = context->input(3);

    const int64 out_batch = out_backprop.dim_size(0);
    const int64 out_rows = out_backprop.dim_size(1);
    const int64 out_cols = out_backprop.dim_size(2);
    const int64 out_depth = out_backprop.dim_size(3);

    OP_REQUIRES(context, row_seq_tensor.NumElements() > out_rows,
                errors::InvalidArgument("Given out_backprop shape ",
                                        out_backprop.shape().DebugString(),
                                        ", row_seq_tensor must have at least ",
                                        out_rows + 1, " elements, but got ",
                                        row_seq_tensor.NumElements()));
    OP_REQUIRES(context, col_seq_tensor.NumElements() > out_cols,
                errors::InvalidArgument("Given out_backprop shape ",
                                        out_backprop.shape().DebugString(),
                                        ", col_seq_tensor must have at least ",
                                        out_cols + 1, " elements, but got ",
                                        col_seq_tensor.NumElements()));

    auto row_seq_tensor_flat = row_seq_tensor.flat<int64>();
    auto col_seq_tensor_flat = col_seq_tensor.flat<int64>();
    auto orig_input_tensor_shape_flat = orig_input_tensor_shape.flat<int64>();

    const int64 in_batch = orig_input_tensor_shape_flat(0);
    const int64 in_rows = orig_input_tensor_shape_flat(1);
    const int64 in_cols = orig_input_tensor_shape_flat(2);
    const int64 in_depth = orig_input_tensor_shape_flat(3);

    constexpr int tensor_in_and_out_dims = 4;
    // Transform orig_input_tensor_shape into TensorShape
    TensorShape in_shape;
    for (auto i = 0; i < tensor_in_and_out_dims; ++i) {
      in_shape.AddDim(orig_input_tensor_shape_flat(i));
    }

    // Create intermediate in_backprop.
    Tensor in_backprop_tensor_temp;
    OP_REQUIRES_OK(context, context->forward_input_or_allocate_temp(
                                {0}, DataTypeToEnum<double>::v(), in_shape,
                                &in_backprop_tensor_temp));
    in_backprop_tensor_temp.flat<double>().setZero();
    // Transform 4D tensor to 2D matrix.
    EigenDoubleMatrixMap in_backprop_tensor_temp_mat(
        in_backprop_tensor_temp.flat<double>().data(), in_depth,
        in_cols * in_rows * in_batch);
    ConstEigenMatrixMap out_backprop_mat(out_backprop.flat<T>().data(),
                                         out_depth,
                                         out_cols * out_rows * out_batch);
    // Loop through each element of out_backprop and evenly distribute the
    // element to the corresponding pooling cell.
    const int64 in_max_row_index = in_rows - 1;
    const int64 in_max_col_index = in_cols - 1;
    for (int64 b = 0; b < out_batch; ++b) {
      for (int64 r = 0; r < out_rows; ++r) {
        const int64 in_row_start = row_seq_tensor_flat(r);
        int64 in_row_end = overlapping_ ? row_seq_tensor_flat(r + 1)
                                        : row_seq_tensor_flat(r + 1) - 1;
        in_row_end = std::min(in_row_end, in_max_row_index);
        for (int64 c = 0; c < out_cols; ++c) {
          const int64 in_col_start = col_seq_tensor_flat(c);
          int64 in_col_end = overlapping_ ? col_seq_tensor_flat(c + 1)
                                          : col_seq_tensor_flat(c + 1) - 1;
          in_col_end = std::min(in_col_end, in_max_col_index);

          const int64 num_elements_in_pooling_cell =
              (in_row_end - in_row_start + 1) * (in_col_end - in_col_start + 1);
          const int64 out_index = (b * out_rows + r) * out_cols + c;
          // Now we can evenly distribute out_backprop(b, h, w, *) to
          // in_backprop(b, hs:he, ws:we, *).
          for (int64 in_r = in_row_start; in_r <= in_row_end; ++in_r) {
            for (int64 in_c = in_col_start; in_c <= in_col_end; ++in_c) {
              const int64 in_index = (b * in_rows + in_r) * in_cols + in_c;
              // Walk through each channel (depth).
              for (int64 d = 0; d < out_depth; ++d) {
                const double out_backprop_element = static_cast<double>(
                    out_backprop_mat.coeffRef(d, out_index));
                double& in_backprop_ref =
                    in_backprop_tensor_temp_mat.coeffRef(d, in_index);
                in_backprop_ref +=
                    out_backprop_element / num_elements_in_pooling_cell;
              }
            }
          }
        }
      }
    }

    // Depending on the type, cast double to type T.
    Tensor* in_backprop_tensor = nullptr;
    OP_REQUIRES_OK(context, context->forward_input_or_allocate_output(
                                {0}, 0, in_shape, &in_backprop_tensor));
    auto in_backprop_tensor_flat = in_backprop_tensor->flat<T>();
    auto in_backprop_tensor_temp_flat = in_backprop_tensor_temp.flat<double>();
    for (int64 i = 0; i < in_backprop_tensor_flat.size(); ++i) {
      in_backprop_tensor_flat(i) =
          static_cast<T>(in_backprop_tensor_temp_flat(i));
    }
  }

Validate inputs of `FractionalAvgPoolGrad`.

PiperOrigin-RevId: 372420640
Change-Id: Icc583928e6cdc3062e12498e4d2337a8fe3da016


static int str_in_list(const char *str, char * const list[], int count)
{
	int i;

	for (i = 0; i < count; i++)
		if (!strcmp(list[i], str))
			return 1;

	return 0;
}

fdt_region: Check for a single root node of the correct name

At present fdt_find_regions() assumes that the FIT is a valid devicetree.
If the FIT has two root nodes this is currently not detected in this
function, nor does libfdt's fdt_check_full() notice. Also it is possible
for the root node to have a name even though it should not.

Add checks for these and return -FDT_ERR_BADSTRUCTURE if a problem is
detected.

CVE-2021-27097

Signed-off-by: Simon Glass <sjg@chromium.org>
Reported-by: Bruce Monroe <bruce.monroe@intel.com>
Reported-by: Arie Haenel <arie.haenel@intel.com>
Reported-by: Julien Lenoir <julien.lenoir@intel.com>

#define FDT_MAX_DEPTH	32

enum {
	FDT_DONE_NOTHING,
	FDT_DONE_MEM_RSVMAP,
	FDT_DONE_STRUCT,
	FDT_DONE_END,
	FDT_DONE_STRINGS,
	FDT_DONE_ALL,
}


int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
			  int max_regions, struct fdt_region_state *info)
{
	int base = fdt_off_dt_struct(fdt);
	int node, node_end, offset;
	int did_alias_header;

	node = fdt_subnode_offset(fdt, 0, "aliases");
	if (node < 0)
		return -FDT_ERR_NOTFOUND;

	/*
	 * Find the next node so that we know where the /aliases node ends. We
	 * need special handling if /aliases is the last node.
	 */
	node_end = fdt_next_subnode(fdt, node);
	if (node_end == -FDT_ERR_NOTFOUND)
		/* Move back to the FDT_END_NODE tag of '/' */
		node_end = fdt_size_dt_struct(fdt) - sizeof(fdt32_t) * 2;
	else if (node_end < 0) /* other error */
		return node_end;
	node_end -= sizeof(fdt32_t);  /* Move to FDT_END_NODE tag of /aliases */

	did_alias_header = 0;
	info->region = region;
	info->count = count;
	info->can_merge = 0;
	info->max_regions = max_regions;

	for (offset = fdt_first_property_offset(fdt, node);
	     offset >= 0;
	     offset = fdt_next_property_offset(fdt, offset)) {
		const struct fdt_property *prop;
		const char *name;
		int target, next;

		prop = fdt_get_property_by_offset(fdt, offset, NULL);
		name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
		target = fdt_path_offset(fdt, name);
		if (!region_list_contains_offset(info, fdt, target))
			continue;
		next = fdt_next_property_offset(fdt, offset);
		if (next < 0)
			next = node_end;

		if (!did_alias_header) {
			fdt_add_region(info, base + node, 12);
			did_alias_header = 1;
		}
		fdt_add_region(info, base + offset, next - offset);
	}

	/* Add the FDT_END_NODE tag */
	if (did_alias_header)
		fdt_add_region(info, base + node_end, sizeof(fdt32_t));

	return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE;
}


int fdt_next_region(const void *fdt,
		int (*h_include)(void *priv, const void *fdt, int offset,
				 int type, const char *data, int size),
		void *priv, struct fdt_region *region,
		char *path, int path_len, int flags,
		struct fdt_region_state *info)
{
	int base = fdt_off_dt_struct(fdt);
	int last_node = 0;
	const char *str;

	info->region = region;
	info->count = 0;
	if (info->ptrs.done < FDT_DONE_MEM_RSVMAP &&
	    (flags & FDT_REG_ADD_MEM_RSVMAP)) {
		/* Add the memory reserve map into its own region */
		if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt),
				   fdt_off_dt_struct(fdt) -
				   fdt_off_mem_rsvmap(fdt)))
			return 0;
		info->can_merge = 0;	/* Don't allow merging with this */
		info->ptrs.done = FDT_DONE_MEM_RSVMAP;
	}

	/*
	 * Work through the tags one by one, deciding whether each needs to
	 * be included or not. We set the variable 'include' to indicate our
	 * decision. 'want' is used to track what we want to include - it
	 * allows us to pick up all the properties (and/or subnode tags) of
	 * a node.
	 */
	while (info->ptrs.done < FDT_DONE_STRUCT) {
		const struct fdt_property *prop;
		struct fdt_region_ptrs p;
		const char *name;
		int include = 0;
		int stop_at = 0;
		uint32_t tag;
		int offset;
		int val;
		int len;

		/*
		 * Make a copy of our pointers. If we make it to the end of
		 * this block then we will commit them back to info->ptrs.
		 * Otherwise we can try again from the same starting state
		 * next time we are called.
		 */
		p = info->ptrs;

		/*
		 * Find the tag, and the offset of the next one. If we need to
		 * stop including tags, then by default we stop *after*
		 * including the current tag
		 */
		offset = p.nextoffset;
		tag = fdt_next_tag(fdt, offset, &p.nextoffset);
		stop_at = p.nextoffset;

		switch (tag) {
		case FDT_PROP:
			stop_at = offset;
			prop = fdt_get_property_by_offset(fdt, offset, NULL);
			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
			val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
					    strlen(str) + 1);
			if (val == -1) {
				include = p.want >= WANT_NODES_AND_PROPS;
			} else {
				include = val;
				/*
				 * Make sure we include the } for this block.
				 * It might be more correct to have this done
				 * by the call to fdt_include_supernodes() in
				 * the case where it adds the node we are
				 * currently in, but this is equivalent.
				 */
				if ((flags & FDT_REG_SUPERNODES) && val &&
				    !p.want)
					p.want = WANT_NODES_ONLY;
			}

			/* Value grepping is not yet supported */
			break;

		case FDT_NOP:
			include = p.want >= WANT_NODES_AND_PROPS;
			stop_at = offset;
			break;

		case FDT_BEGIN_NODE:
			last_node = offset;
			p.depth++;
			if (p.depth == FDT_MAX_DEPTH)
				return -FDT_ERR_BADSTRUCTURE;
			name = fdt_get_name(fdt, offset, &len);
			if (p.end - path + 2 + len >= path_len)
				return -FDT_ERR_NOSPACE;

			/* Build the full path of this node */
			if (p.end != path + 1)
				*p.end++ = '/';
			strcpy(p.end, name);
			p.end += len;
			info->stack[p.depth].want = p.want;
			info->stack[p.depth].offset = offset;

			/*
			 * If we are not intending to include this node unless
			 * it matches, make sure we stop *before* its tag.
			 */
			if (p.want == WANT_NODES_ONLY ||
			    !(flags & (FDT_REG_DIRECT_SUBNODES |
				       FDT_REG_ALL_SUBNODES))) {
				stop_at = offset;
				p.want = WANT_NOTHING;
			}
			val = h_include(priv, fdt, offset, FDT_IS_NODE, path,
					p.end - path + 1);

			/* Include this if requested */
			if (val) {
				p.want = (flags & FDT_REG_ALL_SUBNODES) ?
					WANT_ALL_NODES_AND_PROPS :
					WANT_NODES_AND_PROPS;
			}

			/* If not requested, decay our 'p.want' value */
			else if (p.want) {
				if (p.want != WANT_ALL_NODES_AND_PROPS)
					p.want--;

			/* Not including this tag, so stop now */
			} else {
				stop_at = offset;
			}

			/*
			 * Decide whether to include this tag, and update our
			 * stack with the state for this node
			 */
			include = p.want;
			info->stack[p.depth].included = include;
			break;

		case FDT_END_NODE:
			include = p.want;
			if (p.depth < 0)
				return -FDT_ERR_BADSTRUCTURE;

			/*
			 * If we don't want this node, stop right away, unless
			 * we are including subnodes
			 */
			if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES))
				stop_at = offset;
			p.want = info->stack[p.depth].want;
			p.depth--;
			while (p.end > path && *--p.end != '/')
				;
			*p.end = '\0';
			break;

		case FDT_END:
			/* We always include the end tag */
			include = 1;
			p.done = FDT_DONE_STRUCT;
			break;
		}

		/* If this tag is to be included, mark it as region start */
		if (include && info->start == -1) {
			/* Include any supernodes required by this one */
			if (flags & FDT_REG_SUPERNODES) {
				if (fdt_include_supernodes(info, p.depth))
					return 0;
			}
			info->start = offset;
		}

		/*
		 * If this tag is not to be included, finish up the current
		 * region.
		 */
		if (!include && info->start != -1) {
			if (fdt_add_region(info, base + info->start,
					   stop_at - info->start))
				return 0;
			info->start = -1;
			info->can_merge = 1;
		}

		/* If we have made it this far, we can commit our pointers */
		info->ptrs = p;
	}

	/* Add a region for the END tag and a separate one for string table */
	if (info->ptrs.done < FDT_DONE_END) {
		if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt))
			return -FDT_ERR_BADSTRUCTURE;

		if (fdt_add_region(info, base + info->start,
				   info->ptrs.nextoffset - info->start))
			return 0;
		info->ptrs.done++;
	}
	if (info->ptrs.done < FDT_DONE_STRINGS) {
		if (flags & FDT_REG_ADD_STRING_TAB) {
			info->can_merge = 0;
			if (fdt_off_dt_strings(fdt) <
			    base + info->ptrs.nextoffset)
				return -FDT_ERR_BADLAYOUT;
			if (fdt_add_region(info, fdt_off_dt_strings(fdt),
					   fdt_size_dt_strings(fdt)))
				return 0;
		}
		info->ptrs.done++;
	}

	return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND;
}


static int fdt_add_region(struct fdt_region_state *info, int offset, int size)
{
	struct fdt_region *reg;

	reg = info->region ? &info->region[info->count - 1] : NULL;
	if (info->can_merge && info->count &&
	    info->count <= info->max_regions &&
	    reg && offset <= reg->offset + reg->size) {
		reg->size = offset + size - reg->offset;
	} else if (info->count++ < info->max_regions) {
		if (reg) {
			reg++;
			reg->offset = offset;
			reg->size = size;
		}
	} else {
		return -1;
	}

	return 0;
}


static int region_list_contains_offset(struct fdt_region_state *info,
				       const void *fdt, int target)
{
	struct fdt_region *reg;
	int num;

	target += fdt_off_dt_struct(fdt);
	for (reg = info->region, num = 0; num < info->count; reg++, num++) {
		if (target >= reg->offset && target < reg->offset + reg->size)
			return 1;
	}

	return 0;
}


int fdt_first_region(const void *fdt,
		int (*h_include)(void *priv, const void *fdt, int offset,
				 int type, const char *data, int size),
		void *priv, struct fdt_region *region,
		char *path, int path_len, int flags,
		struct fdt_region_state *info)
{
	struct fdt_region_ptrs *p = &info->ptrs;

	/* Set up our state */
	info->fdt = fdt;
	info->can_merge = 1;
	info->max_regions = 1;
	info->start = -1;
	p->want = WANT_NOTHING;
	p->end = path;
	*p->end = '\0';
	p->nextoffset = 0;
	p->depth = -1;
	p->done = FDT_DONE_NOTHING;

	return fdt_next_region(fdt, h_include, priv, region,
			       path, path_len, flags, info);
}

enum {
	FDT_DONE_NOTHING,
	FDT_DONE_MEM_RSVMAP,
	FDT_DONE_STRUCT,
	FDT_DONE_END,
	FDT_DONE_STRINGS,
	FDT_DONE_ALL,
}


int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
		     char * const exc_prop[], int exc_prop_count,
		     struct fdt_region region[], int max_regions,
		     char *path, int path_len, int add_string_tab)
{
	int stack[FDT_MAX_DEPTH] = { 0 };
	char *end;
	int nextoffset = 0;
	uint32_t tag;
	int count = 0;
	int start = -1;
	int depth = -1;
	int want = 0;
	int base = fdt_off_dt_struct(fdt);
	bool expect_end = false;

	end = path;
	*end = '\0';
	do {
		const struct fdt_property *prop;
		const char *name;
		const char *str;
		int include = 0;
		int stop_at = 0;
		int offset;
		int len;

		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);
		stop_at = nextoffset;

		/* If we see two root nodes, something is wrong */
		if (expect_end && tag != FDT_END)
			return -FDT_ERR_BADLAYOUT;

		switch (tag) {
		case FDT_PROP:
			include = want >= 2;
			stop_at = offset;
			prop = fdt_get_property_by_offset(fdt, offset, NULL);
			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
			if (!str)
				return -FDT_ERR_BADSTRUCTURE;
			if (str_in_list(str, exc_prop, exc_prop_count))
				include = 0;
			break;

		case FDT_NOP:
			include = want >= 2;
			stop_at = offset;
			break;

		case FDT_BEGIN_NODE:
			depth++;
			if (depth == FDT_MAX_DEPTH)
				return -FDT_ERR_BADSTRUCTURE;
			name = fdt_get_name(fdt, offset, &len);

			/* The root node must have an empty name */
			if (!depth && *name)
				return -FDT_ERR_BADLAYOUT;
			if (end - path + 2 + len >= path_len)
				return -FDT_ERR_NOSPACE;
			if (end != path + 1)
				*end++ = '/';
			strcpy(end, name);
			end += len;
			stack[depth] = want;
			if (want == 1)
				stop_at = offset;
			if (str_in_list(path, inc, inc_count))
				want = 2;
			else if (want)
				want--;
			else
				stop_at = offset;
			include = want;
			break;

		case FDT_END_NODE:
			/* Depth must never go below -1 */
			if (depth < 0)
				return -FDT_ERR_BADSTRUCTURE;
			include = want;
			want = stack[depth--];
			while (end > path && *--end != '/')
				;
			*end = '\0';
			if (depth == -1)
				expect_end = true;
			break;

		case FDT_END:
			include = 1;
			break;
		}

		if (include && start == -1) {
			/* Should we merge with previous? */
			if (count && count <= max_regions &&
			    offset == region[count - 1].offset +
					region[count - 1].size - base)
				start = region[--count].offset - base;
			else
				start = offset;
		}

		if (!include && start != -1) {
			if (count < max_regions) {
				region[count].offset = base + start;
				region[count].size = stop_at - start;
			}
			count++;
			start = -1;
		}
	} while (tag != FDT_END);

	if (nextoffset != fdt_size_dt_struct(fdt))
		return -FDT_ERR_BADLAYOUT;

	/* Add a region for the END tag and the string table */
	if (count < max_regions) {
		region[count].offset = base + start;
		region[count].size = nextoffset - start;
		if (add_string_tab)
			region[count].size += fdt_size_dt_strings(fdt);
	}
	count++;

	return count;
}


static int fdt_include_supernodes(struct fdt_region_state *info, int depth)
{
	int base = fdt_off_dt_struct(info->fdt);
	int start, stop_at;
	int i;

	/*
	 * Work down the stack looking for supernodes that we didn't include.
	 * The algortihm here is actually pretty simple, since we know that
	 * no previous subnode had to include these nodes, or if it did, we
	 * marked them as included (on the stack) already.
	 */
	for (i = 0; i <= depth; i++) {
		if (!info->stack[i].included) {
			start = info->stack[i].offset;

			/* Add the FDT_BEGIN_NODE tag of this supernode */
			fdt_next_tag(info->fdt, start, &stop_at);
			if (fdt_add_region(info, base + start, stop_at - start))
				return -1;

			/* Remember that this supernode is now included */
			info->stack[i].included = 1;
			info->can_merge = 1;
		}

		/* Force (later) generation of the FDT_END_NODE tag */
		if (!info->stack[i].want)
			info->stack[i].want = WANT_NODES_ONLY;
	}

	return 0;
}