VirtualBox

Changeset 61589 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 8, 2016 4:05:44 PM (9 years ago)
Author:
vboxsync
Message:

Additions/SharedClipboard: fix for ​bugref:8363: added HTML clipboard support to Linux. Added ability to copy HTML clipboard data between Windows and Linux.

Location:
trunk/src/VBox
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp

    r57413 r61589  
    5454#include <VBox/HostServices/VBoxClipboardSvc.h>
    5555
     56class formats;
    5657static Atom clipGetAtom(CLIPBACKEND *pCtx, const char *pszName);
    5758
     
    6364    TEXT,  /* Treat this as Utf8, but it may really be ascii */
    6465    UTF8,
    65     BMP
     66    BMP,
     67        HTML
    6668};
    6769
     
    8890    { "TEXT", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT },
    8991    { "text/plain", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT },
     92    { "text/html", HTML, VBOX_SHARED_CLIPBOARD_FMT_HTML },
     93    { "text/html;charset=utf-8", HTML,
     94      VBOX_SHARED_CLIPBOARD_FMT_HTML },
    9095    { "image/bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP },
    9196    { "image/x-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP },
    92     { "image/x-MS-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP },
     97    { "image/x-MS-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP }
     98   
     99       
    93100    /* TODO: Inkscape exports image/png but not bmp... */
    94101};
     
    187194     * table */
    188195    CLIPX11FORMAT X11BitmapFormat;
     196    /** The best HTML format X11 has to offer, as an index into the formats
     197     * table */
     198    CLIPX11FORMAT X11HTMLFormat;
    189199    /** What formats does VBox have on offer? */
    190200    uint32_t vboxFormats;
     
    327337    uint32_t u32VBoxFormats = clipVBoxFormatForX11Format(pCtx->X11TextFormat);
    328338    u32VBoxFormats |= clipVBoxFormatForX11Format(pCtx->X11BitmapFormat);
     339    u32VBoxFormats |= clipVBoxFormatForX11Format(pCtx->X11HTMLFormat);
     340    LogRelFlowFunc(("clipReportFormatsToVBox format: %d\n", u32VBoxFormats));
     341    LogRelFlowFunc(("clipReportFormatsToVBox txt: %d, bitm: %d, html:%d, u32VBoxFormats: %d\n",
     342                    pCtx->X11TextFormat, pCtx->X11BitmapFormat, pCtx->X11HTMLFormat,
     343                    u32VBoxFormats ));
    329344    ClipReportX11Formats(pCtx->pFrontend, u32VBoxFormats);
    330345}
     
    337352    pCtx->X11TextFormat = INVALID;
    338353    pCtx->X11BitmapFormat = INVALID;
     354    pCtx->X11HTMLFormat = INVALID;
    339355}
    340356
     
    433449
    434450/**
     451 * Go through an array of X11 clipboard targets to see if they contain a HTML
     452 * format we can support, and if so choose the ones we prefer
     453 * @param  pCtx      the clipboard backend context structure
     454 * @param  pTargets  the list of targets
     455 * @param  cTargets  the size of the list in @a pTargets
     456 */
     457static CLIPX11FORMAT clipGetHtmlFormatFromTargets(CLIPBACKEND *pCtx,
     458                                                  CLIPX11FORMAT *pTargets,
     459                                                  size_t cTargets)
     460{
     461    CLIPX11FORMAT bestHTMLFormat = NIL_CLIPX11FORMAT;
     462    CLIPFORMAT enmBestHtmlTarget = INVALID;
     463    AssertPtrReturn(pCtx, NIL_CLIPX11FORMAT);
     464    AssertReturn(VALID_PTR(pTargets) || cTargets == 0, NIL_CLIPX11FORMAT);
     465    for (unsigned i = 0; i < cTargets; ++i)
     466    {
     467        CLIPX11FORMAT format = pTargets[i];
     468        if (format != NIL_CLIPX11FORMAT)
     469        {
     470            if (   (clipVBoxFormatForX11Format(format) == VBOX_SHARED_CLIPBOARD_FMT_HTML)
     471                    && enmBestHtmlTarget < clipRealFormatForX11Format(format))
     472            {
     473                enmBestHtmlTarget = clipRealFormatForX11Format(format);
     474                bestHTMLFormat = format;
     475            }
     476        }
     477    }
     478    return bestHTMLFormat;
     479}
     480
     481
     482/**
    435483 * Go through an array of X11 clipboard targets to see if we can support any
    436484 * of them and if relevant to choose the ones we prefer (e.g. we like Utf8
     
    447495    CLIPX11FORMAT bestTextFormat;
    448496    CLIPX11FORMAT bestBitmapFormat;
     497    CLIPX11FORMAT bestHtmlFormat;
    449498    bestTextFormat = clipGetTextFormatFromTargets(pCtx, pTargets, cTargets);
    450499    if (pCtx->X11TextFormat != bestTextFormat)
     
    457506    {
    458507        pCtx->X11BitmapFormat = bestBitmapFormat;
     508    }
     509    bestHtmlFormat = clipGetHtmlFormatFromTargets(pCtx, pTargets, cTargets);
     510    if(pCtx->X11HTMLFormat != bestHtmlFormat)
     511    {
     512        pCtx->X11HTMLFormat = bestHtmlFormat;
    459513    }
    460514}
     
    11201174
    11211175/**
     1176 * Satisfy a request from X11 to convert the clipboard HTML fragment to Utf-8.  We
     1177 * return null-terminated text, but can cope with non-null-terminated input.
     1178 *
     1179 * @returns iprt status code
     1180 * @param  pDisplay        an X11 display structure, needed for conversions
     1181 *                         performed by Xlib
     1182 * @param  pv              the text to be converted (UTF8 with Windows EOLs)
     1183 * @param  cb              the length of the text in @cb in bytes
     1184 * @param  atomTypeReturn  where to store the atom for the type of the data
     1185 *                         we are returning
     1186 * @param  pValReturn      where to store the pointer to the data we are
     1187 *                         returning.  This should be to memory allocated by
     1188 *                         XtMalloc, which will be freed by the Xt toolkit
     1189 *                         later.
     1190 * @param  pcLenReturn     where to store the length of the data we are
     1191 *                         returning
     1192 * @param  piFormatReturn  where to store the bit width (8, 16, 32) of the
     1193 *                         data we are returning
     1194 */
     1195static int clipWinHTMLToUtf8ForX11CB(Display *pDisplay, const char* pszSrc,
     1196                                    size_t cbSrc, Atom *atomTarget,
     1197                                    Atom *atomTypeReturn,
     1198                                    XtPointer *pValReturn,
     1199                                    unsigned long *pcLenReturn,
     1200                                    int *piFormatReturn)
     1201{
     1202    /* This may slightly overestimate the space needed. */
     1203    LogRelFlowFunc(("source: %s", pszSrc));
     1204
     1205    char *pszDest = (char *)XtMalloc(cbSrc);
     1206    if(pszDest == NULL)
     1207        return VERR_NO_MEMORY;
     1208       
     1209    memcpy(pszDest, pszSrc, cbSrc);
     1210
     1211    *atomTypeReturn = *atomTarget;
     1212    *pValReturn = (XtPointer)pszDest;
     1213    *pcLenReturn = cbSrc;
     1214    *piFormatReturn = 8;
     1215   
     1216    return VINF_SUCCESS;
     1217}
     1218
     1219
     1220/**
    11221221 * Does this atom correspond to one of the two selection types we support?
    11231222 * @param  widget   a valid Xt widget
     
    11421241    AssertPtrReturnVoid(pText);
    11431242    AssertPtrReturnVoid(pcText);
    1144     AssertReturnVoid((format == UTF8) || (format == TEXT));
     1243    AssertReturnVoid((format == UTF8) || (format == TEXT) || (format == HTML));
    11451244    if (((char *)pText)[*pcText - 1] == '\0')
    11461245       --(*pcText);
     
    12001299        }
    12011300        RTMemFree(pv);
     1301    }
     1302    else if ( (format == HTML)
     1303            && (pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_HTML))
     1304    {
     1305        void *pv = NULL;
     1306        uint32_t cb = 0;
     1307        rc = clipReadVBoxClipboard(pCtx,
     1308                                   VBOX_SHARED_CLIPBOARD_FMT_HTML,
     1309                                   &pv, &cb);
     1310        if (RT_SUCCESS(rc) && (cb == 0))
     1311            rc = VERR_NO_DATA;
     1312        if (RT_SUCCESS(rc))
     1313        {
     1314            /*
     1315            * The common VBox HTML encoding will be - Utf8
     1316            * becuase it more general for HTML formats then UTF16
     1317            * X11 clipboard returns UTF16, so before sending it we should
     1318            * convert it to UTF8
     1319            * It's very strange but here we get utf16 from x11 clipboard
     1320            * in same time we send utf8 to x11 clipboard and it's work
     1321            */
     1322            rc = clipWinHTMLToUtf8ForX11CB(XtDisplay(pCtx->widget),
     1323                (const char*)pv, cb, atomTarget,
     1324                atomTypeReturn, pValReturn,
     1325                pcLenReturn, piFormatReturn);
     1326
     1327
     1328            if (RT_SUCCESS(rc))
     1329                clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, format);
     1330            RTMemFree(pv);
     1331        }
    12021332    }
    12031333    else
     
    14671597}
    14681598
     1599
     1600/**
     1601* Convert Utf16 text into UTF8 as Windows expects
     1602* it and return the result in a RTMemAlloc allocated buffer.
     1603* @returns  IPRT status code
     1604* @param  pcSrc      The source text
     1605* @param  cbSrc      The size of the source in bytes, not counting the
     1606*                    terminating zero
     1607* @param  ppwszDest  Where to store the buffer address
     1608* @param  pcbDest    On success, where to store the number of bytes written.
     1609*                    Undefined otherwise.  Optional
     1610*/
     1611int  clipUTF16ToWinHTML(RTUTF16* buffer, size_t cb, char **output, uint32_t *outsz)
     1612{
     1613    Assert(buffer);
     1614    Assert(cb);
     1615    Assert(output);
     1616    Assert(outsz);
     1617
     1618    size_t i = 0;
     1619    RTUTF16* p = buffer;
     1620    char* result = NULL;
     1621    size_t resultLen = 0;
     1622    LogRelFlowFunc(("clipUTF16ToWinHTML src= %ls cb=%d i=%i, %x %x\n", buffer, cb, i, output, outsz));
     1623    while (i != cb / 2)
     1624    {
     1625        /* find  zero symbol (end of string) */
     1626        for (; i < cb / 2 && buffer[i] != 0; i++);
     1627        LogRelFlowFunc(("skipped nulls i=%d cb/2=%d\n", i, cb / 2));
     1628
     1629        /* convert found string */
     1630        char* cTmp = NULL;
     1631        size_t sz = 0;
     1632        int rc = RTUtf16ToUtf8Ex(p, cb / 2, &cTmp, p - buffer, &sz);
     1633        LogRelFlowFunc(("utf16toutf8 src= %ls res=%s i=%i\n", p, cTmp, i));
     1634        if (!RT_SUCCESS(rc))
     1635            return rc;
     1636
     1637        /* append new substring */
     1638        result = (char*)RTMemRealloc(result, resultLen + sz + 1);
     1639        if (result == NULL)
     1640        {
     1641            RTStrFree(cTmp);
     1642            cTmp = NULL;
     1643            return VERR_NO_MEMORY;
     1644        }
     1645        memcpy(result + resultLen, cTmp, sz + 1);
     1646        LogRelFlowFunc(("Temp result res=%s\n", result + resultLen));
     1647
     1648        /* remove temporary buffer */
     1649        RTStrFree(cTmp);
     1650        resultLen += sz + 1;
     1651        /* skip zero symbols */
     1652        for (; i < cb / 2 && buffer[i] == 0; i++);
     1653        /* remember start of string */
     1654        p += i;
     1655    }
     1656    *output = result;
     1657    *outsz = resultLen;
     1658
     1659    return VINF_SUCCESS;
     1660}
     1661
     1662
     1663
    14691664/** A structure containing information about where to store a request
    14701665 * for the X11 clipboard contents. */
     
    14771672    /** The bitmap format we requested from X11 if we requested bitmap */
    14781673    CLIPX11FORMAT mBitmapFormat;
     1674    /** The HTML format we requested from X11 if we requested HTML */
     1675    CLIPX11FORMAT mHtmlFormat;
    14791676    /** The clipboard context this request is associated with */
    14801677    CLIPBACKEND *mCtx;
     
    14971694    CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *) pClientData;
    14981695    LogRelFlowFunc(("pReq->mFormat=%02X, pReq->mTextFormat=%u, "
    1499                 "pReq->mBitmapFormat=%u, pReq->mCtx=%p\n",
     1696                "pReq->mBitmapFormat=%u, pReq->mHtmlFormat=%u, pReq->mCtx=%p\n",
    15001697                 pReq->mFormat, pReq->mTextFormat, pReq->mBitmapFormat,
    1501                  pReq->mCtx));
     1698                 pReq->mHtmlFormat, pReq->mCtx));
    15021699    AssertPtr(pReq->mCtx);
    15031700    Assert(pReq->mFormat != 0);  /* sanity */
     
    15641761        }
    15651762    }
     1763    else if(pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_HTML)
     1764    {
     1765        /* In which format is the clipboard data? */
     1766        switch (clipRealFormatForX11Format(pReq->mHtmlFormat))
     1767        {
     1768            case HTML:
     1769            {
     1770                /* The common VBox HTML encoding will be - Utf8
     1771                * becuase it more general for HTML formats then UTF16
     1772                * X11 clipboard returns UTF16, so before sending it we should
     1773                * convert it to UTF8
     1774                */
     1775                pvDest = NULL;
     1776                cbDest = 0;
     1777                rc = clipUTF16ToWinHTML((RTUTF16*)pvSrc, cbSrc,
     1778                    (char**)&pvDest, &cbDest);
     1779                LogRelFlowFunc(("Source unicode %ls, cbSrc = %d\n", pvSrc, cbSrc));
     1780                LogRelFlowFunc(("converted to win unicode %s, cbDest = %d, rc = %Rrc\n", pvDest, cbDest, rc));
     1781                rc = VINF_SUCCESS;
     1782                break;
     1783            }
     1784            default:
     1785            {
     1786                rc = VERR_INVALID_PARAMETER;
     1787            }
     1788        }
     1789    }
    15661790    else
    15671791        rc = VERR_NOT_IMPLEMENTED;
     
    16531877            getSelectionValue(pCtx, pCtx->X11BitmapFormat, pReq);
    16541878    }
    1655     else
     1879    else if(pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_HTML)
     1880    {
     1881        /* Send out a request for the data to the current clipboard
     1882             * owner */
     1883        pReq->mHtmlFormat = pCtx->X11HTMLFormat;
     1884        if(pReq->mHtmlFormat == INVALID)
     1885                    /* VBox thinks we have data and we don't */
     1886            rc = VERR_NO_DATA;
     1887        else
     1888            /* Send out a request for the data to the current clipboard
     1889             * owner */
     1890            getSelectionValue(pCtx, pCtx->X11HTMLFormat, pReq);
     1891    }
     1892    else   
    16561893        rc = VERR_NOT_IMPLEMENTED;
    16571894    if (RT_FAILURE(rc))
     
    25452782
    25462783#endif /* SMOKETEST defined */
     2784
     2785                   
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxClipboard-win.cpp

    r60784 r61589  
    4242typedef FNREMOVECLIPBOARDFORMATLISTENER *PFNREMOVECLIPBOARDFORMATLISTENER;
    4343
     44/*Forward declarations*/
     45int ConvertMimeToCFHTML(const char *source, size_t cb, char **output, size_t *pcch);
     46int ConvertCFHtmlToMime(const char *source, const uint32_t cch, char **output, size_t *pcch);
     47bool IsWindowsHTML(const char *source);
     48
     49
    4450#ifndef WM_CLIPBOARDUPDATE
    4551#define WM_CLIPBOARDUPDATE 0x031D
     
    96102        {
    97103            Log(("%s\n", pv));
     104           
     105            //size_t cb = RTStrNLen(pv, );
     106            char* buf = (char*)RTMemAlloc(cb + 1);
     107            RT_BZERO(buf, cb);
     108            RTStrCopy(buf, cb, (const char*)pv);
     109            for (int i = 0; i < cb; ++i)
     110            {
     111                if (buf[i] == '\n' || buf[i] == '\r')
     112                    buf[i] = ' ';
     113            }
     114           
     115            Log(("%s\n", buf));
     116            RTMemFree(buf);
    98117        }
    99118        else
     
    202221    }
    203222
    204     memcpy (pvDst, pvSrc, cbSrc);
     223    if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML &&
     224                            IsWindowsHTML((const char*)pvSrc))
     225    {
     226        char* buffer = NULL;
     227        size_t cbuf = 0;
     228        ConvertCFHtmlToMime((const char*)pvSrc, cbSrc, (char**)&buffer, &cbuf);
     229        if (cbuf > cbDst)
     230        {
     231            /* Do not copy data. The dst buffer is not enough. */
     232            return;
     233        }
     234        memcpy(pvDst, buffer, cbuf);
     235        *pcbActualDst = cbuf;
     236        RTMemFree(buffer);
     237    }
     238    else
     239    {
     240        memcpy(pvDst, pvSrc, cbSrc);
     241    }
    205242
    206243    vboxClipboardDump(pvDst, cbSrc, u32Format);
     
    794831}
    795832
     833int DumpHtml(char* src, size_t cb)
     834{
     835    size_t lenght = 0;
     836    int rc = RTStrNLenEx(src, cb, &lenght);
     837    if (RT_SUCCESS(rc))
     838    {
     839        char* buf = (char*)RTMemAlloc(cb + 1);
     840        if (buf != NULL)
     841        {
     842            RT_BZERO(buf, cb + 1);
     843            rc = RTStrCopy(buf, cb, (const char*)src);
     844            if (RT_SUCCESS(rc))
     845            {
     846                for (int i = 0; i < cb; ++i)
     847                {
     848                    if (buf[i] == '\n' || buf[i] == '\r')
     849                        buf[i] = ' ';
     850                }
     851            }
     852            else
     853            {
     854                Log(("Error in copying string.\n"));
     855            }
     856            Log(("Removed \\r\\n: %s\n", buf));
     857            RTMemFree(buf);
     858        }
     859        else
     860        {
     861            rc = VERR_NO_MEMORY;
     862            Log(("Not enough memory to allocate buffer.\n"));
     863        }
     864    }
     865    return rc;
     866}
     867
    796868int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual)
    797869{
     
    872944                        vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize (hClip),
    873945                                              pv, cb, pcbActual);
    874 
     946                        LogRelFlowFunc(("Raw HTML clipboard data from host :"));
     947                        DumpHtml((char*)pv, cb);
    875948                        GlobalUnlock(hClip);
    876949                    }
     
    913986    if (cb > 0)
    914987    {
    915         pClient->data.pv = RTMemAlloc (cb);
    916 
    917         if (pClient->data.pv)
    918         {
    919             memcpy (pClient->data.pv, pv, cb);
    920             pClient->data.cb = cb;
    921             pClient->data.u32Format = u32Format;
     988        char* result = NULL;
     989        size_t cch;
     990
     991        if(u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML &&
     992            !IsWindowsHTML((const char*)pv))
     993        {
     994            /* check that this is not already CF_HTML */
     995            int rc = ConvertMimeToCFHTML((const char*)pv, cb, &result, &cch);
     996            if (RT_SUCCESS(rc))
     997            {
     998                if (result != NULL && cch != 0)
     999                {
     1000                    pClient->data.pv = result;
     1001                    pClient->data.cb = cch;
     1002                    pClient->data.u32Format = u32Format;
     1003                }
     1004            }
     1005        }
     1006        else
     1007        {
     1008            pClient->data.pv = RTMemAlloc (cb);
     1009            if (pClient->data.pv)
     1010            {
     1011                memcpy (pClient->data.pv, pv, cb);
     1012                pClient->data.cb = cb;
     1013                pClient->data.u32Format = u32Format;
     1014            }
    9221015        }
    9231016    }
     
    9251018    SetEvent(pClient->pCtx->hRenderEvent);
    9261019}
     1020
     1021/*
     1022@StartHtml - pos before <html>
     1023@EndHtml - whole size of text excluding ending zero char
     1024@StartFragment - pos after <!--StartFragment-->
     1025@EndFragment - pos before <!--EndFragment-->
     1026@note: all values includes CR\LF inserted into text
     1027Calculations:
     1028Header length = format Length + (3*6('digits')) - 2('%s') = format length + 16 (control value - 183)
     1029EndHtml  = Header length + fragment length
     1030StartHtml = 105(constant)
     1031StartFragment = 143(constant)
     1032EndFragment  = Header length + fragment length - 40(ending length)
     1033*/
     1034char strFormatSample[] =
     1035    "Version:1.0\r\n"
     1036    "StartHTML:000000101\r\n"
     1037    "EndHTML:%09d\r\n" // END HTML = Header length + fragment lengh
     1038"StartFragment:000000137\r\n"
     1039"EndFragment:%09d\r\n"
     1040"<html>\r\n"
     1041"<body>\r\n"
     1042"<!--StartFragment-->%s<!--EndFragment-->\r\n"
     1043"</body>\r\n"
     1044"</html>\r\n";
     1045
     1046/*
     1047* Extracts field value from CF_HTML struct
     1048* @src - source in CF_HTML format
     1049* @option - name of CF_HTML field
     1050* @value - extracted value of CF_HTML field
     1051* returns RC result code
     1052*/
     1053int GetHeaderValue(const char *src, const char *option, size_t *value)
     1054{
     1055    size_t optionLenght;
     1056    int rc = VERR_INVALID_PARAMETER;
     1057
     1058    Assert(src);
     1059    Assert(option);
     1060
     1061    char* optionValue = RTStrStr(src, option);
     1062    if (optionValue)
     1063    {
     1064        rc = RTStrNLenEx(option, RTSTR_MAX, &optionLenght);
     1065        Assert(optionLenght);
     1066        if (RT_SUCCESS(rc))
     1067        {
     1068            int32_t tmpValue;
     1069            rc = RTStrToInt32Ex(optionValue + optionLenght, NULL, 10, &tmpValue);
     1070            if (RT_SUCCESS(rc))
     1071            {
     1072                *value = tmpValue;
     1073                rc = VINF_SUCCESS;
     1074            }
     1075        }
     1076    }
     1077    return rc;
     1078}
     1079
     1080/*
     1081 * Check that the source string contains CF_HTML struct
     1082 * returns true if the @source string is in CF_HTML format
     1083 */
     1084bool IsWindowsHTML(const char *source)
     1085{
     1086    return RTStrStr(source, "Version:") != NULL
     1087        && RTStrStr(source, "StartHTML:") != NULL;
     1088}
     1089
     1090
     1091/*
     1092* Converts clipboard data from CF_HTML format to mimie clipboard format
     1093* Returns allocated buffer that contains html converted to text/html mime type
     1094* return result code
     1095* parameters - output buffer and size of output buffer
     1096* It allocates the buffer needed for storing converted fragment
     1097* Allocated buffer should be destroyed by RTMemFree after usage
     1098*/
     1099int ConvertCFHtmlToMime(const char *source, const uint32_t cch, char **output, size_t *pcch)
     1100{
     1101    char* result = NULL;
     1102
     1103    Assert(source);
     1104    Assert(cch);
     1105    Assert(output);
     1106    Assert(pcch);
     1107
     1108    size_t startOffset, endOffset;
     1109    int rc = GetHeaderValue(source, "StartFragment:", &startOffset);
     1110    if (!RT_SUCCESS(rc))
     1111    {
     1112        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected StartFragment. rc = %Rrc.\n", rc));
     1113        return VERR_INVALID_PARAMETER;
     1114    }
     1115    rc = GetHeaderValue(source, "EndFragment:", &endOffset);
     1116    if (!RT_SUCCESS(rc))
     1117    {
     1118        LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc.\n", rc));
     1119        return VERR_INVALID_PARAMETER;
     1120    }
     1121    if (startOffset > 0 && endOffset > 0 && endOffset > startOffset)
     1122    {
     1123        size_t substrlen = endOffset - startOffset;
     1124        result = (char*)RTMemAlloc(substrlen + 1);
     1125        if (result)
     1126        {
     1127            RT_BZERO(result, substrlen + 1);
     1128            rc = RTStrCopyEx(result, substrlen + 1, source + startOffset, substrlen);
     1129            if (RT_SUCCESS(rc))
     1130            {
     1131                *output = result;
     1132                *pcch = substrlen + 1;
     1133            }
     1134            else
     1135            {
     1136                LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc\n", rc));
     1137                return rc;
     1138            }
     1139        }
     1140        else
     1141        {
     1142            LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment.\n"));
     1143            return VERR_NO_MEMORY;
     1144        }
     1145    }
     1146
     1147return VINF_SUCCESS;
     1148}
     1149
     1150
     1151
     1152/*
     1153* Converts source Utf16 mime html clipboard data to Utf8 CF_HTML format
     1154* It allocates
     1155* Calculations:
     1156* Header length = format Length + (2*(10 - 5('%010d'))('digits')) - 2('%s') = format length + 8
     1157* EndHtml  = Header length + fragment length
     1158* StartHtml = 105(constant)
     1159* StartFragment = 141(constant) may vary if the header html content will be extended
     1160* EndFragment  = Header length + fragment length - 38(ending length)
     1161* @source: source buffer that contains utf-16 string in mime html format
     1162* @cb: size of source buffer in bytes
     1163* @output: allocated output buffer to put converted Utf8 CF_HTML clipboard data. This function allocates memory for this.
     1164* @pcch: size of allocated result buffer in bytes
     1165* @note: output buffer should be free using RTMemFree()
     1166* @note: Everything inside of fragment can be UTF8. Windows allows it. Everything in header should be Latin1.
     1167*/
     1168int ConvertMimeToCFHTML(const char *source, size_t cb, char **output, size_t *pcch)
     1169{
     1170    Assert(output);
     1171    Assert(pcch);
     1172    Assert(source);
     1173    Assert(cb);
     1174
     1175    size_t fragmentLength = 0;
     1176
     1177    char* buf = (char*)source;
     1178   
     1179    /* construct CF_HTML formatted string */
     1180    char* result = NULL;
     1181    int rc = RTStrNLenEx(buf, RTSTR_MAX, &fragmentLength);
     1182    if (!RT_SUCCESS(rc))
     1183    {
     1184        LogRelFlowFunc(("Error: invalid source fragment. rc = %Rrc.\n"));
     1185        return VERR_INVALID_PARAMETER;
     1186    }
     1187
     1188    /* caluclate parameters of CF_HTML header */
     1189    size_t headerLength = (sizeof(strFormatSample) - 1) + 8;
     1190    size_t endHtml = headerLength + fragmentLength;
     1191    size_t endFragment = headerLength + fragmentLength - 38;
     1192    result = (char*)RTMemAlloc(endHtml + 1);
     1193    if (result == NULL)
     1194    {
     1195        LogRelFlowFunc(("Error: Cannot allocate memory for result buffer. rc = %Rrc.\n"));
     1196        return VERR_NO_MEMORY;
     1197    }
     1198
     1199    /* format result CF_HTML string */
     1200    rc = RTStrPrintf(result, endHtml + 1, strFormatSample, endHtml, endFragment, buf);
     1201    if (rc == -1)
     1202    {
     1203        LogRelFlowFunc(("Error: cannot construct CF_HTML. rc = %Rrc.\n"));
     1204        return VERR_CANT_CREATE;
     1205    }
     1206    Assert(endHtml == rc);
     1207
     1208#ifdef DEBUG
     1209    {
     1210        /*Control calculations. check consistency.*/
     1211        const char strStartFragment[] = "<!--StartFragment-->";
     1212        const char strEndFragment[] = "<!--EndFragment-->";
     1213
     1214        /* check 'StartFragment:' value */
     1215        const char* realStartFragment = RTStrStr(result, strStartFragment);
     1216        Assert((realStartFragment + sizeof(strStartFragment) - 1) - result == 137);//141);
     1217
     1218        /* check 'EndFragment:' value */
     1219        const char* realEndFragment = RTStrStr(result, strEndFragment);
     1220        Assert((realEndFragment - result) == endFragment);
     1221    }
     1222#endif
     1223
     1224    *output = result;
     1225    *pcch = rc+1;
     1226
     1227    return VINF_SUCCESS;
     1228}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette