/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <assert.h>

#include "Tpm.h"
#include "Marshal.h"
#include "TableMarshal.h"

#if TABLE_DRIVEN_MARSHAL

extern ArrayMarshal_mst ArrayLookupTable[];

extern UINT16 MarshalLookupTable[];

typedef struct { int a; } External_Structure_t;

extern struct Exernal_Structure_t MarshalData;

#define IS_SUCCESS(UNMARSHAL_FUNCTION)                                              \
    (TPM_RC_SUCCESS == (result = (UNMARSHAL_FUNCTION)))

marshalIndex_t IntegerDispatch[] = {
    UINT8_MARSHAL_REF, UINT16_MARSHAL_REF, UINT32_MARSHAL_REF, UINT64_MARSHAL_REF,
    INT8_MARSHAL_REF,  INT16_MARSHAL_REF,  INT32_MARSHAL_REF,  INT64_MARSHAL_REF
};

#if 1
#define GetDescriptor(reference)                                                    \
    ((MarshalHeader_mst *)(((BYTE *)(&MarshalData)) + (reference & NULL_MASK)))
#else
static const MarshalHeader_mst *GetDescriptor(marshalIndex_t index)
{
    const MarshalHeader_mst    *mst = MarshalLookupTable[index & NULL_MASK];
    return mst;
}
#endif

#define GetUnionDescriptor(_index_)                                                 \
    ((UnionMarshal_mst *)GetDescriptor(_index_))
#define GetArrayDescriptor(_index_)                                                 \
    ((ArrayMarshal_mst *))(ArrayLookupTable[_index_ & NULL_MASK])

//*** GetUnmarshaledInteger()
// Gets the unmarshaled value and normalizes it to a UIN32 for other
// processing (comparisons and such).
static UINT32 GetUnmarshaledInteger(
    marshalIndex_t       type,
    const void          *target
)
{
    int     size = (type & SIZE_MASK);
//
    if(size == FOUR_BYTES)
        return *((UINT32 *)target);
    if(type & IS_SIGNED)
    {
        if(size == TWO_BYTES)
            return (UINT32)*((int16_t *)target);
        return (UINT32)*((int8_t *)target);
    }
    if(size == TWO_BYTES)
        return (UINT32)*((UINT16 *)target);
    return (UINT32)*((UINT8 *)target);
}

static UINT32 GetSelector(
    void                *structure,
    const UINT16        *values,
    UINT16               descriptor
)
{
    unsigned             sel = GET_ELEMENT_NUMBER(descriptor);
    // Get the offset of the value in the unmarshaled structure
    const UINT16        *entry = &values[(sel * 3)];
//
    return GetUnmarshaledInteger(GET_ELEMENT_SIZE(entry[0]),
                        ((UINT8 *)structure) + entry[2]);
}

static TPM_RC UnmarshalBytes(
    UINT8               *target,        // IN/OUT: place to put the bytes
    UINT8               **buffer,       // IN/OUT: source of the input data
    INT32               *size,          // IN/OUT: remaining bytes in the input buffer
    int                  count          // IN: number of bytes to get
)
{
    if((*size -= count) >= 0)
    {
        memcpy(target, *buffer, count);
        *buffer += count;
        return TPM_RC_SUCCESS;
    }
    return TPM_RC_INSUFFICIENT;
}

//*** MarshalBytes()
// Marshal an array of bytes.
static UINT16 MarshalBytes(
    UINT8               *source,
    UINT8               **buffer,
    INT32               *size,
    int32_t              count
)
{
    if(buffer != NULL)
    {
        if(size != NULL && (size -= count) < 0)
            return 0;
        memcpy(*buffer, source, count);
        *buffer += count;
    }
    return (UINT16)count;
}

//*** ArrayUnmarshal()
// Unmarshal an array. The 'index' is of the form: 'type'_ARRAY_MARSHAL_INDEX.
static TPM_RC ArrayUnmarshal(
    UINT16               index,         // IN: the type of the array
    UINT8               *target,        // IN: target for the data
    UINT8               **buffer,       // IN/OUT: place to get the data
    INT32               *size,          // IN/OUT: remaining unmarshal data
    UINT32               count          // IN: number of values of 'index' to
                                        //      unmarshal
)
{
    marshalIndex_t       which = ArrayLookupTable[index & NULL_MASK].type;
    UINT16               stride = ArrayLookupTable[index & NULL_MASK].stride;
    TPM_RC               result;
//
    if(stride == 1) // A byte array
        result = UnmarshalBytes(target, buffer, size, count);
    else
    {
        which |= index & NULL_FLAG;
        for(result = TPM_RC_SUCCESS; count > 0; target += stride, count--)
            if(!IS_SUCCESS(Unmarshal(which, target, buffer, size)))
                break;
    }
    return result;
}

