/*****************************************************
* unit:    struct            release 0.18            *
* STRUCT.H - Provides some big and little endian abstraction functions,
*	      for manipulating with structures.	
*   Copyright (C) 1999-2024  Jaroslav Fojtik
*****************************************************/
#ifndef _STRUCT_H_
#define _STRUCT_H_

#include "typedfs.h"


/*
#undef LO_ENDIAN	//Signalise that system is native LowEndian
#define HI_ENDIAN	//Signalise that system is native HighEndian
#define EXPAND_OPS	//hack to speed up; please note that EXPAND_OPS does not work on AMD64; works on x86.
*/

#if defined(LO_ENDIAN) && defined(HI_ENDIAN)
 #error Cannot define both LO_ENDIAN and HI_ENDIAN together!
#endif

/* Ensure that prototypes are correctly declared even for C. */
#ifdef __cplusplus

#ifdef EXPAND_OPS
  #ifdef LO_ENDIAN
    inline int RdWORD_LoEnd(uint16_t *pnum,FILE*f) {return fread(pnum,1,2,f);}
    #define RdWORD_LoEnd RdWORD_LoEnd
    inline int RdDWORD_LoEnd(uint32_t *pnum,FILE*f) {return fread(pnum,1,4,f);}
    #define RdDWORD_LoEnd RdDWORD_LoEnd
    inline int RdWORD_HiEnd(uint16_t *pnum,FILE*f) {const int i=fread(pnum,1,2,f);*pnum=LD_UINT16_SWAP(pnum);return i;}
    #define RdWORD_HiEnd RdWORD_HiEnd
    inline int RdDWORD_HiEnd(uint32_t *pnum,FILE*f) {const int i=fread(pnum,1,4,f);*pnum=LD_UINT32_SWAP(pnum);return i;}
    #define RdDWORD_HiEnd RdDWORD_HiEnd
    #if defined(uint64_t_defined)
    #endif
  #endif
  #ifdef HI_ENDIAN
    inline int RdWORD_LoEnd(uint16_t *pnum,FILE*f) {const int i=fread(pnum,1,2,f);*pnum=LD_UINT16_SWAP(pnum);return i;}
    #define RdWORD_LoEnd RdWORD_LoEnd
    inline int RdDWORD_LoEnd(uint32_t *pnum,FILE*f) {const int i=fread(pnum,1,4,f);*pnum=LD_UINT32_SWAP(pnum);return i;}
    #define RdDWORD_LoEnd RdDWORD_LoEnd
    inline int RdWORD_HiEnd(uint16_t *pnum,FILE*f) {return fread(pnum,1,2,f);}
    #define RdWORD_HiEnd RdWORD_HiEnd
    inline int RdDWORD_HiEnd(uint32_t *pnum,FILE*f) {return fread(pnum,1,4,f);}
    #define RdDWORD_HiEnd RdDWORD_HiEnd
    #if defined(uint64_t_defined)
    #endif
  #endif
  #undef EXPAND_OPS
#endif

extern "C" {
#endif
/* functions from struct.c */


#ifdef EXPAND_OPS
 #ifdef LO_ENDIAN
  #define RdWORD_LoEnd(pnum,f)		fread(pnum,1,2,f)
  #define RdDWORD_LoEnd(pnum,f)		fread(pnum,1,4,f)
  #define RdQWORD_LoEnd(pnum,f)		fread(pnum,1,8,f)
  #define WrWORD_LoEnd(_num,f)		fwrite(&(_num),1,2,f)
  #define WrDWORD_LoEnd(_num,f)		fwrite(&(_num),1,4,f)
  #define WrQWORD_LoEnd(_num,f)		fwrite(&(_num),1,8,f)
  #define RdFLOAT_LoEnd(pnum,f)		fread(pnum,1,4,f)
  #define WrFLOAT_LoEnd(_num,f)		fwrite(&(_num),1,4,f)
 #endif
 #ifdef HI_ENDIAN
  #define RdWORD_HiEnd(pnum,f)		fread((pnum),1,2,f)
  #define RdDWORD_HiEnd(pnum,f)		fread((pnum),1,4,f)
/* this speedup is not working on MSB - never mind
  #define WrWORD_HiEnd(_num,f)		fwrite((&_num),1,2,f)
  #define WrDWORD_HiEnd(_num,f)		fwrite((&_num),1,4,f)
*/
 #endif
#endif

#ifndef RdWORD_LoEnd
 int RdWORD_LoEnd(uint16_t *num, FILE *f);
#endif
#ifndef RdDWORD_LoEnd
 int RdDWORD_LoEnd(uint32_t *num, FILE *f);
#endif
#ifndef RdWORD_HiEnd
 int RdWORD_HiEnd(uint16_t *num, FILE *f);
#endif
#ifndef RdDWORD_HiEnd
 int RdDWORD_HiEnd(uint32_t *num, FILE *f);
#endif

#ifndef WrWORD_LoEnd
 int WrWORD_LoEnd(uint16_t num, FILE *f);
#endif
#ifndef WrWORD_HiEnd
 int WrWORD_HiEnd(uint16_t num, FILE *f); 
#endif
#ifndef WrDWORD_LoEnd
 int WrDWORD_LoEnd(uint32_t num, FILE *f);
#endif
#ifndef WrDWORD_HiEnd
 int WrDWORD_HiEnd(uint32_t num, FILE *f);
#endif

#if defined(uint64_t_defined)
 #ifndef RdQORD_HiEnd
  int RdQWORD_HiEnd(uint64_t *num, FILE *f);
 #endif
 #ifndef RdQWORD_LoEnd
  int RdQWORD_LoEnd(uint64_t *num, FILE *f);
 #endif
 #ifndef WrDWORD_LoEnd
  int WrQWORD_LoEnd(uint64_t num, FILE *f);
 #endif
 #ifndef WrDWORD_HiEnd
  int WrQWORD_HiEnd(uint64_t num, FILE *f);
 #endif
#endif

#ifndef RdFLOAT_LoEnd
 #define RdFLOAT_LoEnd(pflt,file)  RdDWORD_LoEnd(((uint32_t*)pflt), file)
#endif

#ifndef RdFLOAT_HiEnd
 #define RdFLOAT_HiEnd(pflt,file)  RdDWORD_HiEnd(((uint32_t*)pflt), file)
#endif

#ifndef WrFLOAT_LoEnd
 #define WrFLOAT_LoEnd(flt,file)  WrDWORD_LoEnd((*(uint32_t*)&flt), file)
#endif

#ifndef WrFLOAT_HiEnd
 #define WrFLOAT_HiEnd(flt,file)  WrDWORD_HiEnd((*(uint32_t*)&flt), file)
#endif

uint16_t fil_sreadU16(const uint8_t *in);
uint32_t fil_sreadU32(const uint8_t *in);

int loadstruct(FILE *F, const char *description, ...);
int savestruct(FILE *F, const char *description, ...);

#ifdef __cplusplus
}
#endif


#endif