int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
{
    NOREF(pThis);
    *ppvPages = RTMemPageAllocZ(cPages << PAGE_SHIFT);
    if (*ppvPages)
        return VINF_SUCCESS;
    return RTErrConvertFromErrno(errno);
}
/**
 * Allocate memory for host buffer and receive it.
 *
 * @param   u32ClientId    Host connection.
 * @param   fFormat        Buffer data format.
 * @param   pData          Where to store received data.
 * @param   cbDataSize     The size of the received data.
 * @param   cbMemSize      The actual size of memory occupied by *pData.
 *
 * @returns IPRT status code.
 */
static int vbclClipboardReadHostData(uint32_t u32ClientId, uint32_t fFormat, void **pData, uint32_t *cbDataSize, uint32_t *cbMemSize)
{
    int rc;

    AssertReturn(pData && cbDataSize && cbMemSize, VERR_INVALID_PARAMETER);

    uint32_t  cbDataSizeInternal = _4K;
    uint32_t  cbMemSizeInternal  = cbDataSizeInternal;
    void     *pDataInternal      = RTMemPageAllocZ(cbDataSizeInternal);

    if (!pDataInternal)
        return VERR_NO_MEMORY;

    rc = VbglR3ClipboardReadData(u32ClientId, fFormat, pDataInternal, cbMemSizeInternal, &cbDataSizeInternal);
    if (rc == VINF_BUFFER_OVERFLOW)
    {
        /* Reallocate bigger buffer and receive all the data */
        RTMemPageFree(pDataInternal, cbMemSizeInternal);
        cbDataSizeInternal = cbMemSizeInternal = RT_ALIGN_32(cbDataSizeInternal, PAGE_SIZE);
        pDataInternal = RTMemPageAllocZ(cbMemSizeInternal);
        if (!pDataInternal)
            return VERR_NO_MEMORY;

        rc = VbglR3ClipboardReadData(u32ClientId, fFormat, pDataInternal, cbMemSizeInternal, &cbDataSizeInternal);
    }

    /* Error occurred of zero-sized buffer */
    if (RT_FAILURE(rc))
    {
        RTMemPageFree(pDataInternal, cbMemSizeInternal);
        return VERR_NO_MEMORY;
    }

    *pData      = pDataInternal;
    *cbDataSize = cbDataSizeInternal;
    *cbMemSize  = cbMemSizeInternal;

    return rc;
}
/**
 * Search for content of specified type in guest clipboard buffer and put
 * it into newly allocated buffer.
 *
 * @param   pPasteboard     Guest PasteBoard reference.
 * @param   fFormat         Data formats we are looking for.
 * @param   ppvData         Where to return pointer to the received data. M
 * @param   pcbData         Where to return the size of the data.
 * @param   pcbAlloc        Where to return the size of the memory block
 *                          *ppvData pointes to. (Usually greater than *cbData
 *                           because the allocation is page aligned.)
 * @returns IPRT status code.
 */
static int vbclClipboardReadGuestData(PasteboardRef pPasteboard, CFStringRef sFormat, void **ppvData, uint32_t *pcbData,
                                      uint32_t *pcbAlloc)
{
    ItemCount cItems, iItem;
    OSStatus  rc;

    void     *pvData  = NULL;
    uint32_t  cbData  = 0;
    uint32_t  cbAlloc = 0;

    AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
    AssertPtrReturn(pcbData, VERR_INVALID_POINTER);
    AssertPtrReturn(pcbAlloc, VERR_INVALID_POINTER);

    rc = PasteboardGetItemCount(pPasteboard, &cItems);
    AssertReturn(rc == noErr, VERR_INVALID_PARAMETER);
    AssertReturn(cItems > 0, VERR_INVALID_PARAMETER);

    /* Walk through all the items in PasteBoard in order to find
       that one that correcponds to requested data format. */
    for (iItem = 1; iItem <= cItems; iItem++)
    {
        PasteboardItemID iItemID;
        CFDataRef        flavorData;

        /* Now, get the item's flavors that corresponds to requested type. */
        rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID);
        AssertReturn(rc == noErr, VERR_INVALID_PARAMETER);
        rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, sFormat, &flavorData);
        if (rc == noErr)
        {
            void *flavorDataPtr = (void *)CFDataGetBytePtr(flavorData);
            cbData = CFDataGetLength(flavorData);
            if (flavorDataPtr && cbData > 0)
            {
                cbAlloc = RT_ALIGN_32(cbData, PAGE_SIZE);
                pvData = RTMemPageAllocZ(cbAlloc);
                if (pvData)
                    memcpy(pvData, flavorDataPtr, cbData);
            }

            CFRelease(flavorData);

            /* Found first matching item, no more search. */
            break;
        }

    }

    /* Found match */
    if (pvData)
    {
        *ppvData  = pvData;
        *pcbData  = cbData;
        *pcbAlloc = cbAlloc;

        return VINF_SUCCESS;
    }

    return VERR_INVALID_PARAMETER;
}