Home | History | Annotate | Download | only in platform
      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