/* 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
