/* '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)
 *
 */

#ifndef FIXIT_TIFF_CHECK_HELPER
#define FIXIT_TIFF_CHECK_HELPER
#include <stdlib.h>
#include "msg_tiffparse.h"
//#include <tiff.h>
//#include <tiffio.h>
#define TIFF_ANY 0

typedef enum {
    FLAGGED=1,
    UNFLAGGED=0,
} flags_t;


/* helper */
uint16 TIFFSwabShort(uint16 a);
uint32 TIFFSwabLong(uint32 a);
long long fsize(int fd);
ret_t check_tag_has_fvalue(ctiff_t * ctif, cifd_t *ifd, tag_t tag, float value);
ret_t check_tag_has_u16value(ctiff_t * ctif, cifd_t *ifd, tag_t tag, uint16 value);
ret_t check_tag_has_u32value(ctiff_t * ctif, cifd_t *ifd, tag_t tag, uint32 value);
uint32 TIFFGetRawTagTypeListEntry( ctiff_t * ctif, cifd_t *ifd, int tagidx );
tag_t TIFFGetRawTagListEntry( ctiff_t * ctif, const cifd_t *ifd, int tagidx ) ;
int TIFFGetRawTagListCount (ctiff_t * ctif, cifd_t *ifd, uint32 ifdpos) ;
TIFFDataType TIFFGetRawTagType(ctiff_t * ctif, cifd_t *ifd, tag_t tag);
ifd_entry_t TIFFGetRawIFDEntry( ctiff_t * ctif, cifd_t *ifd, tag_t tag);
ifd_entry_t TIFFGetRawTagIFDListEntry( ctiff_t * ctif, const cifd_t *ifd, int tagidx );
int TIFFGetRawTagListIndex(const cifd_t *ifd, tag_t tag);
ret_t TIFFGetFieldASCII(ctiff_t * ctif, cifd_t *ifd, const tag_t tag, char** result_string_p, uint32 * result_countp);
ret_t TIFFGetFieldLONG(ctiff_t * ctif, cifd_t *ifd, const tag_t tag, uint32 ** result_long_p, uint32 * result_countp);
ret_t TIFFGetFieldSHORT(ctiff_t * ctif, cifd_t *ifd, const tag_t tag, uint16 ** result_short_p, uint32 * result_countp);
ret_t TIFFGetFieldRATIONAL(ctiff_t * ctif, cifd_t *ifd, const tag_t tag, float ** result_float_p, uint32 * result_countp);
ret_t read_offsetdata(ctiff_t * ctif, const uint32 address, const uint32 count, const uint16 datatype, offset_t * result_offsetp, ret_t * ret_p);

ctiff_t * initialize_ctif( const char * tiff_file, ct_ioflag_t );
void free_ctif( ctiff_t * ctif);
uint32 get_ifd0_pos(const ctiff_t * ctif);
uint32 get_ifd_pos(const cifd_t *ifd);
ret_t parse_header_and_endianess(ctiff_t * ctif );
uint32 get_next_ifd_pos( ctiff_t * ctif, uint32 actual_pos );
uint16 get_ifd0_count(const ctiff_t * ctif );
uint16 get_ifd_count(const cifd_t *ifd);
int is_byteswapped(const ctiff_t * ctif );
ret_t get_first_IFD(ctiff_t * ctif, uint32 * ifd);
ret_t get_IFD_at_pos(ctiff_t * ctif, uint32 pos, cifd_t * resulting_ifd);
uint32 get_streamlen_at_offset(const ifd_entry_t *ifd_entry);
ret_t set_value_found_ret (ret_t * rp, string_t msg);
ret_t set_value_found_ret_with_returncode(ret_t *rp, const string_t msg, returncode_t rc);
ret_t set_value_found_ret_u32_value (ret_t *rp, uint32 value);
ret_t set_value_found_ret_u16_value (ret_t *rp, uint16 value);
ret_t set_value_found_ret_float_value (ret_t *rp, float value);
ret_t set_value_found_ret_formatted (ret_t * rp, const char * fmt, ...);
ret_t set_value_found_ret_formatted_with_returncode(ret_t * rp, returncode_t rc, const char * fmt, ...);
ret_t set_expected_value_formatted( ret_t * rp, const char * fmt, ...);
returncode_t add_to_render_pipeline_via_strncpy (retmsg_t ** pointer, string_t src, rm_type_t src_type);
void clean_render_pipeline(retmsg_t **pointer );
bool tag_is_an_IFD(const ifd_entry_t *ifd_entry);

#define GET_EMPTY_RET(ret) \
  ret_t ret; \
  (ret).value_found = empty_str(); \
  (ret).expected_value = empty_str(); \
  (ret).logical_or_count = 0; \
  (ret).returncode = should_not_occur;

#define EXIST_TAG(ctif, tag, ret) \
  returncode_t rc=check_tag_quiet((ctif), (tag)); \
  if (rc != is_valid) { \
    (ret).returncode = rc; \
    return (ret); \
  }


#endif
