90f82da0fccfa86f07173fbbf4c43c7c2e1702e7
[WebKit-https.git] / Source / WebCore / platform / SharedBuffer.cpp
1 /*
2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "SharedBuffer.h"
29
30 #include "PlatformMemoryInstrumentation.h"
31 #include "PurgeableBuffer.h"
32 #include <wtf/MemoryInstrumentationVector.h>
33 #include <wtf/PassOwnPtr.h>
34 #include <wtf/unicode/UTF8.h>
35 #include <wtf/unicode/Unicode.h>
36
37 using namespace std;
38
39 namespace WebCore {
40
41 static const unsigned segmentSize = 0x1000;
42 static const unsigned segmentPositionMask = 0x0FFF;
43
44 static inline unsigned segmentIndex(unsigned position)
45 {
46     return position / segmentSize;
47 }
48
49 static inline unsigned offsetInSegment(unsigned position)
50 {
51     return position & segmentPositionMask;
52 }
53
54 static inline char* allocateSegment()
55 {
56     return static_cast<char*>(fastMalloc(segmentSize));
57 }
58
59 static inline void freeSegment(char* p)
60 {
61     fastFree(p);
62 }
63
64 SharedBuffer::SharedBuffer()
65     : m_size(0)
66 {
67 }
68
69 SharedBuffer::SharedBuffer(size_t size)
70     : m_size(size)
71     , m_buffer(size)
72 {
73 }
74
75 SharedBuffer::SharedBuffer(const char* data, int size)
76     : m_size(0)
77 {
78     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
79     if (size < 0)
80         CRASH();
81
82     append(data, size);
83 }
84
85 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
86     : m_size(0)
87 {
88     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
89     if (size < 0)
90         CRASH();
91
92     append(reinterpret_cast<const char*>(data), size);
93 }
94     
95 SharedBuffer::~SharedBuffer()
96 {
97     clear();
98 }
99
100 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
101 {
102     RefPtr<SharedBuffer> buffer = create();
103     buffer->m_buffer.swap(vector);
104     buffer->m_size = buffer->m_buffer.size();
105     return buffer.release();
106 }
107
108 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer) 
109
110     ASSERT(!purgeableBuffer->isPurgeable());
111     RefPtr<SharedBuffer> buffer = create();
112     buffer->m_purgeableBuffer = purgeableBuffer;
113     return buffer.release();
114 }
115
116 unsigned SharedBuffer::size() const
117 {
118     if (hasPlatformData())
119         return platformDataSize();
120     
121     if (m_purgeableBuffer)
122         return m_purgeableBuffer->size();
123     
124     return m_size;
125 }
126
127 void SharedBuffer::createPurgeableBuffer() const
128 {
129     if (m_purgeableBuffer)
130         return;
131
132     if (hasPlatformData())
133         return;
134
135 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
136     if (singleDataArrayBuffer())
137         return;
138 #endif
139
140     m_purgeableBuffer = PurgeableBuffer::create(buffer().data(), m_size);
141 }
142
143 const char* SharedBuffer::data() const
144 {
145     if (hasPlatformData())
146         return platformData();
147
148 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
149     if (const char* buffer = singleDataArrayBuffer())
150         return buffer;
151 #endif
152     
153     if (m_purgeableBuffer)
154         return m_purgeableBuffer->data();
155     
156     return this->buffer().data();
157 }
158
159 void SharedBuffer::append(SharedBuffer* data)
160 {
161     const char* segment;
162     size_t position = 0;
163     while (size_t length = data->getSomeData(segment, position)) {
164         append(segment, length);
165         position += length;
166     }
167 }
168
169 void SharedBuffer::append(const char* data, unsigned length)
170 {
171     ASSERT(!m_purgeableBuffer);
172     if (!length)
173         return;
174
175     maybeTransferPlatformData();
176     
177     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
178     m_size += length;
179
180     if (m_size <= segmentSize) {
181         // No need to use segments for small resource data
182         if (m_buffer.isEmpty())
183             m_buffer.reserveInitialCapacity(length);
184         m_buffer.append(data, length);
185         return;
186     }
187
188     char* segment;
189     if (!positionInSegment) {
190         segment = allocateSegment();
191         m_segments.append(segment);
192     } else
193         segment = m_segments.last() + positionInSegment;
194
195     unsigned segmentFreeSpace = segmentSize - positionInSegment;
196     unsigned bytesToCopy = min(length, segmentFreeSpace);
197
198     for (;;) {
199         memcpy(segment, data, bytesToCopy);
200         if (static_cast<unsigned>(length) == bytesToCopy)
201             break;
202
203         length -= bytesToCopy;
204         data += bytesToCopy;
205         segment = allocateSegment();
206         m_segments.append(segment);
207         bytesToCopy = min(length, segmentSize);
208     }
209 }
210
211 void SharedBuffer::append(const Vector<char>& data)
212 {
213     append(data.data(), data.size());
214 }
215
216 void SharedBuffer::clear()
217 {
218     clearPlatformData();
219     
220     for (unsigned i = 0; i < m_segments.size(); ++i)
221         freeSegment(m_segments[i]);
222
223     m_segments.clear();
224     m_size = 0;
225
226     m_buffer.clear();
227     m_purgeableBuffer.clear();
228 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
229     m_dataArray.clear();
230 #endif
231 }
232
233 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
234 {
235     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
236     if (m_purgeableBuffer || hasPlatformData()) {
237         clone->append(data(), size());
238         return clone;
239     }
240
241     clone->m_size = m_size;
242     clone->m_buffer.reserveCapacity(m_size);
243     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
244     for (unsigned i = 0; i < m_segments.size(); ++i)
245         clone->m_buffer.append(m_segments[i], segmentSize);
246     return clone;
247 }
248
249 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
250
251     ASSERT(hasOneRef()); 
252     return m_purgeableBuffer.release(); 
253 }
254
255 const Vector<char>& SharedBuffer::buffer() const
256 {
257     unsigned bufferSize = m_buffer.size();
258     if (m_size > bufferSize) {
259         m_buffer.resize(m_size);
260         char* destination = m_buffer.data() + bufferSize;
261         unsigned bytesLeft = m_size - bufferSize;
262         for (unsigned i = 0; i < m_segments.size(); ++i) {
263             unsigned bytesToCopy = min(bytesLeft, segmentSize);
264             memcpy(destination, m_segments[i], bytesToCopy);
265             destination += bytesToCopy;
266             bytesLeft -= bytesToCopy;
267             freeSegment(m_segments[i]);
268         }
269         m_segments.clear();
270 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
271         copyDataArrayAndClear(destination, bytesLeft);
272 #endif
273     }
274     return m_buffer;
275 }
276
277 void SharedBuffer::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
278 {
279     MemoryClassInfo info(memoryObjectInfo, this);
280     info.addMember(m_buffer, "buffer");
281     for (unsigned i = 0; i < m_segments.size(); ++i)
282         info.addRawBuffer(m_segments[i], segmentSize, "RawBufferSegment", "segment");
283     info.addMember(m_segments, "segments");
284     info.addMember(m_purgeableBuffer, "purgeableBuffer");
285 }
286
287 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
288 {
289     unsigned totalSize = size();
290     if (position >= totalSize) {
291         someData = 0;
292         return 0;
293     }
294
295     if (hasPlatformData() || m_purgeableBuffer) {
296         ASSERT(position < size());
297         someData = data() + position;
298         return totalSize - position;
299     }
300
301     ASSERT(position < m_size);
302     unsigned consecutiveSize = m_buffer.size();
303     if (position < consecutiveSize) {
304         someData = m_buffer.data() + position;
305         return consecutiveSize - position;
306     }
307  
308     position -= consecutiveSize;
309     unsigned segments = m_segments.size();
310     unsigned maxSegmentedSize = segments * segmentSize;
311     unsigned segment = segmentIndex(position);
312     if (segment < segments) {
313         unsigned bytesLeft = totalSize - consecutiveSize;
314         unsigned segmentedSize = min(maxSegmentedSize, bytesLeft);
315
316         unsigned positionInSegment = offsetInSegment(position);
317         someData = m_segments[segment] + positionInSegment;
318         return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
319     }
320 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
321     ASSERT(maxSegmentedSize <= position);
322     position -= maxSegmentedSize;
323     return copySomeDataFromDataArray(someData, position);
324 #else
325     ASSERT_NOT_REACHED();
326     return 0;
327 #endif
328 }
329
330 #if !USE(CF) || PLATFORM(QT)
331
332 inline void SharedBuffer::clearPlatformData()
333 {
334 }
335
336 inline void SharedBuffer::maybeTransferPlatformData()
337 {
338 }
339
340 inline bool SharedBuffer::hasPlatformData() const
341 {
342     return false;
343 }
344
345 inline const char* SharedBuffer::platformData() const
346 {
347     ASSERT_NOT_REACHED();
348
349     return 0;
350 }
351
352 inline unsigned SharedBuffer::platformDataSize() const
353 {
354     ASSERT_NOT_REACHED();
355     
356     return 0;
357 }
358
359 #endif
360
361 PassRefPtr<SharedBuffer> utf8Buffer(const String& string)
362 {
363     // Allocate a buffer big enough to hold all the characters.
364     const int length = string.length();
365     Vector<char> buffer(length * 3);
366
367     // Convert to runs of 8-bit characters.
368     char* p = buffer.data();
369     const UChar* d = string.characters();
370     WTF::Unicode::ConversionResult result = WTF::Unicode::convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), true);
371     if (result != WTF::Unicode::conversionOK)
372         return 0;
373
374     buffer.shrink(p - buffer.data());
375     return SharedBuffer::adoptVector(buffer);
376 }
377
378 } // namespace WebCore