1/*
2 * Copyright (C) 2016 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
27#include "config.h"
28#include "StructuredClone.h"
29
30#include "JSDOMBinding.h"
31#include "JSDOMExceptionHandling.h"
32#include <JavaScriptCore/JSTypedArrays.h>
33
34namespace WebCore {
35using namespace JSC;
36
37enum class CloneMode {
38 Full,
39 Partial,
40};
41
42EncodedJSValue JSC_HOST_CALL cloneArrayBufferImpl(ExecState*, CloneMode);
43
44EncodedJSValue JSC_HOST_CALL cloneArrayBufferImpl(ExecState* state, CloneMode mode)
45{
46 ASSERT(state);
47 ASSERT(state->argumentCount());
48 ASSERT(state->lexicalGlobalObject());
49
50 VM& vm = state->vm();
51 auto* buffer = toUnsharedArrayBuffer(vm, state->uncheckedArgument(0));
52 if (!buffer) {
53 auto scope = DECLARE_THROW_SCOPE(vm);
54 throwDataCloneError(*state, scope);
55 return { };
56 }
57 if (mode == CloneMode::Partial) {
58 ASSERT(state->argumentCount() == 3);
59 int srcByteOffset = static_cast<int>(state->uncheckedArgument(1).toNumber(state));
60 int srcLength = static_cast<int>(state->uncheckedArgument(2).toNumber(state));
61 return JSValue::encode(JSArrayBuffer::create(state->vm(), state->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), buffer->slice(srcByteOffset, srcByteOffset + srcLength)));
62 }
63 return JSValue::encode(JSArrayBuffer::create(state->vm(), state->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), ArrayBuffer::tryCreate(buffer->data(), buffer->byteLength())));
64}
65
66EncodedJSValue JSC_HOST_CALL cloneArrayBuffer(ExecState* state)
67{
68 return cloneArrayBufferImpl(state, CloneMode::Partial);
69}
70
71EncodedJSValue JSC_HOST_CALL structuredCloneArrayBuffer(ExecState* state)
72{
73 return cloneArrayBufferImpl(state, CloneMode::Full);
74}
75
76EncodedJSValue JSC_HOST_CALL structuredCloneArrayBufferView(ExecState* state)
77{
78 ASSERT(state);
79 ASSERT(state->argumentCount());
80
81 JSValue value = state->uncheckedArgument(0);
82 VM& vm = state->vm();
83 auto* bufferView = jsDynamicCast<JSArrayBufferView*>(vm, value);
84 ASSERT(bufferView);
85
86 auto* buffer = bufferView->unsharedBuffer();
87 if (!buffer) {
88 auto scope = DECLARE_THROW_SCOPE(vm);
89 throwDataCloneError(*state, scope);
90 return { };
91 }
92 auto bufferClone = ArrayBuffer::tryCreate(buffer->data(), buffer->byteLength());
93 Structure* structure = bufferView->structure(vm);
94
95 if (jsDynamicCast<JSInt8Array*>(vm, value))
96 return JSValue::encode(JSInt8Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
97 if (jsDynamicCast<JSInt16Array*>(vm, value))
98 return JSValue::encode(JSInt16Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
99 if (jsDynamicCast<JSInt32Array*>(vm, value))
100 return JSValue::encode(JSInt32Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
101 if (jsDynamicCast<JSUint8Array*>(vm, value))
102 return JSValue::encode(JSUint8Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
103 if (jsDynamicCast<JSUint8ClampedArray*>(vm, value))
104 return JSValue::encode(JSUint8ClampedArray::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
105 if (jsDynamicCast<JSUint16Array*>(vm, value))
106 return JSValue::encode(JSUint16Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
107 if (jsDynamicCast<JSUint32Array*>(vm, value))
108 return JSValue::encode(JSUint32Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
109 if (jsDynamicCast<JSFloat32Array*>(vm, value))
110 return JSValue::encode(JSFloat32Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
111 if (jsDynamicCast<JSFloat64Array*>(vm, value))
112 return JSValue::encode(JSFloat64Array::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
113 if (jsDynamicCast<JSDataView*>(vm, value))
114 return JSValue::encode(JSDataView::create(state, structure, WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length()));
115
116 ASSERT_NOT_REACHED();
117 return JSValue::encode(jsUndefined());
118}
119
120} // namespace WebCore
121