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