//---------------------------------------------------------------------------

#define NO_WIN32_LEAN_AND_MEAN
#include <vcl.h>
#pragma hdrstop

#include "Utils.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

/*************************************************************************
 *      _SHStrDupAA	[INTERNAL]
 *
 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
 */
static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
{
	HRESULT hr;
	int len = 0;

	if (src) {
	    len = lstrlenA(src) + 1;
	    *dest = (char *)CoTaskMemAlloc(len);
	} else {
	    *dest = NULL;
	}

	if (*dest) {
	    lstrcpynA(*dest,src, len);
	    hr = S_OK;
	} else {
	    hr = E_OUTOFMEMORY;
	}

//	TRACE("%s->(%p)\n", debugstr_a(src), *dest);
	return hr;
}

/*************************************************************************
 *      _SHStrDupAW	[INTERNAL]
 *
 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
 */
static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
{
	HRESULT hr;
	int len = 0;

	if (src) {
	    len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
	    *dest = (char *)CoTaskMemAlloc(len);
	} else {
	    *dest = NULL;
	}

	if (*dest) {
	    WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
	    hr = S_OK;
	} else {
	    hr = E_OUTOFMEMORY;
	}

//	TRACE("%s->(%p)\n", debugstr_w(src), *dest);
	return hr;
}

/*************************************************************************
 * StrRetToStrA					[SHLWAPI.@]
 *
 * Converts a STRRET to a normal string.
 *
 * PARAMS
 *  lpStrRet [O] STRRET to convert
 *  pidl     [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
 *  ppszName [O] Destination for converted string
 *
 * RETURNS
 *  Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
 *  Failure: E_FAIL, if any parameters are invalid.
 */
HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
{
  HRESULT hRet = E_FAIL;

  switch (lpStrRet->uType)
  {
  case STRRET_WSTR:
    hRet = _SHStrDupAW(lpStrRet->pOleStr, ppszName);
    CoTaskMemFree(lpStrRet->pOleStr);
    break;

  case STRRET_CSTR:
    hRet = _SHStrDupAA(lpStrRet->cStr, ppszName);
    break;

  case STRRET_OFFSET:
    hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->uOffset, ppszName);
    break;

  default:
    *ppszName = NULL;
  }

  return hRet;
}

/*************************************************************************
 * ILGetSize                 [SHELL32.152]
 *
 * Gets the byte size of an ItemIDList including zero terminator
 *
 * PARAMS
 *  pidl       [I]   ItemIDList
 *
 * RETURNS
 *  size of pidl in bytes
 *
 * NOTES
 *  exported by ordinal
 */
UINT WINAPI ILGetSize(LPCITEMIDLIST pidl)
{
    LPCSHITEMID si = &(pidl->mkid);
    UINT len=0;

    if (pidl)
    {
        while (si->cb)
        {
            len += si->cb;
            si  = (LPCSHITEMID)(((const BYTE*)si)+si->cb);
        }
        len += 2;
    }
/*    TRACE("pidl=%p size=%u\n",pidl, len);*/
    return len;
}

/*************************************************************************
 * ILClone [SHELL32.18]
 *
 * NOTES
 *    duplicate an idlist
 */
LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
{
    DWORD    len;
    LPITEMIDLIST  newpidl;

    if (!pidl)
        return NULL;

    len = ILGetSize(pidl);
    newpidl = (LPITEMIDLIST)CoTaskMemAlloc(len);
    if (newpidl)
        memcpy(newpidl,pidl,len);

/*    TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
    pdump(pidl);*/

    return newpidl;
}

/*************************************************************************
 * ILCombine                 [SHELL32.25]
 *
 * Concatenates two complex ItemIDLists.
 *
 * PARAMS
 *  pidl1      [I]   first complex ItemIDLists
 *  pidl2      [I]   complex ItemIDLists to append
 *
 * RETURNS
 *  if both pidl's == NULL      NULL
 *  if pidl1 == NULL            cloned pidl2
 *  if pidl2 == NULL            cloned pidl1
 *  otherwise new pidl with pidl2 appended to pidl1
 *
 * NOTES
 *  exported by ordinal.
 *  Does not destroy the passed in ItemIDLists!
 */
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
    DWORD    len1,len2;
    LPITEMIDLIST  pidlNew;

/*    TRACE("pidl=%p pidl=%p\n",pidl1,pidl2);*/

    if (!pidl1 && !pidl2) return NULL;

/*    pdump (pidl1);
    pdump (pidl2);*/

    if (!pidl1)
    {
        pidlNew = ILClone(pidl2);
        return pidlNew;
    }

    if (!pidl2)
    {
        pidlNew = ILClone(pidl1);
        return pidlNew;
    }

    len1  = ILGetSize(pidl1)-2;
    len2  = ILGetSize(pidl2);
    pidlNew  = (LPITEMIDLIST)CoTaskMemAlloc(len1+len2);

    if (pidlNew)
    {
        memcpy(pidlNew,pidl1,len1);
        memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
    }

    /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
    return pidlNew;
}
