AZ_NODISCARD az_result az_json_token_get_string()

in sdk/src/azure/core/az_json_token.c [380:481]


AZ_NODISCARD az_result az_json_token_get_string(
    az_json_token const* json_token,
    char* destination,
    int32_t destination_max_size,
    int32_t* out_string_length)
{
  _az_PRECONDITION_NOT_NULL(json_token);
  _az_PRECONDITION_NOT_NULL(destination);
  _az_PRECONDITION(destination_max_size > 0);

  if (json_token->kind != AZ_JSON_TOKEN_STRING && json_token->kind != AZ_JSON_TOKEN_PROPERTY_NAME)
  {
    return AZ_ERROR_JSON_INVALID_STATE;
  }

  az_span token_slice = json_token->slice;
  int32_t token_size = json_token->size;

  // There is nothing to unescape here, copy directly.
  if (!json_token->_internal.string_has_escaped_chars)
  {
    // We need enough space to add a null terminator.
    if (token_size >= destination_max_size)
    {
      return AZ_ERROR_NOT_ENOUGH_SPACE;
    }

    // Contiguous token
    if (!json_token->_internal.is_multisegment)
    {
      // This will add a null terminator.
      az_span_to_str(destination, destination_max_size, token_slice);
    }
    else
    {
      // Token straddles more than one segment
      az_span remainder = _az_json_token_copy_into_span_helper(
          json_token, az_span_create((uint8_t*)destination, destination_max_size));

      // Add a null terminator.
      az_span_copy_u8(remainder, 0);
    }

    if (out_string_length != NULL)
    {
      *out_string_length = token_size;
    }
    return AZ_OK;
  }

  // No need to try to unescape the token slice, if the destination is known to be too small.
  // Unescaping always shrinks the string, at most by a factor of 6.
  // We also need enough space to add a null terminator.
  if (token_size / _az_MAX_EXPANSION_FACTOR_WHILE_ESCAPING >= destination_max_size)
  {
    return AZ_ERROR_NOT_ENOUGH_SPACE;
  }

  int32_t dest_idx = 0;
  bool next_char_escaped = false;

  // Contiguous token
  if (!json_token->_internal.is_multisegment)
  {
    _az_RETURN_IF_FAILED(_az_json_token_get_string_helper(
        token_slice, destination, destination_max_size, &dest_idx, &next_char_escaped));
  }
  else
  {
    // Token straddles more than one segment
    for (int32_t i = json_token->_internal.start_buffer_index;
         i <= json_token->_internal.end_buffer_index;
         i++)
    {
      az_span source = json_token->_internal.pointer_to_first_buffer[i];
      if (i == json_token->_internal.start_buffer_index)
      {
        source = az_span_slice_to_end(source, json_token->_internal.start_buffer_offset);
      }
      else if (i == json_token->_internal.end_buffer_index)
      {
        source = az_span_slice(source, 0, json_token->_internal.end_buffer_offset);
      }

      _az_RETURN_IF_FAILED(_az_json_token_get_string_helper(
          source, destination, destination_max_size, &dest_idx, &next_char_escaped));
    }
  }

  if (dest_idx >= destination_max_size)
  {
    return AZ_ERROR_NOT_ENOUGH_SPACE;
  }
  destination[dest_idx] = 0;

  if (out_string_length != NULL)
  {
    *out_string_length = dest_idx;
  }

  return AZ_OK;
}