big merge from master, fix rpm creation, drop fetching swfdec
[gnash.git] / libcore / PropertyList.cpp
blobc39840c6a272c98848f1c8a0709981555c4b3807
1 // PropertyList.cpp: ActionScript property lists, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
5 //
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.
10 //
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 #ifdef HAVE_CONFIG_H
22 #include "gnashconfig.h" // GNASH_STATS_PROPERTY_LOOKUPS
23 #endif
25 #include "PropertyList.h"
27 #include <utility>
28 #include <boost/bind.hpp>
29 #include <boost/tuple/tuple.hpp>
31 #include "Property.h"
32 #include "as_environment.h"
33 #include "log.h"
34 #include "as_function.h"
35 #include "as_value.h"
36 #include "VM.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
50 # include "Stats.h"
51 # include "namedStrings.h"
52 #endif
54 namespace gnash {
56 namespace {
58 inline
59 PropertyList::const_iterator
60 iterator_find(const PropertyList::container& p, const ObjectURI& uri, VM& vm)
62 const bool caseless = vm.getSWFVersion() < 7;
64 if (!caseless) {
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(
78 boost::tuple<>(),
79 boost::make_tuple(
80 KeyExtractor(),
81 ObjectURI::LessThan()
83 boost::make_tuple(
84 KeyExtractor(),
85 ObjectURI::CaseLessThan(getStringTable(obj), true)
89 _owner(obj)
93 bool
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
103 _props.push_back(a);
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());
108 #endif
109 return true;
112 const Property& prop = *found;
113 return prop.setValue(_owner, val);
117 void
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);
124 found->setFlags(f);
128 void
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);
134 it->setFlags(f);
138 Property*
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);
146 kcl.check(uri.name);
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));
153 std::pair<bool,bool>
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);
167 _props.erase(found);
168 return std::make_pair(true, true);
171 void
172 PropertyList::visitKeys(KeyVisitor& visitor, PropertyTracker& donelist)
173 const
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) {
184 visitor(uri);
189 void
190 PropertyList::dump()
192 ObjectURI::Logger l(getStringTable(_owner));
193 for (const_iterator it=_props.begin(), itEnd=_props.end();
194 it != itEnd; ++it) {
195 log_debug(" %s: %s", l(it->uri()), it->getValue(_owner));
199 bool
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),
216 a.getFlags());
217 #endif
220 else {
221 a.setCache(cacheVal);
222 _props.push_back(a);
223 #ifdef GNASH_DEBUG_PROPERTY
224 ObjectURI::Logger l(getStringTable(_owner));
225 log_debug("AS GetterSetter %s inserted with flags %s", l(uri),
226 a.getFlags());
227 #endif
230 return true;
233 bool
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),
249 a.getFlags());
250 #endif
253 else
255 _props.push_back(a);
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());
260 #endif
263 return true;
266 bool
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",
275 l(uri));
276 return false; // Already exists.
279 // destructive getter doesn't need a setter
280 Property a(uri, &getter, 0, flagsIfMissing, true);
282 _props.push_back(a);
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());
288 #endif
290 return true;
293 bool
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);
302 _props.push_back(a);
304 #ifdef GNASH_DEBUG_PROPERTY
305 ObjectURI::Logger l(getStringTable(_owner));
306 log_debug("Destructive native property %s with flags %s", l(uri),
307 a.getFlags());
308 #endif
309 return true;
312 void
313 PropertyList::clear()
315 _props.clear();
318 } // namespace gnash