/* --------------------------------------------------------------------

                      Microsoft OS/2 LAN Manager
		   Copyright(c) Microsoft Corp., 1991

-------------------------------------------------------------------- */
/* --------------------------------------------------------------------

Description :

Provides helper functions for data format conversion

History :

stevez	04-10-91	First bits into the bucket.

-------------------------------------------------------------------- */

#include "rpc.h"
#include "ndrhelp.h"

int _fstrlen(void far *);
void _pascal NDRcopy(void far *, void far *, int);

void PAPI * MIDL_user_allocate(unsigned int);
extern char near ebcdic_to_ascii[];

#define SWAPSHORT(s) { \
/*	_asm mov ax, s */    \
	_asm xchg ah,al	    \
	_asm mov s,ax	    \
}

#define SWAPLONG(l) { \
/*	_asm mov ax, word ptr l */  \
	_asm xchg ah,al	    \
/*	_asm mov dx, word ptr l+2*/ \
	_asm xchg dh,dl	    \
	_asm mov word ptr l+2,ax \
	_asm mov word ptr l,dx \
}

#if 0
#define SWAPSHORT(s) s = (((unsigned char *)&s)[1]<<8 | ((unsigned char *)&s)[0])
#define SWAPLONG(l) l = ( ((long) ((unsigned char *)&ret)[3]<<24) | ((long) ((unsigned char *)&ret)[2]<<16) | \
			  ((long) ((unsigned char *)&ret)[1]<<8) | ((long) ((unsigned char *)&ret)[0]))
#endif

#define Nilp(p) (*((int _far *)&p+1) == 0)

#define NEAR _near

#ifndef THREADS

#define GET_POINTER

#define pBuffCur (&BuffCur)

static NDR_BUFF NEAR BuffCur;	// global static for no thread case

#else

PNDR_BUFF fetNDRCur(void);

#define GET_POINTER PNDR_BUFF pBuffCur = fetNDRCur();

#endif

#define fSelfLittleEndian 1

#define fEBCDIC (pBuffCur->dataType & 0x0f)
#define fSWAP ((pBuffCur->dataType & 0xf0) != fSelfLittleEndian)
#define fFloatType (*(((char *)&pBuffCur->dataType)+1))

enum {F_IEEE, F_VAX, F_CRAY, F_IBM };

static TypeAlign NEAR a1 = {0, 0, 0};
static TypeAlign NEAR a2 = {2-1, 2-1, 2-1};
static TypeAlign NEAR a4 = {2-1, 4-1, 4-1};

static TypeAlign NEAR *mAlignType[] = {0, &a1, &a2, 0, &a4};

#define GET_END_LIST ( (void PAPI *) -1)
typedef void PAPI * PAPI * PP;



void NDR_Put_Init (		// Initialize global objects for marshelling

PRPC_MESSAGE Message,
void PAPI * pParam

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    pBuffCur->pSource = pBuffCur->pCur = pParam;
    pBuffCur->pTarget = Message->Buffer;
    pBuffCur->alignment = mAlignType[sizeof(int)];
}

void NDR_Get_Init (		// Initialize global objects for unmarshelling

PRPC_MESSAGE Message,
void PAPI * pParam

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    pBuffCur->dataType = Message->DataRepresentation;
    pBuffCur->fSwap = fSWAP;
    pBuffCur->pSource = Message->Buffer;
    pBuffCur->pCur = Message->Buffer;
    pBuffCur->pPushLast = (PP)Message->Buffer;
    pBuffCur->pTarget = pParam;
    pBuffCur->pTargetRoot = 0;

    pBuffCur->pAllocator = MIDL_user_allocate;
    pBuffCur->alignment = mAlignType[sizeof(int)];
}

void NDR_Register_Unique(

void PAPI *(PAPI * pAllocator)(unsigned int)

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    pBuffCur->pAllocator = pAllocator;
}


void NDR_Pack_1 (		// Set the alignment to 1

) //-----------------------------------------------------------------------//
{
    GET_POINTER;
    pBuffCur->alignment = &a1;
}

