Home | History | Annotate | Download | only in canvas
      1 /*
      2  * Copyright (C) 2010 Google 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  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "DataView.h"
     28 
     29 #include "CheckedInt.h"
     30 
     31 namespace {
     32 
     33 template<typename T>
     34 union Value {
     35     T data;
     36     char bytes[sizeof(T)];
     37 };
     38 
     39 }
     40 
     41 namespace WebCore {
     42 
     43 PassRefPtr<DataView> DataView::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
     44 {
     45     if (byteOffset > buffer->byteLength())
     46         return 0;
     47     CheckedInt<uint32_t> checkedOffset(byteOffset);
     48     CheckedInt<uint32_t> checkedLength(byteLength);
     49     CheckedInt<uint32_t> checkedMax = checkedOffset + checkedLength;
     50     if (!checkedMax.valid() || checkedMax.value() > buffer->byteLength())
     51         return 0;
     52     return adoptRef(new DataView(buffer, byteOffset, byteLength));
     53 }
     54 
     55 DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
     56     : ArrayBufferView(buffer, byteOffset)
     57     , m_byteLength(byteLength)
     58 {
     59 }
     60 
     61 static bool needToFlipBytes(bool littleEndian)
     62 {
     63 #if CPU(BIG_ENDIAN)
     64     return littleEndian;
     65 #else
     66     return !littleEndian;
     67 #endif
     68 }
     69 
     70 inline void swapBytes(char* p, char* q)
     71 {
     72     char temp = *p;
     73     *p = *q;
     74     *q = temp;
     75 }
     76 
     77 static void flipBytesFor16Bits(char* p)
     78 {
     79     swapBytes(p, p + 1);
     80 }
     81 
     82 static void flipBytesFor32Bits(char* p)
     83 {
     84     swapBytes(p, p + 3);
     85     swapBytes(p + 1, p + 2);
     86 }
     87 
     88 static void flipBytesFor64Bits(char* p)
     89 {
     90     swapBytes(p, p + 7);
     91     swapBytes(p + 1, p + 6);
     92     swapBytes(p + 2, p + 5);
     93     swapBytes(p + 3, p + 4);
     94 }
     95 
     96 static void flipBytesIfNeeded(char* value, size_t size, bool littleEndian)
     97 {
     98     if (!needToFlipBytes(littleEndian))
     99         return;
    100 
    101     switch (size) {
    102     case 1:
    103         // Nothing to do.
    104         break;
    105     case 2:
    106         flipBytesFor16Bits(value);
    107         break;
    108     case 4:
    109         flipBytesFor32Bits(value);
    110         break;
    111     case 8:
    112         flipBytesFor64Bits(value);
    113         break;
    114     default:
    115         ASSERT_NOT_REACHED();
    116         break;
    117     }
    118 }
    119 
    120 template<typename T>
    121 T DataView::getData(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) const
    122 {
    123     if (beyondRange<T>(byteOffset)) {
    124         ec = INDEX_SIZE_ERR;
    125         return 0;
    126     }
    127 
    128     // We do not want to load the data directly since it would cause a bus error on architectures that don't support unaligned loads.
    129     Value<T> value;
    130     memcpy(value.bytes, static_cast<const char*>(m_baseAddress) + byteOffset, sizeof(T));
    131     flipBytesIfNeeded(value.bytes, sizeof(T), littleEndian);
    132     return value.data;
    133 }
    134 
    135 template<typename T>
    136 void DataView::setData(unsigned byteOffset, T value, bool littleEndian, ExceptionCode& ec)
    137 {
    138     if (beyondRange<T>(byteOffset)) {
    139         ec = INDEX_SIZE_ERR;
    140         return;
    141     }
    142 
    143     // We do not want to store the data directly since it would cause a bus error on architectures that don't support unaligned stores.
    144     Value<T> tempValue;
    145     tempValue.data = value;
    146     flipBytesIfNeeded(tempValue.bytes, sizeof(T), littleEndian);
    147     memcpy(static_cast<char*>(m_baseAddress) + byteOffset, tempValue.bytes, sizeof(T));
    148 }
    149 
    150 int8_t DataView::getInt8(unsigned byteOffset, ExceptionCode& ec)
    151 {
    152     return getData<int8_t>(byteOffset, false, ec);
    153 }
    154 
    155 uint8_t DataView::getUint8(unsigned byteOffset, ExceptionCode& ec)
    156 {
    157     return getData<uint8_t>(byteOffset, false, ec);
    158 }
    159 
    160 int16_t DataView::getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
    161 {
    162     return getData<int16_t>(byteOffset, littleEndian, ec);
    163 }
    164 
    165 uint16_t DataView::getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
    166 {
    167     return getData<uint16_t>(byteOffset, littleEndian, ec);
    168 }
    169 
    170 int32_t DataView::getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
    171 {
    172     return getData<int32_t>(byteOffset, littleEndian, ec);
    173 }
    174 
    175 uint32_t DataView::getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
    176 {
    177     return getData<uint32_t>(byteOffset, littleEndian, ec);
    178 }
    179 
    180 float DataView::getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
    181 {
    182     return getData<float>(byteOffset, littleEndian, ec);
    183 }
    184 
    185 double DataView::getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
    186 {
    187     return getData<double>(byteOffset, littleEndian, ec);
    188 }
    189 
    190 void DataView::setInt8(unsigned byteOffset, int8_t value, ExceptionCode& ec)
    191 {
    192     setData<int8_t>(byteOffset, value, false, ec);
    193 }
    194 
    195 void DataView::setUint8(unsigned byteOffset, uint8_t value, ExceptionCode& ec)
    196 {
    197     setData<uint8_t>(byteOffset, value, false, ec);
    198 }
    199 
    200 void DataView::setInt16(unsigned byteOffset, short value, bool littleEndian, ExceptionCode& ec)
    201 {
    202     setData<int16_t>(byteOffset, value, littleEndian, ec);
    203 }
    204 
    205 void DataView::setUint16(unsigned byteOffset, uint16_t value, bool littleEndian, ExceptionCode& ec)
    206 {
    207     setData<uint16_t>(byteOffset, value, littleEndian, ec);
    208 }
    209 
    210 void DataView::setInt32(unsigned byteOffset, int32_t value, bool littleEndian, ExceptionCode& ec)
    211 {
    212     setData<int32_t>(byteOffset, value, littleEndian, ec);
    213 }
    214 
    215 void DataView::setUint32(unsigned byteOffset, uint32_t value, bool littleEndian, ExceptionCode& ec)
    216 {
    217     setData<uint32_t>(byteOffset, value, littleEndian, ec);
    218 }
    219 
    220 void DataView::setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode& ec)
    221 {
    222     setData<float>(byteOffset, value, littleEndian, ec);
    223 }
    224 
    225 void DataView::setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode& ec)
    226 {
    227     setData<double>(byteOffset, value, littleEndian, ec);
    228 }
    229 
    230 }
    231