1 /*
2 * Copyright (C) 2009 Apple 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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef ArrayBufferView_h
27 #define ArrayBufferView_h
28
29 #include "wtf/ArrayBuffer.h"
30
31 #include <algorithm>
32 #include <limits.h>
33 #include "wtf/PassRefPtr.h"
34 #include "wtf/RefCounted.h"
35 #include "wtf/RefPtr.h"
36 #include "wtf/WTFExport.h"
37
38 namespace WTF {
39
40 class WTF_EXPORT ArrayBufferView : public RefCounted<ArrayBufferView> {
41 public:
42 enum ViewType {
43 TypeInt8,
44 TypeUint8,
45 TypeUint8Clamped,
46 TypeInt16,
47 TypeUint16,
48 TypeInt32,
49 TypeUint32,
50 TypeFloat32,
51 TypeFloat64,
52 TypeDataView
53 };
54 virtual ViewType type() const = 0;
55 const char* typeName();
56
buffer()57 PassRefPtr<ArrayBuffer> buffer() const
58 {
59 return m_buffer;
60 }
61
baseAddress()62 void* baseAddress() const
63 {
64 return m_baseAddress;
65 }
66
byteOffset()67 unsigned byteOffset() const
68 {
69 return m_byteOffset;
70 }
71
72 virtual unsigned byteLength() const = 0;
73
setNeuterable(bool flag)74 void setNeuterable(bool flag) { m_isNeuterable = flag; }
isNeuterable()75 bool isNeuterable() const { return m_isNeuterable; }
76
77 virtual ~ArrayBufferView();
78
79 protected:
80 ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset);
81
82 inline bool setImpl(ArrayBufferView*, unsigned byteOffset);
83
84 inline bool setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset);
85
86 inline bool zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength);
87
88 static inline void calculateOffsetAndLength(int start, int end, unsigned arraySize,
89 unsigned* offset, unsigned* length);
90
91 // Helper to verify that a given sub-range of an ArrayBuffer is
92 // within range.
93 template <typename T>
verifySubRange(PassRefPtr<ArrayBuffer> buffer,unsigned byteOffset,unsigned numElements)94 static bool verifySubRange(PassRefPtr<ArrayBuffer> buffer,
95 unsigned byteOffset,
96 unsigned numElements)
97 {
98 if (!buffer)
99 return false;
100 if (sizeof(T) > 1 && byteOffset % sizeof(T))
101 return false;
102 if (byteOffset > buffer->byteLength())
103 return false;
104 unsigned remainingElements = (buffer->byteLength() - byteOffset) / sizeof(T);
105 if (numElements > remainingElements)
106 return false;
107 return true;
108 }
109
110 // Input offset is in number of elements from this array's view;
111 // output offset is in number of bytes from the underlying buffer's view.
112 template <typename T>
clampOffsetAndNumElements(PassRefPtr<ArrayBuffer> buffer,unsigned arrayByteOffset,unsigned * offset,unsigned * numElements)113 static void clampOffsetAndNumElements(PassRefPtr<ArrayBuffer> buffer,
114 unsigned arrayByteOffset,
115 unsigned *offset,
116 unsigned *numElements)
117 {
118 unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T);
119 if (*offset > maxOffset) {
120 *offset = buffer->byteLength();
121 *numElements = 0;
122 return;
123 }
124 *offset = arrayByteOffset + *offset * sizeof(T);
125 *offset = std::min(buffer->byteLength(), *offset);
126 unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T);
127 *numElements = std::min(remainingElements, *numElements);
128 }
129
130 virtual void neuter();
131
132 // This is the address of the ArrayBuffer's storage, plus the byte offset.
133 void* m_baseAddress;
134
135 unsigned m_byteOffset : 31;
136 bool m_isNeuterable : 1;
137
138 private:
139 friend class ArrayBuffer;
140 RefPtr<ArrayBuffer> m_buffer;
141 ArrayBufferView* m_prevView;
142 ArrayBufferView* m_nextView;
143 };
144
setImpl(ArrayBufferView * array,unsigned byteOffset)145 bool ArrayBufferView::setImpl(ArrayBufferView* array, unsigned byteOffset)
146 {
147 if (byteOffset > byteLength()
148 || byteOffset + array->byteLength() > byteLength()
149 || byteOffset + array->byteLength() < byteOffset) {
150 // Out of range offset or overflow
151 return false;
152 }
153
154 char* base = static_cast<char*>(baseAddress());
155 memmove(base + byteOffset, array->baseAddress(), array->byteLength());
156 return true;
157 }
158
setRangeImpl(const char * data,size_t dataByteLength,unsigned byteOffset)159 bool ArrayBufferView::setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset)
160 {
161 if (byteOffset > byteLength()
162 || byteOffset + dataByteLength > byteLength()
163 || byteOffset + dataByteLength < byteOffset) {
164 // Out of range offset or overflow
165 return false;
166 }
167
168 char* base = static_cast<char*>(baseAddress());
169 memmove(base + byteOffset, data, dataByteLength);
170 return true;
171 }
172
zeroRangeImpl(unsigned byteOffset,size_t rangeByteLength)173 bool ArrayBufferView::zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength)
174 {
175 if (byteOffset > byteLength()
176 || byteOffset + rangeByteLength > byteLength()
177 || byteOffset + rangeByteLength < byteOffset) {
178 // Out of range offset or overflow
179 return false;
180 }
181
182 char* base = static_cast<char*>(baseAddress());
183 memset(base + byteOffset, 0, rangeByteLength);
184 return true;
185 }
186
calculateOffsetAndLength(int start,int end,unsigned arraySize,unsigned * offset,unsigned * length)187 void ArrayBufferView::calculateOffsetAndLength(int start, int end, unsigned arraySize,
188 unsigned* offset, unsigned* length)
189 {
190 if (start < 0)
191 start += arraySize;
192 if (start < 0)
193 start = 0;
194 if (end < 0)
195 end += arraySize;
196 if (end < 0)
197 end = 0;
198 if (static_cast<unsigned>(end) > arraySize)
199 end = arraySize;
200 if (end < start)
201 end = start;
202 *offset = static_cast<unsigned>(start);
203 *length = static_cast<unsigned>(end - start);
204 }
205
206 } // namespace WTF
207
208 using WTF::ArrayBufferView;
209
210 #endif // ArrayBufferView_h
211