Huw Davies : rpcrt4: Support for non-encapsulated unions.

Alexandre Julliard julliard at wine.codeweavers.com
Fri May 5 12:10:19 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: b1d5158980a89dd92d23b2ee4f6fd5d6f705296d
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=b1d5158980a89dd92d23b2ee4f6fd5d6f705296d

Author: Huw Davies <huw at codeweavers.com>
Date:   Fri Apr 28 14:28:24 2006 +0100

rpcrt4: Support for non-encapsulated unions.

---

 dlls/rpcrt4/ndr_marshall.c |  264 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 259 insertions(+), 5 deletions(-)

diff --git a/dlls/rpcrt4/ndr_marshall.c b/dlls/rpcrt4/ndr_marshall.c
index 6830530..66a4caa 100644
--- a/dlls/rpcrt4/ndr_marshall.c
+++ b/dlls/rpcrt4/ndr_marshall.c
@@ -1422,6 +1422,20 @@ void WINAPI NdrSimpleStructFree(PMIDL_ST
 }
 
 
+static long NonEncapsulatedUnionSize(PMIDL_STUB_MESSAGE pStubMsg,
+                                     PFORMAT_STRING pFormat)
+{
+    pFormat += 2;
+    if (pStubMsg->fHasNewCorrDesc)
+        pFormat += 6;
+    else
+        pFormat += 4;
+
+    pFormat += *(const SHORT*)pFormat;
+    TRACE("size %d\n", *(const SHORT*)pFormat);
+    return *(const SHORT*)pFormat;
+}
+
 unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg,
                                          PFORMAT_STRING pFormat)
 {
@@ -1433,6 +1447,8 @@ unsigned long WINAPI EmbeddedComplexSize
     return *(const WORD*)&pFormat[2];
   case RPC_FC_USER_MARSHAL:
     return *(const WORD*)&pFormat[4];
+  case RPC_FC_NON_ENCAPSULATED_UNION:
+    return NonEncapsulatedUnionSize(pStubMsg, pFormat);
   default:
     FIXME("unhandled embedded type %02x\n", *pFormat);
   }
@@ -2799,6 +2815,83 @@ void WINAPI NdrEncapsulatedUnionFree(PMI
     FIXME("stub\n");
 }
 
+static PFORMAT_STRING get_arm_offset_from_union_arm_selector(PMIDL_STUB_MESSAGE pStubMsg,
+                                                             unsigned long discriminant,
+                                                             PFORMAT_STRING pFormat)
+{
+    unsigned short num_arms, arm, type;
+
+    num_arms = *(const SHORT*)pFormat & 0x0fff;
+    pFormat += 2;
+    for(arm = 0; arm < num_arms; arm++)
+    {
+        if(discriminant == *(const ULONG*)pFormat)
+        {
+            pFormat += 4;
+            break;
+        }
+        pFormat += 6;
+    }
+
+    type = *(const unsigned short*)pFormat;
+    TRACE("type %04x\n", type);
+    if(arm == num_arms) /* default arm extras */
+    {
+        if(type == 0xffff)
+        {
+            FIXME("should raise an exception here\n");
+            return NULL;
+        }
+        if(type == 0)
+        {
+            /* Don't marshall any type. FIXME is this correct? */
+            return NULL;
+        }
+    }
+    return pFormat;
+}
+
+static PFORMAT_STRING get_non_encapsulated_union_arm(PMIDL_STUB_MESSAGE pStubMsg,
+                                                     unsigned char *pMemory,
+                                                     PFORMAT_STRING pFormat)
+{
+    ULONG value;
+
+    pFormat = ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat,
+                                           0, &value);
+    TRACE("got switch value %lx\n", value);
+    pFormat += *(const SHORT*)pFormat;
+    pFormat += 2;
+
+    return get_arm_offset_from_union_arm_selector(pStubMsg, value, pFormat);
+}
+
+static unsigned char *get_conformance_address(PMIDL_STUB_MESSAGE pStubMsg,
+                                              unsigned char *pMemory,
+                                              PFORMAT_STRING pFormat)
+{
+    short ofs = *(short *)&pFormat[2];
+    LPVOID ptr = NULL;
+
+    switch (pFormat[0] & 0xf0)
+    {
+    case RPC_FC_NORMAL_CONFORMANCE:
+        ptr = pMemory;
+        break;
+    default:
+        FIXME("Conformance type %x\n", pFormat[0]);
+        return NULL;
+    }
+
+    if(pFormat[1])
+    {
+        FIXME("Conformance op %x\n", pFormat[1]);
+        return NULL;
+    }
+
+    return (unsigned char *)ptr + ofs;
+}
+
 /***********************************************************************
  *           NdrNonEncapsulatedUnionMarshall [RPCRT4.@]
  */
@@ -2806,19 +2899,143 @@ unsigned char *  WINAPI NdrNonEncapsulat
                                 unsigned char *pMemory,
                                 PFORMAT_STRING pFormat)
 {
-    FIXME("stub\n");
+    unsigned char *discriminant;
+    unsigned short type;
+
+    TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
+    pFormat++;
+
+    /* Marshall discriminant */
+    discriminant = get_conformance_address(pStubMsg, pMemory, pFormat + 1);
+    NdrBaseTypeMarshall(pStubMsg, discriminant, pFormat);
+    pFormat++;
+
+    pFormat = get_non_encapsulated_union_arm(pStubMsg, pMemory, pFormat);
+    if(!pFormat)
+        return NULL;
+
+    type = *(const unsigned short*)pFormat;
+    if(type & 0x8000)
+    {
+        pFormat++; 
+        return NdrBaseTypeMarshall(pStubMsg, pMemory, pFormat);
+    }
+    else
+    {
+        PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat;
+        NDR_MARSHALL m = NdrMarshaller[*desc & NDR_TABLE_MASK];
+        if (m)
+        {
+            switch(*desc)
+            {
+            case RPC_FC_RP:
+            case RPC_FC_UP:
+            case RPC_FC_OP:
+            case RPC_FC_FP:
+                pMemory = *(void**)pMemory;
+                break;
+            }
+            m(pStubMsg, pMemory, desc);
+        }
+        else FIXME("no marshaller for embedded type %02x\n", *desc);
+    }
     return NULL;
 }
 
