0d35b213bfc21d9d8a9b1da1f3b2bc90574b925e
[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 #if USE(SOUP)
35 #include "GUniquePtrSoup.h"
36 #endif
37
38 namespace WebCore {
39
40 SharedBuffer::SharedBuffer(const char* data, size_t size)
41 {
42     append(data, size);
43 }
44
45 SharedBuffer::SharedBuffer(const unsigned char* data, size_t size)
46 {
47     append(reinterpret_cast<const char*>(data), size);
48 }
49
50 SharedBuffer::SharedBuffer(FileSystem::MappedFileData&& fileData)
51     : m_size(fileData.size())
52 {
53     m_segments.append({0, DataSegment::create(WTFMove(fileData))});
54 }
55
56 SharedBuffer::SharedBuffer(Vector<char>&& data)
57 {
58     append(WTFMove(data));
59 }
60
61 RefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
62 {
63     bool mappingSuccess;
64     FileSystem::MappedFileData mappedFileData(filePath, mappingSuccess);
65
66     if (!mappingSuccess)
67         return SharedBuffer::createFromReadingFile(filePath);
68
69     return adoptRef(new SharedBuffer(WTFMove(mappedFileData)));
70 }
71
72 Ref<SharedBuffer> SharedBuffer::create(Vector<char>&& vector)
73 {
74     return adoptRef(*new SharedBuffer(WTFMove(vector)));
75 }
76
77 void SharedBuffer::combineIntoOneSegment() const
78 {
79 #if !ASSERT_DISABLED
80     // FIXME: We ought to be able to set this to true and have no assertions fire.
81     // Remove all instances of appending after calling this, because they are all O(n^2) algorithms since r215686.
82     // m_hasBeenCombinedIntoOneSegment = true;
83 #endif
84     if (m_segments.size() <= 1)
85         return;
86
87     Vector<char> combinedData;
88     combinedData.reserveInitialCapacity(m_size);
89     for (const auto& segment : m_segments)
90         combinedData.append(segment.segment->data(), segment.segment->size());
91     ASSERT(combinedData.size() == m_size);
92     m_segments.clear();
93     m_segments.append({0, DataSegment::create(WTFMove(combinedData))});
94     ASSERT(m_segments.size() == 1);
95     ASSERT(internallyConsistent());
96 }
97
98 const char* SharedBuffer::data() const
99 {
100     if (!m_segments.size())
101         return nullptr;
102     combineIntoOneSegment();
103     ASSERT(internallyConsistent());
104     return m_segments[0].segment->data();
105 }
106
107 SharedBufferDataView SharedBuffer::getSomeData(size_t position) const
108 {
109     RELEASE_ASSERT(position < m_size);
110     auto comparator = [](const size_t& position, const DataSegmentVectorEntry& entry) {
111         return position < entry.beginPosition;
112     };
113     const DataSegmentVectorEntry* element = std::upper_bound(m_segments.begin(), m_segments.end(), position, comparator);
114     element--; // std::upper_bound gives a pointer to the element that is greater than position. We want the element just before that.
115     return { element->segment.copyRef(), position - element->beginPosition };
116 }
117
118 RefPtr<ArrayBuffer> SharedBuffer::tryCreateArrayBuffer() const
119 {
120     RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::createUninitialized(static_cast<unsigned>(size()), sizeof(char));
121     if (!arrayBuffer) {
122         WTFLogAlways("SharedBuffer::tryCreateArrayBuffer Unable to create buffer. Requested size was %zu x %lu\n", size(), sizeof(char));
123         return nullptr;
124     }
125
126     size_t position = 0;
127     for (const auto& segment : m_segments) {
128         memcpy(static_cast<char*>(arrayBuffer->data()) + position, segment.segment->data(), segment.segment->size());
129         position += segment.segment->size();
130     }
131
132     ASSERT(position == m_size);
133     ASSERT(internallyConsistent());
134     return arrayBuffer;
135 }
136
137 void SharedBuffer::append(const SharedBuffer& data)
138 {
139     ASSERT(!m_hasBeenCombinedIntoOneSegment);
140     m_segments.reserveCapacity(m_segments.size() + data.m_segments.size());
141     for (const auto& element : data.m_segments) {
142         m_segments.uncheckedAppend({m_size, element.segment.copyRef()});
143         m_size += element.segment->size();
144     }
145     ASSERT(internallyConsistent());
146 }
147
148 void SharedBuffer::append(const char* data, size_t length)
149 {
150     ASSERT(!m_hasBeenCombinedIntoOneSegment);
151     Vector<char> vector;
152     vector.append(data, length);
153     m_segments.append({m_size, DataSegment::create(WTFMove(vector))});
154     m_size += length;
155     ASSERT(internallyConsistent());
156 }
157
158 void SharedBuffer::append(Vector<char>&& data)
159 {
160     ASSERT(!m_hasBeenCombinedIntoOneSegment);
161     auto dataSize = data.size();
162     m_segments.append({m_size, DataSegment::create(WTFMove(data))});
163     m_size += dataSize;
164     ASSERT(internallyConsistent());
165 }
166
167 void SharedBuffer::clear()
168 {
169     m_size = 0;
170     m_segments.clear();
171     ASSERT(internallyConsistent());
172 }
173
174 Ref<SharedBuffer> SharedBuffer::copy() const
175 {
176     Ref<SharedBuffer> clone = adoptRef(*new SharedBuffer);
177     clone->m_size = m_size;
178     clone->m_segments.reserveInitialCapacity(m_segments.size());
179     for (const auto& element : m_segments)
180         clone->m_segments.uncheckedAppend({element.beginPosition, element.segment.copyRef()});
181     ASSERT(clone->internallyConsistent());
182     ASSERT(internallyConsistent());
183     return clone;
184 }
185
186 #if !ASSERT_DISABLED
187 bool SharedBuffer::internallyConsistent() const
188 {
189     size_t position = 0;
190     for (const auto& element : m_segments) {
191         if (element.beginPosition != position)
192             return false;
193         position += element.segment->size();
194     }
195     return position == m_size;
196 }
197 #endif
198
199 const char* SharedBuffer::DataSegment::data() const
200 {
201     auto visitor = WTF::makeVisitor(
202         [](const Vector<char>& data) { return data.data(); },
203 #if USE(CF)
204         [](const RetainPtr<CFDataRef>& data) { return reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())); },
205 #endif
206 #if USE(SOUP)
207         [](const GUniquePtr<SoupBuffer>& data) { return data->data; },
208 #endif
209         [](const FileSystem::MappedFileData& data) { return reinterpret_cast<const char*>(data.data()); }
210     );
211     return WTF::visit(visitor, m_immutableData);
212 }
213
214 #if !USE(CF)
215 void SharedBuffer::hintMemoryNotNeededSoon() const
216 {
217 }
218 #endif
219
220 size_t SharedBuffer::DataSegment::size() const
221 {
222     auto visitor = WTF::makeVisitor(
223         [](const Vector<char>& data) { return data.size(); },
224 #if USE(CF)
225         [](const RetainPtr<CFDataRef>& data) { return CFDataGetLength(data.get()); },
226 #endif
227 #if USE(SOUP)
228         [](const GUniquePtr<SoupBuffer>& data) { return static_cast<size_t>(data->length); },
229 #endif
230         [](const FileSystem::MappedFileData& data) { return data.size(); }
231     );
232     return WTF::visit(visitor, m_immutableData);
233 }
234
235 SharedBufferDataView::SharedBufferDataView(Ref<SharedBuffer::DataSegment>&& segment, size_t positionWithinSegment)
236     : m_positionWithinSegment(positionWithinSegment)
237     , m_segment(WTFMove(segment))
238 {
239     ASSERT(positionWithinSegment < m_segment->size());
240 }
241
242 size_t SharedBufferDataView::size() const
243 {
244     return m_segment->size() - m_positionWithinSegment;
245 }
246
247 const char* SharedBufferDataView::data() const
248 {
249     return m_segment->data() + m_positionWithinSegment;
250 }
251
252 RefPtr<SharedBuffer> utf8Buffer(const String& string)
253 {
254     // Allocate a buffer big enough to hold all the characters.
255     const int length = string.length();
256     Vector<char> buffer(length * 3);
257
258     // Convert to runs of 8-bit characters.
259     char* p = buffer.data();
260     WTF::Unicode::ConversionResult result;
261     if (length) {
262         if (string.is8Bit()) {
263             const LChar* d = string.characters8();
264             result = WTF::Unicode::convertLatin1ToUTF8(&d, d + length, &p, p + buffer.size());
265         } else {
266             const UChar* d = string.characters16();
267             result = WTF::Unicode::convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), true);
268         }
269         if (result != WTF::Unicode::conversionOK)
270             return nullptr;
271     }
272
273     buffer.shrink(p - buffer.data());
274     return SharedBuffer::create(WTFMove(buffer));
275 }
276
277 } // namespace WebCore