/* '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 <stdarg.h>
#include "check.h"
#include "check_helper.h"
#include "ctstring.h"
#include <sys/stat.h>
#include <assert.h>
#ifdef __WIN32__
#define bswap_16 _byteswap_ushort
#define bswap_32 _byteswap_ulong
#else
#include <byteswap.h>
#endif
/*
#define DEBUG
*/


string_t float2str(float v) {
  char array[VALUESTRLEN]={0};
  snprintf(array, VALUESTRLEN-1, "%f", v);
  return str(array);
}

string_t uint2str(unsigned int v) {
    char array[VALUESTRLEN]={0};
    snprintf(array, VALUESTRLEN-1, "%u", v);
    return str(array);
}

string_t int2str(int v) {
  char array[VALUESTRLEN]={0};
  snprintf(array, VALUESTRLEN-1, "%i", v);
  return str(array);
}

string_t frac2str(int d, int n) {
  char array[VALUESTRLEN]={0};
  snprintf(array, VALUESTRLEN-1, "%i/%i", d, n);
  return str(array);
}

uint16 TIFFSwabShort(uint16 a) {
    return bswap_16( a );
}

uint32 TIFFSwabLong(uint32 a) {
    return  bswap_32( a );
}

long long fsize(int fd) {
  struct stat st;
  fstat(fd, &st);
  return st.st_size;
}

ret_t set_value_found_ret (ret_t * rp, const string_t msg) {
  assert( NULL != rp);
  rp->value_found=msg;
  return *rp;
}

ret_t set_value_found_ret_with_returncode(ret_t *rp, const string_t msg, returncode_t rc) {
    ret_t r = set_value_found_ret(rp, msg);
    r.returncode = rc;
    return r;
}

ret_t set_value_found_ret_u32_value (ret_t *rp, uint32 value) {
    ret_t ret = set_value_found_ret(rp, uint2str(value));
    return ret;
}

ret_t set_value_found_ret_u16_value (ret_t *rp, uint16 value) {
    ret_t ret = set_value_found_ret(rp, uint2str(value));
    return ret;

}

ret_t set_value_found_ret_float_value (ret_t *rp, float value) {
    ret_t ret = set_value_found_ret(rp, float2str(value));
    return ret;
}



ret_t set_value_found_ret_formatted (ret_t * rp, const char * fmt, ...) {
    va_list argptr;
    char * msg = calloc(VALUESTRLEN, sizeof(char));
    if (NULL == msg) { fprintf(stderr, "could not allocate memory in src function %s", __func__ ); exit(EXIT_FAILURE);}
    va_start(argptr, fmt);
    vsnprintf(msg, VALUESTRLEN-1, fmt, argptr);
    va_end(argptr);
    ret_t ret = set_value_found_ret(rp, str(msg));
    free( msg);
    msg = NULL;
    return ret;
}

ret_t set_value_found_ret_formatted_with_returncode(ret_t * rp, returncode_t rc, const char * fmt, ...) {    va_list argptr;
    char * msg = calloc(VALUESTRLEN, sizeof(char));
    if (NULL == msg) { fprintf(stderr, "could not allocate memory in src function %s", __func__ ); exit(EXIT_FAILURE);}
    va_start(argptr, fmt);
    vsnprintf(msg, VALUESTRLEN-1, fmt, argptr);
    va_end(argptr);
    ret_t ret = set_value_found_ret(rp, str(msg));
    free( msg);
    msg = NULL;
    ret.returncode = rc;
    return ret;
}

ret_t set_expected_value_formatted (ret_t * rp, const char * fmt, ...) {
    va_list argptr;
    char * msg = calloc(VALUESTRLEN, sizeof(char));
    if (NULL == msg) { fprintf(stderr, "could not allocate memory in src funtion %s", __func__ ); exit(EXIT_FAILURE);}
    va_start(argptr, fmt);
    vsnprintf(msg, VALUESTRLEN, fmt, argptr);
    va_end(argptr);
    rp->expected_value = str(msg);
    free( msg);
    msg = NULL;
    return *rp;
}

uint32 get_streamlen_at_offset(const ifd_entry_t *ifd_entry) {
    uint32 streamlen;
    switch ((*ifd_entry).datatype) {
        case TIFF_ASCII:
        case TIFF_BYTE:
        case TIFF_SBYTE:
        case TIFF_UNDEFINED:
            streamlen = (*ifd_entry).count;
            break;
        case TIFF_SHORT:
        case TIFF_SSHORT:
            streamlen = (*ifd_entry).count * 2;
            break;
        case TIFF_LONG:
        case TIFF_SLONG:
        case TIFF_IFD:
        case TIFF_FLOAT:
            streamlen = (*ifd_entry).count * 4;
            break;
        case TIFF_LONG8:
        case TIFF_DOUBLE:
        case TIFF_SLONG8:
        case TIFF_RATIONAL:
        case TIFF_SRATIONAL:
            streamlen = (*ifd_entry).count * 8;
            break;
        default:
            streamlen = (*ifd_entry).count;
    }
    return streamlen;
}

bool tag_is_an_IFD(const ifd_entry_t *ifd_entry) {
    return (*ifd_entry).datatype == TIFF_IFD || (*ifd_entry).datatype == TIFF_IFD8;
}

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