AZ_NODISCARD az_result az_iot_adu_client_parse_update_manifest()

in sdk/src/azure/iot/az_iot_adu_client.c [526:876]


AZ_NODISCARD az_result az_iot_adu_client_parse_update_manifest(
    az_iot_adu_client* client,
    az_json_reader* ref_json_reader,
    az_iot_adu_client_update_manifest* update_manifest)
{
  _az_PRECONDITION_NOT_NULL(client);
  _az_PRECONDITION_NOT_NULL(ref_json_reader);
  _az_PRECONDITION_NOT_NULL(update_manifest);

  (void)client;

  // Initialize the update_manifest with empty values.
  update_manifest->manifest_version = AZ_SPAN_EMPTY;
  update_manifest->update_id.name = AZ_SPAN_EMPTY;
  update_manifest->update_id.provider = AZ_SPAN_EMPTY;
  update_manifest->update_id.version = AZ_SPAN_EMPTY;
  update_manifest->instructions.steps_count = 0;
  update_manifest->files_count = 0;
  update_manifest->create_date_time = AZ_SPAN_EMPTY;

  _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
  RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
  _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

  while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_OBJECT)
  {
    RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

    bool property_parsed = true;

    if (az_json_token_is_text_equal(
            &ref_json_reader->token,
            AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_MANIFEST_VERSION)))
    {
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
      update_manifest->manifest_version = ref_json_reader->token.slice;
    }
    else if (az_json_token_is_text_equal(
                 &ref_json_reader->token,
                 AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_INSTRUCTIONS)))
    {
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

      if (az_json_token_is_text_equal(
              &ref_json_reader->token,
              AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_STEPS)))
      {
        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
        RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_ARRAY);
        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

        update_manifest->instructions.steps_count = 0;

        while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_ARRAY)
        {
          uint32_t step_index = update_manifest->instructions.steps_count;

          RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
          _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

          while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_OBJECT)
          {
            RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

            if (az_json_token_is_text_equal(
                    &ref_json_reader->token,
                    AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_HANDLER)))
            {
              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
              RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);

              update_manifest->instructions.steps[step_index].handler
                  = ref_json_reader->token.slice;
            }
            else if (az_json_token_is_text_equal(
                         &ref_json_reader->token,
                         AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_FILES)))
            {
              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
              RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_ARRAY);
              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

              update_manifest->instructions.steps[step_index].files_count = 0;

              while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_ARRAY)
              {
                // If array isn't ended and we have reached max files allowed, next would overflow.
                if (update_manifest->instructions.steps[step_index].files_count
                    == _az_IOT_ADU_CLIENT_MAX_FILE_COUNT_PER_STEP)
                {
                  return AZ_ERROR_NOT_ENOUGH_SPACE;
                }
                uint32_t file_index = update_manifest->instructions.steps[step_index].files_count;

                RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);

                update_manifest->instructions.steps[step_index].files[file_index]
                    = ref_json_reader->token.slice;
                update_manifest->instructions.steps[step_index].files_count++;

                _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
              }
            }
            else if (az_json_token_is_text_equal(
                         &ref_json_reader->token,
                         AZ_SPAN_FROM_STR(
                             AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_HANDLER_PROPERTIES)))
            {
              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
              RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
              RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

              if (az_json_token_is_text_equal(
                      &ref_json_reader->token,
                      AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_INSTALLED_CRITERIA)))
              {
                _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
                RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
                update_manifest->instructions.steps[step_index]
                    .handler_properties.installed_criteria
                    = ref_json_reader->token.slice;
                _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
                RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_END_OBJECT);
              }
              else
              {
                return AZ_ERROR_JSON_INVALID_STATE;
              }
            }
            else
            {
              return AZ_ERROR_JSON_INVALID_STATE;
            }

            _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
          }

          update_manifest->instructions.steps_count++;

          _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
        }

        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
        RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_END_OBJECT);
      }
      else
      {
        _az_LOG_WRITE(
            AZ_LOG_IOT_ADU, AZ_SPAN_FROM_STR("Unexpected property found in ADU manifest steps:"));
        _az_LOG_WRITE(AZ_LOG_IOT_ADU, ref_json_reader->token.slice);
        return AZ_ERROR_JSON_INVALID_STATE;
      }
    }
    else if (az_json_token_is_text_equal(
                 &ref_json_reader->token,
                 AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_UPDATE_ID)))
    {
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

      while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_OBJECT)
      {
        RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

        if (az_json_token_is_text_equal(
                &ref_json_reader->token,
                AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_PROVIDER)))
        {
          _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
          RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
          update_manifest->update_id.provider = ref_json_reader->token.slice;
        }
        else if (az_json_token_is_text_equal(
                     &ref_json_reader->token,
                     AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_NAME)))
        {
          _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
          RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
          update_manifest->update_id.name = ref_json_reader->token.slice;
        }
        else if (az_json_token_is_text_equal(
                     &ref_json_reader->token,
                     AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_VERSION)))
        {
          _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
          RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
          update_manifest->update_id.version = ref_json_reader->token.slice;
        }
        else
        {
          _az_LOG_WRITE(
              AZ_LOG_IOT_ADU,
              AZ_SPAN_FROM_STR("Unexpected property found in ADU update id object:"));
          _az_LOG_WRITE(AZ_LOG_IOT_ADU, ref_json_reader->token.slice);
          return AZ_ERROR_JSON_INVALID_STATE;
        }

        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      }
    }
    else if (az_json_token_is_text_equal(
                 &ref_json_reader->token,
                 AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_COMPATIBILITY)))
    {
      /*
       * According to ADU design, the ADU service compatibility properties
       * are not intended to be consumed by the ADU agent.
       * To save on processing, the properties are not being exposed.
       */
      _az_RETURN_IF_FAILED(az_json_reader_skip_children(ref_json_reader));
    }
    else if (az_json_token_is_text_equal(
                 &ref_json_reader->token,
                 AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_FILES)))
    {
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

      while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_OBJECT)
      {
        uint32_t files_index = update_manifest->files_count;

        RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

        // If object isn't ended and we have reached max files allowed, next would overflow.
        if (files_index == _az_IOT_ADU_CLIENT_MAX_TOTAL_FILE_COUNT)
        {
          return AZ_ERROR_NOT_ENOUGH_SPACE;
        }

        update_manifest->files[files_index].id = ref_json_reader->token.slice;

        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
        RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

        while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_OBJECT)
        {
          RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);

          if (az_json_token_is_text_equal(
                  &ref_json_reader->token,
                  AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_FILE_NAME)))
          {
            _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
            RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
            update_manifest->files[files_index].file_name = ref_json_reader->token.slice;
          }
          else if (az_json_token_is_text_equal(
                       &ref_json_reader->token,
                       AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_SIZE_IN_BYTES)))
          {
            _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
            RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_NUMBER);

            _az_RETURN_IF_FAILED(az_json_token_get_int64(
                &ref_json_reader->token, &update_manifest->files[files_index].size_in_bytes));
          }
          else if (az_json_token_is_text_equal(
                       &ref_json_reader->token,
                       AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_HASHES)))
          {
            _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
            RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_BEGIN_OBJECT);
            _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));

            update_manifest->files[files_index].hashes_count = 0;

            while (ref_json_reader->token.kind != AZ_JSON_TOKEN_END_OBJECT)
            {
              uint32_t hashes_count = update_manifest->files[files_index].hashes_count;

              RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_PROPERTY_NAME);
              update_manifest->files[files_index].hashes[hashes_count].hash_type
                  = ref_json_reader->token.slice;
              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
              RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
              update_manifest->files[files_index].hashes[hashes_count].hash_value
                  = ref_json_reader->token.slice;

              update_manifest->files[files_index].hashes_count++;

              _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
            }
          }
          /*
           * Embedded C SDK will not support delta updates at this time, so relatedFiles,
           * downloadHandler, and mimeType are not exposed or processed.
           */
          else if (az_json_token_is_text_equal(
                       &ref_json_reader->token,
                       AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_RELATED_FILES)))
          {
            _az_RETURN_IF_FAILED(az_json_reader_skip_children(ref_json_reader));
          }
          else if (az_json_token_is_text_equal(
                       &ref_json_reader->token,
                       AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_DOWNLOAD_HANDLER)))
          {
            _az_RETURN_IF_FAILED(az_json_reader_skip_children(ref_json_reader));
          }
          else if (az_json_token_is_text_equal(
                       &ref_json_reader->token,
                       AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_MIME_TYPE)))
          {
            _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
          }
          else
          {
            return AZ_ERROR_JSON_INVALID_STATE;
          }

          _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
        }

        update_manifest->files_count++;

        _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      }
    }
    else if (az_json_token_is_text_equal(
                 &ref_json_reader->token,
                 AZ_SPAN_FROM_STR(AZ_IOT_ADU_CLIENT_AGENT_PROPERTY_NAME_CREATED_DATE_TIME)))
    {
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      RETURN_IF_JSON_TOKEN_NOT_TYPE((ref_json_reader), AZ_JSON_TOKEN_STRING);
      update_manifest->create_date_time = ref_json_reader->token.slice;
    }
    else
    {
      property_parsed = false;
    }

    if (!property_parsed)
    {
      _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
      _az_RETURN_IF_FAILED(az_json_reader_skip_children(ref_json_reader));
    }

    _az_RETURN_IF_FAILED(az_json_reader_next_token(ref_json_reader));
  }

  return AZ_OK;
}