
/* **************************************************************************

  $Archive:  $
  $Revision:  $
  $Modtime:  $

  Copyright (c) 1997 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/


#include <assert.h>

#include <unicode.h>

#include <nwdstype.h>
#include <nwdserr.h>
#include <nwdsattr.h>

#include "jncpAlias.h"
#include "jdsSwaps.h"

#include "jncpWire.h"


typedef  unsigned long     ptrcast_t;


/*---------------------------------------------------------------------------
 */
N_INTERN_FUNC (void)
jncpWireError
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
);

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetBoolean
(
   ppnstr8  cur,
   pnstr8   limit,
   pnuint8  boolean
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint8))
      return ERR_BUFFER_EMPTY;

   if (*(pnuint8) *cur)
      *boolean = 1;
   else
      *boolean = 0;

   *cur    += sizeof(nuint8);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (nuint8) 
jncpGetBoolean
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   nuint8 boolean;

   if ((nuint)(limit - *cur) < sizeof(nuint8))
   {
      jncpWireError (env, cur, limit);
      return (0);
   }

   if (*(pnuint8) *cur)
      boolean = 1;
   else
      boolean = 0;

   *cur += sizeof(nuint8);

   return (boolean);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutBoolean
(
   ppnstr8  cur,
   pnstr8   limit,
   nuint8 boolean
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint8))
      return ERR_BUFFER_FULL;

   if (boolean)
      *(pnuint8) *cur = 1;
   else
      *(pnuint8) *cur = 0;
   *cur               += sizeof(nuint8);

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetInt8
(
   ppnstr8  cur,
   pnstr8   limit,
   pnuint8  i
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint8))
      return ERR_BUFFER_EMPTY;

   *i    = *(nuint8 N_FAR *) *cur;
   *cur += sizeof(nuint8);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (nuint8)
jncpGetInt8
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   nuint8 i;

   if ((nuint) (limit - *cur) < sizeof(nuint8))
   {
      jncpWireError (env, cur, limit);
      return (0);
   }

   i = *(nuint8 N_FAR *) *cur;

   *cur += sizeof(nuint8);

   return (i);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutInt8
(
   ppnstr8  cur,
   pnstr8   limit,
   nuint8   i
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint8))
      return ERR_BUFFER_FULL;

   *(nuint8 N_FAR *) *cur = i;
   *cur               += sizeof(nuint8);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (nuint16)
jncpGetInt16
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   nuint16 i;

   if ((nuint) (limit - *cur) < sizeof(nuint16))
   {
      jncpWireError (env, cur, limit);
      return (0);
   }

   i = NET2CPU16(*(nuint16 N_FAR *) *cur);

   *cur += sizeof(nuint16);

   return (i);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetInt16
(
   ppnstr8  cur,
   pnstr8   limit,
   pnuint16 i
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint16))
      return ERR_BUFFER_EMPTY;

   *i    = NET2CPU16(*(nuint16 N_FAR *) *cur);
   *cur += sizeof(nuint16);

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutInt16
(
   ppnstr8  cur,
   pnstr8   limit,
   nuint16  i
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint16))
      return ERR_BUFFER_FULL;

   *(nuint16 N_FAR *) *cur = CPU2NET16(i);
   *cur                += sizeof(nuint16);

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetInt32
(
   ppnstr8  cur,
   pnstr8   limit,
   pnuint32 i
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint32))
      return ERR_BUFFER_EMPTY;

   *i    = NET2CPU32(*(nuint32 N_FAR *) *cur);
   *cur += sizeof(nuint32);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (nuint32)
jncpGetInt32
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   nuint32 i;

   if ((nuint) (limit - *cur) < sizeof(nuint32))
   {
      jncpWireError (env, cur, limit);
      return (0);
   }

   i = NET2CPU32(*(nuint32 N_FAR *) *cur);

   *cur += sizeof(nuint32);

   return (i);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutInt32
(
   ppnstr8  cur,
   pnstr8   limit,
   nuint32  i
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint32))
      return ERR_BUFFER_FULL;

   *(nuint32 N_FAR *) *cur = CPU2NET32(i);
   *cur                += sizeof(nuint32);

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WSkipInt8
(
   ppnstr8  cur,
   pnstr8   limit,
   ppnstr8  ip
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint8))
      return ERR_BUFFER_FULL;

   *ip   = *cur;
   *cur += sizeof(nuint8);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (void)
jncpSkipInt8
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint8))
   {
      jncpWireError (env, cur, limit);
      return;
   }

   *cur += sizeof(nuint8);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WSkipInt16