//*** ArrayMarshal()
static UINT16 ArrayMarshal(
    UINT16               index,         // IN: the type of the array
    UINT8               *source,        // IN: source of the data
    UINT8               **buffer,       // IN/OUT: place to put the data
    INT32               *size,          // IN/OUT: amount of space for the data
    UINT32               count          // IN: number of values of 'index' to marshal
)
{
    marshalIndex_t      which = ArrayLookupTable[index & NULL_MASK].type;
    UINT16              stride = ArrayLookupTable[index & NULL_MASK].stride;
    UINT16              retVal;
//
    if(stride == 1) // A byte array
        return MarshalBytes(source, buffer, size, count);
    which |= index & NULL_FLAG;
    for(retVal = 0
        ; count > 0
        ; source += stride, count--)
        retVal += Marshal(which, source, buffer, size);

    return retVal;
}

//***UnmarshalUnion()
TPM_RC
UnmarshalUnion(
    UINT16               typeIndex,         // IN: the thing to unmarshal
    void                *target,            // IN: were the data goes to
    UINT8               **buffer,           // IN/OUT: the data source buffer
    INT32               *size,              // IN/OUT: the remaining size
    UINT32               selector
)
{
    int                  i;
    UnionMarshal_mst    *ut = GetUnionDescriptor(typeIndex);
    marshalIndex_t       selected;
//
    for(i = 0; i < ut->countOfselectors; i++)
    {
        if(selector == ut->selectors[i])
        {
            UINT8           *offset = ((UINT8 *)ut) + ut->offsetOfUnmarshalTypes;
            // Get the selected thing to unmarshal
            selected = ((marshalIndex_t *)offset)[i];
            if(ut->modifiers & IS_ARRAY_UNION)
                return UnmarshalBytes(target, buffer, size, selected);
            else
            {
                // Propagate NULL_FLAG if the null flag was
                // propagated to the structure containing the union
                selected |= (typeIndex & NULL_FLAG);
                return Unmarshal(selected, target, buffer, size);
            }
        }
    }
    // Didn't find the value.
    return TPM_RC_SELECTOR;
}

//*** MarshalUnion()
UINT16
MarshalUnion(
    UINT16               typeIndex,         // IN: the thing to marshal
    void                *source,            // IN: were the data comes from
    UINT8               **buffer,           // IN/OUT: the data source buffer
    INT32               *size,              // IN/OUT: the remaining size
    UINT32               selector           // IN: the union selector
)
{
    int                  i;
    UnionMarshal_mst    *ut = GetUnionDescriptor(typeIndex);
    marshalIndex_t       selected;
//
    for(i = 0; i < ut->countOfselectors; i++)
    {
        if(selector == ut->selectors[i])
        {
            UINT8           *offset = ((UINT8 *)ut) + ut->offsetOfUnmarshalTypes;
            // Get the selected thing to unmarshal
            selected = ((marshalIndex_t *)offset)[i];
            if(ut->modifiers & IS_ARRAY_UNION)
                return MarshalBytes(source, buffer, size, selected);
            else
                return Marshal(selected, source, buffer, size);
        }
    }
    if(size != NULL)
        *size = -1;
    return 0;
}

