1/* 2 * Copyright (C) 2008, 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 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 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28#include "config.h" 29#include "SharedBuffer.h" 30 31#include "PurgeableBuffer.h" 32#include <wtf/cf/TypeCasts.h> 33 34#if ENABLE(DISK_IMAGE_CACHE) 35#include "DiskImageCacheIOS.h" 36#endif 37 38namespace WebCore { 39 40SharedBuffer::SharedBuffer(CFDataRef cfData) 41 : m_size(0) 42 , m_buffer(adoptRef(new DataBuffer)) 43 , m_shouldUsePurgeableMemory(false) 44#if ENABLE(DISK_IMAGE_CACHE) 45 , m_isMemoryMapped(false) 46 , m_diskImageCacheId(DiskImageCache::invalidDiskCacheId) 47 , m_notifyMemoryMappedCallback(nullptr) 48 , m_notifyMemoryMappedCallbackData(nullptr) 49#endif 50 , m_cfData(cfData) 51{ 52} 53 54// Using Foundation allows for an even more efficient implementation of this function, 55// so only use this version for non-Foundation. 56#if !USE(FOUNDATION) 57RetainPtr<CFDataRef> SharedBuffer::createCFData() 58{ 59 if (m_cfData) 60 return m_cfData; 61 62 // Internal data in SharedBuffer can be segmented. We need to get the contiguous buffer. 63 const Vector<char>& contiguousBuffer = buffer(); 64 return adoptCF(CFDataCreate(0, reinterpret_cast<const UInt8*>(contiguousBuffer.data()), contiguousBuffer.size())); 65} 66#endif 67 68PassRefPtr<SharedBuffer> SharedBuffer::wrapCFData(CFDataRef data) 69{ 70 return adoptRef(new SharedBuffer(data)); 71} 72 73bool SharedBuffer::hasPlatformData() const 74{ 75 return m_cfData; 76} 77 78const char* SharedBuffer::platformData() const 79{ 80 return reinterpret_cast<const char*>(CFDataGetBytePtr(m_cfData.get())); 81} 82 83unsigned SharedBuffer::platformDataSize() const 84{ 85 return CFDataGetLength(m_cfData.get()); 86} 87 88void SharedBuffer::maybeTransferPlatformData() 89{ 90 if (!m_cfData) 91 return; 92 93 ASSERT(!m_size); 94 95 // Hang on to the m_cfData pointer in a local pointer as append() will re-enter maybeTransferPlatformData() 96 // and we need to make sure to early return when it does. 97 RetainPtr<CFDataRef> cfData = adoptCF(m_cfData.leakRef()); 98 99 append(reinterpret_cast<const char*>(CFDataGetBytePtr(cfData.get())), CFDataGetLength(cfData.get())); 100} 101 102void SharedBuffer::clearPlatformData() 103{ 104 m_cfData = 0; 105} 106 107void SharedBuffer::tryReplaceContentsWithPlatformBuffer(SharedBuffer* newContents) 108{ 109 if (!newContents->m_cfData) 110 return; 111 112 clear(); 113 m_cfData = newContents->m_cfData; 114} 115 116bool SharedBuffer::maybeAppendPlatformData(SharedBuffer* newContents) 117{ 118 if (size() || !newContents->m_cfData) 119 return false; 120 m_cfData = newContents->m_cfData; 121 return true; 122} 123 124#if USE(NETWORK_CFDATA_ARRAY_CALLBACK) 125PassRefPtr<SharedBuffer> SharedBuffer::wrapCFDataArray(CFArrayRef cfDataArray) 126{ 127 return adoptRef(new SharedBuffer(cfDataArray)); 128} 129 130SharedBuffer::SharedBuffer(CFArrayRef cfDataArray) 131 : m_size(0) 132 , m_buffer(adoptRef(new DataBuffer)) 133 , m_shouldUsePurgeableMemory(false) 134#if ENABLE(DISK_IMAGE_CACHE) 135 , m_isMemoryMapped(false) 136 , m_diskImageCacheId(DiskImageCache::invalidDiskCacheId) 137 , m_notifyMemoryMappedCallback(nullptr) 138 , m_notifyMemoryMappedCallbackData(nullptr) 139#endif 140 , m_cfData(nullptr) 141{ 142 CFIndex dataArrayCount = CFArrayGetCount(cfDataArray); 143 for (CFIndex index = 0; index < dataArrayCount; ++index) 144 append(checked_cf_cast<CFDataRef>(CFArrayGetValueAtIndex(cfDataArray, index))); 145} 146 147void SharedBuffer::append(CFDataRef data) 148{ 149 ASSERT(data); 150 m_dataArray.append(data); 151 m_size += CFDataGetLength(data); 152} 153 154void SharedBuffer::copyBufferAndClear(char* destination, unsigned bytesToCopy) const 155{ 156 if (m_dataArray.isEmpty()) 157 return; 158 159 CFIndex bytesLeft = bytesToCopy; 160 Vector<RetainPtr<CFDataRef>>::const_iterator end = m_dataArray.end(); 161 for (Vector<RetainPtr<CFDataRef>>::const_iterator it = m_dataArray.begin(); it != end; ++it) { 162 CFIndex dataLen = CFDataGetLength(it->get()); 163 ASSERT(bytesLeft >= dataLen); 164 memcpy(destination, CFDataGetBytePtr(it->get()), dataLen); 165 destination += dataLen; 166 bytesLeft -= dataLen; 167 } 168 m_dataArray.clear(); 169} 170 171unsigned SharedBuffer::copySomeDataFromDataArray(const char*& someData, unsigned position) const 172{ 173 Vector<RetainPtr<CFDataRef>>::const_iterator end = m_dataArray.end(); 174 unsigned totalOffset = 0; 175 for (Vector<RetainPtr<CFDataRef>>::const_iterator it = m_dataArray.begin(); it != end; ++it) { 176 unsigned dataLen = static_cast<unsigned>(CFDataGetLength(it->get())); 177 ASSERT(totalOffset <= position); 178 unsigned localOffset = position - totalOffset; 179 if (localOffset < dataLen) { 180 someData = reinterpret_cast<const char *>(CFDataGetBytePtr(it->get())) + localOffset; 181 return dataLen - localOffset; 182 } 183 totalOffset += dataLen; 184 } 185 return 0; 186} 187 188const char *SharedBuffer::singleDataArrayBuffer() const 189{ 190 // If we had previously copied data into m_buffer in copyDataArrayAndClear() or some other 191 // function, then we can't return a pointer to the CFDataRef buffer. 192 if (m_buffer->data.size()) 193 return 0; 194 195 if (m_dataArray.size() != 1) 196 return 0; 197 198 return reinterpret_cast<const char*>(CFDataGetBytePtr(m_dataArray.at(0).get())); 199} 200 201bool SharedBuffer::maybeAppendDataArray(SharedBuffer* data) 202{ 203 if (m_buffer->data.size() || m_cfData || !data->m_dataArray.size()) 204 return false; 205#if !ASSERT_DISABLED 206 unsigned originalSize = size(); 207#endif 208 for (auto cfData : data->m_dataArray) 209 append(cfData.get()); 210 ASSERT(size() == originalSize + data->size()); 211 return true; 212} 213#endif 214 215} 216