/* 'checkit_tiff' is a conformance checker for baseline TIFFs
 *
 * author: Andreas Romeyke, 2015-2022
 * licensed under conditions of libtiff
 * (see http://libtiff.maptools.org/misc.html)
 *
 */

#include "check.h"
#include "check_helper.h"
#include "validate_icc.h"
#include "ctstring.h"

/** checks a ICC tag, see Annex B of http://www.color.org/specification/ICC1v43_2010-12.pdf
 */
ret_t check_icc(ctiff_t * ctif ) {
  GET_EMPTY_RET(ret);
  TIFP_CHECK( ctif, ret);
  EXIST_TAG(ctif, TIFFTAG_ICCPROFILE, ret)
  ifd_entry_t ifd_entry = TIFFGetRawIFDEntry(ctif, ctif->ifd0, TIFFTAG_ICCPROFILE);
  uint32 icc_profile_size;
  char * icc_profile = NULL;
  switch (ifd_entry.datatype) { /* icc datatype should be undefined (val=7) */
      case TIFF_UNDEFINED: {
                      icc_profile_size = ifd_entry.count;
                      /*  offset */
                      if (ifd_entry.value_or_offset == is_offset) {
                        offset_t offset;
                        ret = read_offsetdata(ctif, ifd_entry.data32offset, icc_profile_size, ifd_entry.datatype, &offset, &ret);
                        if (ret.returncode != is_valid) return ret;
                        icc_profile = (char *)offset.data32p;
                      } else {
                        ret.returncode = tagerror_encoded_as_value_excited_space;
                        return ret;
                      }
                       break;
                     }
    default: { /*  none */
               ret = set_value_found_ret_with_returncode(&ret, const_str(TIFFTypeName(ifd_entry.datatype)),
                                                         tagerror_unexpected_type_found);
               return ret;
               /* break; */
             }
  }

  //printf("DEBUG: iccprofile_size=%i\n", icc_profile_size);
  // printf("DEBUG: iccprofile='%s'\n", icc_profile);
  /* DEBUG
  char * p = icc_profile;
  int i=0;
  for (i = 0; i< icc_profile_size; i++, p++) {
    if (0 == i % 8) printf("|");
    printf("%c(%0x) ", (isalnum(*p)?*p:' '),*p);
  }
  printf("\n");
  */
  char * errmessage = calloc(VALUESTRLEN, sizeof(char));
  unsigned long errsize = VALUESTRLEN-1;
  icc_returncode_t icc_ret = parse_icc(icc_profile_size, icc_profile, errsize, errmessage);
  free(icc_profile);
  ret.returncode = should_not_occur;
  switch (icc_ret) { /*  map between returncodes icc profile and tag check */
    case icc_is_valid: ret.returncode = is_valid; break;
    case icc_error_profileclass:
    case icc_error_colorspacedata:
    case icc_error_connectionspacedata:
    case icc_error_primaryplatformsignature:
    case icc_error_header_1v43_2010:
    case icc_error_header_v240_v430:
    case icc_error_header_generic:
    case icc_error_preferredcmmtype:
    case icc_error_committed_size_differs:
    case icc_error_header_v500_2016:
    case icc_error_header_version_undefined:
    case icc_error_header_version_outdated:
    case icc_error_profile_description_tag:
    case icc_error_not_ascii:
    case icc_error_badprofile_id:
    case icc_error_found_by_IccProfLib:
    case icc_hard_error_found_by_IccProfLib:
        ret.returncode = (returncode_t) icc_ret; /* cast because should have same enum offset */
        break;
    case icc_should_not_occur: ret.returncode = should_not_occur;
  }
  ret = set_value_found_ret(&ret, str(errmessage));
  free (errmessage);
  /* printf("icc_ret=%i\n", icc_ret); */
  assert( ret.returncode != (returncode_t) icc_should_not_occur);
  assert( ret.returncode != should_not_occur);
  return ret;
}

/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 smarttab expandtab :*/
