ee6a29fd535318f8d7f43f05bd214743121e9bef
[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 "PurgeableBuffer.h"
31 #include <wtf/PassOwnPtr.h>
32
33 using namespace std;
34
35 namespace WebCore {
36
37 static const unsigned segmentSize = 0x1000;
38 static const unsigned segmentPositionMask = 0x0FFF;
39
40 static inline unsigned segmentIndex(unsigned position)
41 {
42     return position / segmentSize;
43 }
44
45 static inline unsigned offsetInSegment(unsigned position)
46 {
47     return position & segmentPositionMask;
48 }
49
50 static inline char* allocateSegment()
51 {
52     return static_cast<char*>(fastMalloc(segmentSize));
53 }
54
55 static inline void freeSegment(char* p)
56 {
57     fastFree(p);
58 }
59
60 SharedBuffer::SharedBuffer()
61     : m_size(0)
62 {
63 }
64
65 SharedBuffer::SharedBuffer(const char* data, int size)
66     : m_size(0)
67 {
68     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
69     if (size < 0)
70         CRASH();
71
72     append(data, size);
73 }
74
75 SharedBuffer::SharedBuffer(const unsigned 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(reinterpret_cast<const char*>(data), size);
83 }
84     
85 SharedBuffer::~SharedBuffer()
86 {
87     clear();
88 }
89
90 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
91 {
92     RefPtr<SharedBuffer> buffer = create();
93     buffer->m_buffer.swap(vector);
94     buffer->m_size = buffer->m_buffer.size();
95     return buffer.release();
96 }
97
98 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer) 
99
100     ASSERT(!purgeableBuffer->isPurgeable());
101     RefPtr<SharedBuffer> buffer = create();
102     buffer->m_purgeableBuffer = purgeableBuffer;
103     return buffer.release();
104 }
105
106 unsigned SharedBuffer::size() const
107 {
108     if (hasPlatformData())
109         return platformDataSize();
110     
111     if (m_purgeableBuffer)
112         return m_purgeableBuffer->size();
113     
114     return m_size;
115 }
116
117 const char* SharedBuffer::data() const
118 {
119     if (hasPlatformData())
120         return platformData();
121     
122     if (m_purgeableBuffer)
123         return m_purgeableBuffer->data();
124     
125     return buffer().data();
126 }
127
128 void SharedBuffer::append(SharedBuffer* data)
129 {
130     const char* segment;
131     size_t position = 0;
132     while (size_t length = data->getSomeData(segment, position)) {
133         append(segment, length);
134         position += length;
135     }
136 }
137
138 void SharedBuffer::append(const char* data, unsigned length)
139 {
140     ASSERT(!m_purgeableBuffer);
141
142     maybeTransferPlatformData();
143     
144     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
145     m_size += length;
146
147     if (m_size <= segmentSize) {
148         // No need to use segments for small resource data
149         m_buffer.append(data, length);
150         return;
151     }
152
153     char* segment;
154     if (!positionInSegment) {
155         segment = allocateSegment();
156         m_segments.append(segment);
157     } else
158         segment = m_segments.last() + positionInSegment;
159
160     unsigned segmentFreeSpace = segmentSize - positionInSegment;
161     unsigned bytesToCopy = min(length, segmentFreeSpace);
162
163     for (;;) {
164         memcpy(segment, data, bytesToCopy);
165         if (static_cast<unsigned>(length) == bytesToCopy)
166             break;
167
168         length -= bytesToCopy;
169         data += bytesToCopy;
170         segment = allocateSegment();
171         m_segments.append(segment);
172         bytesToCopy = min(length, segmentSize);
173     }
174 }
175
176 void SharedBuffer::append(const Vector<char>& data)
177 {
178     append(data.data(), data.size());
179 }
180
181 void SharedBuffer::clear()
182 {
183     clearPlatformData();
184     
185     for (unsigned i = 0; i < m_segments.size(); ++i)
186         freeSegment(m_segments[i]);
187
188     m_segments.clear();
189     m_size = 0;
190
191     m_buffer.clear();
192     m_purgeableBuffer.clear();
193 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
194     m_dataArray.clear();
195 #endif
196 }
197
198 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
199 {
200     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
201     if (m_purgeableBuffer || hasPlatformData()) {
202         clone->append(data(), size());
203         return clone;
204     }
205
206     clone->m_size = m_size;
207     clone->m_buffer.reserveCapacity(m_size);
208     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
209     for (unsigned i = 0; i < m_segments.size(); ++i)
210         clone->m_buffer.append(m_segments[i], segmentSize);
211     return clone;
212 }
213
214 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
215
216     ASSERT(hasOneRef()); 
217     return m_purgeableBuffer.release(); 
218 }
219
220 const Vector<char>& SharedBuffer::buffer() const
221 {
222     unsigned bufferSize = m_buffer.size();
223     if (m_size > bufferSize) {
224         m_buffer.resize(m_size);
225         char* destination = m_buffer.data() + bufferSize;
226         unsigned bytesLeft = m_size - bufferSize;
227         for (unsigned i = 0; i < m_segments.size(); ++i) {
228             unsigned bytesToCopy = min(bytesLeft, segmentSize);
229             memcpy(destination, m_segments[i], bytesToCopy);
230             destination += bytesToCopy;
231             bytesLeft -= bytesToCopy;
232             freeSegment(m_segments[i]);
233         }
234         m_segments.clear();
235 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
236         copyDataArrayAndClear(destination, bytesLeft);
237 #endif
238     }
239     return m_buffer;
240 }
241
242 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
243 {
244     unsigned totalSize = size();
245     if (position >= totalSize) {
246         someData = 0;
247         return 0;
248     }
249
250     if (hasPlatformData() || m_purgeableBuffer) {
251         ASSERT(position < size());
252         someData = data() + position;
253         return totalSize - position;
254     }
255
256     ASSERT(position < m_size);
257     unsigned consecutiveSize = m_buffer.size();
258     if (position < consecutiveSize) {
259         someData = m_buffer.data() + position;
260         return consecutiveSize - position;
261     }
262  
263     position -= consecutiveSize;
264     unsigned segments = m_segments.size();
265     unsigned maxSegmentedSize = segments * segmentSize;
266     unsigned segment = segmentIndex(position);
267     if (segment < segments) {
268         unsigned bytesLeft = totalSize - consecutiveSize;
269         unsigned segmentedSize = min(maxSegmentedSize, bytesLeft);
270
271         unsigned positionInSegment = offsetInSegment(position);
272         someData = m_segments[segment] + positionInSegment;
273         return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
274     }
275 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
276     ASSERT(maxSegmentedSize <= position);
277     position -= maxSegmentedSize;
278     return copySomeDataFromDataArray(someData, position);
279 #else
280     ASSERT_NOT_REACHED();
281     return 0;
282 #endif
283 }
284
285 #if !USE(CF) || PLATFORM(QT)
286
287 inline void SharedBuffer::clearPlatformData()
288 {
289 }
290
291 inline void SharedBuffer::maybeTransferPlatformData()
292 {
293 }
294
295 inline bool SharedBuffer::hasPlatformData() const
296 {
297     return false;
298 }
299
300 inline const char* SharedBuffer::platformData() const
301 {
302     ASSERT_NOT_REACHED();
303
304     return 0;
305 }
306
307 inline unsigned SharedBuffer::platformDataSize() const
308 {
309     ASSERT_NOT_REACHED();
310     
311     return 0;
312 }
313
314 #endif
315
316 }