1/*
2 * Copyright (C) 2012 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 INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ShareableResource.h"
28
29#if ENABLE(SHAREABLE_RESOURCE)
30
31#include "ArgumentCoders.h"
32#include <WebCore/SharedBuffer.h>
33
34using namespace WebCore;
35
36namespace WebKit {
37
38ShareableResource::Handle::Handle()
39{
40}
41
42void ShareableResource::Handle::encode(IPC::ArgumentEncoder& encoder) const
43{
44    encoder << m_handle;
45    encoder << m_offset;
46    encoder << m_size;
47}
48
49bool ShareableResource::Handle::decode(IPC::ArgumentDecoder& decoder, Handle& handle)
50{
51    if (!decoder.decode(handle.m_handle))
52        return false;
53    if (!decoder.decode(handle.m_offset))
54        return false;
55    if (!decoder.decode(handle.m_size))
56        return false;
57    return true;
58}
59
60static void shareableResourceDeallocate(void *ptr, void *info)
61{
62    (static_cast<ShareableResource*>(info))->deref(); // Balanced by ref() in createShareableResourceDeallocator()
63}
64
65static CFAllocatorRef createShareableResourceDeallocator(ShareableResource* resource)
66{
67    resource->ref(); // Balanced by deref in shareableResourceDeallocate()
68
69    CFAllocatorContext context = { 0,
70        resource,
71        NULL, // retain
72        NULL, // release
73        NULL, // copyDescription
74        NULL, // allocate
75        NULL, // reallocate
76        shareableResourceDeallocate,
77        NULL, // preferredSize
78    };
79
80    return CFAllocatorCreate(kCFAllocatorDefault, &context);
81}
82
83RetainPtr<CFDataRef> ShareableResource::Handle::tryWrapInCFData() const
84{
85    RefPtr<ShareableResource> resource = ShareableResource::create(*this);
86    if (!resource) {
87        LOG_ERROR("Failed to recreate ShareableResource from handle.");
88        return 0;
89    }
90
91    RetainPtr<CFAllocatorRef> deallocator = adoptCF(createShareableResourceDeallocator(resource.get()));
92    return adoptCF(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(resource->data()), static_cast<CFIndex>(resource->size()), deallocator.get()));
93}
94
95PassRefPtr<SharedBuffer> ShareableResource::Handle::tryWrapInSharedBuffer() const
96{
97    return SharedBuffer::wrapCFData(tryWrapInCFData().get());
98}
99
100PassRefPtr<ShareableResource> ShareableResource::create(PassRefPtr<SharedMemory> sharedMemory, unsigned offset, unsigned size)
101{
102    return adoptRef(new ShareableResource(sharedMemory, offset, size));
103}
104
105PassRefPtr<ShareableResource> ShareableResource::create(const Handle& handle)
106{
107    RefPtr<SharedMemory> sharedMemory = SharedMemory::create(handle.m_handle, SharedMemory::ReadOnly);
108    if (!sharedMemory)
109        return 0;
110
111    return create(sharedMemory.release(), handle.m_offset, handle.m_size);
112}
113
114ShareableResource::ShareableResource(PassRefPtr<SharedMemory> sharedMemory, unsigned offset, unsigned size)
115    : m_sharedMemory(sharedMemory)
116    , m_offset(offset)
117    , m_size(size)
118{
119    ASSERT(m_sharedMemory);
120    ASSERT(m_offset + m_size <= m_sharedMemory->size());
121
122    // FIXME (NetworkProcess): This data was received from another process.  If it is bogus, should we assume that process is compromised and we should kill it?
123}
124
125ShareableResource::~ShareableResource()
126{
127}
128
129bool ShareableResource::createHandle(Handle& handle)
130{
131    if (!m_sharedMemory->createHandle(handle.m_handle, SharedMemory::ReadOnly))
132        return false;
133
134    handle.m_offset = m_offset;
135    handle.m_size = m_size;
136
137    return true;
138}
139
140const char* ShareableResource::data() const
141{
142    return static_cast<const char*>(m_sharedMemory->data()) + m_offset;
143}
144
145unsigned ShareableResource::size() const
146{
147    return m_size;
148}
149
150} // namespace WebKit
151
152#endif // ENABLE(SHAREABLE_RESOURCE)
153