utils.cpp 9.66 KB
Newer Older
1 2 3
/*****************************************************************************
 * utils.cpp: ActiveX control for VLC
 *****************************************************************************
4
 * Copyright (C) 2005 the VideoLAN team
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 22
 *****************************************************************************/

23 24 25 26
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

27 28
#include "utils.h"

29 30 31
#include <wchar.h>
#include <wctype.h>

32 33 34 35 36 37
/*
** conversion facilities
*/

using namespace std;

38
char *CStrFromWSTR(UINT codePage, LPCWSTR wstr, UINT len)
39 40 41 42
{
    if( len > 0 )
    {
        size_t mblen = WideCharToMultiByte(codePage,
43
                0, wstr, len, NULL, 0, NULL, NULL);
44 45
        if( mblen > 0 )
        {
Damien Fouilleul's avatar
Damien Fouilleul committed
46
            char *buffer = (char *)CoTaskMemAlloc(mblen+1);
47
            ZeroMemory(buffer, mblen+1);
48
            if( WideCharToMultiByte(codePage, 0, wstr, len, buffer, mblen, NULL, NULL) )
49 50
            {
                buffer[mblen] = '\0';
51
                return buffer;
52
            }
53 54 55 56 57
        }
    }
    return NULL;
};

58 59 60 61 62
char *CStrFromBSTR(UINT codePage, BSTR bstr)
{
    return CStrFromWSTR(codePage, bstr, SysStringLen(bstr));
};

63
BSTR BSTRFromCStr(UINT codePage, LPCSTR s)
64 65
{
    int wideLen = MultiByteToWideChar(codePage, 0, s, -1, NULL, 0);
66
    if( wideLen > 0 )
67
    {
Damien Fouilleul's avatar
Damien Fouilleul committed
68
        WCHAR* wideStr = (WCHAR*)CoTaskMemAlloc(wideLen*sizeof(WCHAR));
69 70 71 72 73 74
        if( NULL != wideStr )
        {
            BSTR bstr;

            ZeroMemory(wideStr, wideLen*sizeof(WCHAR));
            MultiByteToWideChar(codePage, 0, s, -1, wideStr, wideLen);
75
            bstr = SysAllocStringLen(wideStr, wideLen-1);
Damien Fouilleul's avatar
Damien Fouilleul committed
76
            CoTaskMemFree(wideStr);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

            return bstr;
        }
    }
    return NULL;
};

/*
**  properties
*/

HRESULT GetObjectProperty(LPUNKNOWN object, DISPID dispID, VARIANT& v)
{
    IDispatch *pDisp;
    HRESULT hr = object->QueryInterface(IID_IDispatch, (LPVOID *)&pDisp);
    if( SUCCEEDED(hr) )
    {
        DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
        VARIANT vres;
96
        VariantInit(&vres);
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
        hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT,
                DISPATCH_PROPERTYGET, &dispparamsNoArgs, &vres, NULL, NULL);
        if( SUCCEEDED(hr) )
        {
            if( V_VT(&v) != V_VT(&vres) )
            {
                hr = VariantChangeType(&v, &vres, 0, V_VT(&v));
                VariantClear(&vres);
            }
            else
            {
                v = vres;
            }
        }
        pDisp->Release();
    }
    return hr;
};

Damien Fouilleul's avatar
Damien Fouilleul committed
116 117
HDC CreateDevDC(DVTARGETDEVICE *ptd)
{
118
    HDC hdc;
119
    if( NULL == ptd )
Damien Fouilleul's avatar
Damien Fouilleul committed
120
    {
121 122
        hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
    }
Damien Fouilleul's avatar
Damien Fouilleul committed
123 124
    else
    {
125 126
        LPDEVNAMES lpDevNames = (LPDEVNAMES) ptd; // offset for size field
        LPDEVMODE  lpDevMode  = NULL;
Damien Fouilleul's avatar
Damien Fouilleul committed
127

128
        if (ptd->tdExtDevmodeOffset != 0)
Damien Fouilleul's avatar
Damien Fouilleul committed
129
            lpDevMode  = (LPDEVMODE) ((LPTSTR)ptd + ptd->tdExtDevmodeOffset);
Damien Fouilleul's avatar
Damien Fouilleul committed
130

131 132 133 134
        hdc = CreateDC( (LPTSTR) lpDevNames + ptd->tdDriverNameOffset,
                        (LPTSTR) lpDevNames + ptd->tdDeviceNameOffset,
                        (LPTSTR) lpDevNames + ptd->tdPortNameOffset,
                        lpDevMode );
Damien Fouilleul's avatar
Damien Fouilleul committed
135
    }
136
    return hdc;
Damien Fouilleul's avatar
Damien Fouilleul committed
137 138
};

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
#define HIMETRIC_PER_INCH 2540

