// interopsvcdimerpcObj.cpp : Implementation of CinteropsvcdimerpcObj

#include "stdafx.h"
#include "interopsvcdimerpcObj.h"

#include "..\soap_source\DIMEPayload.h"
#include "..\soap_source\charencode.h"
#include "..\wmsoapstruct\wmsoapstruct.h"
#include "..\wmsoapstruct\wmsoapstruct_i.c"
#include "comdef.h"
#include <string>
#include <vector>
using namespace std;

// CinteropsvcdimerpcObj

STDMETHODIMP CinteropsvcdimerpcObj::EchoAttachment(VARIANT In, VARIANT *Out)
{
    if ((In.vt & VT_TYPEMASK) == VT_UNKNOWN)
    {
        // sent as attachment
        IUnknown *pIUnknownIn = In.punkVal;
        if (pIUnknownIn == NULL)
        {
            return E_POINTER;
        }
        IStorage *pIStorageIn;
        HRESULT hRes = pIUnknownIn->QueryInterface(IID_IStorage, (void **)&pIStorageIn);
        if (FAILED(hRes))
        {
            return E_NOINTERFACE;
        }
        DIMEPayload *pPayloadIn = new DIMEPayload(  pIStorageIn,
                                                    string(""),
                                                    string(""),
                                                    DIME_TYPENAME_FORMAT_UNKNOWN);
        if (pPayloadIn == NULL)
        {
            pIStorageIn->Release();
            return E_FAIL;
        }
        pIStorageIn->Release();
        IStorage *pIStorageOut;
        hRes = StgCreateDocfile(NULL,
                                STGM_DELETEONRELEASE | STGM_DIRECT | STGM_READWRITE| STGM_CREATE | STGM_SHARE_EXCLUSIVE,
                                0,
                                &pIStorageOut);
        if (FAILED(hRes))
        {
            return E_FAIL;
        }
        DIMEPayload *pPayloadOut = new DIMEPayload( pIStorageOut,
                                                    string(""),
                                                    string(""),
                                                    DIME_TYPENAME_FORMAT_UNKNOWN);
        // now copy contents
        char szTemp[4096];
        unsigned long ulNumBytes = 0;
        unsigned long ulBytesWritten = 0;
        pPayloadIn->OpenForRead();
        pPayloadOut->OpenForWrite();
        do
        {
            pPayloadIn->Read(szTemp, 4096, &ulNumBytes);
            pPayloadOut->Write(szTemp, ulNumBytes, &ulBytesWritten);
        } while (ulNumBytes == 4096);
        pPayloadIn->Close();
        pPayloadOut->Close();
        delete pPayloadIn;
        delete pPayloadOut;
        
        Out->punkVal = pIStorageOut;
        Out->vt = VT_UNKNOWN;
    }
    else
    {
        if ((In.vt & VT_TYPEMASK) != (VT_ARRAY | VT_UI1))
        {
            return E_INVALIDARG;
        }
        // sent in conventional manner
        SafeArrayCopy(In.parray, &Out->parray);
        Out->vt = (VT_I1 | VT_ARRAY);
    }
    return S_OK;
}

