Unreviewed, rolling out r215608.
[WebKit-https.git] / Source / WebCore / platform / SharedBuffer.cpp
1 /*
2  * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  * Copyright (C) 2015 Canon Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "SharedBuffer.h"
30
31 #include <algorithm>
32 #include <wtf/unicode/UTF8.h>
33
34 namespace WebCore {
35
36 #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
37
38 static const unsigned segmentSize = 0x1000;
39 static const unsigned segmentPositionMask = 0x0FFF;
40
41 static inline unsigned segmentIndex(unsigned position)
42 {
43     return position / segmentSize;
44 }
45
46 static inline unsigned offsetInSegment(unsigned position)
47 {
48     return position & segmentPositionMask;
49 }
50
51 static inline char* allocateSegment() WARN_UNUSED_RETURN;
52 static inline char* allocateSegment()
53 {
54     return static_cast<char*>(fastMalloc(segmentSize));
55 }
56
57 static inline void freeSegment(char* p)
58 {
59     fastFree(p);
60 }
61
62 #endif
63
64 SharedBuffer::SharedBuffer()
65     : m_buffer(adoptRef(*new DataBuffer))
66 {
67 }
68
69 SharedBuffer::SharedBuffer(const char* data, unsigned size)
70     : m_buffer(adoptRef(*new DataBuffer))
71 {
72     append(data, size);
73 }
74
75 SharedBuffer::SharedBuffer(const unsigned char* data, unsigned size)
76     : m_buffer(adoptRef(*new DataBuffer))
77 {
78     append(reinterpret_cast<const char*>(data), size);
79 }
80
81 SharedBuffer::SharedBuffer(MappedFileData&& fileData)
82     : m_buffer(adoptRef(*new DataBuffer))
83     , m_fileData(WTFMove(fileData))
84 {
85 }
86
87 SharedBuffer::~SharedBuffer()
88 {
89     clear();
90 }
91
92 RefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
93 {
94     bool mappingSuccess;
95     MappedFileData mappedFileData(filePath, mappingSuccess);
96
97     if (!mappingSuccess)
98         return SharedBuffer::createFromReadingFile(filePath);
99
100     return adoptRef(new SharedBuffer(WTFMove(mappedFileData)));
101 }
102
103 Ref<SharedBuffer> SharedBuffer::create(Vector<char>&& vector)
104 {
105     auto buffer = create();
106     buffer->m_buffer->data = WTFMove(vector);
107     buffer->m_size = buffer->m_buffer->data.size();
108     return buffer;
109 }
110
111 unsigned SharedBuffer::size() const
112 {
113     if (hasPlatformData())
114         return platformDataSize();
115     
116     if (m_fileData)
117         return m_fileData.size();
118
119     return m_size;
120 }
121
122 const char* SharedBuffer::data() const
123 {
124     if (hasPlatformData())
125         return platformData();
126
127     if (m_fileData)
128         return static_cast<const char*>(m_fileData.data());
129
130 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
131     if (const char* buffer = singleDataArrayBuffer())
132         return buffer;
133 #endif
134
135     return this->buffer().data();
136 }
137
138 RefPtr<ArrayBuffer> SharedBuffer::createArrayBuffer() const
139 {
140     RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::createUninitialized(static_cast<unsigned>(size()), sizeof(char));
141     if (!arrayBuffer) {
142         WTFLogAlways("SharedBuffer::createArrayBuffer Unable to create buffer. Requested size was %d x %lu\n", size(), sizeof(char));
143         return nullptr;
144     }
145
146     const char* segment = 0;
147     unsigned position = 0;
148     while (unsigned segmentSize = getSomeData(segment, position)) {
149         memcpy(static_cast<char*>(arrayBuffer->data()) + position, segment, segmentSize);
150         position += segmentSize;
151     }
152
153     if (position != arrayBuffer->byteLength()) {
154         ASSERT_NOT_REACHED();
155         // Don't return the incomplete ArrayBuffer.
156         return nullptr;
157     }
158
159     return arrayBuffer;
160 }
161
162 void SharedBuffer::append(SharedBuffer& data)
163 {
164     if (maybeAppendPlatformData(data))
165         return;
166 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
167     if (maybeAppendDataArray(data))
168         return;
169 #endif
170
171     const char* segment;
172     size_t position = 0;
173     while (size_t length = data.getSomeData(segment, position)) {
174         append(segment, length);
175         position += length;
176     }
177 }
178
179 void SharedBuffer::append(const char* data, unsigned length)
180 {
181     if (!length)
182         return;
183
184     maybeTransferMappedFileData();
185     maybeTransferPlatformData();
186
187 #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
188     unsigned positionInSegment = offsetInSegment(m_size - m_buffer->data.size());
189     m_size += length;
190
191     if (m_size <= segmentSize) {
192         // No need to use segments for small resource data
193         if (m_buffer->data.isEmpty())
194             m_buffer->data.reserveInitialCapacity(length);
195         appendToDataBuffer(data, length);
196         return;
197     }
198
199     char* segment;
200     if (!positionInSegment) {
201         segment = allocateSegment();
202         m_segments.append(segment);
203     } else
204         segment = m_segments.last() + positionInSegment;
205
206     unsigned segmentFreeSpace = segmentSize - positionInSegment;
207     unsigned bytesToCopy = std::min(length, segmentFreeSpace);
208
209     for (;;) {
210         memcpy(segment, data, bytesToCopy);
211         if (static_cast<unsigned>(length) == bytesToCopy)
212             break;
213
214         length -= bytesToCopy;
215         data += bytesToCopy;
216         segment = allocateSegment();
217         m_segments.append(segment);
218         bytesToCopy = std::min(length, segmentSize);
219     }
220 #else
221     m_size += length;
222     if (m_buffer->data.isEmpty())
223         m_buffer->data.reserveInitialCapacity(length);
224     appendToDataBuffer(data, length);
225 #endif
226 }
227
228 void SharedBuffer::append(Vector<char>&& data)
229 {
230     // This takes its argument as a rvalue reference because we intend to have a future
231     // version take ownership of the vector rather than copying.
232     append(data.data(), data.size());
233 }
234
235 void SharedBuffer::clear()
236 {
237     m_fileData = { };
238
239     clearPlatformData();
240     
241 #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
242     for (char* segment : m_segments)
243         freeSegment(segment);
244     m_segments.clear();
245 #else
246     m_dataArray.clear();
247 #endif
248
249     m_size = 0;
250     clearDataBuffer();
251 }
252
253 Ref<SharedBuffer> SharedBuffer::copy() const
254 {
255     Ref<SharedBuffer> clone { adoptRef(*new SharedBuffer) };
256
257     if (hasPlatformData() || m_fileData) {
258         clone->append(data(), size());
259         return clone;
260     }
261
262     clone->m_size = m_size;
263     clone->m_buffer->data.reserveCapacity(m_size);
264     clone->m_buffer->data.append(m_buffer->data.data(), m_buffer->data.size());
265
266 #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
267     if (!m_segments.isEmpty()) {
268         unsigned lastIndex = m_segments.size() - 1;
269         for (unsigned i = 0; i < lastIndex; ++i)
270             clone->m_buffer->data.append(m_segments[i], segmentSize);
271
272         unsigned sizeOfLastSegment = m_size - m_buffer->data.size() - lastIndex * segmentSize;
273         clone->m_buffer->data.append(m_segments.last(), sizeOfLastSegment);
274     }
275 #else
276     for (auto& data : m_dataArray)
277         clone->m_dataArray.append(data.get());
278 #endif
279     ASSERT(clone->size() == size());
280
281     return clone;
282 }
283
284 void SharedBuffer::duplicateDataBufferIfNecessary() const
285 {
286     size_t currentCapacity = m_buffer->data.capacity();
287     if (m_buffer->hasOneRef() || m_size <= currentCapacity)
288         return;
289
290     size_t newCapacity = std::max(static_cast<size_t>(m_size), currentCapacity * 2);
291     auto newBuffer = adoptRef(*new DataBuffer);
292     newBuffer->data.reserveInitialCapacity(newCapacity);
293     newBuffer->data = m_buffer->data;
294     m_buffer = WTFMove(newBuffer);
295 }
296
297 void SharedBuffer::appendToDataBuffer(const char *data, unsigned length) const
298 {
299     duplicateDataBufferIfNecessary();
300     m_buffer->data.append(data, length);
301 }
302
303 void SharedBuffer::clearDataBuffer()
304 {
305     if (!m_buffer->hasOneRef())
306         m_buffer = adoptRef(*new DataBuffer);
307     else
308         m_buffer->data.clear();
309 }
310
311 #if !USE(CF)
312 void SharedBuffer::hintMemoryNotNeededSoon()
313 {
314 }
315 #endif
316
317 #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
318
319 void SharedBuffer::copyBufferAndClear(char* destination, unsigned bytesToCopy) const
320 {
321     for (char* segment : m_segments) {
322         unsigned effectiveBytesToCopy = std::min(bytesToCopy, segmentSize);
323         memcpy(destination, segment, effectiveBytesToCopy);
324         destination += effectiveBytesToCopy;
325         bytesToCopy -= effectiveBytesToCopy;
326         freeSegment(segment);
327     }
328     m_segments.clear();
329 }
330
331 #endif
332
333 const Vector<char>& SharedBuffer::buffer() const
334 {
335     unsigned bufferSize = m_buffer->data.size();
336     if (m_size > bufferSize) {
337         duplicateDataBufferIfNecessary();
338         m_buffer->data.resize(m_size);
339         copyBufferAndClear(m_buffer->data.data() + bufferSize, m_size - bufferSize);
340     }
341     return m_buffer->data;
342 }
343
344 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
345 {
346     unsigned totalSize = size();
347     if (position >= totalSize) {
348         someData = 0;
349         return 0;
350     }
351
352     if (hasPlatformData() || m_fileData) {
353         ASSERT_WITH_SECURITY_IMPLICATION(position < size());
354         someData = data() + position;
355         return totalSize - position;
356     }
357
358     ASSERT_WITH_SECURITY_IMPLICATION(position < m_size);
359     unsigned consecutiveSize = m_buffer->data.size();
360     if (position < consecutiveSize) {
361         someData = m_buffer->data.data() + position;
362         return consecutiveSize - position;
363     }
364  
365     position -= consecutiveSize;
366 #if !USE(NETWORK_CFDATA_ARRAY_CALLBACK)
367     unsigned segments = m_segments.size();
368     unsigned maxSegmentedSize = segments * segmentSize;
369     unsigned segment = segmentIndex(position);
370     if (segment < segments) {
371         unsigned bytesLeft = totalSize - consecutiveSize;
372         unsigned segmentedSize = std::min(maxSegmentedSize, bytesLeft);
373
374         unsigned positionInSegment = offsetInSegment(position);
375         someData = m_segments[segment] + positionInSegment;
376         return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
377     }
378     ASSERT_NOT_REACHED();
379     return 0;
380 #else
381     return copySomeDataFromDataArray(someData, position);
382 #endif
383 }
384
385 void SharedBuffer::maybeTransferMappedFileData()
386 {
387     if (m_fileData) {
388         auto fileData = WTFMove(m_fileData);
389         append(static_cast<const char*>(fileData.data()), fileData.size());
390     }
391 }
392
393 #if !USE(CF) && !USE(SOUP)
394
395 inline void SharedBuffer::clearPlatformData()
396 {
397 }
398
399 inline void SharedBuffer::maybeTransferPlatformData()
400 {
401 }
402
403 inline bool SharedBuffer::hasPlatformData() const
404 {
405     return false;
406 }
407
408 inline const char* SharedBuffer::platformData() const
409 {
410     ASSERT_NOT_REACHED();
411
412     return nullptr;
413 }
414
415 inline bool SharedBuffer::maybeAppendPlatformData(SharedBuffer&)
416 {
417     return false;
418 }
419
420 #endif
421
422 RefPtr<SharedBuffer> utf8Buffer(const String& string)
423 {
424     // Allocate a buffer big enough to hold all the characters.
425     const int length = string.length();
426     Vector<char> buffer(length * 3);
427
428     // Convert to runs of 8-bit characters.
429     char* p = buffer.data();
430     WTF::Unicode::ConversionResult result;
431     if (length) {
432         if (string.is8Bit()) {
433             const LChar* d = string.characters8();
434             result = WTF::Unicode::convertLatin1ToUTF8(&d, d + length, &p, p + buffer.size());
435         } else {
436             const UChar* d = string.characters16();
437             result = WTF::Unicode::convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), true);
438         }
439         if (result != WTF::Unicode::conversionOK)
440             return nullptr;
441     }
442
443     buffer.shrink(p - buffer.data());
444     return SharedBuffer::create(WTFMove(buffer));
445 }
446
447 } // namespace WebCore