3e55d377624bafaf83f8a56b08af61b6fe8c61eb
[framework/web/webkit-efl.git] / Source / WebCore / html / canvas / DataView.cpp
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 #include "ExceptionCode.h"
31
32 namespace {
33
34 template<typename T>
35 union Value {
36     T data;
37     char bytes[sizeof(T)];
38 };
39
40 }
41
42 namespace WebCore {
43
44 PassRefPtr<DataView> DataView::create(unsigned length)
45 {
46     RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(uint8_t));
47     if (!buffer.get())
48         return 0;
49     return create(buffer, 0, length);
50 }
51
52 PassRefPtr<DataView> DataView::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
53 {
54     if (byteOffset > buffer->byteLength())
55         return 0;
56     CheckedInt<uint32_t> checkedOffset(byteOffset);
57     CheckedInt<uint32_t> checkedLength(byteLength);
58     CheckedInt<uint32_t> checkedMax = checkedOffset + checkedLength;
59     if (!checkedMax.valid() || checkedMax.value() > buffer->byteLength())
60         return 0;
61     return adoptRef(new DataView(buffer, byteOffset, byteLength));
62 }
63
64 DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
65     : ArrayBufferView(buffer, byteOffset)
66     , m_byteLength(byteLength)
67 {
68 }
69
70 static bool needToFlipBytes(bool littleEndian)
71 {
72 #if CPU(BIG_ENDIAN)
73     return littleEndian;
74 #else
75     return !littleEndian;
76 #endif
77 }
78
79 inline void swapBytes(char* p, char* q)
80 {
81     char temp = *p;
82     *p = *q;
83     *q = temp;
84 }
85
86 static void flipBytesFor16Bits(char* p)
87 {
88     swapBytes(p, p + 1);
89 }
90
91 static void flipBytesFor32Bits(char* p)
92 {
93     swapBytes(p, p + 3);
94     swapBytes(p + 1, p + 2);
95 }
96
97 static void flipBytesFor64Bits(char* p)
98 {
99     swapBytes(p, p + 7);
100     swapBytes(p + 1, p + 6);
101     swapBytes(p + 2, p + 5);
102     swapBytes(p + 3, p + 4);
103 }
104
105 static void flipBytesIfNeeded(char* value, size_t size, bool littleEndian)
106 {
107     if (!needToFlipBytes(littleEndian))
108         return;
109
110     switch (size) {
111     case 1:
112         // Nothing to do.
113         break;
114     case 2:
115         flipBytesFor16Bits(value);
116         break;
117     case 4:
118         flipBytesFor32Bits(value);
119         break;
120     case 8:
121         flipBytesFor64Bits(value);
122         break;
123     default:
124         ASSERT_NOT_REACHED();
125         break;
126     }
127 }
128
129 template<typename T>
130 T DataView::getData(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) const
131 {
132     if (beyondRange<T>(byteOffset)) {
133         ec = INDEX_SIZE_ERR;
134         return 0;
135     }
136
137     // We do not want to load the data directly since it would cause a bus error on architectures that don't support unaligned loads.
138     Value<T> value;
139     memcpy(value.bytes, static_cast<const char*>(m_baseAddress) + byteOffset, sizeof(T));
140     flipBytesIfNeeded(value.bytes, sizeof(T), littleEndian);
141     return value.data;
142 }
143
144 template<typename T>
145 void DataView::setData(unsigned byteOffset, T value, bool littleEndian, ExceptionCode& ec)
146 {
147     if (beyondRange<T>(byteOffset)) {
148         ec = INDEX_SIZE_ERR;
149         return;
150     }
151
152     // We do not want to store the data directly since it would cause a bus error on architectures that don't support unaligned stores.
153     Value<T> tempValue;
154     tempValue.data = value;
155     flipBytesIfNeeded(tempValue.bytes, sizeof(T), littleEndian);
156     memcpy(static_cast<char*>(m_baseAddress) + byteOffset, tempValue.bytes, sizeof(T));
157 }
158
159 int8_t DataView::getInt8(unsigned byteOffset, ExceptionCode& ec)
160 {
161     return getData<int8_t>(byteOffset, false, ec);
162 }
163
164 uint8_t DataView::getUint8(unsigned byteOffset, ExceptionCode& ec)
165 {
166     return getData<uint8_t>(byteOffset, false, ec);
167 }
168
169 int16_t DataView::getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
170 {
171     return getData<int16_t>(byteOffset, littleEndian, ec);
172 }
173
174 uint16_t DataView::getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
175 {
176     return getData<uint16_t>(byteOffset, littleEndian, ec);
177 }
178
179 int32_t DataView::getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
180 {
181     return getData<int32_t>(byteOffset, littleEndian, ec);
182 }
183
184 uint32_t DataView::getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
185 {
186     return getData<uint32_t>(byteOffset, littleEndian, ec);
187 }
188
189 float DataView::getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
190 {
191     return getData<float>(byteOffset, littleEndian, ec);
192 }
193
194 double DataView::getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode& ec)
195 {
196     return getData<double>(byteOffset, littleEndian, ec);
197 }
198
199 void DataView::setInt8(unsigned byteOffset, int8_t value, ExceptionCode& ec)
200 {
201     setData<int8_t>(byteOffset, value, false, ec);
202 }
203
204 void DataView::setUint8(unsigned byteOffset, uint8_t value, ExceptionCode& ec)
205 {
206     setData<uint8_t>(byteOffset, value, false, ec);
207 }
208
209 void DataView::setInt16(unsigned byteOffset, short value, bool littleEndian, ExceptionCode& ec)
210 {
211     setData<int16_t>(byteOffset, value, littleEndian, ec);
212 }
213
214 void DataView::setUint16(unsigned byteOffset, uint16_t value, bool littleEndian, ExceptionCode& ec)
215 {
216     setData<uint16_t>(byteOffset, value, littleEndian, ec);
217 }
218
219 void DataView::setInt32(unsigned byteOffset, int32_t value, bool littleEndian, ExceptionCode& ec)
220 {
221     setData<int32_t>(byteOffset, value, littleEndian, ec);
222 }
223
224 void DataView::setUint32(unsigned byteOffset, uint32_t value, bool littleEndian, ExceptionCode& ec)
225 {
226     setData<uint32_t>(byteOffset, value, littleEndian, ec);
227 }
228
229 void DataView::setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode& ec)
230 {
231     setData<float>(byteOffset, value, littleEndian, ec);
232 }
233
234 void DataView::setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode& ec)
235 {
236     setData<double>(byteOffset, value, littleEndian, ec);
237 }
238
239 void DataView::neuter()
240 {
241     ArrayBufferView::neuter();
242     m_byteLength = 0;
243 }
244
245 }