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 "JSDataView.h"
28
29#include "DataView.h"
30#include "ExceptionCode.h"
31#include "JSArrayBufferViewHelper.h"
32#include <wtf/MathExtras.h>
33
34using namespace JSC;
35
36namespace WebCore {
37
38enum DataViewAccessType {
39    AccessDataViewMemberAsInt8,
40    AccessDataViewMemberAsUint8,
41    AccessDataViewMemberAsFloat32,
42    AccessDataViewMemberAsFloat64
43};
44
45JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, DataView* object)
46{
47    return wrap<JSDataView>(exec, globalObject, object);
48}
49
50EncodedJSValue JSC_HOST_CALL JSDataViewConstructor::constructJSDataView(ExecState* exec)
51{
52    if (exec->argument(0).isNull() || !exec->argument(0).isObject())
53        return throwVMTypeError(exec);
54
55    RefPtr<DataView> view = constructArrayBufferViewWithArrayBufferArgument<DataView, char>(exec);
56    if (!view.get()) {
57        setDOMException(exec, INDEX_SIZE_ERR);
58        return JSValue::encode(jsUndefined());
59    }
60
61    JSDataViewConstructor* jsConstructor = static_cast<JSDataViewConstructor*>(exec->callee());
62    return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), view.get())));
63}
64
65static JSValue getDataViewMember(ExecState* exec, DataView* imp, DataViewAccessType type)
66{
67    if (exec->argumentCount() < 1)
68        return throwError(exec, createSyntaxError(exec, "Not enough arguments"));
69    ExceptionCode ec = 0;
70    unsigned byteOffset = exec->argument(0).toUInt32(exec);
71    if (exec->hadException())
72        return jsUndefined();
73
74    bool littleEndian = false;
75    if (exec->argumentCount() > 1 && (type == AccessDataViewMemberAsFloat32 || type == AccessDataViewMemberAsFloat64)) {
76        littleEndian = exec->argument(1).toBoolean(exec);
77        if (exec->hadException())
78            return jsUndefined();
79    }
80
81    JSC::JSValue result;
82    switch (type) {
83    case AccessDataViewMemberAsInt8:
84        result = jsNumber(imp->getInt8(byteOffset, ec));
85        break;
86    case AccessDataViewMemberAsUint8:
87        result = jsNumber(imp->getUint8(byteOffset, ec));
88        break;
89    case AccessDataViewMemberAsFloat32:
90    case AccessDataViewMemberAsFloat64: {
91        double value = (type == AccessDataViewMemberAsFloat32) ? imp->getFloat32(byteOffset, littleEndian, ec) : imp->getFloat64(byteOffset, littleEndian, ec);
92        result = isnan(value) ? JSValue(nonInlineNaN()) : jsNumber(value);
93        break;
94    } default:
95        ASSERT_NOT_REACHED();
96        break;
97    }
98    setDOMException(exec, ec);
99    return result;
100}
101
102JSValue JSDataView::getInt8(ExecState* exec)
103{
104    return getDataViewMember(exec, static_cast<DataView*>(impl()), AccessDataViewMemberAsInt8);
105}
106
107JSValue JSDataView::getUint8(ExecState* exec)
108{
109    return getDataViewMember(exec, static_cast<DataView*>(impl()), AccessDataViewMemberAsUint8);
110}
111
112JSValue JSDataView::getFloat32(ExecState* exec)
113{
114    return getDataViewMember(exec, static_cast<DataView*>(impl()), AccessDataViewMemberAsFloat32);
115}
116
117JSValue JSDataView::getFloat64(ExecState* exec)
118{
119    return getDataViewMember(exec, static_cast<DataView*>(impl()), AccessDataViewMemberAsFloat64);
120}
121
122static JSValue setDataViewMember(ExecState* exec, DataView* imp, DataViewAccessType type)
123{
124    if (exec->argumentCount() < 2)
125        return throwError(exec, createSyntaxError(exec, "Not enough arguments"));
126    ExceptionCode ec = 0;
127    unsigned byteOffset = exec->argument(0).toUInt32(exec);
128    if (exec->hadException())
129        return jsUndefined();
130    int value = exec->argument(1).toInt32(exec);
131    if (exec->hadException())
132        return jsUndefined();
133
134    switch (type) {
135    case AccessDataViewMemberAsInt8:
136        imp->setInt8(byteOffset, static_cast<int8_t>(value), ec);
137        break;
138    case AccessDataViewMemberAsUint8:
139        imp->setUint8(byteOffset, static_cast<uint8_t>(value), ec);
140        break;
141    default:
142        ASSERT_NOT_REACHED();
143        break;
144    }
145    setDOMException(exec, ec);
146    return jsUndefined();
147}
148
149JSValue JSDataView::setInt8(ExecState* exec)
150{
151    return setDataViewMember(exec, static_cast<DataView*>(impl()), AccessDataViewMemberAsInt8);
152}
153
154JSValue JSDataView::setUint8(ExecState* exec)
155{
156    return setDataViewMember(exec, static_cast<DataView*>(impl()), AccessDataViewMemberAsUint8);
157}
158
159} // namespace WebCore
160