1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 //   Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 #ifndef GNASH_PROPERTYLIST_H
20 #define GNASH_PROPERTYLIST_H
21 
22 #include <set>
23 #include <string> // for use within map
24 #include <cassert> // for inlines
25 #include <utility> // for std::pair
26 #include <cstdint>
27 #include <boost/multi_index_container.hpp>
28 #include <boost/multi_index/ordered_index.hpp>
29 #include <boost/multi_index/sequenced_index.hpp>
30 #include <boost/multi_index/key_extractors.hpp>
31 #include <boost/noncopyable.hpp>
32 #include <functional>
33 #include <algorithm>
34 
35 #include "Property.h" // for templated functions
36 #include "dsodefs.h" // for DSOTEXPORT
37 
38 // Forward declaration
39 namespace gnash {
40     class as_object;
41     class as_function;
42     struct ObjectURI;
43     class as_value;
44 }
45 
46 namespace gnash {
47 
48 /// An abstract property visitor
49 class PropertyVisitor {
50 public:
51 
52     /// This function should return false if no further visits are needed.
53     virtual bool accept(const ObjectURI& uri, const as_value& val) = 0;
~PropertyVisitor()54     virtual ~PropertyVisitor() {}
55 };
56 
57 /// An abstract key visitor
58 class KeyVisitor {
59 public:
60 
61     /// This function should return false if no further visits are needed.
62     virtual void operator()(const ObjectURI& uri) = 0;
~KeyVisitor()63     virtual ~KeyVisitor() {}
64 };
65 
66 
67 /// Set of properties associated with an ActionScript object.
68 //
69 /// The PropertyList container is the sole owner of the Property
70 /// elements in it contained and has full responsibility of their
71 /// construction and destruction.
72 //
73 /// A PropertyList holds a reference to the as_object whose properties it
74 /// contains. This reference will always be valid if the PropertyList
75 /// is a member of as_object.
76 //
77 /// It is theoretically possible for a PropertyList to be used with any
78 /// as_object, not just original as_object it was use with. Currently (as
79 /// there is no use for this scenario) it is not possible to change the
80 /// owner.
81 class PropertyList : boost::noncopyable
82 {
83 public:
84 
85     typedef std::set<ObjectURI, ObjectURI::LessThan> PropertyTracker;
86     typedef Property value_type;
87 
88     /// Identifier for the sequenced index
89     struct CreationOrder {};
90 
91     /// The sequenced index in creation order.
92     typedef boost::multi_index::sequenced<
93         boost::multi_index::tag<CreationOrder> > SequencedIndex;
94 
95     struct KeyExtractor
96     {
97         typedef const ObjectURI& result_type;
operatorKeyExtractor98         result_type operator()(const Property& p) const {
99             return p.uri();
100         }
101     };
102 
103     /// Identifier for the case-sensitive index
104     struct Case {};
105 
106     /// The case-sensitive index
107     typedef boost::multi_index::ordered_unique<
108         boost::multi_index::tag<Case>,
109         KeyExtractor,
110         ObjectURI::LessThan> CaseIndex;
111 
112     /// Identifier for the case-insensitive index
113     struct NoCase {};
114 
115     /// The case-insensitive index
116     typedef boost::multi_index::ordered_non_unique<
117         boost::multi_index::tag<NoCase>,
118         KeyExtractor,
119         ObjectURI::CaseLessThan> NoCaseIndex;
120 
121     /// The container of the Properties.
122     typedef boost::multi_index_container<
123         value_type,
124         boost::multi_index::indexed_by<SequencedIndex, CaseIndex, NoCaseIndex>
125         > container;
126 
127     typedef container::iterator iterator;
128     typedef container::const_iterator const_iterator;
129 
130     /// Construct the PropertyList
131     //
132     /// @param obj      The as_object to which this PropertyList belongs.
133     DSOTEXPORT PropertyList(as_object& obj);
134 
135     /// Visit properties
136     //
137     /// The method will invoke the given visitor method
138     /// passing it two arguments: name of the property and
139     /// value of it.
140     //
141     /// @tparam V       The type of the visitor.
142     /// @tparam U       An object that may check property values. The object's
143     ///                 operator() should return false if the property is not
144     ///                 acceptable.
145     //
146     /// @param visitor  The visitor function. It must implement the function:
147     ///                     bool accept(const ObjectURI&, const as_value&);
148     ///                 Scan is by enumeration order and stops when accept()
149     ///                 returns false.
150     template <class U, class V>
151     void visitValues(V& visitor, U cmp = U()) const {
152 
153         for (const auto& prop : _props) {
154 
155             if (!cmp(prop)) continue;
156             as_value val = prop.getValue(_owner);
157             if (!visitor.accept(prop.uri(), val)) return;
158         }
159     }
160 
161     /// Enumerate all non-hidden properties to the given container.
162     //
163     /// Follows enumeration order. Note that this enumeration does not
164     /// access the values. Accessing the values can result in changes to
165     /// the object if the value is a getter-setter, and key enumeration must
166     /// avoid this.
167     ///
168     /// @param donelist     Don't enumerate properties in donelist.
169     ///                     Enumerated properties are added to donelist.
170     void visitKeys(KeyVisitor& v, PropertyTracker& donelist) const;
171 
172     /// Set the value of a property, creating a new one if it doesn't exist.
173     //
174     /// If the named property is a getter/setter one it's setter
175     /// will be invoked using the given as_object as 'this' pointer.
176     /// If the property is not found a SimpleProperty will be created.
177     ///
178     /// @param uri
179     ///    Name of the property.
180     /// @param value
181     ///    a const reference to the as_value to use for setting
182     ///    or creating the property.
183     /// @param flagsIfMissing
184     ///    Flags to associate to the property if a new one is created.
185     /// @return true if the value was successfully set, false
186     ///         otherwise (found a read-only property, most likely).
187     DSOTEXPORT bool setValue(const ObjectURI& uri, const as_value& value,
188             const PropFlags& flagsIfMissing = 0);
189 
190     /// Get a property if it exists.
191     //
192     /// @param uri  Name of the property.
193     /// @return     A Property or 0, if no such property exists.
194     ///             All Property objects are owned by this PropertyList. Do
195     ///             not delete them.
196     DSOTEXPORT Property* getProperty(const ObjectURI& uri) const;
197 
198     /// Delete a Property, if existing and not protected from deletion.
199     //
200     ///
201     /// @param uri      Name of the property.
202     /// @return         a pair of boolean values expressing whether the property
203     ///                 was found (first) and whether it was deleted (second).
204     ///                 Of course a pair(false, true) would be invalid (deleted
205     ///                 a non-found property!?). Valid returns are:
206     ///                     - (false, false) : property not found
207     ///                     - (true, false) : property protected from deletion
208     ///                     - (true, true) : property successfully deleted
209     DSOTEXPORT std::pair<bool,bool> delProperty(const ObjectURI& uri);
210 
211     /// Add a getter/setter property, if not already existing
212     //
213     /// TODO: this function has far too many arguments.
214     //
215     /// @param uri      Name of the property.
216     /// @param getter   A function to invoke when this property value is
217     ///                 requested.
218     /// @param setter   A function to invoke when setting this property's value.
219     /// @param cacheVal The value to use as a cache. If null uses any cache
220     ///                 from pre-existing property with same name.
221     /// @param flagsIfMissing Flags to associate to the property if a new one
222     ///                       is created.
223     /// @return         true if the property was successfully added, false
224     ///                 otherwise.
225     bool addGetterSetter(const ObjectURI& uri, as_function& getter,
226         as_function* setter, const as_value& cacheVal,
227         const PropFlags& flagsIfMissing = 0);
228 
229     /// Add a getter/setter property, if not already existing
230     //
231     /// @param uri      Name of the property.
232     /// @param getter   A function to invoke when this property value is
233     ///                 requested.
234     /// @param setter   A function to invoke when setting this property's value.
235     /// @return         true if the property was successfully added, false
236     ///                 otherwise.
237     bool addGetterSetter(const ObjectURI& uri, as_c_function_ptr getter,
238         as_c_function_ptr setter, const PropFlags& flagsIfMissing);
239 
240     /// Add a destructive getter property, if not already existant.
241     //
242     /// @param uri      Name of the property.
243     /// @param getter   A function to invoke when this property value is
244     ///                 requested.
245     /// @param flagsIfMissing Flags to associate to the property if a new
246     ///                             one is created.
247     /// @return         true if the property was successfully added.
248     bool addDestructiveGetter(const ObjectURI& uri, as_function& getter,
249         const PropFlags& flagsIfMissing = 0);
250 
251     /// Add a destructive getter property, if not already existant.
252     ///
253     /// @param uri      Name of the property.
254     /// @param getter   A function to invoke when this property value is
255     ///                 requested.
256     ///
257     /// @param flagsIfMissing   Flags to associate to the property if a new
258     //                          one is created.
259     /// @return         true if the property was successfully added, false
260     ///                 otherwise.
261     bool addDestructiveGetter(const ObjectURI& uri, as_c_function_ptr getter,
262         const PropFlags& flagsIfMissing = 0);
263 
264     /// Set the flags of a property.
265     //
266     /// @param uri      Name of the property.
267     /// @param setTrue  The set of flags to set
268     /// @param setFalse The set of flags to clear
269     DSOTEXPORT void setFlags(const ObjectURI& uri, int setTrue, int setFalse);
270 
271     /// Set the flags of all properties.
272     //
273     /// @param setTrue      The set of flags to set
274     /// @param setFalse     The set of flags to clear
275     void setFlagsAll(int setTrue, int setFalse);
276 
277     /// Remove all entries in the container
278     void clear();
279 
280     /// Return number of properties in this list
size()281     size_t size() const {
282         return _props.size();
283     }
284 
285     /// Dump all members (using log_debug)
286     //
287     /// This does not reflect the normal enumeration order. It is sorted
288     /// lexicographically by property.
289     void dump();
290 
291     /// Mark all properties reachable
292     //
293     /// This can be called very frequently, so is inlined to allow the
294     /// compiler to optimize it.
setReachable()295     void setReachable() const {
296         std::for_each(_props.begin(), _props.end(),
297                 std::mem_fn(&Property::setReachable));
298     }
299 
300 private:
301 
302     container _props;
303 
304     as_object& _owner;
305 
306 };
307 
308 
309 } // namespace gnash
310 
311 #endif // GNASH_PROPERTYLIST_H
312