/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Copyright 1995-1997, Don Box
  
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
  
    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
    This file contains a datatype, INTERFACE_ENTRY that can be used to build
    tables that map IIDs onto vptrs. 

    This file contains the prototype for a routine that implements
    QueryInterface based on an interface table.

      InterfaceTableQueryInterface - finds and AddRef's vptr on an object
*/

#include "sysdef.h"
#include "cscom/com.h"
#include "cscom/inttable.h"

#ifndef _INLINEISEQUALGUID_DEFINED
#define _INLINEISEQUALGUID_DEFINED
inline COMBOOL  InlineIsEqualGUID(const GUID& rguid1, const GUID& rguid2)
{
  return (((long*) &rguid1)[0] == ((long*) &rguid2)[0] &&
          ((long*) &rguid1)[1] == ((long*) &rguid2)[1] &&
          ((long*) &rguid1)[2] == ((long*) &rguid2)[2] &&
          ((long*) &rguid1)[3] == ((long*) &rguid2)[3]);
}
#endif


// the routine that implements QueryInterface basd on the table
EXTERN_C HRESULT STDAPICALLTYPE InterfaceTableQueryInterface(void *pThis,
  const INTERFACE_ENTRY *pTable, REFIID riid, void **ppv)
{
  if (InlineIsEqualGUID(riid, IID_IUnknown))
  {
    ((IUnknown*)(*ppv = (char*)pThis + pTable->dwData))->AddRef();
    return S_OK;
  }
  else
  {
    HRESULT hr = E_NOINTERFACE;
    while (pTable->pfnFinder)
    {
      if (!pTable->pIID || InlineIsEqualGUID(riid, *pTable->pIID))
      {
        if (pTable->pfnFinder == ENTRY_IS_OFFSET)
        {
          ((IUnknown*)(*ppv = (char*)pThis + pTable->dwData))->AddRef();
          hr = S_OK;
          break;
        }
        else
        {
          hr = pTable->pfnFinder(pThis, pTable->dwData, riid, ppv);
          if (hr == S_OK)
            break;
        }
      }
      pTable++;
    }
    if (hr != S_OK)
      *ppv = 0;
    return hr;
  }
}