STDMETHODIMP CinteropsvcdimerpcObj::EchoAttachments(VARIANT In, VARIANT *Out)
{
    vector<IStorage *> arrAttachmentsOut;
    // extract info from SAFEARRAY
    SAFEARRAY *pArray = In.parray;
    long arrIndex[1];
    // lock array
    SafeArrayLock(pArray);
    // iterate over array
    for (unsigned int i = pArray->rgsabound[0].lLbound;
            i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
            i++)
    {
        arrIndex[0] = i;
        // get pointer to attachment
        VARIANT *pVar = NULL;
        SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);

        IStorage *pIStorageOut;
        if (pVar->vt == VT_UNKNOWN)
        {
            IUnknown *pIUnknownIn = pVar->punkVal;
            IStorage *pIStorageIn;
            HRESULT hRes = pIUnknownIn->QueryInterface(IID_IStorage, (void **)&pIStorageIn);
            if (FAILED(hRes))
            {
                return E_NOINTERFACE;
            }
            DIMEPayload *pPayloadIn = new DIMEPayload(  pIStorageIn,
                                                        string(""),
                                                        string(""),
                                                        DIME_TYPENAME_FORMAT_UNKNOWN);
            if (pPayloadIn == NULL)
            {
                pIStorageIn->Release();
                return E_FAIL;
            }
            pIStorageIn->Release();
            hRes = StgCreateDocfile(NULL,
                                    STGM_DELETEONRELEASE | STGM_DIRECT | STGM_READWRITE| STGM_CREATE | STGM_SHARE_EXCLUSIVE,
                                    0,
                                    &pIStorageOut);
            if (FAILED(hRes))
            {
                return E_FAIL;
            }
            DIMEPayload *pPayloadOut = new DIMEPayload( pIStorageOut,
                                                        string(""),
                                                        string(""),
                                                        DIME_TYPENAME_FORMAT_UNKNOWN);
            // now copy contents
            char szTemp[4096];
            unsigned long ulNumBytes = 0;
            unsigned long ulBytesWritten = 0;
            pPayloadIn->OpenForRead();
            pPayloadOut->OpenForWrite();
            do
            {
                pPayloadIn->Read(szTemp, 4096, &ulNumBytes);
                pPayloadOut->Write(szTemp, ulNumBytes, &ulBytesWritten);
            } while (ulNumBytes == 4096);
            pPayloadIn->Close();
            pPayloadOut->Close();
            delete pPayloadIn;
            delete pPayloadOut;
        }
        else
        {
            // extract info from SAFEARRAY
            HRESULT hRes = StgCreateDocfile(NULL,
                                            STGM_DELETEONRELEASE | STGM_DIRECT | STGM_READWRITE| STGM_CREATE | STGM_SHARE_EXCLUSIVE,
                                            0,
                                            &pIStorageOut);
            if (FAILED(hRes))
            {
                return E_FAIL;
            }
            DIMEPayload *pPayloadOut = new DIMEPayload( pIStorageOut,
                                                        string(""),
                                                        string(""),
                                                        DIME_TYPENAME_FORMAT_UNKNOWN);
            if (pPayloadOut == NULL)
            {
                return E_FAIL;
            }
            
            SAFEARRAY *pArray = pVar->parray;
            void *pData = NULL;
            SafeArrayAccessData(pArray, &pData);

            // now copy contents
            unsigned long ulBytesWritten = 0;
            pPayloadOut->OpenForWrite();
            pPayloadOut->Write((char *)pData, pArray->rgsabound[0].cElements, &ulBytesWritten);
            SafeArrayUnaccessData(pArray);
            pPayloadOut->Close();
            delete pPayloadOut;
        }
        arrAttachmentsOut.push_back(pIStorageOut);
    }
    SafeArrayUnlock(pArray);
    // create SAFEARRAY
    SAFEARRAYBOUND Bounds[1];
    Bounds[0].lLbound = 0;
    Bounds[0].cElements = (ULONG)arrAttachmentsOut.size();
    SAFEARRAY *pArrayOut = SafeArrayCreate(VT_VARIANT, 1, Bounds);
    if (pArray == NULL)
    {
        return E_FAIL;
    }
    Out->parray = pArrayOut;
    Out->vt = (VT_VARIANT | VT_ARRAY);
    // copy ptrs into array
    VARIANT varTemp;
    for (i = 0; i < arrAttachmentsOut.size(); i++)
    {
        varTemp.vt = VT_UNKNOWN;
        varTemp.punkVal = arrAttachmentsOut[i];
        arrIndex[0] = i;
        // put it away
        SafeArrayPutElement(pArrayOut, arrIndex, &varTemp);
        arrAttachmentsOut[i]->Release();
    }
    return S_OK;
}

STDMETHODIMP CinteropsvcdimerpcObj::EchoAttachmentAsBase64(VARIANT In, VARIANT *Out)
{
    if ((In.vt & VT_TYPEMASK) == VT_UNKNOWN)
    {
        // sent as attachment
        IUnknown *pIUnknownIn = In.punkVal;
        if (pIUnknownIn == NULL)
        {
            return E_POINTER;
        }
        IStorage *pIStorageIn;
        HRESULT hRes = pIUnknownIn->QueryInterface(IID_IStorage, (void **)&pIStorageIn);
        if (FAILED(hRes))
        {
            return E_NOINTERFACE;
        }
        DIMEPayload *pPayloadIn = new DIMEPayload(  pIStorageIn,
                                                    string(""),
                                                    string(""),
                                                    DIME_TYPENAME_FORMAT_UNKNOWN);
        if (pPayloadIn == NULL)
        {
            pIStorageIn->Release();
            return E_FAIL;
        }
        pIStorageIn->Release();
        // must open before attempting to get length
        pPayloadIn->OpenForRead();
        unsigned long ulLength = pPayloadIn->GetDataLength();
        // create SAFEARRAY
        SAFEARRAY *pArray = SafeArrayCreateVector(VT_UI1, 0, ulLength);
        if (pArray == NULL)
        {
            return E_FAIL;
        }
        char *pData;
        SafeArrayAccessData(pArray, (void **)&pData);
        // now copy contents
        char szTemp[4096];
        unsigned long ulNumBytes = 0;
        unsigned long ulBytesWritten = 0;
        do
        {
            pPayloadIn->Read(szTemp, 4096, &ulNumBytes);
            memcpy(pData + ulBytesWritten, szTemp, ulNumBytes);
            ulBytesWritten += ulNumBytes;
        } while (ulNumBytes == 4096);
        pPayloadIn->Close();
        delete pPayloadIn;
        SafeArrayUnaccessData(pArray);
        Out->parray = pArray;
        Out->vt = (VT_ARRAY | VT_UI1);
    }
    else
    {
        if ((In.vt & VT_TYPEMASK) != (VT_ARRAY | VT_UI1))
        {
            return E_INVALIDARG;
        }
        // sent in conventional manner, passed in as (VT_ARRAY | VT_UI1)
        SafeArrayCopy(In.parray, &Out->parray);
        Out->vt = (VT_I1 | VT_ARRAY);
    }
    return S_OK;
}

