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
segmentIndex(unsigned position)40 static inline unsigned segmentIndex(unsigned position)
41 {
42 return position / segmentSize;
43 }
44
offsetInSegment(unsigned position)45 static inline unsigned offsetInSegment(unsigned position)
46 {
47 return position & segmentPositionMask;
48 }
49
allocateSegment()50 static inline char* allocateSegment()
51 {
52 return static_cast<char*>(fastMalloc(segmentSize));
53 }
54
freeSegment(char * p)55 static inline void freeSegment(char* p)
56 {
57 fastFree(p);
58 }
59
SharedBuffer()60 SharedBuffer::SharedBuffer()
61 : m_size(0)
62 {
63 }
64
SharedBuffer(const char * data,int size)65 SharedBuffer::SharedBuffer(const char* data, int size)
66 : m_size(0)
67 {
68 append(data, size);
69 }
70
SharedBuffer(const unsigned char * data,int size)71 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
72 : m_size(0)
73 {
74 append(reinterpret_cast<const char*>(data), size);
75 }
76
~SharedBuffer()77 SharedBuffer::~SharedBuffer()
78 {
79 clear();
80 }
81
adoptVector(Vector<char> & vector)82 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
83 {
84 RefPtr<SharedBuffer> buffer = create();
85 buffer->m_buffer.swap(vector);
86 buffer->m_size = buffer->m_buffer.size();
87 return buffer.release();
88 }
89
adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer)90 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer)
91 {
92 ASSERT(!purgeableBuffer->isPurgeable());
93 RefPtr<SharedBuffer> buffer = create();
94 buffer->m_purgeableBuffer = purgeableBuffer;
95 return buffer.release();
96 }
97
size() const98 unsigned SharedBuffer::size() const
99 {
100 if (hasPlatformData())
101 return platformDataSize();
102
103 if (m_purgeableBuffer)
104 return m_purgeableBuffer->size();
105
106 return m_size;
107 }
108
data() const109 const char* SharedBuffer::data() const
110 {
111 if (hasPlatformData())
112 return platformData();
113
114 if (m_purgeableBuffer)
115 return m_purgeableBuffer->data();
116
117 return buffer().data();
118 }
119
append(const char * data,unsigned length)120 void SharedBuffer::append(const char* data, unsigned length)
121 {
122 ASSERT(!m_purgeableBuffer);
123
124 maybeTransferPlatformData();
125
126 unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
127 m_size += length;
128
129 if (m_size <= segmentSize) {
130 // No need to use segments for small resource data
131 m_buffer.append(data, length);
132 return;
133 }
134
135 char* segment;
136 if (!positionInSegment) {
137 segment = allocateSegment();
138 m_segments.append(segment);
139 } else
140 segment = m_segments.last() + positionInSegment;
141
142 unsigned segmentFreeSpace = segmentSize - positionInSegment;
143 unsigned bytesToCopy = min(length, segmentFreeSpace);
144
145 for (;;) {
146 memcpy(segment, data, bytesToCopy);
147 if (static_cast<unsigned>(length) == bytesToCopy)
148 break;
149
150 length -= bytesToCopy;
151 data += bytesToCopy;
152 segment = allocateSegment();
153 m_segments.append(segment);
154 bytesToCopy = min(length, segmentSize);
155 }
156 }
157
clear()158 void SharedBuffer::clear()
159 {
160 clearPlatformData();
161
162 for (unsigned i = 0; i < m_segments.size(); ++i)
163 freeSegment(m_segments[i]);
164
165 m_segments.clear();
166 m_size = 0;
167
168 m_buffer.clear();
169 m_purgeableBuffer.clear();
170 #if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK)
171 m_dataArray.clear();
172 #endif
173 }
174
copy() const175 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
176 {
177 RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
178 if (m_purgeableBuffer || hasPlatformData()) {
179 clone->append(data(), size());
180 return clone;
181 }
182
183 clone->m_size = m_size;
184 clone->m_buffer.reserveCapacity(m_size);
185 clone->m_buffer.append(m_buffer.data(), m_buffer.size());
186 for (unsigned i = 0; i < m_segments.size(); ++i)
187 clone->m_buffer.append(m_segments[i], segmentSize);
188 return clone;
189 }
190
releasePurgeableBuffer()191 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
192 {
193 ASSERT(hasOneRef());
194 return m_purgeableBuffer.release();
195 }
196
buffer() const197 const Vector<char>& SharedBuffer::buffer() const
198 {
199 unsigned bufferSize = m_buffer.size();
200 if (m_size > bufferSize) {
201 m_buffer.resize(m_size);
202 char* destination = m_buffer.data() + bufferSize;
203 unsigned bytesLeft = m_size - bufferSize;
204 for (unsigned i = 0; i < m_segments.size(); ++i) {
205 unsigned bytesToCopy = min(bytesLeft, segmentSize);
206 memcpy(destination, m_segments[i], bytesToCopy);
207 destination += bytesToCopy;
208 bytesLeft -= bytesToCopy;
209 freeSegment(m_segments[i]);
210 }
211 m_segments.clear();
212 #if HAVE(CFNETWORK_DATA_ARRAY_CALLBACK)
213 copyDataArrayAndClear(destination, bytesLeft);
214 #endif
215 }
216 return m_buffer;
217 }
218
getSomeData(const char * & someData,unsigned position) const219 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
220 {
221 if (hasPlatformData() || m_purgeableBuffer) {
222 someData = data() + position;
223 return size() - position;
224 }
225
226 if (position >= m_size) {
227 someData = 0;
228 return 0;
229 }
230
231 unsigned consecutiveSize = m_buffer.size();
232 if (position < consecutiveSize) {
233 someData = m_buffer.data() + position;
234 return consecutiveSize - position;
235 }
236
237 position -= consecutiveSize;
238 unsigned segmentedSize = m_size - consecutiveSize;
239 unsigned segments = m_segments.size();
240 unsigned segment = segmentIndex(position);
241 ASSERT(segment < segments);
242
243 unsigned positionInSegment = offsetInSegment(position);
244 someData = m_segments[segment] + positionInSegment;
245 return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
246 }
247
248 #if !USE(CF) || PLATFORM(QT)
249
clearPlatformData()250 inline void SharedBuffer::clearPlatformData()
251 {
252 }
253
maybeTransferPlatformData()254 inline void SharedBuffer::maybeTransferPlatformData()
255 {
256 }
257
hasPlatformData() const258 inline bool SharedBuffer::hasPlatformData() const
259 {
260 return false;
261 }
262
platformData() const263 inline const char* SharedBuffer::platformData() const
264 {
265 ASSERT_NOT_REACHED();
266
267 return 0;
268 }
269
platformDataSize() const270 inline unsigned SharedBuffer::platformDataSize() const
271 {
272 ASSERT_NOT_REACHED();
273
274 return 0;
275 }
276
277 #endif
278
279 }
280