]>
Commit | Line | Data |
---|---|---|
81345200 A |
1 | /* |
2 | * Copyright (C) 2009, 2013 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 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 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 "ArrayBuffer.h" | |
30 | #include "TypedArrayType.h" | |
31 | #include <algorithm> | |
32 | #include <limits.h> | |
33 | #include <wtf/PassRefPtr.h> | |
34 | #include <wtf/RefCounted.h> | |
35 | #include <wtf/RefPtr.h> | |
36 | ||
37 | namespace JSC { | |
38 | ||
39 | class JSArrayBufferView; | |
40 | class JSGlobalObject; | |
41 | class ExecState; | |
42 | ||
43 | class ArrayBufferView : public RefCounted<ArrayBufferView> { | |
44 | public: | |
45 | virtual TypedArrayType getType() const = 0; | |
46 | ||
47 | bool isNeutered() const | |
48 | { | |
49 | return !m_buffer || m_buffer->isNeutered(); | |
50 | } | |
51 | ||
52 | PassRefPtr<ArrayBuffer> buffer() const | |
53 | { | |
54 | if (isNeutered()) | |
55 | return 0; | |
56 | return m_buffer; | |
57 | } | |
58 | ||
59 | void* baseAddress() const | |
60 | { | |
61 | if (isNeutered()) | |
62 | return 0; | |
63 | return m_baseAddress; | |
64 | } | |
65 | ||
66 | unsigned byteOffset() const | |
67 | { | |
68 | if (isNeutered()) | |
69 | return 0; | |
70 | return m_byteOffset; | |
71 | } | |
72 | ||
73 | virtual unsigned byteLength() const = 0; | |
74 | ||
75 | JS_EXPORT_PRIVATE void setNeuterable(bool flag); | |
76 | bool isNeuterable() const { return m_isNeuterable; } | |
77 | ||
78 | JS_EXPORT_PRIVATE virtual ~ArrayBufferView(); | |
79 | ||
80 | // Helper to verify that a given sub-range of an ArrayBuffer is | |
81 | // within range. | |
82 | // FIXME: This should distinguish between alignment errors and bounds errors. | |
83 | // https://bugs.webkit.org/show_bug.cgi?id=125391 | |
84 | template <typename T> | |
85 | static bool verifySubRange( | |
86 | PassRefPtr<ArrayBuffer> buffer, | |
87 | unsigned byteOffset, | |
88 | unsigned numElements) | |
89 | { | |
90 | unsigned byteLength = buffer->byteLength(); | |
91 | if (sizeof(T) > 1 && byteOffset % sizeof(T)) | |
92 | return false; | |
93 | if (byteOffset > byteLength) | |
94 | return false; | |
95 | unsigned remainingElements = (byteLength - byteOffset) / sizeof(T); | |
96 | if (numElements > remainingElements) | |
97 | return false; | |
98 | return true; | |
99 | } | |
100 | ||
101 | virtual JSArrayBufferView* wrap(ExecState*, JSGlobalObject*) = 0; | |
102 | ||
103 | protected: | |
104 | JS_EXPORT_PRIVATE ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset); | |
105 | ||
106 | inline bool setImpl(ArrayBufferView*, unsigned byteOffset); | |
107 | ||
108 | inline bool setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset); | |
109 | ||
110 | inline bool zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength); | |
111 | ||
112 | static inline void calculateOffsetAndLength( | |
113 | int start, int end, unsigned arraySize, | |
114 | unsigned* offset, unsigned* length); | |
115 | ||
116 | // Input offset is in number of elements from this array's view; | |
117 | // output offset is in number of bytes from the underlying buffer's view. | |
118 | template <typename T> | |
119 | static void clampOffsetAndNumElements( | |
120 | PassRefPtr<ArrayBuffer> buffer, | |
121 | unsigned arrayByteOffset, | |
122 | unsigned *offset, | |
123 | unsigned *numElements) | |
124 | { | |
125 | unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T); | |
126 | if (*offset > maxOffset) { | |
127 | *offset = buffer->byteLength(); | |
128 | *numElements = 0; | |
129 | return; | |
130 | } | |
131 | *offset = arrayByteOffset + *offset * sizeof(T); | |
132 | *offset = std::min(buffer->byteLength(), *offset); | |
133 | unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T); | |
134 | *numElements = std::min(remainingElements, *numElements); | |
135 | } | |
136 | ||
137 | // This is the address of the ArrayBuffer's storage, plus the byte offset. | |
138 | void* m_baseAddress; | |
139 | ||
140 | unsigned m_byteOffset : 31; | |
141 | bool m_isNeuterable : 1; | |
142 | ||
143 | private: | |
144 | friend class ArrayBuffer; | |
145 | RefPtr<ArrayBuffer> m_buffer; | |
146 | }; | |
147 | ||
148 | bool ArrayBufferView::setImpl(ArrayBufferView* array, unsigned byteOffset) | |
149 | { | |
150 | if (byteOffset > byteLength() | |
151 | || byteOffset + array->byteLength() > byteLength() | |
152 | || byteOffset + array->byteLength() < byteOffset) { | |
153 | // Out of range offset or overflow | |
154 | return false; | |
155 | } | |
156 | ||
157 | char* base = static_cast<char*>(baseAddress()); | |
158 | memmove(base + byteOffset, array->baseAddress(), array->byteLength()); | |
159 | return true; | |
160 | } | |
161 | ||
162 | bool ArrayBufferView::setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset) | |
163 | { | |
164 | if (byteOffset > byteLength() | |
165 | || byteOffset + dataByteLength > byteLength() | |
166 | || byteOffset + dataByteLength < byteOffset) { | |
167 | // Out of range offset or overflow | |
168 | return false; | |
169 | } | |
170 | ||
171 | char* base = static_cast<char*>(baseAddress()); | |
172 | memmove(base + byteOffset, data, dataByteLength); | |
173 | return true; | |
174 | } | |
175 | ||
176 | bool ArrayBufferView::zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength) | |
177 | { | |
178 | if (byteOffset > byteLength() | |
179 | || byteOffset + rangeByteLength > byteLength() | |
180 | || byteOffset + rangeByteLength < byteOffset) { | |
181 | // Out of range offset or overflow | |
182 | return false; | |
183 | } | |
184 | ||
185 | char* base = static_cast<char*>(baseAddress()); | |
186 | memset(base + byteOffset, 0, rangeByteLength); | |
187 | return true; | |
188 | } | |
189 | ||
190 | void ArrayBufferView::calculateOffsetAndLength( | |
191 | int start, int end, unsigned arraySize, unsigned* offset, unsigned* length) | |
192 | { | |
193 | if (start < 0) | |
194 | start += arraySize; | |
195 | if (start < 0) | |
196 | start = 0; | |
197 | if (end < 0) | |
198 | end += arraySize; | |
199 | if (end < 0) | |
200 | end = 0; | |
201 | if (static_cast<unsigned>(end) > arraySize) | |
202 | end = arraySize; | |
203 | if (end < start) | |
204 | end = start; | |
205 | *offset = static_cast<unsigned>(start); | |
206 | *length = static_cast<unsigned>(end - start); | |
207 | } | |
208 | ||
209 | } // namespace JSC | |
210 | ||
211 | using JSC::ArrayBufferView; | |
212 | ||
213 | #endif // ArrayBufferView_h |