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