1 // PropertyList.cpp: ActionScript property lists, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "gnashconfig.h" // GNASH_STATS_PROPERTY_LOOKUPS
25 #include "PropertyList.h"
28 #include <boost/bind.hpp>
29 #include <boost/tuple/tuple.hpp>
32 #include "as_environment.h"
34 #include "as_function.h"
37 #include "string_table.h"
38 #include "GnashAlgorithm.h"
40 // Define the following to enable printing address of each property added
41 //#define DEBUG_PROPERTY_ALLOC
43 // Define this to get verbosity of properties insertion and flags setting
44 //#define GNASH_DEBUG_PROPERTY 1
46 // Define this to get stats of property lookups
47 //#define GNASH_STATS_PROPERTY_LOOKUPS 1
49 #ifdef GNASH_STATS_PROPERTY_LOOKUPS
51 # include "namedStrings.h"
59 PropertyList::const_iterator
60 iterator_find(const PropertyList::container
& p
, const ObjectURI
& uri
, VM
& vm
)
62 const bool caseless
= vm
.getSWFVersion() < 7;
65 return p
.project
<PropertyList::CreationOrder
>(
66 p
.get
<PropertyList::Case
>().find(uri
));
69 return p
.project
<PropertyList::CreationOrder
>(
70 p
.get
<PropertyList::NoCase
>().find(uri
));
75 PropertyList::PropertyList(as_object
& obj
)
77 _props(boost::make_tuple(
85 ObjectURI::CaseLessThan(getStringTable(obj
), true)
94 PropertyList::setValue(const ObjectURI
& uri
, const as_value
& val
,
95 const PropFlags
& flagsIfMissing
)
97 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
99 if (found
== _props
.end()) {
100 // create a new member
101 Property
a(uri
, val
, flagsIfMissing
);
102 // Non slot properties are negative ordering in insertion order
104 #ifdef GNASH_DEBUG_PROPERTY
105 ObjectURI::Logger
l(getStringTable(_owner
));
106 log_debug("Simple AS property %s inserted with flags %s",
107 l(uri
), a
.getFlags());
112 const Property
& prop
= *found
;
113 if (readOnly(prop
)) {
114 ObjectURI::Logger
l(getStringTable(_owner
));
115 log_error(_("Property %s is read-only %s, not setting it to %s"),
116 l(uri
), prop
.getFlags(), val
);
120 prop
.setValue(_owner
, val
);
126 PropertyList::setFlags(const ObjectURI
& uri
, int setFlags
, int clearFlags
)
128 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
129 if (found
== _props
.end()) return;
130 PropFlags f
= found
->getFlags();
131 f
.set_flags(setFlags
, clearFlags
);
137 PropertyList::setFlagsAll(int setFlags
, int clearFlags
)
139 for (const_iterator it
= _props
.begin(); it
!= _props
.end(); ++it
) {
140 PropFlags f
= it
->getFlags();
141 f
.set_flags(setFlags
, clearFlags
);
147 PropertyList::getProperty(const ObjectURI
& uri
) const
149 #ifdef GNASH_STATS_PROPERTY_LOOKUPS
150 // HINT: can add a final arg to KeyLookup ctor, like NSV::PROP_ON_MOUSE_MOVE
151 // to have *that* property lookup drive dump triggers
152 static stats::KeyLookup
kcl("getProperty",
153 getStringTable(_owner
), 10000000, NSV::PROP_uuPROTOuu
, 10);
155 #endif // GNASH_STATS_PROPERTY_LOOKUPS
156 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
157 if (found
== _props
.end()) return 0;
158 return const_cast<Property
*>(&(*found
));
162 PropertyList::delProperty(const ObjectURI
& uri
)
164 //GNASH_REPORT_FUNCTION;
165 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
166 if (found
== _props
.end()) {
167 return std::make_pair(false, false);
170 // check if member is protected from deletion
171 if (found
->getFlags().test
<PropFlags::dontDelete
>()) {
172 return std::make_pair(true, false);
176 return std::make_pair(true, true);
180 PropertyList::visitKeys(KeyVisitor
& visitor
, PropertyTracker
& donelist
)
183 // We should enumerate in order of creation, not lexicographically.
184 for (const_iterator i
= _props
.begin(),
185 ie
= _props
.end(); i
!= ie
; ++i
) {
187 if (i
->getFlags().test
<PropFlags::dontEnum
>()) continue;
189 const ObjectURI
& uri
= i
->uri();
191 if (donelist
.insert(uri
).second
) {
200 ObjectURI::Logger
l(getStringTable(_owner
));
201 for (const_iterator it
=_props
.begin(), itEnd
=_props
.end();
203 log_debug(" %s: %s", l(it
->uri()), it
->getValue(_owner
));
208 PropertyList::addGetterSetter(const ObjectURI
& uri
, as_function
& getter
,
209 as_function
* setter
, const as_value
& cacheVal
,
210 const PropFlags
& flagsIfMissing
)
212 Property
a(uri
, &getter
, setter
, flagsIfMissing
);
213 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
215 if (found
!= _props
.end()) {
216 // copy flags from previous member (even if it's a normal member ?)
217 a
.setFlags(found
->getFlags());
218 a
.setCache(found
->getCache());
219 _props
.replace(found
, a
);
221 #ifdef GNASH_DEBUG_PROPERTY
222 ObjectURI::Logger
l(getStringTable(_owner
));
223 log_debug("AS GetterSetter %s replaced copying flags %s", l(uri
),
229 a
.setCache(cacheVal
);
231 #ifdef GNASH_DEBUG_PROPERTY
232 ObjectURI::Logger
l(getStringTable(_owner
));
233 log_debug("AS GetterSetter %s inserted with flags %s", l(uri
),
242 PropertyList::addGetterSetter(const ObjectURI
& uri
, as_c_function_ptr getter
,
243 as_c_function_ptr setter
, const PropFlags
& flagsIfMissing
)
245 Property
a(uri
, getter
, setter
, flagsIfMissing
);
247 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
248 if (found
!= _props
.end())
250 // copy flags from previous member (even if it's a normal member ?)
251 a
.setFlags(found
->getFlags());
252 _props
.replace(found
, a
);
254 #ifdef GNASH_DEBUG_PROPERTY
255 ObjectURI::Logger
l(getStringTable(_owner
));
256 log_debug("Native GetterSetter %s replaced copying flags %s", l(uri
),
264 #ifdef GNASH_DEBUG_PROPERTY
265 string_table
& st
= getStringTable(_owner
);
266 log_debug("Native GetterSetter %s in namespace %s inserted with "
267 "flags %s", st
.value(key
), st
.value(nsId
), a
.getFlags());
275 PropertyList::addDestructiveGetter(const ObjectURI
& uri
, as_function
& getter
,
276 const PropFlags
& flagsIfMissing
)
278 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
279 if (found
!= _props
.end())
281 ObjectURI::Logger
l(getStringTable(_owner
));
282 log_error("Property %s already exists, can't addDestructiveGetter",
284 return false; // Already exists.
287 // destructive getter doesn't need a setter
288 Property
a(uri
, &getter
, 0, flagsIfMissing
, true);
292 #ifdef GNASH_DEBUG_PROPERTY
293 ObjectURI::Logger
l(getStringTable(_owner
));
294 log_debug("Destructive AS property %s inserted with flags %s",
295 l(uri
), a
.getFlags());
302 PropertyList::addDestructiveGetter(const ObjectURI
& uri
,
303 as_c_function_ptr getter
, const PropFlags
& flagsIfMissing
)
305 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
306 if (found
!= _props
.end()) return false;
308 // destructive getter doesn't need a setter
309 Property
a(uri
, getter
, 0, flagsIfMissing
, true);
312 #ifdef GNASH_DEBUG_PROPERTY
313 ObjectURI::Logger
l(getStringTable(_owner
));
314 log_debug("Destructive native property %s with flags %s", l(uri
),
321 PropertyList::clear()