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(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 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 175 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 191 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer() 192 { 193 ASSERT(hasOneRef()); 194 return m_purgeableBuffer.release(); 195 } 196 197 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 219 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 250 inline void SharedBuffer::clearPlatformData() 251 { 252 } 253 254 inline void SharedBuffer::maybeTransferPlatformData() 255 { 256 } 257 258 inline bool SharedBuffer::hasPlatformData() const 259 { 260 return false; 261 } 262 263 inline const char* SharedBuffer::platformData() const 264 { 265 ASSERT_NOT_REACHED(); 266 267 return 0; 268 } 269 270 inline unsigned SharedBuffer::platformDataSize() const 271 { 272 ASSERT_NOT_REACHED(); 273 274 return 0; 275 } 276 277 #endif 278 279 } 280