static az_result _az_base64_decode()

in sdk/src/azure/core/az_base64.c [202:311]


static az_result _az_base64_decode(
    az_span destination_bytes,
    az_span source_base64_url_text,
    int32_t* out_written,
    _az_base64_mode mode)
{
  int32_t source_length = az_span_size(source_base64_url_text);
  uint8_t* source_ptr = az_span_ptr(source_base64_url_text);

  int32_t destination_length = az_span_size(destination_bytes);
  uint8_t* destination_ptr = az_span_ptr(destination_bytes);

  if (destination_length < az_base64_get_max_decoded_size(source_length) - 2)
  {
    return AZ_ERROR_NOT_ENOUGH_SPACE;
  }

  int32_t source_index = 0;
  int32_t destination_index = 0;

  while (source_index < source_length - 4)
  {
    int32_t result = _az_base64_decode_four_bytes(source_ptr + source_index, mode);
    if (result < 0)
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }
    _az_base64_write_three_low_order_bytes(destination_ptr, result);
    destination_ptr += 3;
    destination_index += 3;
    source_index += 4;
  }

  // If using standard base64 decoding, there is a precondition guaranteeing size is divisible by 4.
  // Otherwise with url encoding, we can assume padding characters.
  // If length is divisible by four, do nothing. Else, we assume up to two padding characters.
  int32_t source_length_mod_four = source_length % 4;
  int32_t i0 = *(source_ptr + source_index);
  int32_t i1 = *(source_ptr + source_index + 1);
  int32_t i2 = source_length_mod_four == 2 ? _az_ENCODING_PAD : *(source_ptr + source_index + 2);
  int32_t i3 = source_length_mod_four == 2 || source_length_mod_four == 3
      ? _az_ENCODING_PAD
      : *(source_ptr + source_index + 3);

  i0 = _get_base64_decoded_char(i0, mode);
  i1 = _get_base64_decoded_char(i1, mode);

  i0 <<= 18;
  i1 <<= 12;

  i0 |= i1;

  if (i3 != _az_ENCODING_PAD)
  {
    i2 = _get_base64_decoded_char(i2, mode);
    i3 = _get_base64_decoded_char(i3, mode);

    i2 <<= 6;

    i0 |= i3;
    i0 |= i2;

    if (i0 < 0)
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }
    if (destination_index > destination_length - 3)
    {
      return AZ_ERROR_NOT_ENOUGH_SPACE;
    }
    _az_base64_write_three_low_order_bytes(destination_ptr, i0);
    destination_ptr += 3;
  }
  else if (i2 != _az_ENCODING_PAD)
  {
    i2 = _get_base64_decoded_char(i2, mode);

    i2 <<= 6;

    i0 |= i2;

    if (i0 < 0)
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }
    if (destination_index > destination_length - 2)
    {
      return AZ_ERROR_NOT_ENOUGH_SPACE;
    }
    *(destination_ptr + 1) = (uint8_t)(i0 >> 8);
    *destination_ptr = (uint8_t)(i0 >> 16);
    destination_ptr += 2;
  }
  else
  {
    if (i0 < 0)
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }
    if (destination_index > destination_length - 1)
    {
      return AZ_ERROR_NOT_ENOUGH_SPACE;
    }
    *destination_ptr = (uint8_t)(i0 >> 16);
    destination_ptr += 1;
  }

  *out_written = (int32_t)(destination_ptr - az_span_ptr(destination_bytes));
  return AZ_OK;
}