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
30#include <WebCore/BString.h>
31#include <WebCore/IntRect.h>
32#include <WebCore/KURL.h>
33#include <wtf/MathExtras.h>
34#include <wtf/text/WTFString.h>
35
36using namespace WebCore;
37
38static const double secondsPerDay = 60 * 60 * 24;
39
40CFArrayCallBacks MarshallingHelpers::kIUnknownArrayCallBacks = {0, IUnknownRetainCallback, IUnknownReleaseCallback, 0, 0};
41CFDictionaryValueCallBacks MarshallingHelpers::kIUnknownDictionaryValueCallBacks = {0, IUnknownRetainCallback, IUnknownReleaseCallback, 0, 0};
42
43KURL MarshallingHelpers::BSTRToKURL(BSTR urlStr)
44{
45    return KURL(KURL(), String(urlStr, SysStringLen(urlStr)));
46}
47
48BSTR MarshallingHelpers::KURLToBSTR(const KURL& url)
49{
50    return BString(url.string()).release();
51}
52
53CFURLRef MarshallingHelpers::PathStringToFileCFURLRef(const String& string)
54{
55    CFStringRef cfPath = CFStringCreateWithCharactersNoCopy(0, (const UniChar*)string.characters(), string.length(), kCFAllocatorNull);
56    CFURLRef pathURL = CFURLCreateWithFileSystemPath(0, cfPath, kCFURLWindowsPathStyle, false);
57    CFRelease(cfPath);
58    return pathURL;
59}
60
61String MarshallingHelpers::FileCFURLRefToPathString(CFURLRef fileURL)
62{
63    CFStringRef string = CFURLCopyFileSystemPath(fileURL, kCFURLWindowsPathStyle);
64    String result(string);
65    CFRelease(string);
66    return result;
67}
68
69CFURLRef MarshallingHelpers::BSTRToCFURLRef(BSTR urlStr)
70{
71    CFStringRef urlCFString = BSTRToCFStringRef(urlStr);
72    if (!urlCFString)
73        return 0;
74
75    CFURLRef urlRef = CFURLCreateWithString(0, urlCFString, 0);
76    CFRelease(urlCFString);
77
78    return urlRef;
79}
80
81CFStringRef MarshallingHelpers::BSTRToCFStringRef(BSTR str)
82{
83    return CFStringCreateWithCharacters(0, (const UniChar*)(str ? str : TEXT("")), SysStringLen(str));
84}
85
86CFStringRef MarshallingHelpers::LPCOLESTRToCFStringRef(LPCOLESTR str)
87{
88    return CFStringCreateWithCharacters(0, (const UniChar*)(str ? str : TEXT("")), (CFIndex)(str ? wcslen(str) : 0));
89}
90
91BSTR MarshallingHelpers::CFStringRefToBSTR(CFStringRef str)
92{
93    return BString(str).release();
94}
95
96int MarshallingHelpers::CFNumberRefToInt(CFNumberRef num)
97{
98    int number;
99    CFNumberGetValue(num, kCFNumberIntType, &number);
100    return number;
101}
102
103CFNumberRef MarshallingHelpers::intToCFNumberRef(int num)
104{
105    return CFNumberCreate(0, kCFNumberSInt32Type, &num);
106}
107
108CFAbsoluteTime MarshallingHelpers::windowsEpochAbsoluteTime()
109{
110    static CFAbsoluteTime windowsEpochAbsoluteTime = 0;
111    if (!windowsEpochAbsoluteTime) {
112        CFGregorianDate windowsEpochDate = {1899, 12, 30, 0, 0, 0.0};
113        windowsEpochAbsoluteTime = CFGregorianDateGetAbsoluteTime(windowsEpochDate, 0) / secondsPerDay;
114    }
115    return windowsEpochAbsoluteTime;
116}
117
118CFAbsoluteTime MarshallingHelpers::DATEToCFAbsoluteTime(DATE date)
119{
120    // <http://msdn2.microsoft.com/en-us/library/ms221627.aspx>
121    // DATE: This is the same numbering system used by most spreadsheet programs,
122    // although some specify incorrectly that February 29, 1900 existed, and thus
123    // set January 1, 1900 to 1.0. The date can be converted to and from an MS-DOS
124    // representation using VariantTimeToDosDateTime, which is discussed in
125    // Conversion and Manipulation Functions.
126
127    // CFAbsoluteTime: Type used to represent a specific point in time relative
128    // to the absolute reference date of 1 Jan 2001 00:00:00 GMT.
129    // Absolute time is measured by the number of seconds between the reference
130    // date and the specified date. Negative values indicate dates/times before
131    // the reference date. Positive values indicate dates/times after the
132    // reference date.
133
134    return round((date + windowsEpochAbsoluteTime()) * secondsPerDay);
135}
136
137DATE MarshallingHelpers::CFAbsoluteTimeToDATE(CFAbsoluteTime absoluteTime)
138{
139    return (round(absoluteTime)/secondsPerDay - windowsEpochAbsoluteTime());
140}
141
142// utility method to store a 1-dim string vector into a newly created SAFEARRAY
143SAFEARRAY* MarshallingHelpers::stringArrayToSafeArray(CFArrayRef inArray)
144{
145    CFIndex size = CFArrayGetCount(inArray);
146    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_BSTR, 0, (ULONG) size, 0);
147    long count = 0;
148    for (CFIndex i=0; i<size; i++) {
149        CFStringRef item = (CFStringRef) CFArrayGetValueAtIndex(inArray, i);
150        BString bstr(item);
151        ::SafeArrayPutElement(sa, &count, bstr); // SafeArrayPutElement() copies the string correctly.
152        count++;
153    }
154    return sa;
155}
156
157// utility method to store a 1-dim int vector into a newly created SAFEARRAY
158SAFEARRAY* MarshallingHelpers::intArrayToSafeArray(CFArrayRef inArray)
159{
160    CFIndex size = CFArrayGetCount(inArray);
161    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_I4, 0, (ULONG) size, 0);
162    long count = 0;
163    for (CFIndex i=0; i<size; i++) {
164        CFNumberRef item = (CFNumberRef) CFArrayGetValueAtIndex(inArray, i);
165        int number = CFNumberRefToInt(item);
166        ::SafeArrayPutElement(sa, &count, &number);
167        count++;
168    }
169    return sa;
170}
171
172SAFEARRAY* MarshallingHelpers::intRectToSafeArray(const WebCore::IntRect& rect)
173{
174    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_I4, 0, 4, 0);
175    long count = 0;
176    int value;
177
178    value = rect.x();
179    ::SafeArrayPutElement(sa, &count, &value);
180    count++;
181
182    value = rect.y();
183    ::SafeArrayPutElement(sa, &count, &value);
184    count++;
185
186    value = rect.width();
187    ::SafeArrayPutElement(sa, &count, &value);
188    count++;
189
190    value = rect.height();
191    ::SafeArrayPutElement(sa, &count, &value);
192    count++;
193
194    return sa;
195}
196
197// utility method to store a 1-dim IUnknown* vector into a newly created SAFEARRAY
198SAFEARRAY* MarshallingHelpers::iunknownArrayToSafeArray(CFArrayRef inArray)
199{
200    CFIndex size = CFArrayGetCount(inArray);
201    SAFEARRAY* sa = ::SafeArrayCreateVectorEx(VT_UNKNOWN, 0, (ULONG) size, (LPVOID)&IID_IUnknown);
202    long count = 0;
203    for (CFIndex i=0; i<size; i++) {
204        IUnknown* item = (IUnknown*) CFArrayGetValueAtIndex(inArray, i);
205        ::SafeArrayPutElement(sa, &count, item);    // SafeArrayPutElement() adds a reference to the IUnknown added
206        count++;
207    }
208    return sa;
209}
210
211CFArrayRef MarshallingHelpers::safeArrayToStringArray(SAFEARRAY* inArray)
212{
213    long lBound=0, uBound=-1;
214    HRESULT hr = ::SafeArrayGetLBound(inArray, 1, &lBound);
215    if (SUCCEEDED(hr))
216        hr = ::SafeArrayGetUBound(inArray, 1, &uBound);
217    long len = (SUCCEEDED(hr)) ? (uBound-lBound+1) : 0;
218    CFStringRef* items = 0;
219    if (len > 0) {
220        items = new CFStringRef[len];
221        for (; lBound <= uBound; lBound++) {
222            BString str;
223            hr = ::SafeArrayGetElement(inArray, &lBound, &str);
224            items[lBound] = BSTRToCFStringRef(str);
225        }
226    }
227    CFArrayRef result = CFArrayCreate(0, (const void**)items, len, &kCFTypeArrayCallBacks);
228    if (items)
229        delete[] items;
230    return result;
231}
232
233CFArrayRef MarshallingHelpers::safeArrayToIntArray(SAFEARRAY* inArray)
234{
235    long lBound=0, uBound=-1;
236    HRESULT hr = ::SafeArrayGetLBound(inArray, 1, &lBound);
237    if (SUCCEEDED(hr))
238        hr = ::SafeArrayGetUBound(inArray, 1, &uBound);
239    long len = (SUCCEEDED(hr)) ? (uBound-lBound+1) : 0;
240    CFNumberRef* items = 0;
241    if (len > 0) {
242        items = new CFNumberRef[len];
243        for (; lBound <= uBound; lBound++) {
244            int num;
245            hr = ::SafeArrayGetElement(inArray, &lBound, &num);
246            items[lBound] = intToCFNumberRef(num);
247        }
248    }
249    CFArrayRef result = CFArrayCreate(0, (const void**) items, len, &kCFTypeArrayCallBacks);
250    if (items)
251        delete[] items;
252    return result;
253}
254
255CFArrayRef MarshallingHelpers::safeArrayToIUnknownArray(SAFEARRAY* inArray)
256{
257    long lBound=0, uBound=-1;
258    HRESULT hr = ::SafeArrayGetLBound(inArray, 1, &lBound);
259    if (SUCCEEDED(hr))
260        hr = ::SafeArrayGetUBound(inArray, 1, &uBound);
261    long len = (SUCCEEDED(hr)) ? (uBound-lBound+1) : 0;
262    void* items;
263    hr = ::SafeArrayAccessData(inArray, &items);
264    CFArrayRef result = CFArrayCreate(0, (const void**) items, len, &kIUnknownArrayCallBacks);
265    hr = ::SafeArrayUnaccessData(inArray);
266    return result;
267}
268
269const void* MarshallingHelpers::IUnknownRetainCallback(CFAllocatorRef /*allocator*/, const void* value)
270{
271    ((IUnknown*) value)->AddRef();
272    return value;
273}
274
275void MarshallingHelpers::IUnknownReleaseCallback(CFAllocatorRef /*allocator*/, const void* value)
276{
277    ((IUnknown*) value)->Release();
278}
279