1 // PropertyList.cpp: ActionScript property lists, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
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 return prop
.setValue(_owner
, val
);
118 PropertyList::setFlags(const ObjectURI
& uri
, int setFlags
, int clearFlags
)
120 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
121 if (found
== _props
.end()) return;
122 PropFlags f
= found
->getFlags();
123 f
.set_flags(setFlags
, clearFlags
);
129 PropertyList::setFlagsAll(int setFlags
, int clearFlags
)
131 for (const_iterator it
= _props
.begin(); it
!= _props
.end(); ++it
) {
132 PropFlags f
= it
->getFlags();
133 f
.set_flags(setFlags
, clearFlags
);
139 PropertyList::getProperty(const ObjectURI
& uri
) const
141 #ifdef GNASH_STATS_PROPERTY_LOOKUPS
142 // HINT: can add a final arg to KeyLookup ctor, like NSV::PROP_ON_MOUSE_MOVE
143 // to have *that* property lookup drive dump triggers
144 static stats::KeyLookup
kcl("getProperty",
145 getStringTable(_owner
), 10000000, NSV::PROP_uuPROTOuu
, 10);
147 #endif // GNASH_STATS_PROPERTY_LOOKUPS
148 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
149 if (found
== _props
.end()) return 0;
150 return const_cast<Property
*>(&(*found
));
154 PropertyList::delProperty(const ObjectURI
& uri
)
156 //GNASH_REPORT_FUNCTION;
157 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
158 if (found
== _props
.end()) {
159 return std::make_pair(false, false);
162 // check if member is protected from deletion
163 if (found
->getFlags().test
<PropFlags::dontDelete
>()) {
164 return std::make_pair(true, false);
168 return std::make_pair(true, true);
172 PropertyList::visitKeys(KeyVisitor
& visitor
, PropertyTracker
& donelist
)
175 // We should enumerate in order of creation, not lexicographically.
176 for (const_iterator i
= _props
.begin(),
177 ie
= _props
.end(); i
!= ie
; ++i
) {
179 if (i
->getFlags().test
<PropFlags::dontEnum
>()) continue;
181 const ObjectURI
& uri
= i
->uri();
183 if (donelist
.insert(uri
).second
) {
192 ObjectURI::Logger
l(getStringTable(_owner
));
193 for (const_iterator it
=_props
.begin(), itEnd
=_props
.end();
195 log_debug(" %s: %s", l(it
->uri()), it
->getValue(_owner
));
200 PropertyList::addGetterSetter(const ObjectURI
& uri
, as_function
& getter
,
201 as_function
* setter
, const as_value
& cacheVal
,
202 const PropFlags
& flagsIfMissing
)
204 Property
a(uri
, &getter
, setter
, flagsIfMissing
);
205 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
207 if (found
!= _props
.end()) {
208 // copy flags from previous member (even if it's a normal member ?)
209 a
.setFlags(found
->getFlags());
210 a
.setCache(found
->getCache());
211 _props
.replace(found
, a
);
213 #ifdef GNASH_DEBUG_PROPERTY
214 ObjectURI::Logger
l(getStringTable(_owner
));
215 log_debug("AS GetterSetter %s replaced copying flags %s", l(uri
),
221 a
.setCache(cacheVal
);
223 #ifdef GNASH_DEBUG_PROPERTY
224 ObjectURI::Logger
l(getStringTable(_owner
));
225 log_debug("AS GetterSetter %s inserted with flags %s", l(uri
),
234 PropertyList::addGetterSetter(const ObjectURI
& uri
, as_c_function_ptr getter
,
235 as_c_function_ptr setter
, const PropFlags
& flagsIfMissing
)
237 Property
a(uri
, getter
, setter
, flagsIfMissing
);
239 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
240 if (found
!= _props
.end())
242 // copy flags from previous member (even if it's a normal member ?)
243 a
.setFlags(found
->getFlags());
244 _props
.replace(found
, a
);
246 #ifdef GNASH_DEBUG_PROPERTY
247 ObjectURI::Logger
l(getStringTable(_owner
));
248 log_debug("Native GetterSetter %s replaced copying flags %s", l(uri
),
256 #ifdef GNASH_DEBUG_PROPERTY
257 string_table
& st
= getStringTable(_owner
);
258 log_debug("Native GetterSetter %s in namespace %s inserted with "
259 "flags %s", st
.value(key
), st
.value(nsId
), a
.getFlags());
267 PropertyList::addDestructiveGetter(const ObjectURI
& uri
, as_function
& getter
,
268 const PropFlags
& flagsIfMissing
)
270 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
271 if (found
!= _props
.end())
273 ObjectURI::Logger
l(getStringTable(_owner
));
274 log_error(_("Property %s already exists, can't addDestructiveGetter"),
276 return false; // Already exists.
279 // destructive getter doesn't need a setter
280 Property
a(uri
, &getter
, 0, flagsIfMissing
, true);
284 #ifdef GNASH_DEBUG_PROPERTY
285 ObjectURI::Logger
l(getStringTable(_owner
));
286 log_debug("Destructive AS property %s inserted with flags %s",
287 l(uri
), a
.getFlags());
294 PropertyList::addDestructiveGetter(const ObjectURI
& uri
,
295 as_c_function_ptr getter
, const PropFlags
& flagsIfMissing
)
297 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
298 if (found
!= _props
.end()) return false;
300 // destructive getter doesn't need a setter
301 Property
a(uri
, getter
, 0, flagsIfMissing
, true);
304 #ifdef GNASH_DEBUG_PROPERTY
305 ObjectURI::Logger
l(getStringTable(_owner
));
306 log_debug("Destructive native property %s with flags %s", l(uri
),
313 PropertyList::clear()