2
// Copyright (C) 2007, 2008 Free Software Foundation, Inc.
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
#include "as_object.h"
20
#include "as_prop_flags.h"
22
#include "as_function.h" // for function_class_init
23
#include "button_character_instance.h"
25
#include "AsBroadcaster.h"
26
#include "Accessibility_as.h"
30
#include "ContextMenu.h"
31
#include "CustomActions.h"
35
#include "String_as.h"
37
#include "LoadVars_as.h"
38
#include "LocalConnection.h"
39
#include "Microphone.h"
44
#include "MovieClipLoader.h"
45
#include "movie_definition.h"
46
#include "NetConnection.h"
47
#include "NetStream.h"
48
#include "Selection.h"
49
#include "SharedObject.h"
52
#include "System_as.h"
53
#include "TextSnapshot.h"
54
#include "TextFormat.h"
55
#include "video_stream_instance.h"
56
#include "extension.h"
59
#include "URL.h" // for URL::encode and URL::decode (escape/unescape)
60
#include "builtin_function.h"
61
#include "edit_text_character.h"
62
#include "namedStrings.h"
63
#include "ClassHierarchy.h"
64
#include "builtin_function.h"
65
#include "XMLSocket_as.h"
72
namespace { // anonymous namespace
74
class declare_extension_function : public as_function
77
ClassHierarchy::extensionClass mDeclaration;
79
Extension *mExtension;
82
bool isBuiltin() { return true; }
84
declare_extension_function(ClassHierarchy::extensionClass &c,
85
as_object *g, Extension* e) :
86
as_function(getObjectInterface()),
87
mDeclaration(c), mTarget(g), mExtension(e)
89
init_member("constructor", as_function::getFunctionConstructor().get());
92
virtual as_value operator()(const fn_call& /*fn*/)
94
string_table& st = VM::get().getStringTable();
95
log_debug("Loading extension class %s", st.value(mDeclaration.name));
98
if (mDeclaration.super_name)
100
// Check to be sure our super exists.
101
// This will trigger its instantiation if necessary.
102
if (!mTarget->get_member(mDeclaration.super_name, &super))
104
// Error here -- doesn't exist.
105
log_error("Can't find %s (Superclass of %s)",
106
st.value(mDeclaration.super_name),
107
st.value(mDeclaration.name));
108
super.set_undefined();
111
if (!super.is_as_function())
113
// Error here -- not an object.
114
log_error("%s (Superclass of %s) is not a function (%s)",
115
st.value(mDeclaration.super_name),
116
st.value(mDeclaration.name), super);
117
super.set_undefined();
121
if (mExtension->initModuleWithFunc(mDeclaration.file_name,
122
mDeclaration.init_name, *mTarget))
124
// Successfully loaded it, now find it, set its proto, and return.
126
mTarget->get_member(mDeclaration.name, &us);
127
if (mDeclaration.super_name && !us.to_object()->hasOwnProperty(NSV::PROP_uuPROTOuu))
129
us.to_object()->set_prototype(super.to_as_function()->getPrototype());
133
// Error here -- not successful in loading.
134
log_error("Could not load class %s", st.value(mDeclaration.name));
135
super.set_undefined();
140
class declare_native_function : public as_function
143
ClassHierarchy::nativeClass mDeclaration;
145
Extension *mExtension;
148
bool isBuiltin() { return true; }
150
declare_native_function(const ClassHierarchy::nativeClass &c,
151
as_object *g, Extension *e) :
152
as_function(getObjectInterface()),
153
mDeclaration(c), mTarget(g), mExtension(e)
155
// does it make any sense to set a 'constructor' here ??
156
//init_member("constructor", this);
157
//init_member("constructor", as_function::getFunctionConstructor().get());
160
virtual as_value operator()(const fn_call& /*fn*/)
162
string_table& st = VM::get().getStringTable();
163
log_debug("Loading native class %s", st.value(mDeclaration.name));
165
mDeclaration.initializer(*mTarget);
166
// Successfully loaded it, now find it, set its proto, and return.
168
if ( mTarget->get_member(mDeclaration.name, &us) )
171
if (mDeclaration.super_name)
173
// Check to be sure our super exists.
174
// This will trigger its instantiation if necessary.
175
if (!mTarget->get_member(mDeclaration.super_name, &super))
177
// Error here -- doesn't exist.
178
log_error("Can't find %s (Superclass of %s)",
179
st.value(mDeclaration.super_name),
180
st.value(mDeclaration.name));
181
super.set_undefined();
184
if (!super.is_as_function())
186
// Error here -- not an object.
187
log_error("%s (Superclass of %s) is not a function (%s)",
188
st.value(mDeclaration.super_name),
189
st.value(mDeclaration.name), super);
190
super.set_undefined();
193
assert(super.to_as_function());
195
if ( ! us.to_object() )
197
log_error("Native class %s is not an object after initialization (%s)",
198
st.value(mDeclaration.name), us);
200
if (mDeclaration.super_name && !us.to_object()->hasOwnProperty(NSV::PROP_uuPROTOuu))
202
us.to_object()->set_prototype(super.to_as_function()->getPrototype());
207
log_error("Native class %s is not found after initialization",
208
st.value(mDeclaration.name));
214
} // end anonymous namespace
216
ClassHierarchy::~ClassHierarchy()
221
ClassHierarchy::declareClass(extensionClass& c)
223
if (mExtension == NULL)
224
return false; // Extensions can't be loaded.
226
mGlobalNamespace->stubPrototype(c.name);
227
mGlobalNamespace->getClass(c.name)->setDeclared();
228
mGlobalNamespace->getClass(c.name)->setSystem();
230
boost::intrusive_ptr<as_function> getter =
231
new declare_extension_function(c, mGlobal, mExtension);
233
return mGlobal->init_destructive_property(c.name, *getter);
237
ClassHierarchy::declareClass(const nativeClass& c)
239
// For AS2 and below, registering with mGlobal _should_ make it equivalent
240
// to being in the global namespace, since everything is global there.
241
asNamespace *nso = findNamespace(c.namespace_name);
243
nso = addNamespace(c.namespace_name);
244
nso->stubPrototype(c.name);
245
nso->getClass(c.name)->setDeclared();
246
nso->getClass(c.name)->setSystem();
248
boost::intrusive_ptr<as_function> getter =
249
new declare_native_function(c, mGlobal, mExtension);
251
return mGlobal->init_destructive_property(c.name,
255
static const ClassHierarchy::nativeClass knownClasses[] =
257
// This makes clear the difference between "We don't know where the
258
// class belongs" and "it belongs in the global namespace", even though
259
// the result is the same.
263
// { function_name, name key, super name key, lowest version },
264
{ system_class_init, NSV::CLASS_SYSTEM, 0, NSV::NS_FLASH_SYSTEM, 1 },
265
{ stage_class_init, NSV::CLASS_STAGE, 0, NSV::NS_FLASH_DISPLAY, 1 },
266
{ movieclip_class_init, NSV::CLASS_MOVIE_CLIP, 0, NSV::NS_FLASH_DISPLAY, 3 },
267
{ textfield_class_init, NSV::CLASS_TEXT_FIELD, 0, NSV::NS_FLASH_TEXT, 3 },
268
{ math_class_init, NSV::CLASS_MATH, 0, NS_GLOBAL, 4 },
269
{ boolean_class_init, NSV::CLASS_BOOLEAN, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
270
{ button_class_init, NSV::CLASS_BUTTON, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
271
{ color_class_init, NSV::CLASS_COLOR, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
272
{ selection_class_init, NSV::CLASS_SELECTION, NSV::CLASS_OBJECT, NS_UNKNOWN, 5 },
273
{ sound_class_init, NSV::CLASS_SOUND, NSV::CLASS_OBJECT, NSV::NS_FLASH_MEDIA, 5 },
274
{ xmlsocket_class_init, NSV::CLASS_X_M_L_SOCKET, NSV::CLASS_OBJECT, NSV::NS_FLASH_NET, 5 },
275
{ date_class_init, NSV::CLASS_DATE, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
276
{ xml_class_init, NSV::CLASS_X_M_L, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
277
{ xmlnode_class_init, NSV::CLASS_X_M_L_NODE, NSV::CLASS_OBJECT, NSV::NS_FLASH_XML, 5 },
278
{ mouse_class_init, NSV::CLASS_MOUSE, NSV::CLASS_OBJECT, NSV::NS_FLASH_UI, 5 },
279
{ number_class_init, NSV::CLASS_NUMBER, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
280
{ textformat_class_init, NSV::CLASS_TEXT_FORMAT, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
281
{ key_class_init, NSV::CLASS_KEY, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
282
{ AsBroadcaster_init, NSV::CLASS_AS_BROADCASTER, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
283
{ textsnapshot_class_init, NSV::CLASS_TEXT_SNAPSHOT, NSV::CLASS_OBJECT, NSV::NS_FLASH_TEXT, 6 },
284
{ video_class_init, NSV::CLASS_VIDEO, NSV::CLASS_OBJECT, NSV::NS_FLASH_MEDIA, 6 },
285
{ camera_class_init, NSV::CLASS_CAMERA, NSV::CLASS_OBJECT, NSV::NS_FLASH_UI, 6 },
286
{ microphone_class_init, NSV::CLASS_MICROPHONE, NSV::CLASS_OBJECT, NSV::NS_FLASH_UI, 6 },
287
{ sharedobject_class_init, NSV::CLASS_SHARED_OBJECT, NSV::CLASS_OBJECT, NSV::NS_FLASH_NET, 6 },
288
{ loadvars_class_init, NSV::CLASS_LOAD_VARS, NSV::CLASS_OBJECT, NS_GLOBAL, 6 },
289
{ customactions_class_init, NSV::CLASS_CUSTOM_ACTIONS, NSV::CLASS_OBJECT, NSV::NS_ADOBE_UTILS, 6 },
290
{ netconnection_class_init, NSV::CLASS_NET_CONNECTION, NSV::CLASS_OBJECT, NSV::NS_FLASH_NET, 6 },
291
{ netstream_class_init, NSV::CLASS_NET_STREAM, NSV::CLASS_OBJECT, NSV::NS_FLASH_NET, 6 },
292
{ contextmenu_class_init, NSV::CLASS_CONTEXT_MENU, NSV::CLASS_OBJECT, NSV::NS_FLASH_UI, 7 },
293
{ moviecliploader_class_init, NSV::CLASS_MOVIE_CLIP_LOADER, NSV::CLASS_OBJECT, NS_GLOBAL, 7 },
294
{ Error_class_init, NSV::CLASS_ERROR, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
295
{ Accessibility_class_init, NSV::CLASS_ACCESSIBILITY, NSV::CLASS_OBJECT, NS_GLOBAL, 5 }
296
// These classes are all implicitly constructed; that is, it is not necessary for
297
// the class name to be used to construct the class, so they must always be available.
298
// { object_class_init, NSV::CLASS_OBJECT, 0, NS_GLOBAL, 5 }
299
// { function_class_init, NSV::CLASS_FUNCTION, NSV::CLASS_OBJECT, NS_GLOBAL, 6 }
300
// { array_class_init, NSV::CLASS_ARRAY, NSV::CLASS_OBJECT, NS_GLOBAL, 5 }
301
// { string_class_init, NSV::CLASS_STRING, NSV::CLASS_OBJECT, NS_GLOBAL, 5 }
306
ClassHierarchy::massDeclare(int version)
308
// Natives get declared first. It doesn't make any sense for a native
309
// to depend on an extension, but it does make sense the other way
311
const size_t size = sizeof (knownClasses) / sizeof (nativeClass);
312
for (size_t i = 0; i < size; ++i)
314
const nativeClass& c = knownClasses[i];
315
if (c.version > version) continue;
317
if ( ! declareClass(c) )
319
log_error("Could not declare class %s", c);
323
if (mExtension != NULL)
325
/* Load extensions here */
330
ClassHierarchy::markReachableResources() const
335
std::ostream& operator << (std::ostream& os, const ClassHierarchy::nativeClass& c)
337
string_table& st = VM::get().getStringTable();
340
<< " name:" << st.value(c.name)
341
<< " super:" << st.value(c.super_name)
342
<< " namespace:" << st.value(c.namespace_name)
343
<< " version:" << c.version
349
std::ostream& operator << (std::ostream& os, const ClassHierarchy::extensionClass& c)
351
string_table& st = VM::get().getStringTable();
353
os << "(file:" << c.file_name
354
<< " init:" << c.init_name
355
<< " name:" << st.value(c.name)
356
<< " super:" << st.value(c.super_name)
357
<< " namespace:" << st.value(c.namespace_name)
358
<< " version:" << c.version
364
} /* namespace gnash */