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