void NDR_Pack_2 (		// Set the alignment to 2

) //-----------------------------------------------------------------------//
{
    GET_POINTER;
    pBuffCur->alignment = &a2;
}

void NDR_Pack_4 (		// Set the alignment to 4

) //-----------------------------------------------------------------------//
{
    GET_POINTER;
    pBuffCur->alignment = &a4;
}



#define ALIGN(ptr, byte) pBuffCur->ptr += (byte)-1; \
			 *(int *)&pBuffCur->ptr &= ~((byte)-1);

#define ALIGNCUR(ptr, TYPE) pBuffCur->ptr += pBuffCur->alignment->a##TYPE; \
			 *(int *)&pBuffCur->ptr &= ~pBuffCur->alignment->a##TYPE;

void NDR_Align_2 (		// Align the Target buffer to 2 byte boundary

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 2);
}


void NDR_Align_4 (		// Align the Target buffer to 4 byte boundary

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 4);
}


void NDR_Align_8 (		// Align the Target buffer to 8 byte boundary

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 8);
}


void NDR_Put_Set_Arg (		// set the source cursor to a value

void PAPI *pNew

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    // if at the root level, save the next pointer

    if (Nilp(pBuffCur->pCur))
	pBuffCur->pCur = pBuffCur->pSource;

    pBuffCur->pSource = pNew;
}

void NDR_Put_Next_Arg ( 	// move the cursor to the next base argment


) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    pBuffCur->pSource = pBuffCur->pCur;
    pBuffCur->pCur = 0;
}


void NDR_Skip_B_Long (		// Skip past a long in the Target Buffer

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    pBuffCur->pTarget += 4;
}

void NDR_Skip_M_Long (		// Skip past a long in the Source Buffer

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    pBuffCur->pSource += 4;
}


void NDR_Put_B_Short (		// Put an immediate Short
short immediate			// value to put

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 2);

    *(short PAPI *) pBuffCur->pTarget = immediate;
    pBuffCur->pTarget += 2;

}

void NDR_Put_B_Long (		// Put an immediate Long
long immediate			// value to put

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 4);

    *(long PAPI *) pBuffCur->pTarget = immediate;
    pBuffCur->pTarget += 4;

}


void NDR_Put_Char (		// Put a char from the Target to Source

) //-----------------------------------------------------------------------//
{
    GET_POINTER;


    *(char PAPI *) pBuffCur->pTarget = *(char PAPI *) pBuffCur->pSource;

    pBuffCur->pTarget += 1;
    pBuffCur->pSource += 1;

}


void NDR_Put_Short (		// Put a short from the Target to Source

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 2);
    ALIGNCUR(pSource, short);

    *(short PAPI *) pBuffCur->pTarget = *(short PAPI *) pBuffCur->pSource;

    pBuffCur->pTarget += 2;
    pBuffCur->pSource += 2;

}


void NDR_Put_Long (		// Put a from the Target to Source

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    ALIGN(pTarget, 4);
    ALIGNCUR(pSource, long);

    *(long PAPI *) pBuffCur->pTarget = *(long PAPI *) pBuffCur->pSource;

    pBuffCur->pTarget += 4;
    pBuffCur->pSource += 4;

}


void NDR_Put_String (		// Put a 0 terminated from the Target to Source

) //-----------------------------------------------------------------------//
{
    short cbString;
    GET_POINTER;

    ALIGN(pTarget, 2);
    ALIGNCUR(pSource, short);

    *(short PAPI *) pBuffCur->pTarget = cbString = _fstrlen(*(char PAPI * PAPI *) pBuffCur->pTarget);
    pBuffCur->pTarget += 2;

    NDRcopy(pBuffCur->pTarget, pBuffCur->pTarget, cbString);
    pBuffCur->pSource += cbString;

}

