text: // ----------------------------------------------------------------------------
  // Copyright 2016-2017 ARM Ltd.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  // ----------------------------------------------------------------------------
  
  #include <stdlib.h>
  #include "pv_error_handling.h"
  #include "fcc_status.h"
  #include "fcc_output_info_handler.h"
  #include "fcc_malloc.h"
  #include "kcm_defs.h"
  #include "fcc_bundle_utils.h"
  
  // Macros for stringizing defines
  #define xstr(a) str(a)
  #define str(a) #a
  
  
  //General error string
  const char g_fcc_general_status_error_str[] = "General error:";
  
  //fcc error strings
  const char g_fcc_ca_error_str[] = "CA error:";
  const char g_fcc_rot_error_str[] = "Root of trust error:";
  const char g_fcc_entropy_error_str[] = "Entropy error:";
  const char g_fcc_disabled_error_str[] = "Factory disabled error:";
  const char g_fcc_invalid_certificate_error_str[] = "Certificate invalid:";
  const char g_fcc_item_not_exists_error_str[] = "Item does not exist:";
  const char g_fcc_meta_data_not_exists_error_str[] = "Meta data does not exist:";
  const char g_fcc_meta_data_size_error_str[] = "Meta data does not exist:";
  const char g_fcc_wrong_item_size_error_str[] = "Item size is wrong:";
  const char g_fcc_empty_item_error_str[] = "Item empty:";
  const char g_fcc_uri_wrong_format_error_str[] = "URI format incorrect:";
  const char g_fcc_first_to_claim_not_allowed_error_str[] = "first to claim not allowed:";
  const char g_fcc_wrong_utc_offset_value_error_str[] = "UTC offset incorrect:";
  const char g_fcc_wrong_bootstrap_use_value_error_str[] = "Bootstrap mode value incorrect:";
  const char g_fcc_not_permitted_error_str[] = "Operation not permitted:";
  const char g_fcc_wrong_ca_certificate_error_str[] = "Validation of CA certificate failed:";
  const char g_fcc_invalid_cn_certificate_error_str[] = "Certificate CN attribute invalid:";
  const char g_fcc_crypto_public_key_correlation_error_str[] = "Certificate public key validation failed:";
  const char g_fcc_internal_storage_error_str[] = "Internal storage error:";
  const char g_fcc_csr_requests_too_many[] = "Too many CSR requests. Maximum CSR requests supported is " xstr(CSR_MAX_NUMBER_OF_CSRS);
  
  //kcm crypto error strings
  const char g_fcc_kcm_file_error_str[] = "File operation general error:";
  const char g_fcc_kcm_invalid_file_version_str[] = "File version invalid:";
  const char g_fcc_kcm_file_data_corrupted_str[] = "File data corrupted:";
  const char g_fcc_kcm_file_name_corrupted_str[] = "File name corrupted:";
  const char g_fcc_kcm_not_initialized_str[] = "KCM not initialized:";
  const char g_fcc_kcm_close_incomplete_chain_str[] = "Closing incomplete KCM chain:";
  const char g_fcc_kcm_invalid_chain_str[] = "Corrupted certificate chain file:";
  const char g_fcc_kcm_invalid_num_of_cert_in_chain_str[] = "Maximum chain length supported is " xstr(KCM_MAX_NUMBER_OF_CERTIFICATES_IN_CHAIN) ". Chain length of the item is invalid:";
  const char g_fcc_kcm_file_exist_error_str[] = "Data already exists:";
  const char g_fcc_kcm_key_exist_error_str[] = "Desired generated key name already exists:";
  const char g_fcc_kcm_file_name_too_long_error_str[] = "File name too long:";
  const char g_fcc_crypto_kcm_error_str[] = "KCM crypto error:";
  const char g_fcc_crypto_empty_item_error_str[] = "Item data empty:";
  const char g_fcc_crypto_unsupported_hash_mode_error_str[] = "Hash mode unsupported:";
  const char g_fcc_crypto_parsing_der_pivate_key_error_str[] = "Private key parse failed:";
  const char g_fcc_crypto_parsing_der_public_key_error_str[] = "Public key parse failed:";
  const char g_fcc_crypto_verify_private_key_error_str[] = "Private key verification failed:";
  const char g_fcc_crypto_verify_public_key_error_str[] = "Public key verification failed:";
  const char g_fcc_crypto_unsupported_curve_error_str[] = "Curve unsupported:";
  const char g_fcc_crypto_parsing_der_cert_error_str[] = "Certificate parse failed:";
  const char g_fcc_crypto_cert_expired_error_str[] = "Certificate expired:";
  const char g_fcc_crypto_cert_future_error_str[] = "Certificate will be valid in the future:";
  const char g_fcc_crypto_cert_md_alg_error_str[] = "Certificate MD algorithm error:";
  const char g_fcc_crypto_cert_public_key_type_error_str[] = "Certificate public key type error:";
  const char g_fcc_crypto_cert_public_key_error_str[] = "Certificate public key error:";
  const char g_fcc_crypto_cert_not_trusted_error_str[] = "Certificate not trusted:";
  const char g_fcc_crypto_invalid_x509_attr_error_str[] = "X509 attribute invalid:";
  const char g_fcc_crypto_invalid_pk_key_format_error_str[] = "Public key format invalid:";
  const char g_fcc_crypto_invalid_public_key_error_str[] = "Public key invalid:";
  const char g_fcc_crypto_ecp_invalid_key_error_str[] = "EC key invalid:";
  const char g_fcc_crypto_pk_key_invalid_version_error_str[] = "Public key version invalid:";
  const char g_fcc_crypto_pk_password_requerd_error_str[] = "Public key password required:";
  const char g_fcc_crypto_unknown_pk_algorithm_error_str[] = "Public key algorithm unknown:";
  const char g_fcc_crypto_chain_validation_error_str[] = "Chain validation error:";
  const char g_fcc_self_generated_certificate_validation_error_str[] = "Self-generated certificate validation failed:";
  //warning strings
  const char g_fcc_item_not_set_warning_str[] = "Item not set:";
  
  const char g_fcc_bootstrap_mode_false_warning_str[] = "Bootstrap mode not activated:";
  const char g_fcc_self_signed_warning_str[] = "Certificate is self signed:";
  const char g_fcc_item_is_empty_warning_str[] = "Item empty:";
  const char g_fcc_redundant_item_warning_str[] = "Item redundant:";
  const char g_fcc_cert_time_validity_warning_str[] = "Certificate validity cannot be checked:";
  const char g_fcc_cert_validity_less_10_years_warning_str[] = "Certificate validity is less than 10 years:";
  const char g_fcc_ca_identifier_warning_str[] = "CA identifier wasn't set properly:";
  
  fcc_output_info_s g_output_info;
  
  
  /**  The function frees all allocated buffers
  * @param output_warning_info[in]          The pointer to created fcc_warning_info_s structure
  */
  static void fcc_free_list_of_warnings(fcc_warning_info_s  *output_warning_info)
  {
      fcc_warning_info_s *current_node = output_warning_info;
      fcc_warning_info_s *next_node = output_warning_info->next;
  
      while (current_node != NULL) {
          if (current_node->warning_info_string != NULL) {
              fcc_free(current_node->warning_info_string);
          }
          fcc_free(current_node);
          current_node = next_node;
          if (current_node != NULL) {
              next_node = current_node->next;
          }
      }
  }
  /**  The function combines message string info and failed item, and sets it to passed pointer.
  * @param message_string[in]          The message string - error or warning
  * @param failed_item_name[in]        The name of item.
  * @param failed_item_name_size[in]   The size of item's name.
  * @param out_string[in/out]          The output string where the combined message should be copied.
  */
  static fcc_status_e fcc_set_output_string_info(const char *message_string, const uint8_t *failed_item_name, size_t failed_item_name_size, char **out_string)
  {
      fcc_status_e fcc_status = FCC_STATUS_SUCCESS;
  
      SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS();
  
      //Allocate memory for error info
      *out_string = fcc_malloc(strlen(message_string) + failed_item_name_size + 1); // 1 char for '\0'
      SA_PV_ERR_RECOVERABLE_RETURN_IF((out_string == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, "Failed to allocate buffer for output info");
  
      //Copy to  the global structure error string info
      strcpy((*out_string), message_string);
  
      //Copy to  the global structure the name of failed item if it exists.
      if (failed_item_name != NULL) {
          memcpy((uint8_t*)(*out_string) + strlen(message_string), failed_item_name, failed_item_name_size);
          //Set '\0' in the end of error string info
          (*out_string)[strlen(message_string) + failed_item_name_size] = '\0';
      }
  
  
      SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS();
      return fcc_status;
  }
  
  static size_t fcc_get_size_of_all_warning_strings()
  {
      fcc_warning_info_s *current_node = g_output_info.head_of_warning_list;
      size_t size_of_all_warning_strings = 0;
  
      SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS();
  
      while (current_node != NULL) {
          size_of_all_warning_strings += strlen(current_node->warning_info_string);
          current_node = current_node->next;
      }
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
      return size_of_all_warning_strings;
  }
  
  static bool copy_all_warning_to_buffer(char *out_warning_string, size_t size_of_out_warning_string)
  {
      fcc_warning_info_s *current_node = g_output_info.head_of_warning_list;
      size_t length_of_iterated_strings = 0;
  
      memset(out_warning_string, 0, size_of_out_warning_string);
  
      while (current_node != NULL) {
          //Calculate size of current warning
          if (length_of_iterated_strings + strlen(current_node->warning_info_string) + 1 > size_of_out_warning_string) {
              return false;
          }
          strcpy(out_warning_string + length_of_iterated_strings, current_node->warning_info_string);
          //Set '\n' in the end of warning string info
          (out_warning_string)[length_of_iterated_strings + strlen(current_node->warning_info_string)] = '\n';
          length_of_iterated_strings += strlen(current_node->warning_info_string) + 1;
          current_node = current_node->next;
      }
      //Increase the size for '\0'
      if (length_of_iterated_strings >= size_of_out_warning_string) {
          return false;
      }
      (out_warning_string)[length_of_iterated_strings] = '\0';
  
      return true;
  }
  /**  The function returns error string according to passed fcc_status.
  * @param fcc_status[in]          The fcc_status
  *
  */
  
  char* fcc_get_fcc_error_string(fcc_status_e fcc_status)
  {
      SA_PV_LOG_TRACE_FUNC_ENTER("fcc_status is %d", fcc_status);
      char *fcc_error_string = NULL;
  
      switch (fcc_status) {
          case FCC_STATUS_ERROR:
          case FCC_STATUS_MEMORY_OUT:
          case FCC_STATUS_INVALID_PARAMETER:
          case FCC_STATUS_KCM_ERROR:
          case FCC_STATUS_BUNDLE_ERROR:
          case FCC_STATUS_BUNDLE_RESPONSE_ERROR:
          case FCC_STATUS_BUNDLE_UNSUPPORTED_GROUP:
          case FCC_STATUS_BUNDLE_INVALID_SCHEME:
          case FCC_STATUS_BUNDLE_INVALID_KEEP_ALIVE_SESSION_STATUS:
          case FCC_STATUS_BUNDLE_INVALID_GROUP:
          case FCC_STATUS_KCM_STORAGE_ERROR:
          case FCC_STATUS_KCM_FILE_EXIST_ERROR:
          case FCC_STATUS_NOT_INITIALIZED:
          case FCC_STATUS_OUTPUT_INFO_ERROR:
          case FCC_STATUS_WARNING_CREATE_ERROR:
          case FCC_STATUS_INVALID_CERT_ATTRIBUTE:
          case FCC_STATUS_INTERNAL_ITEM_ALREADY_EXIST:
              fcc_error_string = (char*)g_fcc_general_status_error_str;
              break;
          case FCC_STATUS_CA_ERROR:
              fcc_error_string = (char*)g_fcc_ca_error_str;
              break;
          case FCC_STATUS_ROT_ERROR:
              fcc_error_string = (char*)g_fcc_rot_error_str;
              break;
          case FCC_STATUS_STORE_ERROR:
              fcc_error_string = (char*)g_fcc_internal_storage_error_str;
              break;
          case FCC_STATUS_KCM_CRYPTO_ERROR:
              fcc_error_string = (char*)g_fcc_crypto_kcm_error_str;
              break;
          case FCC_STATUS_INVALID_CERTIFICATE:
              fcc_error_string = (char*)g_fcc_invalid_certificate_error_str;
              break;
          case FCC_STATUS_INVALID_LWM2M_CN_ATTR:
              fcc_error_string = (char*)g_fcc_invalid_cn_certificate_error_str;
              break;
          case FCC_STATUS_ENTROPY_ERROR:
              fcc_error_string = (char*)g_fcc_entropy_error_str;
              break;
          case FCC_STATUS_FACTORY_DISABLED_ERROR:
              fcc_error_string = (char*)g_fcc_disabled_error_str;
              break;
          case FCC_STATUS_ITEM_NOT_EXIST:
              fcc_error_string = (char*)g_fcc_item_not_exists_error_str;
              break;
          case FCC_STATUS_WRONG_ITEM_DATA_SIZE:
              fcc_error_string = (char*)g_fcc_wrong_item_size_error_str;
              break;
          case FCC_STATUS_EMPTY_ITEM:
              fcc_error_string = (char*)g_fcc_empty_item_error_str;
              break;
          case FCC_STATUS_URI_WRONG_FORMAT:
              fcc_error_string = (char*)g_fcc_uri_wrong_format_error_str;
              break;
          case FCC_STATUS_FIRST_TO_CLAIM_NOT_ALLOWED:
              fcc_error_string = (char*)g_fcc_first_to_claim_not_allowed_error_str;
              break;
          case FCC_STATUS_BOOTSTRAP_MODE_ERROR:
              fcc_error_string = (char*)g_fcc_wrong_bootstrap_use_value_error_str;
              break;
          case FCC_STATUS_UTC_OFFSET_WRONG_FORMAT:
              fcc_error_string = (char*)g_fcc_wrong_utc_offset_value_error_str;
              break;
          case FCC_STATUS_INVALID_CA_CERT_SIGNATURE:
              fcc_error_string = (char*)g_fcc_wrong_ca_certificate_error_str;
              break;
          case FCC_STATUS_EXPIRED_CERTIFICATE:
              fcc_error_string = (char*)g_fcc_crypto_cert_expired_error_str;
              break;
          case FCC_STATUS_CERTIFICATE_PUBLIC_KEY_CORRELATION_ERROR:
              fcc_error_string = (char*)g_fcc_crypto_public_key_correlation_error_str;
              break;
          case FCC_STATUS_TOO_MANY_CSR_REQUESTS:
              fcc_error_string = (char*)g_fcc_csr_requests_too_many;
              break;
          case FCC_STATUS_SUCCESS:
          case FCC_MAX_STATUS:
              return fcc_error_string;
  
      }
      if (fcc_error_string != NULL) {
          SA_PV_LOG_TRACE_FUNC_EXIT("fcc_error_string is %s", fcc_error_string);
      }
      return fcc_error_string;
  }
  
  /**  The function returns error string according to passed kcm_status.
  * @param kcm_status[in]          The kcm_status
  *
  */
  
  char* fcc_get_kcm_error_string(kcm_status_e kcm_status)
  {
      SA_PV_LOG_TRACE_FUNC_ENTER("kcm_status is %d", kcm_status);
  
      char *kcm_error_string = NULL;
  
      switch (kcm_status) {
          case KCM_STATUS_ERROR:
          case KCM_STATUS_INVALID_PARAMETER:
          case KCM_STATUS_INSUFFICIENT_BUFFER:
          case KCM_STATUS_OUT_OF_MEMORY:
          case KCM_STATUS_INVALID_FILE_ACCESS_MODE:
          case KCM_STATUS_UNKNOWN_STORAGE_ERROR:
          case KCM_CRYPTO_STATUS_INVALID_MD_TYPE:
          case KCM_CRYPTO_STATUS_FAILED_TO_WRITE_SIGNATURE:
          case KCM_CRYPTO_STATUS_VERIFY_SIGNATURE_FAILED:
          case KCM_CRYPTO_STATUS_FAILED_TO_WRITE_PRIVATE_KEY:
          case KCM_CRYPTO_STATUS_FAILED_TO_WRITE_PUBLIC_KEY:
          case KCM_CRYPTO_STATUS_FAILED_TO_WRITE_CSR:
          case KCM_CRYPTO_STATUS_INVALID_OID:
          case KCM_CRYPTO_STATUS_INVALID_NAME_FORMAT:
              kcm_error_string = (char*)g_fcc_general_status_error_str;
              break;
          case KCM_STATUS_SELF_GENERATED_CERTIFICATE_VERIFICATION_ERROR:
              kcm_error_string = (char*)g_fcc_self_generated_certificate_validation_error_str;
              break;
          case KCM_STATUS_STORAGE_ERROR:
              kcm_error_string = (char*)g_fcc_kcm_file_error_str;
              break;
          case KCM_STATUS_INVALID_FILE_VERSION:
              kcm_error_string = (char*)g_fcc_kcm_invalid_file_version_str;
              break;
          case KCM_STATUS_FILE_CORRUPTED:
              kcm_error_string = (char*)g_fcc_kcm_file_data_corrupted_str;
              break;
          case KCM_STATUS_NOT_INITIALIZED:
              kcm_error_string = (char*)g_fcc_kcm_not_initialized_str;
              break;
          case KCM_STATUS_CLOSE_INCOMPLETE_CHAIN:
              kcm_error_string = (char*)g_fcc_kcm_close_incomplete_chain_str;
              break;
          case KCM_STATUS_CORRUPTED_CHAIN_FILE:
              kcm_error_string = (char*)g_fcc_kcm_invalid_chain_str;
              break;
          case KCM_STATUS_INVALID_NUM_OF_CERT_IN_CHAIN:
              kcm_error_string = (char*)g_fcc_kcm_invalid_num_of_cert_in_chain_str;
              break;
          case KCM_STATUS_CERTIFICATE_CHAIN_VERIFICATION_FAILED:
              kcm_error_string = (char*)g_fcc_crypto_chain_validation_error_str;
              break;
          case KCM_STATUS_ITEM_NOT_FOUND:
              kcm_error_string = (char*)g_fcc_item_not_exists_error_str;
              break;
          case KCM_STATUS_META_DATA_NOT_FOUND:
              kcm_error_string = (char*)g_fcc_meta_data_not_exists_error_str;
              break;
          case KCM_STATUS_META_DATA_SIZE_ERROR:
              kcm_error_string = (char*)g_fcc_meta_data_size_error_str;
              break;
          case KCM_STATUS_NOT_PERMITTED:
              kcm_error_string = (char*)g_fcc_not_permitted_error_str;
              break;
          case KCM_STATUS_FILE_EXIST:
              kcm_error_string = (char*)g_fcc_kcm_file_exist_error_str;
              break;
          case KCM_STATUS_KEY_EXIST:
              kcm_error_string = (char*)g_fcc_kcm_key_exist_error_str;
              break;
          case KCM_STATUS_FILE_NAME_CORRUPTED:
              kcm_error_string = (char*)g_fcc_kcm_file_name_corrupted_str;
              break;
          case KCM_STATUS_ITEM_IS_EMPTY:
              kcm_error_string = (char*)g_fcc_crypto_empty_item_error_str;
              break;
          case KCM_STATUS_FILE_NAME_TOO_LONG:
              kcm_error_string = (char*)g_fcc_kcm_file_name_too_long_error_str;
              break;
          case KCM_CRYPTO_STATUS_UNSUPPORTED_HASH_MODE:
              kcm_error_string = (char*)g_fcc_crypto_unsupported_hash_mode_error_str;
              break;
          case KCM_CRYPTO_STATUS_PARSING_DER_PRIVATE_KEY:
              kcm_error_string = (char*)g_fcc_crypto_parsing_der_pivate_key_error_str;
              break;
          case  KCM_CRYPTO_STATUS_PARSING_DER_PUBLIC_KEY:
              kcm_error_string = (char*)g_fcc_crypto_parsing_der_public_key_error_str;
              break;
          case  KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED:
              kcm_error_string = (char*)g_fcc_crypto_verify_private_key_error_str;
              break;
          case  KCM_CRYPTO_STATUS_PUBLIC_KEY_VERIFICATION_FAILED:
              kcm_error_string = (char*)g_fcc_crypto_verify_public_key_error_str;
              break;
          case  KCM_CRYPTO_STATUS_UNSUPPORTED_CURVE:
              kcm_error_string = (char*)g_fcc_crypto_unsupported_curve_error_str;
              break;
          case  KCM_CRYPTO_STATUS_PARSING_DER_CERT:
              kcm_error_string = (char*)g_fcc_crypto_parsing_der_cert_error_str;
              break;
          case  KCM_CRYPTO_STATUS_CERT_EXPIRED:
              kcm_error_string = (char*)g_fcc_crypto_cert_expired_error_str;
              break;
          case  KCM_CRYPTO_STATUS_CERT_FUTURE:
              kcm_error_string = (char*)g_fcc_crypto_cert_future_error_str;
              break;
          case  KCM_CRYPTO_STATUS_CERT_MD_ALG:
              kcm_error_string = (char*)g_fcc_crypto_cert_md_alg_error_str;
              break;
          case  KCM_CRYPTO_STATUS_CERT_PUB_KEY_TYPE:
              kcm_error_string = (char*)g_fcc_crypto_cert_public_key_type_error_str;
              break;
          case  KCM_CRYPTO_STATUS_CERT_PUB_KEY:
              kcm_error_string = (char*)g_fcc_crypto_cert_public_key_error_str;
              break;
          case  KCM_CRYPTO_STATUS_CERT_NOT_TRUSTED:
              kcm_error_string = (char*)g_fcc_crypto_cert_not_trusted_error_str;
              break;
          case  KCM_CRYPTO_STATUS_INVALID_X509_ATTR:
              kcm_error_string = (char*)g_fcc_crypto_invalid_x509_attr_error_str;
              break;
          case KCM_CRYPTO_STATUS_PK_KEY_INVALID_FORMAT:
              kcm_error_string = (char*)g_fcc_crypto_invalid_pk_key_format_error_str;
              break;
          case KCM_CRYPTO_STATUS_INVALID_PK_PUBKEY:
              kcm_error_string = (char*)g_fcc_crypto_invalid_public_key_error_str;
              break;
          case KCM_CRYPTO_STATUS_ECP_INVALID_KEY:
              kcm_error_string = (char*)g_fcc_crypto_ecp_invalid_key_error_str;
              break;
          case KCM_CRYPTO_STATUS_PK_KEY_INVALID_VERSION:
              kcm_error_string = (char*)g_fcc_crypto_pk_key_invalid_version_error_str;
              break;
          case KCM_CRYPTO_STATUS_PK_PASSWORD_REQUIRED:
              kcm_error_string = (char*)g_fcc_crypto_pk_password_requerd_error_str;
              break;
          case KCM_CRYPTO_STATUS_PK_UNKNOWN_PK_ALG:
              kcm_error_string = (char*)g_fcc_crypto_unknown_pk_algorithm_error_str;
              break;
          case KCM_STATUS_SUCCESS:
          case KCM_MAX_STATUS:
              return kcm_error_string;
      }
  
      if (kcm_error_string != NULL) {
          SA_PV_LOG_TRACE_FUNC_EXIT("kcm_error_string is %s", kcm_error_string);
      }
      return kcm_error_string;
  }
  
  fcc_output_info_s* get_output_info(void)
  {
      return &g_output_info;
  }
  
  void  fcc_init_output_info_handler()
  {
      SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS();
  
      g_output_info.error_string_info = NULL;
      g_output_info.head_of_warning_list = NULL;
      g_output_info.tail_of_warning_list = NULL;
      g_output_info.size_of_warning_info_list = 0;
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
  }
  
  void  fcc_clean_output_info_handler()
  {
      SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS();
  
      fcc_free(g_output_info.error_string_info);
      g_output_info.error_string_info = NULL;
  
      if (g_output_info.head_of_warning_list != NULL) {
          fcc_free_list_of_warnings(g_output_info.head_of_warning_list);
      }
      g_output_info.size_of_warning_info_list = 0;
      g_output_info.tail_of_warning_list = NULL;
      g_output_info.head_of_warning_list = NULL;
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
  }
  
  fcc_status_e fcc_store_warning_info(const uint8_t *failed_item_name, size_t failed_item_name_size, const char *warning_string)
  {
      fcc_status_e fcc_status = FCC_STATUS_SUCCESS;
      fcc_warning_info_s *new_node = NULL;
  
      SA_PV_ERR_RECOVERABLE_RETURN_IF((warning_string == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Warning string is empty");
      SA_PV_LOG_INFO_FUNC_ENTER("warning_string is %s", warning_string);
      //Check parameters (failed_item_name can be NULL)
      SA_PV_ERR_RECOVERABLE_RETURN_IF((failed_item_name != NULL && failed_item_name_size == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Wrong failed item name parameters");
  
      //Allocate new node
      new_node = (fcc_warning_info_s*)fcc_malloc(sizeof(fcc_warning_info_s));
      SA_PV_ERR_RECOVERABLE_RETURN_IF((new_node == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, "Failed to allocate memory for new warning list");
  
      //Set the new node with warning info (message and item name)
      fcc_status = fcc_set_output_string_info(warning_string, failed_item_name, failed_item_name_size, &(new_node->warning_info_string));
      SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_ERROR, exit_with_error, "Failed to set warning string info\n");
  
      //Update the list
      if (g_output_info.head_of_warning_list == NULL) {
          //In case this is the first node
          g_output_info.head_of_warning_list = g_output_info.tail_of_warning_list = new_node;
      } else {
          //In case this is an additional node
          g_output_info.tail_of_warning_list->next = new_node;
          g_output_info.tail_of_warning_list = new_node;
      }
      g_output_info.tail_of_warning_list->next = NULL;
      g_output_info.size_of_warning_info_list++;
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
      return fcc_status;
  
  exit_with_error:
      fcc_free(new_node);
      return fcc_status;
  }
  
  fcc_status_e fcc_bundle_store_error_info(const uint8_t *failed_item_name, size_t failed_item_name_size, kcm_status_e kcm_status)
  {
      fcc_status_e fcc_status = FCC_STATUS_SUCCESS;
      char *error_string_info = NULL;
  
      SA_PV_LOG_INFO_FUNC_ENTER("kcm_status is %d", kcm_status);
  
      //Check parameters (failed_item_name can be NULL)
      SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status == KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_INVALID_PARAMETER, "The fcc_bundle_store_error_info should not be called with success status");
      SA_PV_ERR_RECOVERABLE_RETURN_IF((failed_item_name != NULL && failed_item_name_size == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Wrong failed item name parameters");
  
      //Get kcm error string
      error_string_info = fcc_get_kcm_error_string(kcm_status);
      SA_PV_ERR_RECOVERABLE_RETURN_IF((error_string_info == NULL), fcc_status = FCC_STATUS_ERROR, "Failed to get kcm error string");
  
      //Store kcm error string with item name
      fcc_status = fcc_set_output_string_info(error_string_info, failed_item_name, failed_item_name_size, &(g_output_info.error_string_info));
      SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_ERROR, "Failed to set error string info ");
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
      return fcc_status;
  }
  
  fcc_status_e fcc_store_error_info(const uint8_t *failed_item_name, size_t failed_item_name_size, fcc_status_e fcc_status)
  {
      fcc_status_e fcc_result = FCC_STATUS_SUCCESS;
      char *error_string_info = NULL;
  
      SA_PV_LOG_INFO_FUNC_ENTER("fcc_status is %d", fcc_status);
      //Check parameters (failed_item_name can be NULL)
      SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status == FCC_STATUS_SUCCESS), FCC_STATUS_INVALID_PARAMETER, "The fcc_store_error_info should not be called with success status");
      SA_PV_ERR_RECOVERABLE_RETURN_IF((failed_item_name != NULL && failed_item_name_size == 0), FCC_STATUS_INVALID_PARAMETER, "Wrong failed item name parameters");
  
      //Get fcc error string
      error_string_info = fcc_get_fcc_error_string(fcc_status);
      SA_PV_ERR_RECOVERABLE_RETURN_IF((error_string_info == NULL), FCC_STATUS_ERROR, "Failed to get fcc error string");
  
      if (g_output_info.error_string_info == NULL) {
          //Store fcc error string with item name
          fcc_result = fcc_set_output_string_info(error_string_info, failed_item_name, failed_item_name_size, &(g_output_info.error_string_info));
          SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_result != FCC_STATUS_SUCCESS), FCC_STATUS_ERROR, "Failed to set error string info ");
      }
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
      return fcc_result;
  }
  
  char* fcc_get_output_error_info()
  {
      char *error_info = NULL;
  
      SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS();
  
      if (g_output_info.error_string_info != NULL) {
          error_info = g_output_info.error_string_info;
      }
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
      return error_info;
  }
  
  
  char*  fcc_get_output_warning_info()
  {
      char *warrning_string_collection = NULL;
      size_t size_of_warning_string_collection = 0;
      size_t total_size_of_strings_with_delimeters = 0;
      bool status = false;
  
      SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS();
  
      if (g_output_info.head_of_warning_list == NULL || g_output_info.size_of_warning_info_list == 0) {
          return NULL;
      } else {
          //Get size of all warning
          size_of_warning_string_collection = fcc_get_size_of_all_warning_strings();
  
          //total_size_of_strings_with_delimeters -size_of_warning_string_collection +add '\n'  - as delimiter between the warnings and '\0' in the end
          total_size_of_strings_with_delimeters = size_of_warning_string_collection + g_output_info.size_of_warning_info_list + 1;
  
          //Allocate memory  buffer for all warnings
          warrning_string_collection = fcc_malloc(total_size_of_strings_with_delimeters);
          if (warrning_string_collection == NULL) {
              SA_PV_LOG_INFO("Failed to allocate memory for warning strings");
              return warrning_string_collection;
          }
          status = copy_all_warning_to_buffer(warrning_string_collection, total_size_of_strings_with_delimeters);
          if (status != true) {
              fcc_free(warrning_string_collection);
              return NULL;
          }
      }
  
      SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
      return warrning_string_collection;
  }
  
  bool fcc_get_warning_status()
  {
      if (g_output_info.head_of_warning_list != NULL) {
          return true;
      } else {
          return false;
      }
  }
  