void DPFromHimetric(HDC hdc, LPPOINT pt, int count)
{
    LONG lpX = GetDeviceCaps(hdc, LOGPIXELSX);
    LONG lpY = GetDeviceCaps(hdc, LOGPIXELSY);
    while( count-- )
    {
        pt->x = pt->x*lpX/HIMETRIC_PER_INCH;
        pt->y = pt->y*lpY/HIMETRIC_PER_INCH;
        ++pt;
    }
};

void HimetricFromDP(HDC hdc, LPPOINT pt, int count)
{
    LONG lpX = GetDeviceCaps(hdc, LOGPIXELSX);
    LONG lpY = GetDeviceCaps(hdc, LOGPIXELSY);
    while( count-- )
    {
        pt->x = pt->x*HIMETRIC_PER_INCH/lpX;
        pt->y = pt->y*HIMETRIC_PER_INCH/lpY;
        ++pt;
    }
};
164

165 166 167 168 169 170 171 172 173 174 175

LPWSTR CombineURL(LPCWSTR baseUrl, LPCWSTR url)
{
    if( NULL != url )
    {
        // check whether URL is already absolute
        const wchar_t *end=wcschr(url, L':');
        if( (NULL != end) && (end != url) )
        {
            // validate protocol header
            const wchar_t *start = url;
176 177
            wchar_t c = *start;
            if( iswalpha(c) )
178
            {
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
                ++start;
                while( start != end )
                {
                    c = *start;
                    if( ! (iswalnum(c)
                       || (L'-' == c)
                       || (L'+' == c)
                       || (L'.' == c)
                       || (L'/' == c)) ) /* VLC uses / to allow user to specify a demuxer */
                        // not valid protocol header, assume relative URL
                        goto relativeurl;
                    ++start;
                }
                /* we have a protocol header, therefore URL is absolute */
                UINT len = wcslen(url);
                wchar_t *href = (LPWSTR)CoTaskMemAlloc((len+1)*sizeof(wchar_t));
                if( href )
                {
                    memcpy(href, url, len*sizeof(wchar_t));
                    href[len] = L'\0';
                }
                return href;
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
            }
        }

relativeurl:

        if( baseUrl )
        {
            size_t baseLen = wcslen(baseUrl);
            wchar_t *href = (LPWSTR)CoTaskMemAlloc((baseLen+wcslen(url)+1)*sizeof(wchar_t));
            if( href )
            {
                /* prepend base URL */
                wcscpy(href, baseUrl);

                /*
                ** relative url could be empty,
                ** in which case return base URL
                */
                if( L'\0' == *url )
                    return href;

                /*
                ** locate pathname part of base URL
                */

                /* skip over protocol part  */
                wchar_t *pathstart = wcschr(href, L':');
                wchar_t *pathend;
                if( pathstart )
                {
                    if( L'/' == *(++pathstart) )
                    {
                        if( L'/' == *(++pathstart) )
                        {
                            ++pathstart;
                        }
                    }
                    /* skip over host part */
                    pathstart = wcschr(pathstart, L'/');
                    pathend = href+baseLen;
                    if( ! pathstart )
                    {
                        // no path, add a / past end of url (over '\0')
                        pathstart = pathend;
                        *pathstart = L'/';
                    }
                }
                else
                {
                    /* baseURL is just a UNIX file path */
                    if( L'/' != *href )
                    {
                        /* baseURL is not an absolute path */
254
                        CoTaskMemFree(href);
255 256 257 258 259 260 261 262 263 264 265 266 267 268
                        return NULL;
                    }
                    pathstart = href;
                    pathend = href+baseLen;
                }

                /* relative URL made of an absolute path ? */
                if( L'/' == *url )
                {
                    /* replace path completely */
                    wcscpy(pathstart, url);
                    return href;
                }

269
                /* find last path component and replace it */
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
                while( L'/' != *pathend )
                    --pathend;

                /*
                ** if relative url path starts with one or more './' or '../',
                ** factor them out of href so that we return a
                ** normalized URL
                */
                while( pathend > pathstart )
                {
                    const wchar_t *p = url;
                    if( L'.' != *p )
                        break;
                    ++p;
                    if( L'\0' == *p  )
                    {
                        /* relative url is just '.' */
                        url = p;
                        break;
                    }
                    if( L'/' == *p  )
                    {
                        /* relative url starts with './' */
                        url = ++p;
                        continue;
                    }
296
                    if( L'.' != *p )
297 298 299 300 301 302 303 304
                        break;
                    ++p;
                    if( L'\0' == *p )
                    {
                        /* relative url is '..' */
                    }
                    else
                    {
305
                        if( L'/' != *p )
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
                            break;
                        /* relative url starts with '../' */
                        ++p;
                    }
                    url = p;
                    do
                    {
                        --pathend;
                    }
                    while( L'/' != *pathend );
                }
                /* skip over '/' separator */
                ++pathend;
                /* concatenate remaining base URL and relative URL */
                wcscpy(pathend, url);
            }
            return href;
        }
    }
    return NULL;
}