void NDR_Put_Memory (		// Put a block of memory from the Target to Source
unsigned int cb

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    NDRcopy(pBuffCur->pTarget, pBuffCur->pTarget, cb);
    pBuffCur->pSource += cb;
    pBuffCur->pTarget += cb;

}


short NDR_Get_B_Short (		// Return a short from the marshell buffer

) //-----------------------------------------------------------------------//
{
    short ret;
    GET_POINTER;

    ALIGN(pSource, 2);

    ret = *(short PAPI *) pBuffCur->pSource;
    pBuffCur->pSource += 2;

    if (pBuffCur->fSwap)
	return (((unsigned char *)&ret)[1]<<8 | ((unsigned char *)&ret)[0]);
    else
	return(ret);

}

long NDR_Get_B_Long (		// Return a long from the marshell buffer

) //-----------------------------------------------------------------------//
{
    long lval;
    GET_POINTER;

    ALIGN(pSource, 4);

    lval = *(long PAPI *) pBuffCur->pSource;
    pBuffCur->pSource += 4;

    if (pBuffCur->fSwap)
	SWAPLONG(lval)

    return(lval);

}

void NDR_Get_Byte(	// Copy a byte from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    *(char PAPI *) pBuffCur->pTarget = *(char PAPI *) pBuffCur->pSource;

    pBuffCur->pTarget += 1;
    pBuffCur->pSource += 1;

}

void NDR_Get_Char(	// Copy a char from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    unsigned char c;
    GET_POINTER;

    c = *(char PAPI *) pBuffCur->pSource;
    if (fEBCDIC)
	c =  ebcdic_to_ascii[c];

    *(char PAPI *) pBuffCur->pTarget = c;

    pBuffCur->pTarget += 1;
    pBuffCur->pSource += 1;

}

void NDR_Get_Short(	// Copy a short from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    short sval;
    GET_POINTER;

    ALIGN(pSource, 2);
    ALIGNCUR(pTarget, short);

    sval = *(short PAPI *) pBuffCur->pSource;
    if (pBuffCur->fSwap)
	SWAPSHORT(sval);

    *(short PAPI *) pBuffCur->pTarget = sval;

    pBuffCur->pSource += 2;
    pBuffCur->pTarget += 2;
}


void NDR_Get_Long(	// Copy a long from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    long lval;
    GET_POINTER;

    ALIGN(pSource, 4);
    ALIGNCUR(pTarget, long);

    lval = *(long PAPI *) pBuffCur->pSource;
    if (pBuffCur->fSwap)
	SWAPLONG(lval);

    *(long PAPI *) pBuffCur->pTarget = lval;

    pBuffCur->pSource += 4;
    pBuffCur->pTarget += 4;
}


void NDR_Get_Float(	// Copy a float from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    long lval;
    GET_POINTER;

    ALIGN(pSource, 4);
    ALIGNCUR(pTarget, long);

    lval = *(long PAPI *) pBuffCur->pSource;
    if (pBuffCur->fSwap)
	SWAPLONG(lval);

    switch(fFloatType) {

	case F_IEEE:
	  break;

	case F_VAX:
	case F_CRAY:
	case F_IBM:
	  ;
    }
    *(long PAPI *) pBuffCur->pTarget = lval;

    pBuffCur->pSource += 4;
    pBuffCur->pTarget += 4;
}

void NDR_Get_Double(	// Copy a double from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    long lval[2];
    GET_POINTER;

    ALIGN(pSource, 4);
    ALIGNCUR(pTarget, long);

    if (pBuffCur->fSwap) {

	lval[1] = *(long PAPI *) pBuffCur->pSource;
	SWAPLONG(lval[1]);

	lval[0] = *((long PAPI *) pBuffCur->pSource + 1);
	SWAPLONG(lval[0]);
    }
    else {
	lval[0] = *(long PAPI *) pBuffCur->pSource;
	lval[1] = *((long PAPI *) pBuffCur->pSource + 1);
    }

    switch(fFloatType) {

	case F_IEEE:
	  break;

	case F_VAX:
	case F_CRAY:
	case F_IBM:
	  ;
    }

    *(long PAPI *) pBuffCur->pTarget = lval[0];
    *((long PAPI *) pBuffCur->pTarget+1) = lval[1];

    pBuffCur->pSource += 8;
    pBuffCur->pTarget += 8;
}

