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
21 #include "PropertyList.h"
23 #include "as_environment.h"
25 #include "as_function.h"
26 #include "as_value.h" // for enumerateValues
27 #include "VM.h" // For string_table
28 #include "string_table.h"
29 #include "GnashAlgorithm.h"
31 #include "gnashconfig.h" // GNASH_STATS_PROPERTY_LOOKUPS
34 #include <utility> // for std::make_pair
35 #include <boost/bind.hpp>
37 // Define the following to enable printing address of each property added
38 //#define DEBUG_PROPERTY_ALLOC
40 // Define this to get verbosity of properties insertion and flags setting
41 //#define GNASH_DEBUG_PROPERTY 1
43 // Define this to get stats of property lookups
44 //#define GNASH_STATS_PROPERTY_LOOKUPS 1
47 #ifdef GNASH_STATS_PROPERTY_LOOKUPS
49 # include "namedStrings.h"
57 PropertyList::const_iterator
58 iterator_find(const PropertyList::container
& p
, const ObjectURI
& uri
, VM
& vm
)
60 const bool caseless
= vm
.getSWFVersion() < 7;
63 return p
.project
<0>(p
.get
<1>().find(uri
));
67 ObjectURI
uri3 ( uri
);
69 string_table
& st
= vm
.getStringTable();
70 const string_table::key nocase
= uri
.noCase(st
);
71 return p
.project
<0>(p
.get
<2>().find(nocase
));
77 PropertyList::setValue(const ObjectURI
& uri
, const as_value
& val
,
78 const PropFlags
& flagsIfMissing
)
80 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
82 string_table
& st
= getStringTable(_owner
);
84 if (found
== _props
.end())
86 // create a new member
87 Property
a(uri
, val
, flagsIfMissing
);
88 // Non slot properties are negative ordering in insertion order
89 _props
.push_back(std::make_pair(a
, uri
.noCase(st
)));
90 #ifdef GNASH_DEBUG_PROPERTY
91 ObjectURI::Logger
l(getStringTable(_owner
));
92 log_debug("Simple AS property %s inserted with flags %s",
93 l(uri
), a
.getFlags());
98 const Property
& prop
= found
->first
;
99 if (readOnly(prop
) && ! prop
.isDestructive())
101 ObjectURI::Logger
l(getStringTable(_owner
));
102 log_error(_("Property %s is read-only %s, not setting it to %s"),
103 l(uri
), prop
.getFlags(), val
);
107 prop
.setValue(_owner
, val
);
113 PropertyList::setFlags(const ObjectURI
& uri
, int setFlags
, int clearFlags
)
115 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
116 if (found
== _props
.end()) return;
117 PropFlags f
= found
->first
.getFlags();
118 f
.set_flags(setFlags
, clearFlags
);
119 found
->first
.setFlags(f
);
124 PropertyList::setFlagsAll(int setFlags
, int clearFlags
)
126 for (const_iterator it
= _props
.begin(); it
!= _props
.end(); ++it
) {
127 PropFlags f
= it
->first
.getFlags();
128 f
.set_flags(setFlags
, clearFlags
);
129 it
->first
.setFlags(f
);
134 PropertyList::getProperty(const ObjectURI
& uri
) const
136 #ifdef GNASH_STATS_PROPERTY_LOOKUPS
137 // HINT: can add a final arg to KeyLookup ctor, like NSV::PROP_ON_MOUSE_MOVE
138 // to have *that* property lookup drive dump triggers
139 static stats::KeyLookup
kcl("getProperty",
140 getStringTable(_owner
), 10000000, NSV::PROP_uuPROTOuu
, 10);
142 #endif // GNASH_STATS_PROPERTY_LOOKUPS
143 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
144 if (found
== _props
.end()) return 0;
145 return const_cast<Property
*>(&(found
->first
));
149 PropertyList::delProperty(const ObjectURI
& uri
)
151 //GNASH_REPORT_FUNCTION;
152 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
153 if (found
== _props
.end()) {
154 return std::make_pair(false, false);
157 // check if member is protected from deletion
158 if (found
->first
.getFlags().get_dont_delete()) {
159 return std::make_pair(true, false);
163 return std::make_pair(true, true);
167 PropertyList::dump(std::map
<std::string
, as_value
>& to
)
169 ObjectURI::Logger
l(getStringTable(_owner
));
171 for (const_iterator i
=_props
.begin(), ie
=_props
.end();
174 to
.insert(std::make_pair(l(i
->first
.uri()), i
->first
.getValue(_owner
)));
179 PropertyList::enumerateKeys(as_environment
& env
, PropertyTracker
& donelist
)
182 string_table
& st
= getStringTable(_owner
);
184 // We should enumerate in order of creation, not lexicographically.
185 for (const_iterator i
= _props
.begin(),
186 ie
= _props
.end(); i
!= ie
; ++i
) {
188 if (i
->first
.getFlags().get_dont_enum()) continue;
190 const ObjectURI
& uri
= i
->first
.uri();
192 if (donelist
.insert(uri
).second
) {
193 const std::string
& qname
= st
.value(getName(uri
));
202 ObjectURI::Logger
l(getStringTable(_owner
));
203 for (const_iterator it
=_props
.begin(), itEnd
=_props
.end();
205 log_debug(" %s: %s", l(it
->first
.uri()), it
->first
.getValue(_owner
));
210 PropertyList::addGetterSetter(const ObjectURI
& uri
, as_function
& getter
,
211 as_function
* setter
, const as_value
& cacheVal
,
212 const PropFlags
& flagsIfMissing
)
214 Property
a(uri
, &getter
, setter
, flagsIfMissing
);
215 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
217 string_table
& st
= getStringTable(_owner
);
218 if (found
!= _props
.end())
220 // copy flags from previous member (even if it's a normal member ?)
221 a
.setFlags(found
->first
.getFlags());
222 a
.setCache(found
->first
.getCache());
223 _props
.replace(found
, std::make_pair(a
, uri
.noCase(st
)));
225 #ifdef GNASH_DEBUG_PROPERTY
226 ObjectURI::Logger
l(getStringTable(_owner
));
227 log_debug("AS GetterSetter %s replaced copying flags %s", l(uri
),
234 a
.setCache(cacheVal
);
235 _props
.push_back(std::make_pair(a
, uri
.noCase(st
)));
236 #ifdef GNASH_DEBUG_PROPERTY
237 ObjectURI::Logger
l(getStringTable(_owner
));
238 log_debug("AS GetterSetter %s inserted with flags %s", l(uri
),
247 PropertyList::addGetterSetter(const ObjectURI
& uri
, as_c_function_ptr getter
,
248 as_c_function_ptr setter
, const PropFlags
& flagsIfMissing
)
250 Property
a(uri
, getter
, setter
, flagsIfMissing
);
252 string_table
& st
= getStringTable(_owner
);
253 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
254 if (found
!= _props
.end())
256 // copy flags from previous member (even if it's a normal member ?)
257 a
.setFlags(found
->first
.getFlags());
258 _props
.replace(found
, std::make_pair(a
, uri
.noCase(st
)));
260 #ifdef GNASH_DEBUG_PROPERTY
261 ObjectURI::Logger
l(getStringTable(_owner
));
262 log_debug("Native GetterSetter %s replaced copying flags %s", l(uri
),
269 _props
.push_back(std::make_pair(a
, uri
.noCase(st
)));
270 #ifdef GNASH_DEBUG_PROPERTY
271 string_table
& st
= getStringTable(_owner
);
272 log_debug("Native GetterSetter %s in namespace %s inserted with "
273 "flags %s", st
.value(key
), st
.value(nsId
), a
.getFlags());
281 PropertyList::addDestructiveGetter(const ObjectURI
& uri
, as_function
& getter
,
282 const PropFlags
& flagsIfMissing
)
284 const_iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
285 if (found
!= _props
.end())
287 ObjectURI::Logger
l(getStringTable(_owner
));
288 log_error("Property %s already exists, can't addDestructiveGetter",
290 return false; // Already exists.
293 // destructive getter don't need a setter
294 Property
a(uri
, &getter
, (as_function
*)0, flagsIfMissing
, true);
296 string_table
& st
= getStringTable(_owner
);
297 _props
.push_back(std::make_pair(a
, uri
.noCase(st
)));
299 #ifdef GNASH_DEBUG_PROPERTY
300 ObjectURI::Logger
l(getStringTable(_owner
));
301 log_debug("Destructive AS property %s inserted with flags %s",
302 l(uri
), a
.getFlags());
309 PropertyList::addDestructiveGetter(const ObjectURI
& uri
,
310 as_c_function_ptr getter
, const PropFlags
& flagsIfMissing
)
312 iterator found
= iterator_find(_props
, uri
, getVM(_owner
));
313 if (found
!= _props
.end()) return false;
315 // destructive getter don't need a setter
316 Property
a(uri
, getter
, (as_c_function_ptr
)0, flagsIfMissing
, true);
317 string_table
& st
= getStringTable(_owner
);
318 _props
.push_back(std::make_pair(a
, uri
.noCase(st
)));
320 #ifdef GNASH_DEBUG_PROPERTY
321 ObjectURI::Logger
l(getStringTable(_owner
));
322 log_debug("Destructive native property %s with flags %s", l(uri
),
329 PropertyList::clear()
335 PropertyList::setReachable() const
337 foreachFirst(_props
.begin(), _props
.end(),
338 boost::mem_fn(&Property::setReachable
));