/* '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 <errno.h>
#include "ctstring.h"

ret_t check_tagorder(ctiff_t * ctif) {
  GET_EMPTY_RET(ret);
  TIFP_CHECK( ctif, ret);
  if (has_sorted_tags != ctif->ifd0->tagorder) {
    uint32 offset = get_ifd0_pos(ctif);
    uint16 count = get_ifd0_count(ctif);

    /* read count of tags (2 Bytes) */
    /* replace i/o operatrions with in-memory-operations */
    uint8 * ifdentries = NULL;
    ifdentries = malloc ( sizeof(uint8) * 12 * count);
    if (NULL == ifdentries) {
      ret.returncode = could_not_allocate_memory;
      return ret;
    }
    if (ct_seek(ctif, offset+2, SEEK_SET) != (offset+2)) {
      ret = set_value_found_ret_formatted_with_returncode(&ret, tiff_seek_error_header, "%u bytes, errorcode=%i", offset+2, errno);
      free(ifdentries);
      return ret;
    }
    if (ct_read8(ctif, ifdentries,  (12 * (size_t) count)) != 12 * count ) {
      ret = set_value_found_ret_formatted_with_returncode(&ret, tiff_read_error_header, "%i bytes, errorcode=%i", 12*count, errno);
      free(ifdentries);
      return ret;
    } else {
      const uint8 * e = ifdentries;
      uint16 lasttag = 0;
      for (int i = 0; i<count; i++) {
        uint8 lo = *e;
        e++;
        uint8 hi = *e;
        uint16 tag = ((uint16) hi << 8) + lo;
        e++;
        if (is_byteswapped(ctif))
          tag = TIFFSwabShort(tag);
        if (i>0 && lasttag >= tag) {
          // printf("tag idx=%i, tag=%u (0x%04x) (0x%02x) (0x%02x)\n", i, tag, tag, hi, lo);
          free( ifdentries );
          // FIXME: tif_fails?
          ret = set_value_found_ret_formatted_with_returncode( &ret, ifderror_tags_not_in_ascending_order, "previous tag:%u (%s) , actual tag:%u (%s) at pos %i of %i\n", lasttag,  TIFFTagName(lasttag),  tag,  TIFFTagName(tag), i, count);
          ctif->ifd0->tagorder = has_unsorted_tags;
          return ret;
        }
        lasttag = tag;
        e+=10;
      }
      /* loop each tag until end or given tag found */
      free( ifdentries );
      ctif->ifd0->tagorder = has_sorted_tags;
    }
  }
  ret.returncode=is_valid;
  return ret;
}


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