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 31namespace { 32 33template<typename T> 34union Value { 35 T data; 36 char bytes[sizeof(T)]; 37}; 38 39} 40 41namespace WebCore { 42 43PassRefPtr<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 55DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength) 56 : ArrayBufferView(buffer, byteOffset) 57 , m_byteLength(byteLength) 58{ 59} 60 61static bool needToFlipBytes(bool littleEndian) 62{ 63#if CPU(BIG_ENDIAN) 64 return littleEndian; 65#else 66 return !littleEndian; 67#endif 68} 69 70inline void swapBytes(char* p, char* q) 71{ 72 char temp = *p; 73 *p = *q; 74 *q = temp; 75} 76 77static void flipBytesFor16Bits(char* p) 78{ 79 swapBytes(p, p + 1); 80} 81 82static void flipBytesFor32Bits(char* p) 83{ 84 swapBytes(p, p + 3); 85 swapBytes(p + 1, p + 2); 86} 87 88static 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 96static 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 120template<typename T> 121T 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 135template<typename T> 136void 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 150int8_t DataView::getInt8(unsigned byteOffset, ExceptionCode& ec) 151{ 152 return getData<int8_t>(byteOffset, false, ec); 153} 154 155uint8_t DataView::getUint8(unsigned byteOffset, ExceptionCode& ec) 156{ 157 return getData<uint8_t>(byteOffset, false, ec); 158} 159 160int16_t DataView::getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) 161{ 162 return getData<int16_t>(byteOffset, littleEndian, ec); 163} 164 165uint16_t DataView::getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) 166{ 167 return getData<uint16_t>(byteOffset, littleEndian, ec); 168} 169 170int32_t DataView::getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) 171{ 172 return getData<int32_t>(byteOffset, littleEndian, ec); 173} 174 175uint32_t DataView::getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) 176{ 177 return getData<uint32_t>(byteOffset, littleEndian, ec); 178} 179 180float DataView::getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) 181{ 182 return getData<float>(byteOffset, littleEndian, ec); 183} 184 185double DataView::getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) 186{ 187 return getData<double>(byteOffset, littleEndian, ec); 188} 189 190void DataView::setInt8(unsigned byteOffset, int8_t value, ExceptionCode& ec) 191{ 192 setData<int8_t>(byteOffset, value, false, ec); 193} 194 195void DataView::setUint8(unsigned byteOffset, uint8_t value, ExceptionCode& ec) 196{ 197 setData<uint8_t>(byteOffset, value, false, ec); 198} 199 200void DataView::setInt16(unsigned byteOffset, short value, bool littleEndian, ExceptionCode& ec) 201{ 202 setData<int16_t>(byteOffset, value, littleEndian, ec); 203} 204 205void DataView::setUint16(unsigned byteOffset, uint16_t value, bool littleEndian, ExceptionCode& ec) 206{ 207 setData<uint16_t>(byteOffset, value, littleEndian, ec); 208} 209 210void DataView::setInt32(unsigned byteOffset, int32_t value, bool littleEndian, ExceptionCode& ec) 211{ 212 setData<int32_t>(byteOffset, value, littleEndian, ec); 213} 214 215void DataView::setUint32(unsigned byteOffset, uint32_t value, bool littleEndian, ExceptionCode& ec) 216{ 217 setData<uint32_t>(byteOffset, value, littleEndian, ec); 218} 219 220void DataView::setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode& ec) 221{ 222 setData<float>(byteOffset, value, littleEndian, ec); 223} 224 225void DataView::setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode& ec) 226{ 227 setData<double>(byteOffset, value, littleEndian, ec); 228} 229 230} 231