[Cocoa] Teach SharedBuffer to return an NSArray of data segments to avoid flattening
[WebKit-https.git] / Source / WebCore / platform / cocoa / SharedBufferCocoa.mm
1 /*
2  * Copyright (C) 2006-2017 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. ``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 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 "SharedBuffer.h"
28
29 #include "WebCoreObjCExtras.h"
30 #include <runtime/InitializeThreading.h>
31 #include <string.h>
32 #include <wtf/MainThread.h>
33
34 using namespace WebCore;
35
36 @interface WebCoreSharedBufferData : NSData
37 {
38     RefPtr<SharedBuffer::DataBuffer> sharedBufferDataBuffer;
39 }
40
41 - (id)initWithSharedBufferDataBuffer:(SharedBuffer::DataBuffer*)dataBuffer;
42 @end
43
44 @implementation WebCoreSharedBufferData
45
46 + (void)initialize
47 {
48 #if !USE(WEB_THREAD)
49     JSC::initializeThreading();
50     WTF::initializeMainThreadToProcessMainThread();
51 #endif // !USE(WEB_THREAD)
52 }
53
54 - (void)dealloc
55 {
56     if (WebCoreObjCScheduleDeallocateOnMainThread([WebCoreSharedBufferData class], self))
57         return;
58
59     [super dealloc];
60 }
61
62 - (id)initWithSharedBufferDataBuffer:(SharedBuffer::DataBuffer*)dataBuffer
63 {
64     self = [super init];
65     
66     if (self)
67         sharedBufferDataBuffer = dataBuffer;
68
69     return self;
70 }
71
72 - (NSUInteger)length
73 {
74     return sharedBufferDataBuffer->data.size();
75 }
76
77 - (const void *)bytes
78 {
79     return sharedBufferDataBuffer->data.data();
80 }
81
82 @end
83
84 namespace WebCore {
85
86 Ref<SharedBuffer> SharedBuffer::wrapNSData(NSData *nsData)
87 {
88     return adoptRef(*new SharedBuffer((CFDataRef)nsData));
89 }
90
91 RetainPtr<NSData> SharedBuffer::createNSData()
92 {
93     return adoptNS((NSData *)createCFData().leakRef());
94 }
95
96 CFDataRef SharedBuffer::existingCFData()
97 {
98     if (m_cfData)
99         return m_cfData.get();
100
101 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
102     if (m_dataArray.size() == 1)
103         return m_dataArray.at(0).get();
104 #endif
105
106     return nullptr;
107 }
108
109 RetainPtr<CFDataRef> SharedBuffer::createCFData()
110 {
111     if (CFDataRef cfData = existingCFData())
112         return cfData;
113
114     data(); // Force data into m_buffer from segments or data array.
115     return adoptCF((CFDataRef)adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataBuffer:m_buffer.ptr()]).leakRef());
116 }
117
118 RefPtr<SharedBuffer> SharedBuffer::createFromReadingFile(const String& filePath)
119 {
120     NSData *resourceData = [NSData dataWithContentsOfFile:filePath];
121     if (resourceData) 
122         return SharedBuffer::wrapNSData(resourceData);
123     return nullptr;
124 }
125
126 RetainPtr<NSArray> SharedBuffer::createNSDataArray()
127 {
128     if (auto platformData = (NSData *)m_cfData.get())
129         return @[ platformData ];
130
131     if (m_fileData)
132         return @[ [NSData dataWithBytes:m_fileData.data() length:m_fileData.size()] ];
133
134     auto dataArray = adoptNS([[NSMutableArray alloc] init]);
135     if (m_buffer->data.size())
136         [dataArray addObject:adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataBuffer:m_buffer.ptr()]).get()];
137
138 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
139     for (auto& data : m_dataArray)
140         [dataArray addObject:(NSData *)data.get()];
141 #else
142     // Cocoa platforms all currently USE(NETWORK_CFDATA_ARRAY_CALLBACK), so implementing a code path for copying segments would be dead code.
143     // If this ever changes, the following static_assert will detect it.
144     static_assert(false, "FIXME: Copy the segments into an array of NSData objects.");
145 #endif
146
147     return WTFMove(dataArray);
148 }
149
150 }