Example #1
0
// Decode unsigned integer values in any base between 10 and 36.
int decode(uint64_t value, char* const rc, int radix)
{
	int rev = DECODE_BUF_LEN;
	if (radix < MIN_RADIX || radix > MAX_RADIX)
		radix = MIN_RADIX;

	if (radix == 10) // go faster for this option
	{
		while (true)
		{
			rc[rev--] = static_cast<unsigned char>(value % 10) + '0';
			value /= 10;
			if (!value)
				break;
		}
	}
	else
	{
		while (true)
		{
			int temp = static_cast<int>(value % radix);
			rc[rev--] = static_cast<unsigned char>(temp < 10 ? temp + '0' : temp - 10 + 'A');
			value /= radix;
			if (!value)
				break;
		}
	}

	return adjust_prefix(radix, rev, false, rc);
}
Example #2
0
// Decode signed integer values in any base between 10 and 36.
int decode(int64_t value, char* const rc, int radix)
{
	if (value >= 0)
		return decode(static_cast<uint64_t>(value), rc, radix);

	int rev = DECODE_BUF_LEN;
	if (radix < MIN_RADIX || radix > MAX_RADIX)
		radix = MIN_RADIX;

	// The remainder with negative values is not consistent across compilers.
	if (radix == 10) // go faster for this option
	{
		while (true)
		{
			int64_t temp = (value / 10) * 10 - value;
			rc[rev--] = static_cast<unsigned char>(temp) + '0';
			value /= 10;
			if (!value)
				break;
		}
	}
	else
	{
		while (true)
		{
			int64_t temp = (value / radix) * radix - value;
			rc[rev--] = static_cast<unsigned char>(temp < 10 ? temp + '0' : temp - 10 + 'A');
			value /= radix;
			if (!value)
				break;
		}
	}

	return adjust_prefix(radix, rev, true, rc);
}
Example #3
0
/*!
 * Perform a recursive length prefix update on all messages containing the
 * given part and possibly the part as such up to its origin.
 *
 * This is where all the magic happens. This function takes a binary stream and
 * reads data from it, until it reaches a length-prefixed field. Messages are
 * always length-prefixed, so binary parts that are not can be safely skipped.
 * If the binary stream's current offset matches the tag offset of the part
 * exactly, and the part is empty, we ran into an initialization update, so we
 * can directly abort here.
 *
 * Otherwise, if the binary part contains the part, and thus does not match
 * exactly, we must have found a submessage and need to recurse. The length
 * prefixes must be updated from within, since they are encoded as
 * variable-sized integers and may also affect the size of parent messages.
 *
 * After recursing, it is mandatory to check if the part needs to be
 * realigned, since there may have been updates on the length prefixes of
 * submessages that affect the offsets of the part, and perform such a
 * realignment if necessary.
 *
 * Finally, we write the new length prefix and adjust the delta value if the
 * new length prefix exceeds the length of the current one. That easy.
 *
 * \warning The lines excluded from code coverage are impossible to occur,
 * but they are necessary to ensure application-wide proper error handling.
 *
 * \param[in,out] part   Part
 * \param[in,out] stream Binary stream
 * \param[in,out] delta  Delta
 * \return               Error code
 */
static pb_error_t
adjust_recursive(
    pb_part_t *part, pb_binary_stream_t *stream, ptrdiff_t *delta) {
  assert(part && stream && delta && *delta);
  assert(pb_part_aligned(part));
  pb_error_t error = PB_ERROR_NONE;

  /* Read from the binary stream until the end of the part */
  while (pb_binary_stream_offset(stream) < part->offset.end) {
    if (pb_binary_stream_offset(stream) == part->offset.start - *delta &&
        pb_part_empty(part))
      break;

    /* Skip non-length-prefixed fields */
    pb_tag_t tag = 0; uint32_t bytes;
    size_t offset = pb_binary_stream_offset(stream);
    if ((error = pb_binary_stream_read_varint32(stream, &tag)))
      break;                                               /* LCOV_EXCL_LINE */
    if ((tag & 7) != PB_WIRETYPE_LENGTH) {
      if (!skip_jump[tag & 7] || (error = skip_jump[tag & 7](stream)))
        break;                                             /* LCOV_EXCL_LINE */
      continue;
    }

    /* Create a temporary part, so we can use adjust_prefix() */
    pb_part_t temp = {
      .binary  = pb_part_binary(part),
      .version = pb_part_version(part),
      .offset  = {
        .start = 0,
        .end   = 0,
        .diff  = {
          .origin = offset,
          .tag    = offset,
          .length = pb_binary_stream_offset(stream)
        }
      }
    };

    /* Read length from length-prefixed field */
    if ((error = pb_binary_stream_read_varint32(stream, &bytes)))
      break;                                               /* LCOV_EXCL_LINE */

    /* Update offsets */
    temp.offset.start        = pb_binary_stream_offset(stream);
    temp.offset.end          = temp.offset.start + bytes;
    temp.offset.diff.origin -= temp.offset.start;
    temp.offset.diff.tag    -= temp.offset.start;
    temp.offset.diff.length -= temp.offset.start;

    /* Abort, if we're past the origin */
    if (temp.offset.start > part->offset.start + part->offset.diff.origin)
      break;

    /* The temporary part lies within the part */
    if (temp.offset.start <= part->offset.start &&
        temp.offset.end   >= part->offset.end - *delta) {
      temp.offset.end += *delta;

      /* The parts don't match, so recurse */
      if (temp.offset.start != part->offset.start ||
          temp.offset.end   != part->offset.end) {
        pb_binary_stream_t substream = pb_binary_stream_create_at(
          pb_binary_stream_binary(stream), temp.offset.start);
        error = adjust_recursive(part, &substream, delta);
        pb_binary_stream_destroy(&substream);
        if (unlikely_(error))
          break;                                           /* LCOV_EXCL_LINE */

        /* Parts may be unaligned due to length prefix update */
        if ((!pb_part_aligned(part)  && (error = pb_part_align(part))) ||
            (!pb_part_aligned(&temp) && (error = pb_part_align(&temp))))
          break;                                           /* LCOV_EXCL_LINE */
      }

      /* Adjust length prefix */
      error = adjust_prefix(&temp, delta);
      break;

    /* Otherwise just skip binary part */
    } else if ((error = pb_binary_stream_skip(stream, bytes))) {
      break;                                               /* LCOV_EXCL_LINE */
    }
  }

  /* Invalidate part on error */
  if (unlikely_(error))
    pb_part_invalidate(part);                              /* LCOV_EXCL_LINE */
  return error;
}