TPM_RC
UnmarshalInteger(
    int                  iSize,             // IN: Number of bytes in the integer
    void                *target,            // OUT: receives the integer
    UINT8               **buffer,           // IN/OUT: source of the data
    INT32               *size,              // IN/OUT: amount of data available
    UINT32              *value              // OUT: optional copy of 'target'
)
{
    // This is just to save typing
#define _MB_ (*buffer)
    // The size is a power of two so convert to regular integer
    int              bytes = (1 << (iSize & SIZE_MASK));
//
    // Check to see if there is enough data to fulfill the request
    if((*size -= bytes) >= 0)
    {
        // The most comon size
        if(bytes == 4)
        {
            *((UINT32 *)target) = (UINT32)((((((_MB_[0] << 8) | _MB_[1]) << 8)
                                           | _MB_[2]) << 8) | _MB_[3]);
            // If a copy is needed, copy it.
            if(value != NULL)
                *value = *((UINT32 *)target);
        }
        else if(bytes == 2)
        {
            *((UINT16 *)target) = (UINT16)((_MB_[0] << 8) | _MB_[1]);
            // If a copy is needed, copy with the appropriate sign extension
            if(value != NULL)
            {
                if(iSize & IS_SIGNED)
                    *value = (UINT32)(*((INT16 *)target));
                else
                    *value = (UINT32)(*((UINT16 *)target));
            }
        }
        else if(bytes == 1)
        {
            *((UINT8*)target) = (UINT8)_MB_[0];
            // If a copy is needed, copy with the appropriate sign extension
            if(value != NULL)
            {
                if(iSize & IS_SIGNED)
                    *value = (UINT32)(*((INT8 *)target));
                else
                    *value = (UINT32)(*((UINT8 *)target));
            }
        }
        else
        {
            // There is no input type that is a 64-bit value other than a UINT64. So
            // there is no reason to do anything other than unmarshal it.
            *((UINT64 *)target) = BYTE_ARRAY_TO_UINT64(*buffer);
        }
        *buffer += bytes;
        return TPM_RC_SUCCESS;
#undef _MB_
    }
    return TPM_RC_INSUFFICIENT;
}

