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