/************************************************************************************************
 * Copyright/Copyleft:
 *
 * For this source the LGPL Lesser General Public License,
 * published by the Free Software Foundation is valid.
 * It means:
 * 1) You can use this source without any restriction for any desired purpose.
 * 2) You can redistribute copies of this source to everybody.
 * 3) Every user of this source, also the user of redistribute copies
 *    with or without payment, must accept this license for further using.
 * 4) But the LPGL ist not appropriate for a whole software product,
 *    if this source is only a part of them. It means, the user
 *    must publish this part of source,
 *    but don't need to publish the whole source of the own product.
 * 5) You can study and modify (improve) this source
 *    for own using or for redistribution, but you have to license the
 *    modified sources likewise under this LGPL Lesser General Public License.
 *    You mustn't delete this Copyright/Copyleft inscription in this source file.
 *
 * This source may be used also with another licence, if the author 
 * and all other here named co-authors have agreed to this contract.
 * Especially a company can use a copy of this sources in its products without publishing.
 * The user should have a underwritten contract therefore.
 *
 * @author Hartmut Schorrig, Germany, Pinzberg, www.vishia.org
 *
 **copyright***************************************************************************************
 *
 * @version 0.92
 * @content Implementation of access for network payload data for the Intel-type-Processor
 * list of changes:
 * 2011-11-08; Hartmut use notification int32_t instead int32 etc. It is the C99-standard. 
 * 2009-11-24: JcHartmut created as new idea.
 *
 ****************************************************************************/
#include <os_endian.h>

int64_t getInt64BigEndian(int64BigEndian* addr)
{ int32_t loBig,hiBig, lo, hi;
  int64_t ret;
  //NOTE: do only 1 access to memory.
  hiBig = addr->hiBigEndian__;
  loBig = addr->loBigEndian__;
  hi = ((hiBig <<24) & 0xff000000) | ((hiBig <<8) & 0x00ff0000) |((hiBig >>8) & 0x0000ff00) |((hiBig >>24) & 0x0000ff);
  lo = ((loBig <<24) & 0xff000000) | ((loBig <<8) & 0x00ff0000) |((loBig >>8) & 0x0000ff00) |((loBig >>24) & 0x0000ff);
  ret = ((int64_t)hi)<<32 | lo;
  return ret;
}

int32_t getInt32BigEndian(int32BigEndian* addr)
{ int32_t loBig;
  int32_t ret;
  //NOTE: do only 1 access to memory.
  loBig = addr->loBigEndian__;
  ret = ((loBig <<24) & 0xff000000) | ((loBig <<8) & 0x00ff0000) |((loBig >>8) & 0x0000ff00) |((loBig >>24) & 0x0000ff);
  return ret;
}

int16_t getInt16BigEndian(int16BigEndian* addr)
{ int16_t loBig;
  int16_t ret;
  //NOTE: do only 1 access to memory.
  loBig = addr->loBigEndian__;
  ret = (int16_t)(((loBig <<8) & 0xff00) |((loBig >>8) & 0x00ff));
  return ret;
}

float getFloatBigEndian(floatBigEndian* addr)
{ int32_t loBig;
  int32_t lo;
  float ret;
  //NOTE: do only 1 access to memory.
  loBig = addr->floatBigEndian__;
  lo = ((loBig <<24) & 0xff000000) | ((loBig <<8) & 0x00ff0000) |((loBig >>8) & 0x0000ff00) |((loBig >>24) & 0x0000ff);
  ret = *(float*)&lo;
  return ret;
}

double getDoubleBigEndian(doubleBigEndian* addr)
{ int32_t loBig,hiBig, lo, hi;
  int64_t value;
  double ret;
  //NOTE: do only 1 access to memory.
  hiBig = addr->hiBigEndian__;
  loBig = addr->loBigEndian__;
  hi = ((hiBig <<24) & 0xff000000) | ((hiBig <<8) & 0x00ff0000) |((hiBig >>8) & 0x0000ff00) |((hiBig >>24) & 0x0000ff);
  lo = ((loBig <<24) & 0xff000000) | ((loBig <<8) & 0x00ff0000) |((loBig >>8) & 0x0000ff00) |((loBig >>24) & 0x0000ff);
  value = ((int64_t)hi)<<32 | lo;
  ret = *(double*)&value;
  return ret;
}

void* getPtrBigEndian(ptrBigEndian* addr)
{ int32_t loBig, hiBig;
  struct ptr_t{int32_t lo; int32_t hi; }imgPtr = {0, 0};
  int sizePtr = sizeof(void*); //may be depending on several compiler options.
  int ix;
  void* ret;
  //NOTE: do only 1 access to memory.
  hiBig = ((int32_t*)addr)[0];  //reads 4 byte.
  if(sizePtr >4){
    loBig = ((int32_t*)addr)[1]; //reads next 4 byte, part of them are for the pointer.
  } else {
    loBig = 0;
  }
  for(ix=0; ix<4 && ix<sizePtr; ix++){
    imgPtr.lo <<=8;
    imgPtr.lo |= hiBig & 0xff;
    hiBig >>=8;
  }
  while(ix < sizePtr){  //continue with next bytes.
    imgPtr.hi <<=8;
    imgPtr.hi |= loBig & 0xff;
    loBig >>=8;
  }
  ret = *(void**)&imgPtr; //interprete it as pointer-image in stack.
  return ret;
}