void NDR_Get_String(	// Copy a string from the marshell buffer to the output buffer

) //-----------------------------------------------------------------------//
{
    short cbString;
    GET_POINTER;

    ALIGN(pSource, 2);
    ALIGNCUR(pTarget, long);

    cbString = *(short PAPI *) pBuffCur->pSource;
    if (pBuffCur->fSwap)
	SWAPSHORT(cbString);

    pBuffCur->pSource += 2;

    if (fEBCDIC) {

	while (--cbString >= 0)
	    *pBuffCur->pTarget++ = ebcdic_to_ascii[*pBuffCur->pSource++];
    }
    else {
	NDRcopy(pBuffCur->pTarget, pBuffCur->pSource, cbString);

	pBuffCur->pTarget += cbString;
	pBuffCur->pSource += cbString;
    }
}

void NDR_Get_Char_Array(   // Copy a character array doing byte translation

unsigned int Size
) //-----------------------------------------------------------------------//
{
    GET_POINTER;
}



// For unmarshalling, pointers are retrieved by Get_Ptr.  The current
// target offset is saved in a quque to be retrieved later.  If the returned
// pointer is NIL, then no offset is retained

void NDR_Get_Ptr(	 // Get a pointer and save offset for later

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    if (*(void PAPI * PAPI *)(pBuffCur->pSource))

	*pBuffCur->pPushLast = (void PAPI *)pBuffCur->pTarget;
    else
	*pBuffCur->pPushLast = 0;

    pBuffCur->pPushLast++;
    pBuffCur->pSource += 4;
    pBuffCur->pTarget += 4;
}

int NDR_Get_Peek_Ptr(	 // Return TRUE if the current saved pointer is valid

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    return(!Nilp(pBuffCur->pCur));
}

void NDR_Get_Next_Arg(	 // Set the target pointer to the next root item

) //-----------------------------------------------------------------------//
{
    GET_POINTER;

    // set alignment back to one suitable for walking the stack

    pBuffCur->alignment = mAlignType[sizeof(int)];

    pBuffCur->pTarget = pBuffCur->pTargetRoot;
    pBuffCur->pCur = (char PAPI *) pBuffCur->pPushLast;

    pBuffCur->pTargetRoot = 0;

}


int NDR_Get_Push_Unique(	// Push the current target pointer and allocate memory

unsigned int Size

) //-----------------------------------------------------------------------//
{
    void PAPI *pT;
    GET_POINTER;

    // first check to see if you have to pop back a level

    while(  (PP) pBuffCur->pCur >= pBuffCur->pPushLast ||
	   *(PP) pBuffCur->pCur == GET_END_LIST) {

	pBuffCur->pCur = (char PAPI *)pBuffCur->pPushRet;
	pBuffCur->pPushRet = (PP) (PP) pBuffCur->pCur[-1];
    }

    pT = *(PP)(pBuffCur->pCur);
    *(PP)pBuffCur->pCur = GET_END_LIST;

    if (!Nilp(pT)) {

	// there exists a valid pointer in the marshell buffer

	pT = *(PP)pT;

	// if there is no pointer to unmarshell into, allocate one

	if (Nilp(pT))
	    pT = (pBuffCur->pAllocator)(Size);

	// if your leaving the root level, remember it for Next_Arg

	if (Nilp(pBuffCur->pTargetRoot))
	     pBuffCur->pTargetRoot = pBuffCur->pTarget;

	// push the return address

	*(PP) pBuffCur->pCur = pBuffCur->pPushRet;
	pBuffCur->pPushRet = (PP)pBuffCur->pCur+1;

	pBuffCur->pTarget = pT;
	return (1);
    }

    pBuffCur->pCur += 4;
    return(0);
}