//*** Unmarshal()
// This is the function that performs unmarshaling of different numbered types. Each
// TPM type has a number. The number is used to lookup the address of the data
// structure that describes how to unmarshal that data type.
//
TPM_RC
Unmarshal(
    UINT16               typeIndex,         // IN: the thing to marshal
    void                *target,            // IN: were the data goes from
    UINT8               **buffer,           // IN/OUT: the data source buffer
    INT32               *size               // IN/OUT: the remaining size
)
{
    const MarshalHeader_mst     *sel;
    TPM_RC                       result;
//
    sel = GetDescriptor(typeIndex);
    switch(sel->marshalType)
    {
        case UINT_MTYPE:
        {
            // A simple signed or unsigned integer value.
            return UnmarshalInteger(sel->modifiers, target,
                                      buffer, size, NULL);
        }
        case VALUES_MTYPE:
        {
            // This is the general-purpose structure that can handle things like
            // TPMI_DH_PARENT that has multiple ranges, multiple singles and a
            // 'null' value. When things cover a large range with holes in the range
            // they can be turned into multiple ranges. There is no option for a bit
            // field.
            // The structure is:
            //  typedef const struct ValuesMarshal_mst
            //  {
            //      UINT8           marshalType;        // VALUES_MTYPE
            //      UINT8           modifiers;
            //      UINT8           errorCode;
            //      UINT8           ranges;
            //      UINT8           singles;
            //      UINT32          values[1];
            //  } ValuesMarshal_mst;
            // Unmarshal the base type
            UINT32                   val;
            if(IS_SUCCESS(UnmarshalInteger(sel->modifiers, target,
                                           buffer, size, &val)))
            {
                ValuesMarshal_mst   *vmt = ((ValuesMarshal_mst *)sel);
                const UINT32        *check = vmt->values;
            //
                // if the TAKES_NULL flag is set, then the first entry in the values
                // list is the NULL value. Iy is not included in the 'ranges' or
                // 'singles' count.
                if((vmt->modifiers & TAKES_NULL) && (val == *check++))
                {
                    if((typeIndex & NULL_FLAG) == 0)
                        result = (TPM_RC)(sel->errorCode);
                }
                // No NULL value or input is not the NULL value
                else
                {
                    int               i;
                //
                    // Check all the min-max ranges.
                    for(i = vmt->ranges - 1; i >= 0; check = &check[2], i--)
                        if((UINT32)(val - check[0]) <= check[1])
                            break;
                    // if the input is in a selected range, then i >= 0
                    if(i < 0)
                    {
                        // Not in any range, so check sigles
                        for(i = vmt->singles - 1; i >= 0; i--)
                            if(val == check[i])
                                break;
                    }
                    // If input not in range and not in any single so return error
                    if(i < 0)
                        result = (TPM_RC)(sel->errorCode);
                }
            }
            break;
        }
        case TABLE_MTYPE:
        {
            // This is a table with or without bit checking. The input is checked
            // against each value in the table. If the value is in the table, and
            // a bits table is present, then the bit field is checked to see if the
            // indicated value is implemented. For example, if there is a table of
            // allowed RSA key sizes and the 2nd entry matches, then the 2nd bit in
            // the bit field is checked to see if that allowed size is implemented 
            // in this TPM.
            //  typedef const struct TableMarshal_mst
            //  {
            //      UINT8           marshalType;        // TABLE_MTYPE
            //      UINT8           modifiers;
            //      UINT8           errorCode;
            //      UINT8           singles;
            //      UINT32          values[singles + 1 if TAKES_NULL];
            //  } TableMarshal_mst;

            UINT32                  val;
        //
            // Unmarshal the base type
            if(IS_SUCCESS(UnmarshalInteger(sel->modifiers, target,
                                            buffer, size, &val)))
            {
                TableMarshal_mst    *tmt = ((TableMarshal_mst *)sel);
                const UINT32        *check = tmt->values;
            //
                // If this type has a null value, then it is the first value in the
                // list of values. It does not count in the count of values
                if((tmt->modifiers & TAKES_NULL) && (val == *check++))
                {
                    if((typeIndex & NULL_FLAG) == 0)
                        result = (TPM_RC)(sel->errorCode);
                }
                else
                {
                    int               i;
                //
                    // Process the singles
                    for(i = tmt->singles - 1; i >= 0; i--)
                    {
                        // does the input value match the value in the table
                        if(val == check[i])
                        {
                            // If there is an associated bit table, make sure that
                            // the corresponding bit is SET
                            if((HAS_BITS & tmt->modifiers)
                               && (!IS_BIT_SET32(i, &(check[tmt->singles]))))
                                // if not SET, then this is a failure.
                                i = -1;
                            break;
                        }
                    }
                    // error if not found or bit not SET
                    if(i < 0)
                        result = (TPM_RC)(sel->errorCode);
                }
            }
            break;
        }
        case MIN_MAX_MTYPE:
        {
            // A MIN_MAX is a range. It can have a bit field and a NULL value that is
            // outside of the range. If the input value is in the min-max range then
            // it is valid unless there is an associated bit field. Otherwise, it
            // it is only valid if the corresponding value in the bit field is SET.
            // The min value is 'values[0]' or 'values[1]' if there is a NULL value.
            // The max value is the value after min. The max value is in the table as
            // max minus min. This allows 'val' to be subtracted from min and then
            // checked against max with one unsigned comparison. If present, the bit
            // field will be the first 'values' after max.
            //  typedef const struct MinMaxMarshal_mst
            //  {
            //      UINT8           marshalType;        // MIN_MAX_MTYPE
            //      UINT8           modifiers;
            //      UINT8           errorCode;
            //      UINT32          values[2 + 1 if TAKES_NULL];
            //  } MinMaxMarshal_mst;
            UINT32               val;
        //
            // A min-max has a range. It can have a bit-field that is indexed to the
            // min value (something that matches min has a bit at 0. This is useful
            // for algorithms. The min-max define a range of algorithms to be checked
            // and the bit field can check to see if the algorithm in that range is
            // allowed.
            if(IS_SUCCESS(UnmarshalInteger(sel->modifiers, target,
                                           buffer, size, &val)))
            {
                MinMaxMarshal_mst   *mmt = (MinMaxMarshal_mst *)sel;
                const UINT32        *check = mmt->values;
            //
                // If this type takes a NULL, see if it matches. This
                if((mmt->modifiers & TAKES_NULL) && (val == *check++))
                {
                    if((typeIndex & NULL_FLAG) == 0)
                        result = (TPM_RC)(mmt->errorCode);
                }
                else
                {
                    val -= *check;
                    if((val > check[1])
                       || ((mmt->modifiers & HAS_BITS) &&
                           !IS_BIT_SET32(val, &check[2])))
                        result = (TPM_RC)(mmt->errorCode);
                }
            }
            break;
        }
        case ATTRIBUTES_MTYPE:
        {
            //  This is used for TPMA values.
            UINT32                   mask;
            AttributesMarshal_mst   *amt = (AttributesMarshal_mst *)sel;
        //
            if(IS_SUCCESS(UnmarshalInteger(sel->modifiers, target,
                                    buffer, size, &mask)))
            {
                if((mask & amt->attributeMask) != 0)
                    result = TPM_RC_RESERVED_BITS;
            }
            break;
        }
        case STRUCTURE_MTYPE:
        {
            // A structure (not a union). A structure has elements (one defined per
            // row). Three UINT16 values are used for each row. The first indicates
            // the type of the entry. They choices are: simple, union, or array. A
            // simple type can be a simple integer or another structure. It can also
            // be a specific "interface type." For example, when a structure entry is
            // a value that is used define the dimension of an array, the entry of
            // the structure will reference a "synthetic" interface type, most often
            // a min-max value. If the type of the entry is union or array, then the
            // first value indicates which of the previous elements provides the union
            // selector or the array dimension. That previous entry is referenced in
            // the unmarshaled structure in memory (Not the marshaled buffer). The
            // previous entry indicates the location in the structure of the value.
            // The second entry of each structure entry indicated the index of the
            // type associated with the entry. This is an index into the array of
            // arrays or the union table (merged with the normal table in this
            // implementation). The final entry is the offset in the unmarshaled
            // structure where the value is located. This is the offsetof(STRUcTURE,
            // element). This value is added to the input 'target' or 'source' value
            // to determine where the value goes.
            StructMarshal_mst   *mst = (StructMarshal_mst *)sel;
            int                  i;
            const UINT16        *value = mst->values;
        //
            for(result = TPM_RC_SUCCESS, i = mst->elements
                ; (TPM_RC_SUCCESS == result) && (i > 0)
                ; value = &value[3], i--)
            {
                UINT16           descriptor = value[0];
                marshalIndex_t   index = value[1];
                // The offset of the object in the structure is in the last value in
                // the triplet. Add that value to the start of the structure
                UINT8           *offset = ((UINT8 *)target) + value[2];
            //
                if ((ELEMENT_PROPAGATE & descriptor)
                    && (typeIndex & NULL_FLAG))
                    index |= NULL_FLAG;
                switch(GET_ELEMENT_TYPE(descriptor))
                {
                    case SIMPLE_STYPE:
                    {
                        result = Unmarshal(index, offset, buffer, size);
                        break;
                    }
                    case UNION_STYPE:
                    {
                        UINT32               choice;
                    //
                        // Get the selector or array dimension value
                        choice = GetSelector(target, mst->values, descriptor);
                        result = UnmarshalUnion(index, offset, buffer, size, choice);
                        break;
                    }
                    case ARRAY_STYPE:
                    {
                        UINT32            dimension;
                    //
                        dimension = GetSelector(target, mst->values, descriptor);
                        result = ArrayUnmarshal(index, offset, buffer,
                                                size, dimension);
                        break;
                    }
                    default:
                        result = TPM_RC_FAILURE;
                        break;
                }
            }
            break;
        }
        case TPM2B_MTYPE:
        {
            // A primitive TPM2B. A size and byte buffer. The single value (other than
            // the tag) references the synthetic 'interface' value for the size
            // parameter.
            Tpm2bMarshal_mst        *m2bt = (Tpm2bMarshal_mst *)sel;
        //
            if(IS_SUCCESS(Unmarshal(m2bt->sizeIndex, target, buffer, size)))
                result = UnmarshalBytes(((TPM2B *)target)->buffer,
                               buffer, size, *((UINT16 *)target));
            break;
        }
        case TPM2BS_MTYPE:
        {
            // This is used when a TPM2B contains a structure.
            Tpm2bsMarshal_mst   *m2bst = (Tpm2bsMarshal_mst *)sel;
            INT32          count;
        //
            if(IS_SUCCESS(Unmarshal(m2bst->sizeIndex, target, buffer, size)))
            {
                // fetch the size value and convert it to a 32-bit count value
                count = (int32_t)*((UINT16 *)target);
                if(count == 0)
                {
                    if(m2bst->modifiers & SIZE_EQUAL)
                        result = TPM_RC_SIZE;
                }
                else if((*size -= count) >= 0)
                {
                    marshalIndex_t  index = m2bst->dataIndex;
                //
                    // If this type propigates a null (PROPIGATE_NULL), propigate it
                    if ((m2bst->modifiers & PROPAGATE_NULL) 
                        && (typeIndex & typeIndex))
                        index |= NULL_FLAG;
                    // The structure might not start two bytes after the start of the
                    // size field. The offset to the start of the structure is between
                    // 2 and 8 bytes. This is encoded into the low 4 bits of the
                    // modifiers byte byte
                    if(IS_SUCCESS(Unmarshal(index,
                        ((UINT8 *)target) + (m2bst->modifiers & OFFSET_MASK),
                                           buffer, &count)))
                    {
                        if(count != 0)
                            result = TPM_RC_SIZE;
                    }
                }
                else
                    result = TPM_RC_INSUFFICIENT;
            }
            break;
        }
        case LIST_MTYPE:
        {
            // Used for a list. A list is a qualified 32-bit 'count' value followed
            // by a type indicator.
            ListMarshal_mst     *mlt = (ListMarshal_mst *)sel;
            marshalIndex_t      index = mlt->arrayRef;
        //
            if(IS_SUCCESS(Unmarshal(mlt->sizeIndex, target, buffer, size)))
            {
                // If this type propigates a null (PROPIGATE_NULL), propigate it
                if ((mlt->modifiers & PROPAGATE_NULL)
                    && (typeIndex & NULL_FLAG))
                    index |= NULL_FLAG;
                result = ArrayUnmarshal(index,
                    ((UINT8 *)target) +(mlt->modifiers & OFFSET_MASK),
                                        buffer, size, *((UINT32 *)target));
            }
            break;
        }
        case NULL_MTYPE:
        {
            result = TPM_RC_SUCCESS;
            break;
        }
#if 0
        case COMPOSITE_MTYPE:
        {
            CompositeMarshal_mst    *mct = (CompositeMarshal_mst *)sel;
            int                      i;
            UINT8                   *buf = *buffer;
            INT32                   sz = *size;
        //
            result = TPM_RC_VALUE;
            for(i = GET_ELEMENT_COUNT(mct->modifiers) - 1; i <= 0; i--)
            {
                marshalIndex_t      index = mct->types[i];
            //
                // This type might take a null so set it in each called value, just
                // in case it is needed in that value. Only one value in each
                // composite should have the takes null SET.
                index |= typeIndex & NULL_MASK;
                result = Unmarshal(index, target, buffer, size);
                if(result == TPM_RC_SUCCESS)
                    break;
                // Each of the composite values does its own unmarshaling. This
                // has some execution overhead if it is unmarshaled multiple times
                // but it saves code size in not having to reproduce the various
                // unmarshaling types that can be in a composite. So, what this means
                // is that the buffer pointer and size have to be reset for each
                // unmarshaled value.
                *buffer = buf;
                *size = sz;
            }
            break;
        }
#endif // 0
        default:
        {
            result = TPM_RC_FAILURE;
            break;
        }
    }
    return result;
}