(
   ppnstr8  cur,
   pnstr8   limit,
   ppnstr8  ip
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint16))
      return ERR_BUFFER_FULL;

   *ip   = *cur;
   *cur += sizeof(nuint16);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (void)
jncpSkipInt16
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint16))
   {
      jncpWireError (env, cur, limit);
      return;
   }

   *cur += sizeof(nuint16);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WSkipInt32
(
   ppnstr8  cur,
   pnstr8   limit,
   ppnstr8  ip
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint32))
      return ERR_BUFFER_FULL;

   *ip   = *cur;
   *cur += sizeof(nuint32);

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (void)
jncpSkipInt32
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint32))
   {
      jncpWireError (env, cur, limit);
      return;
   }

   *cur += sizeof(nuint32);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutAlign32
(
   ppnstr8  cur,
   pnstr8   limit
)
{
   if ((nuint) (limit - *cur) < sizeof(nuint32))
      return ERR_BUFFER_FULL;

   *cur = (void N_FAR *) (((ptrcast_t) *cur + 3) & ~3);

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetAlign32
(
   ppnstr8  cur,
   pnstr8   limit
)
{

   pnstr8   newCur;

   newCur = (void N_FAR *) (((ptrcast_t) *(cur) + 3) & ~3);

   if ( newCur > limit )
      return ERR_BUFFER_EMPTY;

   *cur = newCur;

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutData
(
   ppnstr8  cur,
   pnstr8   limit,
   nuint32  size,
   nptr     data
)
{
   NWDSCCODE ccode;

   if ((ccode = WPutInt32(cur, limit, size)) != 0)
      return ccode;

   if ((nuint) (limit - *cur) < (nuint)size)
      return ERR_BUFFER_FULL;

   nwmemcpy(*cur, data, (int)size);
   *cur += (size_t)size;

   return 0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetData
(
   ppnstr8  cur,
   pnstr8   limit,
   pnuint32 size,
   ppnstr8  data
)
{
   NWDSCCODE      ccode;
   nuint32   tmpSize;

   if ((ccode = WGetInt32(cur, limit, &tmpSize)) != 0)
      return ccode;

   *size = tmpSize;

   if ((nuint) (limit - *cur) < (nuint)*size)
      return ERR_BUFFER_EMPTY;

   *data = *cur;
   *cur += (nuint)*size;

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (pnstr8)
jncpGetData
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit,
   pnuint32 size
)
{
   pnstr8  data;

   *size = jncpGetInt32 (env, cur, limit);

   if ((nuint) (limit - *cur) < (nuint)*size)
   {
      *size = 0;
      jncpWireError (env, cur, limit);
      return (limit);
   }

   data = *cur;

   *cur += (nuint) *size;

   return (data);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetString
(
   ppnstr8 cur,
   pnstr8 limit,
   ppunicode str
)
{
   NWDSCCODE      ccode;
   nuint32   tmpSize;
   register nuint32   size;

   *str = (unicode N_FAR *) *cur;   /* in case size is 0 */

   if (((ccode = WGetInt32(cur, limit, &tmpSize)) != 0) || !tmpSize)
      return ccode;

   size = tmpSize;

   if ((nuint)(limit - *cur) < (nuint)size || (*cur)[(nuint)size - 1])
      return ERR_BUFFER_EMPTY;

   *str  = (unicode N_FAR *) *cur;
   *cur += (size_t) size;

#ifdef N_INT_ENDIAN_HI_LO      /* swap the bytes of the Unicode characters */
   {
      register unicode N_FAR *p = *str;
      size /= sizeof(unicode);
      while (size--)
         *p++ = NET2CPU16(*p);
   }
#endif

   return 0;
}

/*---------------------------------------------------------------------------
 */
N_GLOBAL_FUNC (jstring)
jncpGetString
(
   JNIEnv *env,
   ppnstr8 cur,
   pnstr8 limit
)
{
   punicode cString;
   nuint32 length = jncpGetInt32 (env, cur, limit);

   cString  = (unicode *) *cur;

   if ((nuint)(limit - *cur) < (nuint)length)
   {
      unicode c = 0;

      jncpWireError (env, cur, limit);
      return ((*env)->NewString (env, &c, 0));
   }

   *cur += length;

   return ((*env)->NewString (env, cString, length ? (length/2 - 1) : 0));
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutString
(
   ppnstr8  cur,
   pnstr8   limit,
   punicode str
)
{
   NWDSCCODE   ccode;
   nuint32     size = unisize(str);
#ifdef N_INT_ENDIAN_HI_LO
   register unicode N_FAR *savCur = (unicode N_FAR *)*cur; /* (assuming aligned!) */
#endif

   ccode = WPutData(cur, limit, size, str);

#ifdef N_INT_ENDIAN_HI_LO      /* swap the bytes of the Unicode characters */
   if (!ccode)
   {
      savCur += sizeof(nuint32) / sizeof(unicode);

      size /= sizeof(unicode);
      while (size--)
         *savCur++ = NET2CPU16(*savCur);
   }
#endif

   return ccode;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetTimeStamp
(
   ppnstr8        cur,
   pnstr8         limit,
   pTimeStamp_T   timeStamp
)
{
   NWDSCCODE   ccode;

   if ((ccode = WGetInt32(cur, limit, &timeStamp->wholeSeconds)) != 0)
      return ccode;

   if ((ccode = WGetInt16(cur, limit, &timeStamp->replicaNum)) != 0)
      return ccode;

   if ((ccode = WGetInt16(cur, limit, &timeStamp->eventID)) != 0)
      return ccode;

   return (NWDSCCODE)0;
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WPutTimeStamp
(
   ppnstr8        cur,
   pnstr8         limit,
   pTimeStamp_T   timeStamp
)
{
   NWDSCCODE ccode;

   if ((ccode = WPutInt32(cur, limit, timeStamp->wholeSeconds)) != 0)
      return ccode;

   if ((ccode = WPutInt16(cur, limit, timeStamp->replicaNum)) != 0)
      return ccode;

   if ((ccode = WPutInt16(cur, limit, timeStamp->eventID)) != 0)
      return ccode;

   return (NWDSCCODE)0;
}

/*---------------------------------------------------------------------------
 * this routine assumes that referral has already been validated
 */
nuint32 SizeOfReferral
(
   pnstr8   referral,
   pnstr8   limit
)
{
   nuint32     count, i, type;
   nstr8 N_FAR *cur = referral,
         N_FAR *data;
   nuint32     size;

   WGetInt32(&cur, limit, &count);
   for (i = 0; i < count; i++)
   {
      WGetAlign32(&cur, limit);
      WGetInt32(&cur, limit, &type);
      WGetData(&cur, limit, &size, &data);
   }

   return (nuint32)(cur - referral);
}

/*---------------------------------------------------------------------------
 */
NWDSCCODE WGetReferral
(
   ppnstr8  cur,
   pnstr8   limit,
   ppnstr8  referralData
)
{
   NWDSCCODE   err;
   nuint32     count, i, type;
   pnstr8      data;
   nuint32     size;

   *referralData = *cur;
   if (0 != (err = WGetInt32(cur, limit, &count)))
      return err;
   for (i = 0; i < count; i++)
   {
      if ((0 != (err = WGetAlign32(cur, limit)))
            || (0 != (err = WGetInt32(cur, limit, &type)))
            || (0 != (err = WGetData(cur, limit, &size, &data))))
         return err;
   }
   return 0;
}

/*---------------------------------------------------------------------------
 * this routine assumes that referral has already been validated
 */
NWDSCCODE WPutReferral
(
   ppnstr8  cur,
   pnstr8   limit,
   pnstr8   referral
)
{
   nuint32  size = SizeOfReferral(referral, limit);
   if ((nuint32)(limit - *cur) < size)
      return ERR_INSUFFICIENT_BUFFER;
   nwmemcpy(*cur, referral, (size_t)size);
   *cur += (nuint)size;
   return 0;
}

/*---------------------------------------------------------------------------
 */
N_INTERN_FUNC (void)
jncpWireError
(
   JNIEnv *env,
   ppnstr8  cur,
   pnstr8   limit
)
{
   *cur = limit;

   if (NULL == (*env)->ExceptionOccurred (env))
   {
      jclass cls;
      jmethodID mid;
      char *message = "Received invalid NCP Packet from NDS.";

      cls = (*env)->FindClass (env, "com/novell/service/jncp/NSIExceptionBuilder");
      if (NULL == cls)
         goto FATAL_ERROR;
      mid = (*env)->GetStaticMethodID (env, cls, "build", "(I)Lcom/novell/service/jncp/NSIException;");
      if (NULL == mid)
         goto FATAL_ERROR;
      if(0 == (*env)->Throw (env, (*env)->CallStaticObjectMethod (env, cls, mid, -319)))
         return;

      FATAL_ERROR:
      (*env)->FatalError (env, message);
   }
}


