1 /*
2     This file is part of the KDE libraries
3     Copyright 2012  Bernd Buschinski <b.buschinski@googlemail.com>
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "propertydescriptor.h"
20 #include "object.h"
21 #include "operations.h"
22 
23 #include <stdio.h>
24 
25 namespace KJS
26 {
27 
PropertyDescriptor()28 PropertyDescriptor::PropertyDescriptor()
29     : m_attributes(DontEnum | DontDelete | ReadOnly),
30       m_setAttributes(0),
31       m_value(nullptr),
32       m_getter(nullptr),
33       m_setter(nullptr)
34 {
35 }
36 
37 //ECMAScript Edition 5.1r6 - 8.10.1
isAccessorDescriptor() const38 bool PropertyDescriptor::isAccessorDescriptor() const
39 {
40     return (m_getter || m_setter);
41 }
42 
43 //ECMAScript Edition 5.1r6 - 8.10.2
isDataDescriptor() const44 bool PropertyDescriptor::isDataDescriptor() const
45 {
46     if (!m_value && !(writableSet())) {
47         return false;
48     }
49     return true;
50 }
51 
52 //ECMAScript Edition 5.1r6 - 8.10.3
isGenericDescriptor() const53 bool PropertyDescriptor::isGenericDescriptor() const
54 {
55     return (!isAccessorDescriptor() && !isDataDescriptor());
56 }
57 
58 //ECMAScript Edition 5.1r6 - 8.10.4 - FromPropertyDescriptor
fromPropertyDescriptor(ExecState * exec)59 JSObject *PropertyDescriptor::fromPropertyDescriptor(ExecState *exec)
60 {
61     JSObject *ret = new JSObject(exec->lexicalInterpreter()->builtinObjectPrototype());
62 
63     if (isDataDescriptor()) {
64         ret->put(exec, exec->propertyNames().writable, jsBoolean(writable()));
65         ret->put(exec, exec->propertyNames().value, value() ? value() : jsUndefined());
66     } else {
67         ret->put(exec, exec->propertyNames().get, getter() ? getter() : jsUndefined());
68         ret->put(exec, exec->propertyNames().set, setter() ? setter() : jsUndefined());
69     }
70 
71     ret->put(exec, exec->propertyNames().enumerable, jsBoolean(enumerable()));
72     ret->put(exec, exec->propertyNames().configurable, jsBoolean(configurable()));
73 
74     return ret;
75 }
76 
77 //ECMAScript Edition 5.1r6 - 8.10.5 - ToPropertyDescriptor
setPropertyDescriptorFromObject(ExecState * exec,JSValue * jsValue)78 bool PropertyDescriptor::setPropertyDescriptorFromObject(ExecState *exec, JSValue *jsValue)
79 {
80     JSObject *obj = JSValue::getObject(jsValue);
81     if (!obj) {
82         throwError(exec, TypeError, "not an Object");
83         return false;
84     }
85 
86     if (obj->hasProperty(exec, exec->propertyNames().enumerable)) {
87         setEnumerable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().enumerable), exec));
88     }
89 
90     if (obj->hasProperty(exec, exec->propertyNames().configurable)) {
91         setConfigureable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().configurable), exec));
92     }
93 
94     if (obj->hasProperty(exec, exec->propertyNames().value)) {
95         setValue(obj->get(exec, exec->propertyNames().value));
96     }
97 
98     if (obj->hasProperty(exec, exec->propertyNames().writable)) {
99         setWritable(JSValue::toBoolean(obj->get(exec, exec->propertyNames().writable), exec));
100     }
101 
102     if (obj->hasProperty(exec, exec->propertyNames().get)) {
103         JSValue *getter = obj->get(exec, exec->propertyNames().get);
104         if (!JSValue::isUndefined(getter)) {
105             if (!JSValue::implementsCall(getter)) {
106                 throwError(exec, TypeError, "Getter: \'" + JSValue::toString(getter, exec) + "\' is not Callable");
107                 return false;
108             }
109         }
110         setGetter(getter);
111     }
112 
113     if (obj->hasProperty(exec, exec->propertyNames().set)) {
114         JSValue *setter = obj->get(exec, exec->propertyNames().set);
115         if (!JSValue::isUndefined(setter)) {
116             if (!JSValue::implementsCall(setter)) {
117                 throwError(exec, TypeError, "Setter: \'" + JSValue::toString(setter, exec) + "\' is not Callable");
118                 return false;
119             }
120         }
121         setSetter(setter);
122     }
123 
124     if (getter() || setter()) {
125         if (value() || writableSet()) {
126             throwError(exec, TypeError, "can not mix accessor descriptor and data descriptor");
127             return false;
128         }
129     }
130     return true;
131 }
132 
setPropertyDescriptorValues(ExecState *,JSValue * value,unsigned int attributes)133 bool PropertyDescriptor::setPropertyDescriptorValues(ExecState *, JSValue *value, unsigned int attributes)
134 {
135     setEnumerable(!(attributes & DontEnum));
136     setConfigureable(!(attributes & DontDelete));
137 
138     if (!value) {
139         return false;
140     }
141     if (JSValue::isUndefined(value) || JSValue::type(value) != GetterSetterType) {
142         setValue(value);
143         setWritable(!(attributes & ReadOnly));
144     } else {
145         GetterSetterImp *gs = static_cast<GetterSetterImp *>(value);
146         setGetter(gs->getGetter() ? gs->getGetter() : jsUndefined());
147         setSetter(gs->getSetter() ? gs->getSetter() : jsUndefined());
148     }
149     return true;
150 }
151 
configurable() const152 bool PropertyDescriptor::configurable() const
153 {
154     return !(m_attributes & DontDelete);
155 }
156 
enumerable() const157 bool PropertyDescriptor::enumerable() const
158 {
159     return !(m_attributes & DontEnum);
160 }
161 
writable() const162 bool PropertyDescriptor::writable() const
163 {
164     return !(m_attributes & ReadOnly);
165 }
166 
configureSet() const167 bool PropertyDescriptor::configureSet() const
168 {
169     return m_setAttributes & ConfigurableSet;
170 }
171 
enumerableSet() const172 bool PropertyDescriptor::enumerableSet() const
173 {
174     return m_setAttributes & EnumerableSet;
175 }
176 
writableSet() const177 bool PropertyDescriptor::writableSet() const
178 {
179     return m_setAttributes & WritableSet;
180 }
181 
getter() const182 JSValue *PropertyDescriptor::getter() const
183 {
184     return m_getter;
185 }
186 
setter() const187 JSValue *PropertyDescriptor::setter() const
188 {
189     return m_setter;
190 }
191 
value() const192 JSValue *PropertyDescriptor::value() const
193 {
194     return m_value;
195 }
196 
setEnumerable(bool enumerable)197 void PropertyDescriptor::setEnumerable(bool enumerable)
198 {
199     if (enumerable) {
200         m_attributes &= ~DontEnum;
201     } else {
202         m_attributes |= DontEnum;
203     }
204     m_setAttributes |= EnumerableSet;
205 }
206 
setConfigureable(bool configurable)207 void PropertyDescriptor::setConfigureable(bool configurable)
208 {
209     if (configurable) {
210         m_attributes &= ~DontDelete;
211     } else {
212         m_attributes |= DontDelete;
213     }
214     m_setAttributes |= ConfigurableSet;
215 }
216 
setValue(JSValue * value)217 void PropertyDescriptor::setValue(JSValue *value)
218 {
219     m_value = value;
220 }
221 
setWritable(bool writable)222 void PropertyDescriptor::setWritable(bool writable)
223 {
224     if (writable) {
225         m_attributes &= ~ReadOnly;
226     } else {
227         m_attributes |= ReadOnly;
228     }
229     m_setAttributes |= WritableSet;
230 }
231 
setGetter(JSValue * getter)232 void PropertyDescriptor::setGetter(JSValue *getter)
233 {
234     m_getter = getter;
235     m_attributes &= ~ReadOnly;
236 }
237 
setSetter(JSValue * setter)238 void PropertyDescriptor::setSetter(JSValue *setter)
239 {
240     m_setter = setter;
241     m_attributes &= ~ReadOnly;
242 }
243 
attributes() const244 unsigned int PropertyDescriptor::attributes() const
245 {
246     return m_attributes;
247 }
248 
isEmpty() const249 bool PropertyDescriptor::isEmpty() const
250 {
251     return !m_setAttributes && !m_getter && !m_setter && !m_value;
252 }
253 
compareValue(ExecState * exec,JSValue * a,JSValue * b)254 inline bool compareValue(ExecState *exec, JSValue *a, JSValue *b)
255 {
256     return (a == b || (a && b && sameValue(exec, a, b)));
257 }
258 
259 // different from compareValue, if "own" getter/setter is missing (is 0) we are still the same
compareFunction(ExecState * exec,JSValue * a,JSValue * b)260 inline bool compareFunction(ExecState *exec, JSValue *a, JSValue *b)
261 {
262     return (a == b || (b != nullptr && a == nullptr) || (a && b && sameValue(exec, a, b)));
263 }
264 
equalTo(ExecState * exec,PropertyDescriptor & other) const265 bool PropertyDescriptor::equalTo(ExecState *exec, PropertyDescriptor &other) const
266 {
267     return (compareValue(exec, m_value, other.value()) &&
268             compareFunction(exec, m_getter, other.getter()) &&
269             compareFunction(exec, m_setter, other.setter()) &&
270             attributes() == other.attributes());
271 }
272 
attributesWithOverride(PropertyDescriptor & other) const273 unsigned int PropertyDescriptor::attributesWithOverride(PropertyDescriptor &other) const
274 {
275     unsigned int mismatch = other.m_attributes ^ m_attributes;
276     unsigned int sharedSeen = other.m_setAttributes & m_setAttributes;
277     unsigned int newAttributes = m_attributes & (DontEnum | DontDelete | ReadOnly);
278 
279     if ((sharedSeen & WritableSet) && (mismatch & ReadOnly)) {
280         newAttributes ^= ReadOnly;
281     }
282     if ((sharedSeen & ConfigurableSet) && (mismatch & DontDelete)) {
283         newAttributes ^= DontDelete;
284     }
285     if ((sharedSeen & EnumerableSet) && (mismatch & DontEnum)) {
286         newAttributes ^= DontEnum;
287     }
288 
289     return newAttributes;
290 }
291 
operator ==(PropertyDescriptor & other) const292 bool PropertyDescriptor::operator==(PropertyDescriptor &other) const
293 {
294     return (m_value == other.value() &&
295             m_setter == other.setter() &&
296             m_getter == other.getter() &&
297             m_attributes == other.m_attributes &&
298             writableSet() == other.writableSet() &&
299             enumerableSet() == other.enumerableSet() &&
300             configureSet() == other.configureSet());
301 }
302 
303 }
304 
305