-/***********************************************************************
- *           NdrNonEncapsulatedUnionUnmarshall [RPCRT4.@]
+static long unmarshall_discriminant(PMIDL_STUB_MESSAGE pStubMsg,
+                                    PFORMAT_STRING *ppFormat)
+{
+    long discriminant = 0;
+
+    switch(**ppFormat)
+    {
+    case RPC_FC_BYTE:
+    case RPC_FC_CHAR:
+    case RPC_FC_SMALL:
+    case RPC_FC_USMALL:
+        discriminant = *(UCHAR *)pStubMsg->Buffer;
+        pStubMsg->Buffer += sizeof(UCHAR);
+        break;
+    case RPC_FC_WCHAR:
+    case RPC_FC_SHORT:
+    case RPC_FC_USHORT:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT) - 1);
+        discriminant = *(USHORT *)pStubMsg->Buffer;
+        pStubMsg->Buffer += sizeof(USHORT);
+        break;
+    case RPC_FC_LONG:
+    case RPC_FC_ULONG:
+        ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG) - 1);
+        discriminant = *(ULONG *)pStubMsg->Buffer;
+        pStubMsg->Buffer += sizeof(ULONG);
+        break;
+    default:
+        FIXME("Unhandled base type: 0x%02x\n", **ppFormat);
+    }
+    (*ppFormat)++;
+
+    if (pStubMsg->fHasNewCorrDesc)
+        *ppFormat += 6;
+    else
+        *ppFormat += 4;
+    return discriminant;
+}
+
+/**********************************************************************
+ *           NdrNonEncapsulatedUnionUnmarshall[RPCRT4.@]
  */
 unsigned char *  WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pStubMsg,
                                 unsigned char **ppMemory,
                                 PFORMAT_STRING pFormat,
                                 unsigned char fMustAlloc)
 {
-    FIXME("stub\n");
+    long discriminant;
+    unsigned short type, size;
+
+    TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc);
+    pFormat++;
+
+    /* Unmarshall discriminant */
+    discriminant = unmarshall_discriminant(pStubMsg, &pFormat);
+    TRACE("unmarshalled discriminant %lx\n", discriminant);
+
+    pFormat += *(const SHORT*)pFormat;
+
+    size = *(const unsigned short*)pFormat;
+    pFormat += 2;
+
+    pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat);
+    if(!pFormat)
+        return NULL;
+
+    if(!*ppMemory || fMustAlloc)
+        *ppMemory = NdrAllocate(pStubMsg, size);
+
+    type = *(const unsigned short*)pFormat;
+    if(type & 0x8000)
+    {
+        pFormat++; 
+        return NdrBaseTypeUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc);
+    }
+    else
+    {
+        PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat;
+        NDR_UNMARSHALL m = NdrUnmarshaller[*desc & NDR_TABLE_MASK];
+        if (m)
+        {
+            switch(*desc)
+            {
+            case RPC_FC_RP:
+            case RPC_FC_UP:
+            case RPC_FC_OP:
+            case RPC_FC_FP:
+                **(void***)ppMemory = NULL;
+                break;
+            }
+            return m(pStubMsg, (unsigned char **)*ppMemory, desc, fMustAlloc);
+        }
+        else FIXME("no marshaller for embedded type %02x\n", *desc);
+    }
     return NULL;
 }
 
@@ -2829,7 +3046,44 @@ void WINAPI NdrNonEncapsulatedUnionBuffe
                                 unsigned char *pMemory,
                                 PFORMAT_STRING pFormat)
 {
-    FIXME("stub\n");
+    unsigned short type;
+    TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat);
+
+    pFormat++;
+    /* Add discriminant size */
+    NdrBaseTypeBufferSize(pStubMsg, pMemory, pFormat);
+    pFormat++;
+
+    pFormat = get_non_encapsulated_union_arm(pStubMsg, pMemory, pFormat);
+    if(!pFormat)
+        return;
+
+    type = *(const unsigned short*)pFormat;
+    if(type & 0x8000)
+    {
+        pFormat++; 
+        NdrBaseTypeBufferSize(pStubMsg, pMemory, pFormat);
+    }
+    else
+    {
+        PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat;
+        NDR_BUFFERSIZE m = NdrBufferSizer[*desc & NDR_TABLE_MASK];
+        if (m)
+        {
+            switch(*desc)
+            {
+            case RPC_FC_RP:
+            case RPC_FC_UP:
+            case RPC_FC_OP:
+            case RPC_FC_FP:
+                pMemory = *(void**)pMemory;
+                break;
+            }
+            m(pStubMsg, pMemory, desc);
+        }
+        else FIXME("no buffersizer for embedded type %02x\n", *desc);
+    }
+    return;
 }
 
 /***********************************************************************




More information about the wine-cvs mailing list