int64_t setInt64BigEndian(int64BigEndian* addr, int64_t value)
{ int32_t loBig,hiBig, lo, hi;
  hi = (int32_t)(value >> 32);
  lo = (int32_t)value;
  hiBig = ((hi <<24) & 0xff000000) | ((hi <<8) & 0x00ff0000) |((hi >>8) & 0x0000ff00) |((hi >>24) & 0x0000ff);
  loBig = ((lo <<24) & 0xff000000) | ((lo <<8) & 0x00ff0000) |((lo >>8) & 0x0000ff00) |((lo >>24) & 0x0000ff);
  //NOTE: do only 1 access to memory.
  addr->hiBigEndian__ = hiBig;
  addr->loBigEndian__ = loBig;
  return value;
}

int32_t setInt32BigEndian(int32BigEndian* addr, int32_t value)
{ int32_t loBig;
  loBig = ((value <<24) & 0xff000000) | ((value <<8) & 0x00ff0000) |((value >>8) & 0x0000ff00) |((value >>24) &
    0x0000ff);
  //NOTE: do only 1 access to memory.
  addr->loBigEndian__ = loBig;
  return value;
}

u_int32_t setUint32BigEndian(uint32BigEndian* addr, u_int32_t value)
{ int32_t loBig;
  loBig = ((value <<24) & 0xff000000) | ((value <<8) & 0x00ff0000) |((value >>8) & 0x0000ff00) |((value >>24) &
    0x0000ff);
  //NOTE: do only 1 access to memory.
  addr->loBigEndian__ = loBig;
  return value;
}

int16_t setInt16BigEndian(int16BigEndian* addr, int16_t value)
{ int16_t loBig;
  loBig = (int16_t)(((value <<8) & 0xff00) |((value >>8) & 0x00ff));

  //NOTE: do only 1 access to memory.
  addr->loBigEndian__ = loBig;
  return value;
}

float setFloatBigEndian(floatBigEndian* addr, float value)
{ int32_t img, imgBig;
  img = *(int32_t*)&value;
  imgBig = ((img <<24) & 0xff000000) | ((img <<8) & 0x00ff0000) |((img >>8) & 0x0000ff00) |((img >>24) & 0x0000ff);
  //NOTE: do only 1 access to memory.
  addr->floatBigEndian__ = imgBig;
  return value;
}

double setDoubleBigEndian(doubleBigEndian* addr, double value)
{ int32_t loBig,hiBig, lo, hi;
  int64_t img;
  img = *(int64_t*)&value;
  hi = (int32_t)(img >> 32);
  lo = (int32_t)img;
  hiBig = ((hi <<24) & 0xff000000) | ((hi <<8) & 0x00ff0000) |((hi >>8) & 0x0000ff00) |((hi >>24) & 0x0000ff);
  loBig = ((lo <<24) & 0xff000000) | ((lo <<8) & 0x00ff0000) |((lo >>8) & 0x0000ff00) |((lo >>24) & 0x0000ff);
  //NOTE: do only 1 access to memory.
  addr->hiBigEndian__ = hiBig;
  addr->loBigEndian__ = loBig;
  return value;
}


void* setPtrBigEndian(ptrBigEndian* addr, void const* value)
{ int sizePtr = sizeof(void*); //may be depending on several compiler options.
  switch(sizePtr){
    case 2: //it may be a near ptr
    { int16_t ptrImg = *(int16_t*)&value;
      setInt16BigEndian((int16BigEndian*)addr, ptrImg);
    } break;
    case 4: //it may be a normal far ptr
    { int32_t ptrImg = *(int32_t*)&value;
      setInt32BigEndian((int32BigEndian*)addr, ptrImg);
    } break;
    case 6: //it may be a far ptr
    { int32_t ptrImgLo = *(int32_t*)&value;
      int16_t ptrImgHi = ((int16_t*)&value)[2];
      setInt16BigEndian((int16BigEndian*)addr, ptrImgHi);
      setInt32BigEndian((int32BigEndian*)(((int16BigEndian*)addr)+1), ptrImgLo);  //set to next 16 bit position, but set
        32 bit.
    } break;
    case 8: //it may be a far ptr
    { int32_t ptrImgLo = *(int32_t*)&value;
      int32_t ptrImgHi = ((int32_t*)&value)[1];
      setInt32BigEndian((int32BigEndian*)addr, ptrImgHi);
      setInt32BigEndian(((int32BigEndian*)addr)+1, ptrImgLo);  //set to next 32 bit position, set 32 bit.
    } break;
  }
  return (void*) value;
}