1/*
2 * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebKitDLL.h"
28#include "MarshallingHelpers.h"
29#include "MathExtras.h"
30
31#pragma warning(push, 0)
32#include <WebCore/IntRect.h>
33#include <WebCore/KURL.h>
34#include <WebCore/PlatformString.h>
35#pragma warning(pop)
36
37using namespace WebCore;
38
39static const double secondsPerDay = 60 * 60 * 24;
40
41CFArrayCallBacks MarshallingHelpers::kIUnknownArrayCallBacks = {0, IUnknownRetainCallback, IUnknownReleaseCallback, 0, 0};
42CFDictionaryValueCallBacks MarshallingHelpers::kIUnknownDictionaryValueCallBacks = {0, IUnknownRetainCallback, IUnknownReleaseCallback, 0, 0};
43
44KURL MarshallingHelpers::BSTRToKURL(BSTR urlStr)
45{
46    return KURL(KURL(), String(urlStr, SysStringLen(urlStr)));
47}
48
49BSTR MarshallingHelpers::KURLToBSTR(const KURL& url)
50{
51    return SysAllocStringLen(url.string().characters(), url.string().length());
52}
53
54CFURLRef MarshallingHelpers::PathStringToFileCFURLRef(const String& string)
55{
56    CFStringRef cfPath = CFStringCreateWithCharactersNoCopy(0, (const UniChar*)string.characters(), string.length(), kCFAllocatorNull);
57    CFURLRef pathURL = CFURLCreateWithFileSystemPath(0, cfPath, kCFURLWindowsPathStyle, false);
58    CFRelease(cfPath);
59    return pathURL;
60}
61
62String MarshallingHelpers::FileCFURLRefToPathString(CFURLRef fileURL)
63{
64    CFStringRef string = CFURLCopyFileSystemPath(fileURL, kCFURLWindowsPathStyle);
65    String result(string);
66    CFRelease(string);
67    return result;
68}
69
70CFURLRef MarshallingHelpers::BSTRToCFURLRef(BSTR urlStr)
71{
72    CFStringRef urlCFString = BSTRToCFStringRef(urlStr);
73    if (!urlCFString)
74        return 0;
75
76    CFURLRef urlRef = CFURLCreateWithString(0, urlCFString, 0);
77    CFRelease(urlCFString);
78
79    return urlRef;
80}
81
82CFStringRef MarshallingHelpers::BSTRToCFStringRef(BSTR str)
83{
84    return CFStringCreateWithCharacters(0, (const UniChar*)(str ? str : TEXT("")), SysStringLen(str));
85}
86
87CFStringRef MarshallingHelpers::LPCOLESTRToCFStringRef(LPCOLESTR str)
88{
89    return CFStringCreateWithCharacters(0, (const UniChar*)(str ? str : TEXT("")), (CFIndex)(str ? wcslen(str) : 0));
90}
91
92BSTR MarshallingHelpers::CFStringRefToBSTR(CFStringRef str)
93{
94    if (!str)
95        return 0;
96
97    const UniChar* uniChars = CFStringGetCharactersPtr(str);
98    if (uniChars)
99        return SysAllocStringLen((LPCTSTR)uniChars, CFStringGetLength(str));
100
101    CFIndex length = CFStringGetLength(str);
102    BSTR bstr = SysAllocStringLen(0, length);
103    if (bstr) {
104        CFStringGetCharacters(str, CFRangeMake(0, length), (UniChar*)bstr);
105        bstr[length] = 0;
106    }
107    return bstr;
108}
109
110int MarshallingHelpers::CFNumberRefToInt(CFNumberRef num)
111{
112    int number;
113    CFNumberGetValue(num, kCFNumberIntType, &number);
114    return number;
115}
116
117CFNumberRef MarshallingHelpers::intToCFNumberRef(int num)
118{
119    return CFNumberCreate(0, kCFNumberSInt32Type, &num);
120}
121
122CFAbsoluteTime MarshallingHelpers::windowsEpochAbsoluteTime()
123{
124    static CFAbsoluteTime windowsEpochAbsoluteTime = 0;
125    if (!windowsEpochAbsoluteTime) {
126        CFGregorianDate windowsEpochDate = {1899, 12, 30, 0, 0, 0.0};
127        windowsEpochAbsoluteTime = CFGregorianDateGetAbsoluteTime(windowsEpochDate, 0) / secondsPerDay;
128    }
129    return windowsEpochAbsoluteTime;
130}
131
132CFAbsoluteTime MarshallingHelpers::DATEToCFAbsoluteTime(DATE date)
133{
134    // <http://msdn2.microsoft.com/en-us/library/ms221627.aspx>
135    // DATE: This is the same numbering system used by most spreadsheet programs,
136    // although some specify incorrectly that February 29, 1900 existed, and thus
137    // set January 1, 1900 to 1.0. The date can be converted to and from an MS-DOS
138    // representation using VariantTimeToDosDateTime, which is discussed in
139    // Conversion and Manipulation Functions.
140
141    // CFAbsoluteTime: Type used to represent a specific point in time relative
142    // to the absolute reference date of 1 Jan 2001 00:00:00 GMT.
143    // Absolute time is measured by the number of seconds between the reference
144    // date and the specified date. Negative values indicate dates/times before
145    // the reference date. Positive values indicate dates/times after the
146    // reference date.
147
148    return round((date + windowsEpochAbsoluteTime()) * secondsPerDay);
149}
150
151DATE MarshallingHelpers::CFAbsoluteTimeToDATE(CFAbsoluteTime absoluteTime)
152{
153    return (round(absoluteTime)/secondsPerDay - windowsEpochAbsoluteTime());
154}
155
156// utility method to store a 1-dim string vector into a newly created SAFEARRAY
157SAFEARRAY* MarshallingHelpers::stringArrayToSafeArray(CFArrayRef inArray)
158{
159    CFIndex size = CFArrayGetCount(inArray);
160    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_BSTR, 0, (ULONG) size, 0);
161    long count = 0;
162    for (CFIndex i=0; i<size; i++) {
163        CFStringRef item = (CFStringRef) CFArrayGetValueAtIndex(inArray, i);
164        BSTR bstr = CFStringRefToBSTR(item);
165        ::SafeArrayPutElement(sa, &count, bstr);
166        SysFreeString(bstr);    // SafeArrayPutElement() should make a copy of the string
167        count++;
168    }
169    return sa;
170}
171
172// utility method to store a 1-dim int vector into a newly created SAFEARRAY
173SAFEARRAY* MarshallingHelpers::intArrayToSafeArray(CFArrayRef inArray)
174{
175    CFIndex size = CFArrayGetCount(inArray);
176    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_I4, 0, (ULONG) size, 0);
177    long count = 0;
178    for (CFIndex i=0; i<size; i++) {
179        CFNumberRef item = (CFNumberRef) CFArrayGetValueAtIndex(inArray, i);
180        int number = CFNumberRefToInt(item);
181        ::SafeArrayPutElement(sa, &count, &number);
182        count++;
183    }
184    return sa;
185}
186
187SAFEARRAY* MarshallingHelpers::intRectToSafeArray(const WebCore::IntRect& rect)
188{
189    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_I4, 0, 4, 0);
190    long count = 0;
191    int value;
192
193    value = rect.x();
194    ::SafeArrayPutElement(sa, &count, &value);
195    count++;
196
197    value = rect.y();
198    ::SafeArrayPutElement(sa, &count, &value);
199    count++;
200
201    value = rect.width();
202    ::SafeArrayPutElement(sa, &count, &value);
203    count++;
204
205    value = rect.height();
206    ::SafeArrayPutElement(sa, &count, &value);
207    count++;
208
209    return sa;
210}
211
212// utility method to store a 1-dim IUnknown* vector into a newly created SAFEARRAY
213SAFEARRAY* MarshallingHelpers::iunknownArrayToSafeArray(CFArrayRef inArray)
214{
215    CFIndex size = CFArrayGetCount(inArray);
216    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_UNKNOWN, 0, (ULONG) size, (LPVOID)&IID_IUnknown);
217    long count = 0;
218    for (CFIndex i=0; i<size; i++) {
219        IUnknown* item = (IUnknown*) CFArrayGetValueAtIndex(inArray, i);
220        ::SafeArrayPutElement(sa, &count, item);    // SafeArrayPutElement() adds a reference to the IUnknown added
221        count++;
222    }
223    return sa;
224}
225
226CFArrayRef MarshallingHelpers::safeArrayToStringArray(SAFEARRAY* inArray)
227{
228    long lBound=0, uBound=-1;
229    HRESULT hr = ::SafeArrayGetLBound(inArray, 1, &lBound);
230    if (SUCCEEDED(hr))
231        hr = ::SafeArrayGetUBound(inArray, 1, &uBound);
232    long len = (SUCCEEDED(hr)) ? (uBound-lBound+1) : 0;
233    CFStringRef* items = 0;
234    if (len > 0) {
235        items = new CFStringRef[len];
236        for (; lBound <= uBound; lBound++) {
237            BSTR str;
238            hr = ::SafeArrayGetElement(inArray, &lBound, &str);
239            items[lBound] = BSTRToCFStringRef(str);
240            SysFreeString(str);
241        }
242    }
243    CFArrayRef result = CFArrayCreate(0, (const void**)items, len, &kCFTypeArrayCallBacks);
244    if (items)
245        delete[] items;
246    return result;
247}
248
249CFArrayRef MarshallingHelpers::safeArrayToIntArray(SAFEARRAY* inArray)
250{
251    long lBound=0, uBound=-1;
252    HRESULT hr = ::SafeArrayGetLBound(inArray, 1, &lBound);
253    if (SUCCEEDED(hr))
254        hr = ::SafeArrayGetUBound(inArray, 1, &uBound);
255    long len = (SUCCEEDED(hr)) ? (uBound-lBound+1) : 0;
256    CFNumberRef* items = 0;
257    if (len > 0) {
258        items = new CFNumberRef[len];
259        for (; lBound <= uBound; lBound++) {
260            int num;
261            hr = ::SafeArrayGetElement(inArray, &lBound, &num);
262            items[lBound] = intToCFNumberRef(num);
263        }
264    }
265    CFArrayRef result = CFArrayCreate(0, (const void**) items, len, &kCFTypeArrayCallBacks);
266    if (items)
267        delete[] items;
268    return result;
269}
270
271CFArrayRef MarshallingHelpers::safeArrayToIUnknownArray(SAFEARRAY* inArray)
272{
273    long lBound=0, uBound=-1;
274    HRESULT hr = ::SafeArrayGetLBound(inArray, 1, &lBound);
275    if (SUCCEEDED(hr))
276        hr = ::SafeArrayGetUBound(inArray, 1, &uBound);
277    long len = (SUCCEEDED(hr)) ? (uBound-lBound+1) : 0;
278    void* items;
279    hr = ::SafeArrayAccessData(inArray, &items);
280    CFArrayRef result = CFArrayCreate(0, (const void**) items, len, &kIUnknownArrayCallBacks);
281    hr = ::SafeArrayUnaccessData(inArray);
282    return result;
283}
284
285const void* MarshallingHelpers::IUnknownRetainCallback(CFAllocatorRef /*allocator*/, const void* value)
286{
287    ((IUnknown*) value)->AddRef();
288    return value;
289}
290
291void MarshallingHelpers::IUnknownReleaseCallback(CFAllocatorRef /*allocator*/, const void* value)
292{
293    ((IUnknown*) value)->Release();
294}
295