//*** Marshal()
// This is the function that drives marshaling of output. Because there is no
// validation of the output, there is a lot less code.
UINT16 Marshal(
    UINT16               typeIndex,         // IN: the thing to marshal
    void                *source,            // IN: were the data comes from
    UINT8               **buffer,           // IN/OUT: the data source buffer
    INT32               *size               // IN/OUT: the remaining size
)
{
#define _source  ((UINT8 *)source)

    const MarshalHeader_mst     *sel;
    UINT16                       retVal;
//
    sel = GetDescriptor(typeIndex);
    switch(sel->marshalType)
    {
        case VALUES_MTYPE:
        case UINT_MTYPE:
        case TABLE_MTYPE:
        case MIN_MAX_MTYPE:
        case ATTRIBUTES_MTYPE:
        case COMPOSITE_MTYPE:
        {
#if BIG_ENDIAN_TPM
#define MM16    0
#define MM32    0
#define MM64    0
#else
// These flip the constant index values so that they count in reverse order when doing
// little-endian stuff
#define MM16    1
#define MM32    3
#define MM64    7
#endif
// Just change the name and cast the type of the input parameters for typing purposes
#define mb (*buffer)
#define _source ((UINT8 *)source)
            retVal = (1 << (sel->modifiers & SIZE_MASK));
            if(buffer != NULL)
            {
                if((size == NULL) || ((*size -= retVal) >= 0))
                {
                    if(retVal == 4)
                    {
                        mb[0 ^ MM32] = _source[0];
                        mb[1 ^ MM32] = _source[1];
                        mb[2 ^ MM32] = _source[2];
                        mb[3 ^ MM32] = _source[3];
                    }
                    else if(retVal == 2)
                    {
                        mb[0 ^ MM16] = _source[0];
                        mb[1 ^ MM16] = _source[1];
                    }
                    else if(retVal == 1)
                        mb[0] = _source[0];
                    else
                    {
                        mb[0 ^ MM64] = _source[0];
                        mb[1 ^ MM64] = _source[1];
                        mb[2 ^ MM64] = _source[2];
                        mb[3 ^ MM64] = _source[3];
                        mb[4 ^ MM64] = _source[4];
                        mb[5 ^ MM64] = _source[5];
                        mb[6 ^ MM64] = _source[6];
                        mb[7 ^ MM64] = _source[7];
                    }
                    *buffer += retVal;
                }
            }
            break;
        }
        case STRUCTURE_MTYPE:
        {
//#define _mst  ((StructMarshal_mst *)sel)
            StructMarshal_mst *mst = ((StructMarshal_mst *)sel);
            int              i;
            const UINT16  *value = mst->values;

        //
            for(retVal = 0, i = mst->elements; i > 0; value = &value[3], i--)
            {
                UINT16           des = value[0];
                marshalIndex_t   index = value[1];
                UINT8           *offset = _source + value[2];
            //
                switch(GET_ELEMENT_TYPE(des))
                {
                    case UNION_STYPE:
                    {
                        UINT32           choice;
                    //
                        choice = GetSelector(source, mst->values, des);
                        retVal += MarshalUnion(index, offset, buffer, size, choice);
                        break;
                    }
                    case ARRAY_STYPE:
                    {
                        UINT32               count;
                    //
                        count = GetSelector(source, mst->values, des);
                        retVal += ArrayMarshal(index, offset, buffer, size, count);
                        break;
                    }
                    case SIMPLE_STYPE:
                    default:
                    {
                        // This is either another structure or a simple type
                        retVal += Marshal(index, offset, buffer, size);
                        break;
                    }
                }
            }
            break;
        }
        case TPM2B_MTYPE:
        {
            // Get the number of bytes being marshaled
            INT32         val = (int32_t)*((UINT16 *)source);
        //
            retVal = Marshal(UINT16_MARSHAL_REF, source, buffer, size);

            // This is a standard 2B with a byte buffer
            retVal += MarshalBytes(((TPM2B *)_source)->buffer, buffer, size, val);
            break;
        }
        case TPM2BS_MTYPE: // A structure in a TPM2B
        {
            Tpm2bsMarshal_mst       *m2bst = (Tpm2bsMarshal_mst *)sel;
            UINT8                   *offset;
            UINT16                   amount;
            UINT8                   *marshaledSize;
        //
            // Save the address of where the size should go
            marshaledSize = *buffer;

            // marshal the size (checks the space and advanced the pointer)
            retVal = Marshal(UINT16_MARSHAL_REF, source, buffer, size);

            // This gets the 'offsetof' the structure to marshal. It was placed in the
            // modifiers byte because the offset from the start of the TPM2B to the
            // start of the structure is going to be less than 8 and the modifiers
            // byte isn't needed for anything else.
            offset = _source + (m2bst->modifiers & SIGNED_MASK);

            // Marshal the structure and get its size
            amount = Marshal(m2bst->dataIndex, offset, buffer, size);

            // put the size in the space used when the size was marshaled.
            if(buffer != NULL)
                UINT16_TO_BYTE_ARRAY(amount, marshaledSize);
            retVal += amount;
            break;
        }
        case LIST_MTYPE:
        {
            ListMarshal_mst *    mlt = ((ListMarshal_mst *)sel);
            UINT8               *offset = _source + (mlt->modifiers & SIGNED_MASK);
            retVal = Marshal(UINT32_MARSHAL_REF, source, buffer, size);
            retVal += ArrayMarshal((marshalIndex_t)(mlt->arrayRef), offset,
                                   buffer, size, *((UINT32 *)source));
            break;
        }
        case NULL_MTYPE:
            retVal = 0;
            break;
       case ERROR_MTYPE:
       default:
        {
            if(size != NULL)
               *size = -1;
            retVal = 0;
            break;
        }
    }
    return retVal;

}

#endif // TABLE_DRIVEN_MARSHAL
