initial import
[vuplus_webkit] / 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     append(data, size);
69 }
70
71 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
72     : m_size(0)
73 {
74     append(reinterpret_cast<const char*>(data), size);
75 }
76     
77 SharedBuffer::~SharedBuffer()
78 {
79     clear();
80 }
81
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
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
98 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
109 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
120 void SharedBuffer::append(SharedBuffer* data)
121 {
122     const char* segment;
123     size_t position = 0;
124     while (size_t length = data->getSomeData(segment, position)) {
125         append(segment, length);
126         position += length;
127     }
128 }
129
130 void SharedBuffer::append(const char* data, unsigned length)
131 {
132     ASSERT(!m_purgeableBuffer);
133
134     maybeTransferPlatformData();
135     
136     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
137     m_size += length;
138
139     if (m_size <= segmentSize) {
140         // No need to use segments for small resource data
141         m_buffer.append(data, length);
142         return;
143     }
144
145     char* segment;
146     if (!positionInSegment) {
147         segment = allocateSegment();
148         m_segments.append(segment);
149     } else
150         segment = m_segments.last() + positionInSegment;
151
152     unsigned segmentFreeSpace = segmentSize - positionInSegment;
153     unsigned bytesToCopy = min(length, segmentFreeSpace);
154
155     for (;;) {
156         memcpy(segment, data, bytesToCopy);
157         if (static_cast<unsigned>(length) == bytesToCopy)
158             break;
159
160         length -= bytesToCopy;
161         data += bytesToCopy;
162         segment = allocateSegment();
163         m_segments.append(segment);
164         bytesToCopy = min(length, segmentSize);
165     }
166 }
167
168 void SharedBuffer::append(const Vector<char>& data)
169 {
170     append(data.data(), data.size());
171 }
172
173 void SharedBuffer::clear()
174 {
175     clearPlatformData();
176     
177     for (unsigned i = 0; i < m_segments.size(); ++i)
178         freeSegment(m_segments[i]);
179
180     m_segments.clear();
181     m_size = 0;
182
183     m_buffer.clear();
184     m_purgeableBuffer.clear();
185 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
186     m_dataArray.clear();
187 #endif
188 }
189
190 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
191 {
192     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
193     if (m_purgeableBuffer || hasPlatformData()) {
194         clone->append(data(), size());
195         return clone;
196     }
197
198     clone->m_size = m_size;
199     clone->m_buffer.reserveCapacity(m_size);
200     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
201     for (unsigned i = 0; i < m_segments.size(); ++i)
202         clone->m_buffer.append(m_segments[i], segmentSize);
203     return clone;
204 }
205
206 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
207
208     ASSERT(hasOneRef()); 
209     return m_purgeableBuffer.release(); 
210 }
211
212 const Vector<char>& SharedBuffer::buffer() const
213 {
214     unsigned bufferSize = m_buffer.size();
215     if (m_size > bufferSize) {
216         m_buffer.resize(m_size);
217         char* destination = m_buffer.data() + bufferSize;
218         unsigned bytesLeft = m_size - bufferSize;
219         for (unsigned i = 0; i < m_segments.size(); ++i) {
220             unsigned bytesToCopy = min(bytesLeft, segmentSize);
221             memcpy(destination, m_segments[i], bytesToCopy);
222             destination += bytesToCopy;
223             bytesLeft -= bytesToCopy;
224             freeSegment(m_segments[i]);
225         }
226         m_segments.clear();
227 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
228         copyDataArrayAndClear(destination, bytesLeft);
229 #endif
230     }
231     return m_buffer;
232 }
233
234 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
235 {
236     if (hasPlatformData() || m_purgeableBuffer) {
237         someData = data() + position;
238         return size() - position;
239     }
240
241     if (position >= m_size) {
242         someData = 0;
243         return 0;
244     }
245
246     unsigned consecutiveSize = m_buffer.size();
247     if (position < consecutiveSize) {
248         someData = m_buffer.data() + position;
249         return consecutiveSize - position;
250     }
251  
252     position -= consecutiveSize;
253     unsigned segmentedSize = m_size - consecutiveSize;
254     unsigned segments = m_segments.size();
255     unsigned segment = segmentIndex(position);
256     ASSERT(segment < segments);
257
258     unsigned positionInSegment = offsetInSegment(position);
259     someData = m_segments[segment] + positionInSegment;
260     return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
261 }
262
263 #if !USE(CF) || PLATFORM(QT)
264
265 inline void SharedBuffer::clearPlatformData()
266 {
267 }
268
269 inline void SharedBuffer::maybeTransferPlatformData()
270 {
271 }
272
273 inline bool SharedBuffer::hasPlatformData() const
274 {
275     return false;
276 }
277
278 inline const char* SharedBuffer::platformData() const
279 {
280     ASSERT_NOT_REACHED();
281
282     return 0;
283 }
284
285 inline unsigned SharedBuffer::platformDataSize() const
286 {
287     ASSERT_NOT_REACHED();
288     
289     return 0;
290 }
291
292 #endif
293
294 }