STDMETHODIMP CinteropsvcdimerpcObj::EchoBase64AsAttachment(VARIANT In, VARIANT *Out)
{
    // extract info from SAFEARRAY
    SAFEARRAY *pArray = In.parray;
    unsigned char *pData = NULL;
    SafeArrayAccessData(pArray, (void **)&pData);

    IStorage *pIStorageOut;
    HRESULT hRes;
    hRes = StgCreateDocfile(NULL,
                            STGM_DELETEONRELEASE | STGM_DIRECT | STGM_READWRITE| STGM_CREATE | STGM_SHARE_EXCLUSIVE,
                            0,
                            &pIStorageOut);
    if (FAILED(hRes))
    {
        return E_FAIL;
    }
    DIMEPayload *pPayloadOut = new DIMEPayload( pIStorageOut,
                                                string(""),
                                                string(""),
                                                DIME_TYPENAME_FORMAT_UNKNOWN);
    // now copy contents
    pPayloadOut->OpenForWrite();
    unsigned long ulBytesWritten;
    pPayloadOut->Write((char *)pData, pArray->rgsabound[0].cElements, &ulBytesWritten);
    SafeArrayUnaccessData(pArray);
    pPayloadOut->Close();
    delete pPayloadOut;
    // set up output variant
    Out->punkVal = pIStorageOut;
    Out->vt = VT_UNKNOWN;
    return S_OK;
}

STDMETHODIMP CinteropsvcdimerpcObj::EchoAttachmentAsString(VARIANT In, BSTR *Out)
{
    if ((In.vt & VT_TYPEMASK) == VT_UNKNOWN)
    {
        // sent as attachment
        IUnknown *pIUnknownIn = In.punkVal;
        if (pIUnknownIn == NULL)
        {
            return E_POINTER;
        }
        IStorage *pIStorageIn;
        HRESULT hRes = pIUnknownIn->QueryInterface(IID_IStorage, (void **)&pIStorageIn);
        if (FAILED(hRes))
        {
            return E_NOINTERFACE;
        }
        DIMEPayload *pPayloadIn = new DIMEPayload(  pIStorageIn,
                                                    string(""),
                                                    string(""),
                                                    DIME_TYPENAME_FORMAT_UNKNOWN);
        if (pPayloadIn == NULL)
        {
            pIStorageIn->Release();
            return E_FAIL;
        }
        pIStorageIn->Release();
        // must open before attempting to get length
        pPayloadIn->OpenForRead();
        unsigned long ulLength = pPayloadIn->GetDataLength();
        unsigned long ulNumBytes = 0;
        // create BSTR
        char *pszBuffer = (char *)malloc(ulLength);
        pPayloadIn->Read(pszBuffer, ulLength, &ulNumBytes);
        pPayloadIn->Close();
        delete pPayloadIn;
        wstring wstrTemp;
        UTF8ToWideString(pszBuffer, ulNumBytes, wstrTemp);
        free(pszBuffer);
        *Out = SysAllocString(wstrTemp.c_str());
    }
    else
    {
        if ((In.vt & VT_TYPEMASK) != (VT_ARRAY | VT_UI1))
        {
            return E_INVALIDARG;
        }
        SAFEARRAY *pArray = In.parray;
        void *pData = NULL;
        SafeArrayAccessData(pArray, &pData);
        // create BSTR
        wstring wstrTemp;
        UTF8ToWideString((char *)pData, pArray->rgsabound[0].cElements, wstrTemp);
        *Out = SysAllocString(wstrTemp.c_str());
    }
    return S_OK;
}
