[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] /srv/bzr/gnash/trunk r10401: Various fixes to SharedObjec
From: |
Benjamin Wolsey |
Subject: |
[Gnash-commit] /srv/bzr/gnash/trunk r10401: Various fixes to SharedObject AS compatibility. |
Date: |
Tue, 09 Dec 2008 17:15:01 +0100 |
User-agent: |
Bazaar (1.5) |
------------------------------------------------------------
revno: 10401
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Tue 2008-12-09 17:15:01 +0100
message:
Various fixes to SharedObject AS compatibility.
modified:
libamf/sol.cpp
libamf/sol.h
libcore/as_value.cpp
libcore/asobj/ClassHierarchy.cpp
libcore/asobj/ClassHierarchy.h
libcore/asobj/Global.cpp
libcore/asobj/SharedObject.cpp
libcore/asobj/SharedObject.h
libcore/namedStrings.cpp
libcore/namedStrings.h
testsuite/actionscript.all/ASnative.as
testsuite/actionscript.all/SharedObject.as
------------------------------------------------------------
revno: 10400.1.1
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 14:32:22 +0100
message:
Stub unimplemented undocumented methods of SharedObject. Tidy up. Correct
prop flags. Don't initialize data member until a SharedObject instance
exists, and even then not if the SOL file existed but was invalid.
modified:
libcore/asobj/ClassHierarchy.cpp
libcore/asobj/ClassHierarchy.h
libcore/asobj/Global.cpp
libcore/asobj/SharedObject.cpp
libcore/asobj/SharedObject.h
testsuite/actionscript.all/SharedObject.as
------------------------------------------------------------
revno: 10400.1.2
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 14:58:38 +0100
message:
Comments and tests on ASnative SharedObject.
modified:
libcore/asobj/SharedObject.cpp
testsuite/actionscript.all/ASnative.as
------------------------------------------------------------
revno: 10400.1.3
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 15:29:19 +0100
message:
Return undefined from SharedObject.flush() when there is no data member.
Alter SharedObject::flush() to take the data object as an argument to
facilitate this.
Add some tests.
Add PROP_DATA to namedStrings.
modified:
libcore/asobj/SharedObject.cpp
libcore/namedStrings.cpp
libcore/namedStrings.h
testsuite/actionscript.all/SharedObject.as
------------------------------------------------------------
revno: 10400.1.4
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 15:51:39 +0100
message:
Invalid SOL files act the same as non-existent ones. Only files with
a header and no data end up with no data member.
modified:
libcore/asobj/SharedObject.cpp
------------------------------------------------------------
revno: 10400.1.5
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 16:11:10 +0100
message:
Use a scoped_array for the buffer. Make the readSOL more readable.
modified:
libamf/sol.cpp
------------------------------------------------------------
revno: 10400.1.6
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 16:57:34 +0100
message:
Various cleanups.
modified:
libamf/sol.cpp
libamf/sol.h
libcore/as_value.cpp
libcore/asobj/SharedObject.cpp
------------------------------------------------------------
revno: 10400.1.7
committer: Benjamin Wolsey <address@hidden>
branch nick: work
timestamp: Tue 2008-12-09 16:58:56 +0100
message:
Comment.
modified:
libcore/asobj/SharedObject.cpp
=== modified file 'libamf/sol.cpp'
--- a/libamf/sol.cpp 2008-11-21 13:05:13 +0000
+++ b/libamf/sol.cpp 2008-12-09 15:57:34 +0000
@@ -282,7 +282,7 @@
_filesize = size;
boost::scoped_array<char> body ( new char[size + 20] );
- memset(body.get(), 0, size);
+ std::fill_n(body.get(), size, 0);
ptr = body.get();
char* endPtr = ptr+size+20; // that's the amount we allocated..
@@ -348,14 +348,15 @@
if ( ofs.write(head.get(), _header.size()).fail() )
{
- log_error("Error writing %d bytes of header to output file %s",
_header.size(), filespec.c_str());
+ log_error("Error writing %d bytes of header to output file %s",
+ _header.size(), filespec);
return false;
}
-// ofs.write(body, (ptr - body));
if ( ofs.write(body.get(), _filesize).fail() )
{
- log_error("Error writing %d bytes of body to output file %s",
_filesize, filespec.c_str());
+ log_error("Error writing %d bytes of body to output file %s",
+ _filesize, filespec);
return false;
}
ofs.close();
@@ -374,19 +375,23 @@
// GNASH_REPORT_FUNCTION;
struct stat st;
boost::uint16_t size;
- Network::byte_t *buf = 0;
- Network::byte_t *ptr = 0;
size_t bodysize;
// Make sure it's an SOL file
- if (stat(filespec.c_str(), &st) == 0) {
+ if (stat(filespec.c_str(), &st) != 0) return false;
try {
+
+ Network::byte_t *ptr = 0;
+
ifstream ifs(filespec.c_str(), ios::binary);
- _filesize = st.st_size;
- buf = new Network::byte_t[_filesize + sizeof(int)];
- ptr = buf;
- Network::byte_t* tooFar = buf+_filesize;
+
+ _filesize = st.st_size;
+ boost::scoped_array<Network::byte_t> buf(
+ new Network::byte_t[_filesize + sizeof(int)]);
+
+ ptr = buf.get();
+ Network::byte_t* tooFar = buf.get() + _filesize;
bodysize = st.st_size - 6;
_filespec = filespec;
@@ -409,22 +414,25 @@
// consistency check
if ((buf[0] == 0) && (buf[1] == 0xbf)) {
- if (bodysize == length) {
- log_debug("%s is an SOL file", filespec.c_str());
- } else {
- log_error("%s looks like an SOL file, but the length is
wrong. Should be %d, got %d",
- filespec.c_str(), (_filesize - 6), length);
- }
-
- } else {
- log_error("%s isn't an SOL file", filespec.c_str());
+ if (bodysize == length) {
+ log_debug("%s is an SOL file", filespec);
+ }
+ else {
+ log_error("%s looks like an SOL file, but the length is
wrong. "
+ "Should be %d, got %d",
+ filespec, (_filesize - 6), length);
+ }
+ }
+ else {
+ log_error("%s isn't an SOL file", filespec);
}
#ifndef GNASH_TRUST_AMF
ENSUREBYTES(ptr, tooFar, 2);
#endif
- // 2 bytes for the length of the object name, but it's also null
terminated
+ // 2 bytes for the length of the object name, but it's also
+ // null terminated
size = *(reinterpret_cast<boost::uint16_t *>(ptr));
size = ntohs(size);
ptr += 2;
@@ -444,31 +452,24 @@
AMF amf_obj;
boost::shared_ptr<amf::Element> el;
while ( ptr < tooFar) {
- if (ptr) {
- el = amf_obj.extractProperty(ptr, tooFar);
- if (el != 0) {
- ptr += amf_obj.totalsize() + 1;
- _amfobjs.push_back(el);
- } else {
- break;
- }
-// log_debug("Bodysize is: %d size is: %d for %s", bodysize, size,
el->getName());
- } else {
- break;
- }
+ if (ptr) {
+ el = amf_obj.extractProperty(ptr, tooFar);
+ if (el != 0) {
+ ptr += amf_obj.totalsize() + 1;
+ _amfobjs.push_back(el);
+ }
+ else break;
+ } else break;
}
- delete[] buf;
ifs.close();
return true;
- } catch (std::exception& e) {
+ }
+ catch (std::exception& e) {
log_error("Reading SharedObject %s: %s", filespec, e.what());
return false;
}
- }
-// log_error("Couldn't open file: %s", strerror(errno));
- return false;
}
/// \brief Dump the internal data of this class in a human readable form.
=== modified file 'libamf/sol.h'
--- a/libamf/sol.h 2008-10-26 23:35:38 +0000
+++ b/libamf/sol.h 2008-12-09 15:57:34 +0000
@@ -15,8 +15,8 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#ifndef _SOL_H_
-#define _SOL_H_
+#ifndef GNASH_SOL_H
+#define GNASH_SOL_H
#ifdef HAVE_CONFIG_H
#include "gnashconfig.h"
@@ -64,8 +64,10 @@
/// \brief Get the number of Elements in this class.
///
/// @return The count of Elements.
- size_t size() const { return _amfobjs.size(); };
-
+ size_t size() const { return _amfobjs.size(); }
+
+ size_t fileSize() const { return _filesize; }
+
/// \brief Extract the header from the file.
///
/// @param data a reference to a vector of bytes that contains the
=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp 2008-12-05 08:03:35 +0000
+++ b/libcore/as_value.cpp 2008-12-09 15:57:34 +0000
@@ -63,8 +63,6 @@
// Define this macto to make AMF writing verbose
//#define GNASH_DEBUG_AMF_SERIALIZE
-using namespace std;
-
namespace {
@@ -102,81 +100,87 @@
// This class is used to iterate through all the properties of an AS object,
// so we can change them to children of an AMF0 element.
-class PropsSerializer : public AbstractPropertyVisitor {
+class PropsSerializer : public AbstractPropertyVisitor
+{
+
+public:
+
+ PropsSerializer(amf::Element& el, VM& vm)
+ :
+ _obj(el),
+ _st(vm.getStringTable())
+ {}
+
+ void accept(string_table::key key, const as_value& val)
+ {
+
+ // Test conducted with AMFPHP:
+ // '__proto__' and 'constructor' members
+ // of an object don't get back from an 'echo-service'.
+ // Dunno if they are not serialized or just not sent back.
+ // A '__constructor__' member gets back, but only if
+ // not a function. Actually no function gets back.
+ //
+ if (key == NSV::PROP_uuPROTOuu || key == NSV::PROP_CONSTRUCTOR)
+ {
+#ifdef GNASH_DEBUG_AMF_SERIALIZE
+ log_debug(" skip serialization of specially-named property %s",
+ _st.value(key));
+#endif
+ return;
+ }
+
+ amf::AMF amf;
+ boost::shared_ptr<amf::Element> el;
+
+ const std::string& name = _st.value(key);
+
+ if (val.is_string()) {
+ std::string str;
+ if (!val.is_undefined()) {
+ str = val.to_string();
+ }
+ el.reset(new amf::Element(name, str));
+ }
+
+ else if (val.is_bool()) {
+ bool flag = val.to_bool();
+ el.reset(new amf::Element(name, flag));
+ }
+
+ else if (val.is_number()) {
+ double dub;
+ if (val.is_undefined()) {
+ dub = 0.0;
+ } else {
+ dub = val.to_number();
+ }
+ el.reset(new amf::Element(name, dub));
+ }
+
+ if (el) {
+ _obj.addProperty(el);
+ }
+ }
+
+private:
+
amf::Element& _obj;
string_table& _st;
-public:
- PropsSerializer(amf::Element& el, VM& vm)
- : _obj(el),
- _st(vm.getStringTable())
- {};
-
- void accept(string_table::key key, const as_value& val)
- {
-
- // Test conducted with AMFPHP:
- // '__proto__' and 'constructor' members
- // of an object don't get back from an 'echo-service'.
- // Dunno if they are not serialized or just not sent back.
- // A '__constructor__' member gets back, but only if
- // not a function. Actually no function gets back.
- //
- if ( key == NSV::PROP_uuPROTOuu ||
- key == NSV::PROP_CONSTRUCTOR )
- {
-#ifdef GNASH_DEBUG_AMF_SERIALIZE
- log_debug(" skip serialization of specially-named property
%s", _st.value(key));
-#endif
- return;
- }
-
- //GNASH_REPORT_FUNCTION;
- amf::AMF amf;
- boost::shared_ptr<amf::Element> el;
-
- const string& name = _st.value(key);
-
-
-// cerr << "FIXME: yes!!!!! " << name << ": "<< val << std::endl;
-
- if (val.is_string()) {
- string str;
- if (!val.is_undefined()) {
- str = val.to_string();
- }
- el.reset(new amf::Element(name, str));
- }
- if (val.is_bool()) {
- bool flag = val.to_bool();
- el.reset(new amf::Element(name, flag));
- }
- if (val.is_number()) {
- double dub;
- if (val.is_undefined()) {
- dub = 0.0;
- } else {
- dub = val.to_number();
- }
- el.reset(new amf::Element(name, dub));
- }
-
- if (el) {
- _obj.addProperty(el);
- }
- }
+
};
-} // anonimous namespace
+} // anonymous namespace
/// Class used to serialize properties of an object to a buffer
-class PropsBufSerializer : public AbstractPropertyVisitor {
- SimpleBuffer& _buf;
- VM& _vm;
- string_table& _st;
- std::map<as_object*, size_t>& _offsetTable;
- mutable bool _error;
+class PropsBufSerializer : public AbstractPropertyVisitor
+{
+
+ typedef std::map<as_object*, size_t> PropertyOffsets;
+
public:
- PropsBufSerializer(SimpleBuffer& buf, VM& vm, std::map<as_object*,
size_t>& offsetTable)
+ PropsBufSerializer(SimpleBuffer& buf, VM& vm,
+ PropertyOffsets& offsetTable)
:
_buf(buf),
_vm(vm),
@@ -205,17 +209,17 @@
// A '__constructor__' member gets back, but only if
// not a function. Actually no function gets back.
//
- if ( key == NSV::PROP_uuPROTOuu ||
- key == NSV::PROP_CONSTRUCTOR )
+ if (key == NSV::PROP_uuPROTOuu || key == NSV::PROP_CONSTRUCTOR)
{
#ifdef GNASH_DEBUG_AMF_SERIALIZE
- log_debug(" skip serialization of specially-named property %s",
_st.value(key));
+ log_debug(" skip serialization of specially-named property %s",
+ _st.value(key));
#endif
return;
}
// write property name
- const string& name = _st.value(key);
+ const std::string& name = _st.value(key);
#ifdef GNASH_DEBUG_AMF_SERIALIZE
log_debug(" serializing property %s", name);
#endif
@@ -228,6 +232,15 @@
_error=true;
}
}
+
+private:
+
+ SimpleBuffer& _buf;
+ VM& _vm;
+ string_table& _st;
+ PropertyOffsets& _offsetTable;
+ mutable bool _error;
+
};
//
@@ -2094,8 +2107,8 @@
// TODO restore first parameter on parse errors
//
static bool
-amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end, as_value& ret, int
inType,
- std::vector<as_object*>& objRefs, VM& vm)
+amf0_read_value(boost::uint8_t *&b, boost::uint8_t *end,
+ as_value& ret, int inType, std::vector<as_object*>& objRefs, VM& vm)
{
int amf_type;
@@ -2387,7 +2400,9 @@
{
size_t len = ary->size();
#ifdef GNASH_DEBUG_AMF_SERIALIZE
- log_debug(_("writeAMF0: serializing array of %d elements
as ECMA_ARRAY (index %d)"), len, idx);
+ log_debug(_("writeAMF0: serializing array of %d "
+ "elements as ECMA_ARRAY (index %d)"),
+ len, idx);
#endif
buf.appendByte(amf::Element::ECMA_ARRAY_AMF0);
buf.appendNetworkLong(len);
@@ -2395,7 +2410,8 @@
else
{
#ifdef GNASH_DEBUG_AMF_SERIALIZE
- log_debug(_("writeAMF0: serializing object (or function)
with index %d"), idx);
+ log_debug(_("writeAMF0: serializing object (or function) "
+ "with index %d"), idx);
#endif
buf.appendByte(amf::Element::OBJECT_AMF0);
}
@@ -2415,7 +2431,8 @@
{
size_t idx = it->second;
#ifdef GNASH_DEBUG_AMF_SERIALIZE
- log_debug(_("writeAMF0: serializing object (or function) as
reference to %d"), idx);
+ log_debug(_("writeAMF0: serializing object (or function) "
+ "as reference to %d"), idx);
#endif
buf.appendByte(amf::Element::REFERENCE_AMF0);
buf.appendNetworkShort(idx);
=== modified file 'libcore/asobj/ClassHierarchy.cpp'
--- a/libcore/asobj/ClassHierarchy.cpp 2008-12-08 11:11:44 +0000
+++ b/libcore/asobj/ClassHierarchy.cpp 2008-12-09 13:32:22 +0000
@@ -71,14 +71,27 @@
namespace { // anonymous namespace
-static void
+void
addVisibilityFlag(int& flags, int version)
{
// TODO: more visibility for swf10+?
- if ( version >= 9 ) flags |= as_prop_flags::onlySWF9Up;
- else if ( version >= 8 ) flags |= as_prop_flags::onlySWF8Up;
- else if ( version >= 7 ) flags |= as_prop_flags::onlySWF7Up;
- else if ( version >= 6 ) flags |= as_prop_flags::onlySWF6Up;
+ switch (version)
+ {
+ default:
+ return;
+ case 9:
+ flags |= as_prop_flags::onlySWF9Up;
+ break;
+ case 8:
+ flags |= as_prop_flags::onlySWF8Up;
+ break;
+ case 7:
+ flags |= as_prop_flags::onlySWF7Up;
+ break;
+ case 6:
+ flags |= as_prop_flags::onlySWF6Up;
+ break;
+ }
}
class declare_extension_function : public as_function
@@ -230,8 +243,7 @@
bool
ClassHierarchy::declareClass(extensionClass& c)
{
- if (mExtension == NULL)
- return false; // Extensions can't be loaded.
+ if (mExtension == NULL) return false;
mGlobalNamespace->stubPrototype(c.name);
mGlobalNamespace->getClass(c.name)->setDeclared();
@@ -251,8 +263,9 @@
// For AS2 and below, registering with mGlobal _should_ make it
equivalent
// to being in the global namespace, since everything is global there.
asNamespace *nso = findNamespace(c.namespace_name);
- if (!nso)
- nso = addNamespace(c.namespace_name);
+
+ if (!nso) nso = addNamespace(c.namespace_name);
+
nso->stubPrototype(c.name);
nso->getClass(c.name)->setDeclared();
nso->getClass(c.name)->setSystem();
@@ -260,10 +273,9 @@
boost::intrusive_ptr<as_function> getter =
new declare_native_function(c, mGlobal, mExtension);
- int flags=as_prop_flags::dontEnum;
+ int flags = as_prop_flags::dontEnum;
addVisibilityFlag(flags, c.version);
- return mGlobal->init_destructive_property(c.name,
- *getter, flags);
+ return mGlobal->init_destructive_property(c.name, *getter, flags);
}
static const ClassHierarchy::nativeClass knownClasses[] =
@@ -299,7 +311,7 @@
{ video_class_init, NSV::CLASS_VIDEO, NSV::CLASS_OBJECT,
NSV::NS_FLASH_MEDIA, 6 },
{ camera_class_init, NSV::CLASS_CAMERA, NSV::CLASS_OBJECT,
NSV::NS_FLASH_UI, 6 },
{ microphone_class_init, NSV::CLASS_MICROPHONE, NSV::CLASS_OBJECT,
NSV::NS_FLASH_UI, 6 },
- { sharedobject_class_init, NSV::CLASS_SHARED_OBJECT, NSV::CLASS_OBJECT,
NSV::NS_FLASH_NET, 6 },
+ { sharedobject_class_init, NSV::CLASS_SHARED_OBJECT, NSV::CLASS_OBJECT,
NSV::NS_FLASH_NET, 5 },
{ loadvars_class_init, NSV::CLASS_LOAD_VARS, NSV::CLASS_OBJECT,
NS_GLOBAL, 6 },
{ localconnection_class_init, NSV::CLASS_LOCAL_CONNECTION,
NSV::CLASS_OBJECT, NS_GLOBAL, 6 }, // FIXME: not global ?
{ customactions_class_init, NSV::CLASS_CUSTOM_ACTIONS,
NSV::CLASS_OBJECT, NSV::NS_ADOBE_UTILS, 6 },
@@ -322,7 +334,7 @@
};
void
-ClassHierarchy::massDeclare(int /*version*/) // drop version...
+ClassHierarchy::massDeclare()
{
// Natives get declared first. It doesn't make any sense for a native
// to depend on an extension, but it does make sense the other way
@@ -331,7 +343,6 @@
for (size_t i = 0; i < size; ++i)
{
const nativeClass& c = knownClasses[i];
- //if (c.version > version) continue;
if ( ! declareClass(c) )
{
=== modified file 'libcore/asobj/ClassHierarchy.h'
--- a/libcore/asobj/ClassHierarchy.h 2008-06-18 16:19:22 +0000
+++ b/libcore/asobj/ClassHierarchy.h 2008-12-09 13:32:22 +0000
@@ -127,7 +127,7 @@
/// Declare all of the native and extension classes from the
/// tables contained in the source file.
///
- void massDeclare(int version);
+ void massDeclare();
/// The global namespace
///
=== modified file 'libcore/asobj/Global.cpp'
--- a/libcore/asobj/Global.cpp 2008-12-08 11:11:44 +0000
+++ b/libcore/asobj/Global.cpp 2008-12-09 13:32:22 +0000
@@ -153,9 +153,7 @@
ch->setExtension(&_et);
#endif
- const int version = vm.getSWFVersion();
-
- ch->massDeclare(version);
+ ch->massDeclare();
object_class_init(*this);
string_class_init(*this);
@@ -167,6 +165,7 @@
// SWF8 visibility:
flash_package_init(*this);
+ const int version = vm.getSWFVersion();
switch (version)
{
@@ -671,6 +670,7 @@
registerMathNative(global);
registerSystemNative(global);
registerStageNative(global);
+ registerSharedObjectNative(global);
// LoadableObject has natives shared between LoadVars and XML, so
// should be registered first.
=== modified file 'libcore/asobj/SharedObject.cpp'
--- a/libcore/asobj/SharedObject.cpp 2008-11-21 15:15:25 +0000
+++ b/libcore/asobj/SharedObject.cpp 2008-12-09 15:58:56 +0000
@@ -66,25 +66,37 @@
#define MAXHOSTNAMELEN 64
#endif
-static as_value sharedobject_connect(const fn_call& fn);
-static as_value sharedobject_send(const fn_call& fn);
-static as_value sharedobject_flush(const fn_call& fn);
-static as_value sharedobject_close(const fn_call& fn);
-static as_value sharedobject_getsize(const fn_call& fn);
-static as_value sharedobject_setFps(const fn_call& fn);
-static as_value sharedobject_clear(const fn_call& fn);
-
-static as_value sharedobject_getlocal(const fn_call& fn);
-static as_value sharedobject_ctor(const fn_call& fn);
-
-void sharedobject_iter(SOL &sol, string_table::key key, const as_value
&reference);
-
+// Forward declarations
+namespace {
+
+ as_value sharedobject_connect(const fn_call& fn);
+ as_value sharedobject_send(const fn_call& fn);
+ as_value sharedobject_flush(const fn_call& fn);
+ as_value sharedobject_close(const fn_call& fn);
+ as_value sharedobject_getsize(const fn_call& fn);
+ as_value sharedobject_setFps(const fn_call& fn);
+ as_value sharedobject_clear(const fn_call& fn);
+ as_value sharedobject_deleteAll(const fn_call& fn);
+ as_value sharedobject_getDiskUsage(const fn_call& fn);
+ as_value sharedobject_getRemote(const fn_call& fn);
+
+ as_value sharedobject_getLocal(const fn_call& fn);
+ as_value sharedobject_ctor(const fn_call& fn);
+
+ as_object* readSOL(VM& vm, const std::string& filespec);
+
+ as_object* getSharedObjectInterface();
+ void attachSharedObjectStaticInterface(as_object& o);
+ bool createDirForFile(const std::string& filespec);
+}
+
+// Serializer helper
namespace {
-class PropsSerializer : public AbstractPropertyVisitor {
- SOL& _sol;
- string_table& _st;
+class PropsSerializer : public AbstractPropertyVisitor
+{
public:
+
PropsSerializer(SOL& sol, VM& vm)
:
_sol(sol),
@@ -92,51 +104,56 @@
{};
void accept(string_table::key key, const as_value& val)
- {
- //GNASH_REPORT_FUNCTION;
- AMF amf;
- boost::shared_ptr<amf::Element> el;
-
- const std::string& name = _st.string_table::value(key);
-
- //log_debug("Serializing SharedObject property %s:%s", name, val);
-
- if (val.is_string()) {
- std::string str;
- if (!val.is_undefined()) {
- str = val.to_string();
- }
- el.reset(new amf::Element(name, str));
- }
- if (val.is_bool()) {
- bool flag = val.to_bool();
- el.reset(new amf::Element(name, flag));
- }
- if (val.is_number()) {
- double dub;
- if (val.is_undefined()) {
- dub = 0.0;
- } else {
- dub = val.to_number();
- }
- el.reset(new amf::Element(name, dub));
- }
-
- if (el) {
- _sol.addObj(el);
- }
- }
+ {
+ AMF amf;
+ boost::shared_ptr<amf::Element> el;
+
+ const std::string& name = _st.string_table::value(key);
+
+ //log_debug("Serializing SharedObject property %s:%s", name, val);
+
+ if (val.is_string()) {
+ std::string str;
+ if (!val.is_undefined()) {
+ str = val.to_string();
+ }
+ el.reset(new amf::Element(name, str));
+ }
+ if (val.is_bool()) {
+ bool flag = val.to_bool();
+ el.reset(new amf::Element(name, flag));
+ }
+ if (val.is_number()) {
+ double dub;
+ if (val.is_undefined()) {
+ dub = 0.0;
+ } else {
+ dub = val.to_number();
+ }
+ el.reset(new amf::Element(name, dub));
+ }
+
+ if (el) {
+ _sol.addObj(el);
+ }
+ }
+
+private:
+
+ SOL& _sol;
+ string_table& _st;
};
/// Class used to serialize properties of an object to a buffer in SOL format
-class SOLPropsBufSerializer : public AbstractPropertyVisitor {
- SimpleBuffer& _buf;
- VM& _vm;
- string_table& _st;
- std::map<as_object*, size_t>& _offsetTable;
- bool _error;
+class SOLPropsBufSerializer : public AbstractPropertyVisitor
+{
+
+ typedef std::map<as_object*, size_t> PropertiesOffsetTable;
+
public:
- SOLPropsBufSerializer(SimpleBuffer& buf, VM& vm, std::map<as_object*,
size_t>& offsetTable)
+
+ SOLPropsBufSerializer(SimpleBuffer& buf, VM& vm,
+ PropertiesOffsetTable& offsetTable)
:
_buf(buf),
_vm(vm),
@@ -164,11 +181,11 @@
// A '__constructor__' member gets back, but only if
// not a function. Actually no function gets back.
//
- if ( key == NSV::PROP_uuPROTOuu ||
- key == NSV::PROP_CONSTRUCTOR )
+ if ( key == NSV::PROP_uuPROTOuu || key == NSV::PROP_CONSTRUCTOR )
{
#ifdef GNASH_DEBUG_AMF_SERIALIZE
- log_debug(" skip serialization of specially-named property %s",
_st.value(key));
+ log_debug(" skip serialization of specially-named property %s",
+ _st.value(key));
#endif
return;
}
@@ -183,75 +200,28 @@
_buf.append(name.c_str(), namelen);
if ( ! val.writeAMF0(_buf, _offsetTable, _vm) )
{
- log_error("Problems serializing an object's member %s=%s", name,
val);
- _error=true;
+ log_error("Problems serializing an object's member %s=%s",
+ name, val);
+ _error = true;
}
_buf.appendByte(0); // SOL-specific
}
+
+private:
+
+ SimpleBuffer& _buf;
+
+ VM& _vm;
+
+ string_table& _st;
+
+ PropertiesOffsetTable& _offsetTable;
+
+ bool _error;
};
-} // anonimous namespace
-
-static void
-attachProperties(as_object& o)
-{
-// GNASH_REPORT_FUNCTION;
- as_object *proto = new as_object(getObjectInterface());
- o.init_member("data", proto,
as_prop_flags::dontDelete|as_prop_flags::readOnly);
-}
-
-static void
-attachSharedObjectInterface(as_object& o)
-{
-// GNASH_REPORT_FUNCTION;
-
- VM& vm = o.getVM();
-
- // ASnative table registration
- vm.registerNative(sharedobject_connect, 2106, 0);
- vm.registerNative(sharedobject_send, 2106, 1);
- vm.registerNative(sharedobject_flush, 2106, 2);
- vm.registerNative(sharedobject_close, 2106, 3);
- vm.registerNative(sharedobject_getsize, 2106, 4);
- vm.registerNative(sharedobject_setFps, 2106, 5);
- vm.registerNative(sharedobject_clear, 2106, 6);
-
- const int swfVersion = vm.getSWFVersion();
-
- // clear, flush and getSize not in SWF<6 , it seems
- if ( swfVersion < 6 ) return;
-
- o.init_member("connect", new builtin_function(sharedobject_connect)); //
asnative 2106,0
- o.init_member("send", new builtin_function(sharedobject_send)); //
asnative 2106,1
- o.init_member("flush", new builtin_function(sharedobject_flush)); //
asnative 2106,2
- o.init_member("close", new builtin_function(sharedobject_close)); //
asnative 2106,3
- o.init_member("getSize", new builtin_function(sharedobject_getsize)); //
asnative 2106,4
- o.init_member("setFps", new builtin_function(sharedobject_setFps)); //
asnative 2106,5
- o.init_member("clear", new builtin_function(sharedobject_clear)); //
asnative 2106,6
-}
-
-static void
-attachSharedObjectStaticInterface(as_object& o)
-{
-// GNASH_REPORT_FUNCTION;
-
- o.init_member("getLocal", new builtin_function(sharedobject_getlocal));
-}
-
-static as_object*
-getSharedObjectInterface()
-{
-// GNASH_REPORT_FUNCTION;
-
- static boost::intrusive_ptr<as_object> o;
- if ( ! o ) {
- o = new as_object(getObjectInterface());
- attachSharedObjectInterface(*o);
- }
- return o.get();
-}
-
+} // anonymous namespace
class SharedObject: public as_object
{
@@ -263,10 +233,9 @@
:
as_object(getSharedObjectInterface())
{
- attachProperties(*this);
}
- bool flush() const;
+ bool flush(as_object& data) const;
const std::string& getFilespec() const {
return _sol.getFilespec();
@@ -284,17 +253,115 @@
_sol.setObjectName(s);
}
+ /// This isn't correct, as the default implementation doesn't use SOL
+ /// for reading.
size_t size() const {
- return _sol.size(); // TODO: fix this, is bogus
+ return _sol.fileSize();
}
- bool readSOL(const std::string& filename);
-
private:
SOL _sol;
};
+
+SharedObject::~SharedObject()
+{
+}
+
+
+bool
+SharedObject::flush(as_object& data) const
+{
+ const std::string& filespec = _sol.getFilespec();
+
+ if ( ! createDirForFile(filespec) )
+ {
+ log_error("Couldn't create dir for flushing SharedObject %s",
filespec);
+ return false;
+ }
+
+#ifdef USE_SOL_READONLY
+ log_debug(_("SharedObject %s not flushed (compiled as read-only mode)"),
+ filespec);
+ return false;
+#endif
+
+ if (rcfile.getSOLReadOnly() ) {
+ log_security("Attempting to write object %s when it's SOL "
+ "Read Only is set! Refusing...", filespec);
+ return false;
+ }
+
+#ifdef BUFFERED_AMF_SOL
+
+ gnash::SimpleBuffer buf;
+ // see http://osflash.org/documentation/amf/envelopes/sharedobject
+ buf.append("\x00\xbf\x00\x00\x00\x00TCSO\x00\x04\x00\x00\x00\x00", 16); //
length field filled in later
+
+ // append object name
+ std::string object_name = getObjectName();
+ boost::uint16_t len = object_name.length();
+ buf.appendNetworkShort(len);
+ buf.append(object_name.c_str(), len);
+
+ // append padding
+ buf.append("\x00\x00\x00\x00", 4);
+
+ // append properties of object
+ VM& vm = getVM();
+
+ std::map<as_object*, size_t> offsetTable;
+ SOLPropsBufSerializer props(buf, vm, offsetTable);
+ data.visitPropertyValues(props);
+ if ( ! props.success() )
+ {
+ log_error("Could not serialize object");
+ return false;
+ }
+
+ // fix length field
+ *(reinterpret_cast<uint32_t*>(buf.data() + 2)) = htonl(buf.size() - 6);
+
+ // TODO write file
+ std::ofstream ofs(filespec.c_str(), std::ios::binary);
+ if (!ofs) {
+ log_error("SharedObject::flush(): Failed opening file '%s' in "
+ "binary mode", filespec.c_str());
+ return false;
+ }
+
+ if (ofs.write(reinterpret_cast<const char*>(buf.data()),
buf.size()).fail())
+ {
+ log_error("Error writing %d bytes to output file %s",
+ buf.size(), filespec.c_str());
+ ofs.close();
+ return false;
+ }
+ ofs.close();
+
+#else // amf::SOL-based serialization
+
+ // append properties of object
+ VM& vm = getVM();
+
+ SOL sol;
+ PropsSerializer props(sol, vm);
+ data.visitPropertyValues(props);
+ // We only want to access files in this directory
+ bool ret = sol.writeFile(filespec, getObjectName().c_str());
+ if ( ! ret )
+ {
+ log_error("writing SharedObject file to %s", filespec);
+ return false;
+ }
+#endif
+
+ log_security("SharedObject '%s' written to filesystem.", filespec);
+ return true;
+}
+
+
SharedObjectLibrary::SharedObjectLibrary(VM& vm)
:
_vm(vm),
@@ -310,8 +377,8 @@
struct stat statbuf;
if ( -1 == stat(_solSafeDir.c_str(), &statbuf) )
{
- log_debug("Invalid SOL safe dir %s: %s. Will try to create on
flush/exit.", _solSafeDir, std::strerror(errno));
- //_solSafeDir.clear();
+ log_debug("Invalid SOL safe dir %s: %s. Will try to create on "
+ "flush/exit.", _solSafeDir, std::strerror(errno));
}
// Which URL we should use here is under research.
@@ -338,7 +405,8 @@
// Get the domain part, or take as 'localhost' if none
// (loaded from filesystem)
URL url(swfURL);
-// log_debug(_("BASE URL=%s (%s)"), url.str(), url.hostname());
+
+ // log_debug(_("BASE URL=%s (%s)"), url.str(), url.hostname());
_baseDomain = url.hostname();
if ( _baseDomain.empty() ) _baseDomain = "localhost";
@@ -352,68 +420,36 @@
void
SharedObjectLibrary::markReachableResources() const
{
- for (SoLib::const_iterator it=_soLib.begin(), itE=_soLib.end(); it!=itE;
++it)
+ for (SoLib::const_iterator it = _soLib.begin(), itE = _soLib.end();
+ it != itE; ++it)
{
SharedObject* sh = it->second;
sh->setReachable();
}
}
-static bool createDirForFile(const std::string& filename)
-{
- if (filename.find("/", 0) != std::string::npos)
- {
- typedef boost::tokenizer<boost::char_separator<char> > Tok;
- boost::char_separator<char> sep("/");
- Tok t(filename, sep);
- Tok::iterator tit;
- std::string newdir = "/";
- for(tit=t.begin(); tit!=t.end();++tit){
- //cout << *tit << "\n";
- newdir += *tit;
- if (newdir.find("..", 0) != std::string::npos) {
- log_error("Invalid SharedObject path (contains '..'): %s",
filename);
- return false;
- }
- // Don't try to create a directory of the .sol file name!
- // TODO: don't fail if the movie url has a component ending with
.sol (eh...)
- //
- if (newdir.rfind(".sol") != (newdir.size()-4)) {
-#ifndef _WIN32
- int ret = mkdir(newdir.c_str(), S_IRUSR|S_IWUSR|S_IXUSR);
-#else
- int ret = mkdir(newdir.c_str());
-#endif
- if ((errno != EEXIST) && (ret != 0)) {
- log_error(_("Couldn't create SOL files directory %s: %s"),
- newdir, std::strerror(errno));
- return false;
- }
- } // else log_debug("newdir %s ends with .sol", newdir);
- newdir += "/";
- }
- }
- else log_debug("no slash in filespec %s", filename);
- return true;
-}
-
SharedObject*
-SharedObjectLibrary::getLocal(const std::string& objName, const std::string&
root)
+SharedObjectLibrary::getLocal(const std::string& objName,
+ const std::string& root)
{
assert ( ! objName.empty() );
- if ( _solSafeDir.empty() ) return 0; // already warned about it at
construction time
+ // already warned about it at construction time
+ if ( _solSafeDir.empty() ) return 0;
// TODO: this check sounds kind of lame, fix it
if ( rcfile.getSOLLocalDomain() && _baseDomain != "localhost")
{
- log_security("Attempting to open SOL file from non localhost-loaded
SWF");
+ log_security("Attempting to open SOL file from non "
+ "localhost-loaded SWF");
return 0;
}
// The optional second argument drops the domain and the swf file name
std::string key;
- if ( root.empty() ) key = "/" + _baseDomain + "/" + _basePath + "/" +
objName;
+ if ( root.empty() ) {
+ key = "/" + _baseDomain + "/" + _basePath + "/" + objName;
+ }
else key = root + "/" + objName;
// TODO: normalize key!
@@ -441,37 +477,335 @@
log_debug("SharedObject path: %s", newspec);
- if ( ! obj->readSOL(newspec) )
- {
- log_debug("Couldn't read SOL %s, will create on flush/exit.", newspec);
+ boost::intrusive_ptr<as_object> data = readSOL(_vm, newspec);
+
+ if (data) {
+ const int flags = as_prop_flags::dontDelete |
+ as_prop_flags::readOnly;
+ obj->init_member(NSV::PROP_DATA, data, flags);
}
return obj;
}
-bool
-SharedObject::readSOL(const std::string& filespec)
-{
+
+// extern (used by Global.cpp)
+void
+sharedobject_class_init(as_object& global)
+{
+ static boost::intrusive_ptr<builtin_function> cl;
+
+ if (cl == NULL) {
+ cl=new builtin_function(&sharedobject_ctor,
getSharedObjectInterface());
+ attachSharedObjectStaticInterface(*cl);
+ }
+
+ // Register _global.SharedObject
+ global.init_member("SharedObject", cl.get());
+}
+
+void
+registerSharedObjectNative(as_object& o)
+{
+ VM& vm = o.getVM();
+
+ // ASnative table registration
+ vm.registerNative(sharedobject_connect, 2106, 0);
+ vm.registerNative(sharedobject_send, 2106, 1);
+ vm.registerNative(sharedobject_flush, 2106, 2);
+ vm.registerNative(sharedobject_close, 2106, 3);
+ vm.registerNative(sharedobject_getsize, 2106, 4);
+ vm.registerNative(sharedobject_setFps, 2106, 5);
+ vm.registerNative(sharedobject_clear, 2106, 6);
+
+ // FIXME: getRemote and getLocal use both these methods,
+ // but aren't identical with either of them.
+ // TODO: The first method looks in a library and returns either a
+ // SharedObject or null. The second takes a new SharedObject as
+ // its first argument and populates its data member (more or less
+ // like readSOL). This is only important for ASNative compatibility.
+ vm.registerNative(sharedobject_getLocal, 2106, 202);
+ vm.registerNative(sharedobject_getRemote, 2106, 203);
+ vm.registerNative(sharedobject_getLocal, 2106, 204);
+ vm.registerNative(sharedobject_getRemote, 2106, 205);
+
+ vm.registerNative(sharedobject_deleteAll, 2106, 206);
+ vm.registerNative(sharedobject_getDiskUsage, 2106, 207);
+}
+
+
+/// SharedObject AS interface
+namespace {
+
+void
+attachSharedObjectInterface(as_object& o)
+{
+
+ VM& vm = o.getVM();
+
+ const int flags = as_prop_flags::dontEnum |
+ as_prop_flags::dontDelete |
+ as_prop_flags::onlySWF6Up;
+
+ o.init_member("connect", vm.getNative(2106, 0), flags);
+ o.init_member("send", vm.getNative(2106, 1), flags);
+ o.init_member("flush", vm.getNative(2106, 2), flags);
+ o.init_member("close", vm.getNative(2106, 3), flags);
+ o.init_member("getSize", vm.getNative(2106, 4), flags);
+ o.init_member("setFps", vm.getNative(2106, 5), flags);
+ o.init_member("clear", vm.getNative(2106, 6), flags);
+
+}
+
+
+void
+attachSharedObjectStaticInterface(as_object& o)
+{
+ VM& vm = o.getVM();
+
+ const int flags = 0;
+
+ o.init_member("getLocal",
+ new builtin_function(sharedobject_getLocal), flags);
+ o.init_member("getRemote",
+ new builtin_function(sharedobject_getRemote), flags);
+
+ const int hiddenOnly = as_prop_flags::dontEnum;
+
+ o.init_member("deleteAll", vm.getNative(2106, 206), hiddenOnly);
+ o.init_member("getDiskUsage", vm.getNative(2106, 207), hiddenOnly);
+}
+
+
+as_object*
+getSharedObjectInterface()
+{
+
+ static boost::intrusive_ptr<as_object> o;
+ if ( ! o ) {
+ o = new as_object(getObjectInterface());
+ attachSharedObjectInterface(*o);
+ }
+ return o.get();
+}
+
+
+as_value
+sharedobject_clear(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl (__FUNCTION__));
+
+ return as_value();
+}
+
+as_value
+sharedobject_connect(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.connect"));
+ return as_value();
+}
+
+as_value
+sharedobject_close(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.close"));
+ return as_value();
+}
+
+as_value
+sharedobject_setFps(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.setFps"));
+ return as_value();
+}
+
+as_value
+sharedobject_send(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.send"));
+ return as_value();
+}
+
+as_value
+sharedobject_flush(const fn_call& fn)
+{
+
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+
+ IF_VERBOSE_ASCODING_ERRORS(
+ if ( fn.nargs )
+ {
+ std::stringstream ss;
+ fn.dump_args(ss);
+ log_aserror(_("Arguments to SharedObject.flush(%s) will be "
+ "ignored"), ss.str());
+ }
+ );
+
+ /// If there is no data member, returns undefined.
+ as_value dataMember;
+ if (!obj->get_member(NSV::PROP_DATA, &dataMember)) return as_value();
+
+ as_object* data = dataMember.to_object().get();
+ if (!data) return as_value();
+
+ // If there is an object data member, returns the success of flush().
+ return as_value(obj->flush(*data));
+}
+
+// Set the file name
+as_value
+sharedobject_getLocal(const fn_call& fn)
+{
+
+ VM& vm = fn.env().getVM();
+ int swfVersion = vm.getSWFVersion();
+
+ as_value objNameVal;
+ if (fn.nargs > 0) objNameVal = fn.arg(0);
+ std::string objName = objNameVal.to_string_versioned(swfVersion);
+ if ( objName.empty() )
+ {
+ IF_VERBOSE_ASCODING_ERRORS(
+ std::ostringstream ss;
+ fn.dump_args(ss);
+ log_aserror("SharedObject.getLocal(%s): %s",
+ _("missing object name"));
+ );
+ as_value ret;
+ ret.set_null();
+ return ret;
+ }
+
+ std::string root;
+ if (fn.nargs > 1)
+ {
+ root = fn.arg(1).to_string_versioned(swfVersion);
+ }
+
+ log_debug("SO name:%s, root:%s", objName, root);
+
+ SharedObject* obj = vm.getSharedObjectLibrary().getLocal(objName, root);
+
+ as_value ret(obj);
+ log_debug("SharedObject.getLocal returning %s", ret);
+ return ret;
+}
+
+/// Undocumented
+as_value
+sharedobject_getRemote(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.getRemote()"));
+ return as_value();
+}
+
+
+/// Undocumented
+//
+/// Takes a URL argument and deletes all SharedObjects under that URL.
+as_value
+sharedobject_deleteAll(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.deleteAll()"));
+ return as_value();
+}
+
+/// Undocumented
+//
+/// Should be quite obvious what it does.
+as_value
+sharedobject_getDiskUsage(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+
+ UNUSED(obj);
+
+ LOG_ONCE(log_unimpl("SharedObject.getDiskUsage()"));
+ return as_value();
+}
+
+as_value
+sharedobject_getsize(const fn_call& fn)
+{
+ boost::intrusive_ptr<SharedObject> obj =
+ ensureType<SharedObject>(fn.this_ptr);
+ return as_value(obj->size());
+}
+
+as_value
+sharedobject_ctor(const fn_call& /* fn */)
+{
+ boost::intrusive_ptr<as_object> obj = new SharedObject;
+
+ return as_value(obj.get()); // will keep alive
+}
+
+as_object*
+readSOL(VM& vm, const std::string& filespec)
+{
+
#ifdef BUFFERED_AMF_SOL
+
+ // The 'data' member is initialized only on getLocal() (and probably
+ // getRemote()): i.e. when there is some data, or when it's ready to
+ // be added.
+ as_object* data = new as_object(getObjectInterface());
+
struct stat st;
if (stat(filespec.c_str(), &st) != 0)
{
- return false;
+ // No existing SOL file. A new one will be created.
+ log_debug("No existing SOL %s found. Will create on flush/exit.",
+ filespec);
+ return data;
}
- if( st.st_size < 28 )
+ if (st.st_size < 28)
{
- log_error("SharedObject::readSOL: SOL file %s is too short (only %s
bytes long) to be valid.", filespec, st.st_size);
- return false;
+ // A SOL file exists, but it was invalid. Count it as not existing.
+ log_error("SharedObject::readSOL: SOL file %s is too short "
+ "(only %s bytes long) to be valid.", filespec, st.st_size);
+ return data;
}
boost::scoped_array<boost::uint8_t> sbuf(new boost::uint8_t[st.st_size]);
boost::uint8_t *buf = sbuf.get();
boost::uint8_t *end = buf + st.st_size;
- // FIXME clear existing key/value pairs?
-
try
{
std::ifstream ifs(filespec.c_str(), std::ios::binary);
@@ -487,22 +821,24 @@
buf += 4; // skip past padding
- if( buf >= end )
+ if (buf >= end)
{
+ // In this case there is no data member.
log_error("SharedObject::readSOL: file ends before data segment");
- return false;
+ return 0;
}
- string_table& strtab = _vm.getStringTable();
std::vector<as_object*> objRefs;
- boost::intrusive_ptr<as_object> data =
getMember(strtab.string_table::find("data")).to_object();
- while( buf < end )
+ while (buf < end)
{
- log_debug("SharedObject::readSOL: reading property name at byte
%s", buf - sbuf.get());
+ log_debug("SharedObject::readSOL: reading property name at "
+ "byte %s", buf - sbuf.get());
// read property name
- boost::uint16_t len =
ntohs(*(reinterpret_cast<boost::uint16_t*>(buf)));
+ boost::uint16_t len =
+ ntohs(*(reinterpret_cast<boost::uint16_t*>(buf)));
buf += 2;
+
if( buf + len >= end )
{
log_error("SharedObject::readSOL: premature end of input");
@@ -517,34 +853,36 @@
// read value
as_value as;
- if(as.readAMF0(buf, end, -1 /* read type from buffer */, objRefs,
_vm) == false) {
- log_error("SharedObject::readSOL: Parsing SharedObject '%s'",
filespec);
+ if (!as.readAMF0(buf, end, -1, objRefs, vm)) {
+ log_error("SharedObject::readSOL: Parsing SharedObject '%s'",
+ filespec);
return false;
}
- log_debug("parsed sol member named '%s' (len %s), value '%s'",
prop_name, len, as);
+ log_debug("parsed sol member named '%s' (len %s), value '%s'",
+ prop_name, len, as);
// set name/value as a member of this (SharedObject) object
- data->set_member(strtab.find(prop_name), as);
+ string_table& st = vm.getStringTable();
+ data->set_member(st.find(prop_name), as);
buf += 1; // skip null byte after each property
}
- log_debug("setting data member: %s, %s",
strtab.find(std::string("data")), as_value(data.get()));
- set_member(strtab.find(std::string("data")), as_value(data.get()));
- return true;
+ return data;
}
catch (std::exception& e)
{
- log_error("SharedObject::readSOL: Reading SharedObject %s: %s",
filespec, e.what());
- return false;
+ log_error("SharedObject::readSOL: Reading SharedObject %s: %s",
+ filespec, e.what());
+ return 0;
}
-
#else
SOL sol;
log_security("Opening SharedObject file: %s", filespec);
if (sol.readFile(filespec) == false) {
- log_security("empty or non-existing SOL file \"%s\", will be created
on flush/exit", filespec);
+ log_security("empty or non-existing SOL file \"%s\", will be "
+ "created on flush/exit", filespec);
return false;
}
@@ -552,9 +890,7 @@
std::vector<boost::shared_ptr<amf::Element> > els = sol.getElements();
log_debug("Read %d AMF objects from %s", els.size(), filespec);
- string_table& st = _vm.getStringTable();
- string_table::key dataKey = st.find("data");
- as_value as = getMember(dataKey);
+ as_value as = getMember(NSV::PROP_DATA);
boost::intrusive_ptr<as_object> ptr = as.to_object();
for (it = els.begin(), e = els.end(); it != e; it++) {
@@ -573,7 +909,8 @@
case Element::NUMBER_AMF0:
{
double dub = *(reinterpret_cast<double*>(el->getData()));
- ptr->set_member(st.string_table::find(el->getName()),
as_value(dub));
+ ptr->set_member(st.string_table::find(el->getName()),
+ as_value(dub));
break;
}
@@ -585,12 +922,13 @@
case Element::STRING_AMF0:
{
if (el->getLength() == 0) {
- ptr->set_member(st.string_table::find(el->getName()),
as_value(""));
+ ptr->set_member(st.string_table::find(el->getName()), "");
break;
}
- std::string str(reinterpret_cast<const char*>(el->getData()),
el->getLength());
- ptr->set_member(st.string_table::find(el->getName()),
as_value(str));
+ std::string str(reinterpret_cast<const char*>(el->getData()),
+ el->getLength());
+ ptr->set_member(st.string_table::find(el->getName()), str);
break;
}
@@ -617,253 +955,45 @@
#endif
}
-
-SharedObject::~SharedObject()
-{
- // flush(); // needs more care, if destroyed after VM we get killed
-}
-
-
bool
-SharedObject::flush() const
+createDirForFile(const std::string& filename)
{
- const std::string& filespec = _sol.getFilespec();
-
- if ( ! createDirForFile(filespec) )
- {
- log_error("Couldn't create dir for flushing SharedObject %s",
filespec);
- return false;
- }
-
-#ifdef USE_SOL_READONLY
- log_debug(_("SharedObject %s not flushed (compiled as read-only mode)"),
filespec);
- return false;
-#endif
-
-// log_debug("Flushing to file %s", filespec);
-
- VM& vm = getVM();
-
- if (rcfile.getSOLReadOnly() ) {
- log_security("Attempting to write object %s when it's SOL Read Only is
set! Refusing...",
- filespec);
- return false;
- }
-
- // TODO: cache the dataKey in SharedObject prototype on first use ?
- // a SharedObject::getDataKey() might do...
- string_table::key dataKey = vm.getStringTable().find("data");
-
- as_value as = const_cast<SharedObject*>(this)->getMember(dataKey);
- log_debug("data member of this SharedObject is %s", as);
- boost::intrusive_ptr<as_object> ptr = as.to_object();
- if ( ! ptr ) {
- log_aserror("'data' member of SharedObject is not an object (%s)",
- as);
- return true;
- }
-
-#ifdef BUFFERED_AMF_SOL
-
- gnash::SimpleBuffer buf;
- // see http://osflash.org/documentation/amf/envelopes/sharedobject
- buf.append("\x00\xbf\x00\x00\x00\x00TCSO\x00\x04\x00\x00\x00\x00", 16); //
length field filled in later
-
- // append object name
- std::string object_name = getObjectName();
- boost::uint16_t len = object_name.length();
- buf.appendNetworkShort(len);
- buf.append(object_name.c_str(), len);
-
- // append padding
- buf.append("\x00\x00\x00\x00", 4);
-
- // append properties of object
- std::map<as_object*, size_t> offsetTable;
- SOLPropsBufSerializer props(buf, vm, offsetTable);
- ptr->visitPropertyValues(props);
- if ( ! props.success() )
- {
- log_error("Could not serialize object");
- return false;
- }
-
- // fix length field
- *(reinterpret_cast<uint32_t*>(buf.data() + 2)) = htonl(buf.size() - 6);
-
- // TODO write file
- std::ofstream ofs(filespec.c_str(), std::ios::binary);
- if(! ofs) {
- log_error("SharedObject::flush(): Failed opening file '%s' in binary
mode", filespec.c_str());
- return false;
- }
-
- if(ofs.write(reinterpret_cast<const char*>(buf.data()), buf.size()).fail()
)
- {
- log_error("Error writing %d bytes to output file %s", buf.size(),
filespec.c_str());
- ofs.close();
- return false;
- }
- ofs.close();
-
-#else // amf::SOL-based serialization
-
- SOL sol;
- PropsSerializer props(sol, vm);
- ptr->visitPropertyValues(props);
- // We only want to access files in this directory
- bool ret = sol.writeFile(filespec, getObjectName().c_str());
- if ( ! ret )
- {
- log_error("writing SharedObject file to %s", filespec);
- return false;
- }
-#endif
-
- log_security("SharedObject '%s' written to filesystem.", filespec);
+ if (filename.find("/", 0) != std::string::npos)
+ {
+ typedef boost::tokenizer<boost::char_separator<char> > Tok;
+ boost::char_separator<char> sep("/");
+ Tok t(filename, sep);
+ Tok::iterator tit;
+ std::string newdir = "/";
+ for(tit=t.begin(); tit!=t.end();++tit){
+ //cout << *tit << "\n";
+ newdir += *tit;
+ if (newdir.find("..", 0) != std::string::npos) {
+ log_error("Invalid SharedObject path (contains '..'): %s",
filename);
+ return false;
+ }
+ // Don't try to create a directory of the .sol file name!
+ // TODO: don't fail if the movie url has a component
+ // ending with .sol (eh...)
+ //
+ if (newdir.rfind(".sol") != (newdir.size()-4)) {
+#ifndef _WIN32
+ int ret = mkdir(newdir.c_str(), S_IRUSR|S_IWUSR|S_IXUSR);
+#else
+ int ret = mkdir(newdir.c_str());
+#endif
+ if ((errno != EEXIST) && (ret != 0)) {
+ log_error(_("Couldn't create SOL files directory %s: %s"),
+ newdir, std::strerror(errno));
+ return false;
+ }
+ } // else log_debug("newdir %s ends with .sol", newdir);
+ newdir += "/";
+ }
+ }
+ else log_debug("no slash in filespec %s", filename);
return true;
}
-
-as_value
-sharedobject_clear(const fn_call& fn)
-{
-// GNASH_REPORT_FUNCTION;
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
- UNUSED(obj);
-
- LOG_ONCE(log_unimpl (__FUNCTION__));
-
- return as_value();
-}
-
-as_value
-sharedobject_connect(const fn_call& fn)
-{
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
- UNUSED(obj);
-
- LOG_ONCE(log_unimpl("SharedObject.connect"));
- return as_value();
-}
-
-as_value
-sharedobject_close(const fn_call& fn)
-{
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
- UNUSED(obj);
-
- LOG_ONCE(log_unimpl("SharedObject.close"));
- return as_value();
-}
-
-as_value
-sharedobject_setFps(const fn_call& fn)
-{
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
- UNUSED(obj);
-
- LOG_ONCE(log_unimpl("SharedObject.setFps"));
- return as_value();
-}
-
-as_value
-sharedobject_send(const fn_call& fn)
-{
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
- UNUSED(obj);
-
- LOG_ONCE(log_unimpl("SharedObject.send"));
- return as_value();
-}
-
-as_value
-sharedobject_flush(const fn_call& fn)
-{
-// GNASH_REPORT_FUNCTION;
-
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
-
- IF_VERBOSE_ASCODING_ERRORS(
- if ( fn.nargs )
- {
- std::stringstream ss;
- fn.dump_args(ss);
- log_aserror(_("Arguments to SharedObject.flush(%s) will be ignored"),
ss.str());
- }
- )
-
- return as_value(obj->flush());
-}
-
-// Set the file name
-as_value
-sharedobject_getlocal(const fn_call& fn)
-{
-// GNASH_REPORT_FUNCTION;
-
- VM& vm = fn.env().getVM();
- int swfVersion = vm.getSWFVersion();
-
- as_value objNameVal;
- if (fn.nargs > 0) objNameVal = fn.arg(0);
- std::string objName = objNameVal.to_string_versioned(swfVersion);
- if ( objName.empty() )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- std::stringstream ss; fn.dump_args(ss);
- log_aserror("SharedObject.getLocal(%s): %s", _("missing object name"));
- );
- as_value ret; ret.set_null();
- return ret;
- }
-
- std::string root;
- if (fn.nargs > 1)
- {
- root = fn.arg(1).to_string_versioned(swfVersion);
- }
-
- log_debug("SO name:%s, root:%s", objName, root);
-
- SharedObject* obj = vm.getSharedObjectLibrary().getLocal(objName, root);
- as_value ret(obj);
- log_debug("SharedObject.getLocal returning %s", ret);
- return ret;
-}
-
-as_value
-sharedobject_getsize(const fn_call& fn)
-{
-// GNASH_REPORT_FUNCTION;
- boost::intrusive_ptr<SharedObject> obj =
ensureType<SharedObject>(fn.this_ptr);
- return as_value(obj->size());
-}
-
-as_value
-sharedobject_ctor(const fn_call& /* fn */)
-{
-// GNASH_REPORT_FUNCTION;
- boost::intrusive_ptr<as_object> obj = new SharedObject;
-// static boost::intrusive_ptr<as_object> obj = new
as_object(getSharedObjectInterface());
-
- return as_value(obj.get()); // will keep alive
-}
-
-// extern (used by Global.cpp)
-void sharedobject_class_init(as_object& global)
-{
-// GNASH_REPORT_FUNCTION;
- // This is going to be the global SharedObject "class"/"function"
- static boost::intrusive_ptr<builtin_function> cl;
-
- if (cl == NULL) {
- cl=new builtin_function(&sharedobject_ctor,
getSharedObjectInterface());
- attachSharedObjectStaticInterface(*cl);
- }
-
- // Register _global.SharedObject
- global.init_member("SharedObject", cl.get());
-}
-
+} // anonymous namespace
} // end of gnash namespace
=== modified file 'libcore/asobj/SharedObject.h'
--- a/libcore/asobj/SharedObject.h 2008-09-10 13:55:34 +0000
+++ b/libcore/asobj/SharedObject.h 2008-12-09 13:32:22 +0000
@@ -16,10 +16,9 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-#ifndef __GNASH_ASOBJ_SHAREDOBJECT_H__
-#define __GNASH_ASOBJ_SHAREDOBJECT_H__
+#ifndef GNASH_ASOBJ_SHAREDOBJECT_H
+#define GNASH_ASOBJ_SHAREDOBJECT_H
-#include <memory> // for auto_ptr
#include <string>
#include <map>
@@ -70,11 +69,9 @@
/// Initialize the global SharedObject class
void sharedobject_class_init(as_object& global);
-/// Return a SharedObject instance (in case the core lib needs it)
-//std::auto_ptr<as_object> init_sharedobject_instance();
+void registerSharedObjectNative(as_object& o);
} // end of gnash namespace
-// __GNASH_ASOBJ_SHAREDOBJECT_H__
#endif
=== modified file 'libcore/namedStrings.cpp'
--- a/libcore/namedStrings.cpp 2008-12-01 21:30:39 +0000
+++ b/libcore/namedStrings.cpp 2008-12-09 14:29:19 +0000
@@ -51,6 +51,7 @@
string_table::svt( "_currentframe", NSV::PROP_uCURRENTFRAME ),
string_table::svt( "_customHeaders", NSV::PROP_uCUSTOM_HEADERS ),
string_table::svt( "d", NSV::PROP_D ),
+ string_table::svt( "data", NSV::PROP_DATA ),
string_table::svt( "decode", NSV::PROP_DECODE ),
string_table::svt( "e", NSV::PROP_E ),
string_table::svt( "_droptarget", NSV::PROP_uDROPTARGET ),
=== modified file 'libcore/namedStrings.h'
--- a/libcore/namedStrings.h 2008-12-01 21:30:39 +0000
+++ b/libcore/namedStrings.h 2008-12-09 14:29:19 +0000
@@ -115,6 +115,7 @@
PROP_CONSTRUCTOR,
PROP_CONTENT_TYPE,
PROP_D,
+ PROP_DATA,
PROP_DECODE,
PROP_E,
PROP_ENABLED,
=== modified file 'testsuite/actionscript.all/ASnative.as'
--- a/testsuite/actionscript.all/ASnative.as 2008-08-04 12:02:51 +0000
+++ b/testsuite/actionscript.all/ASnative.as 2008-12-09 13:58:38 +0000
@@ -262,8 +262,21 @@
xcheck_equals (countVO, 25);
+/// SharedObject undocumented functions.
+
+a = ASnative(2106, 202);
+f = a("level1/level2/settings", "/", undefined);
+xcheck_equals(typeof(f), "null");
+
+a = ASnative(2106, 204);
+f = new SharedObject;
+check_equals (typeof(f.data), "undefined");
+ret = a(f, "level1/level2/settings", "/", undefined);
+xcheck_equals(ret, true);
+xcheck_equals (typeof(f.data), "object");
+
#if OUTPUT_VERSION > 5
-check_totals(79);
+check_totals(83);
#else
-check_totals(76);
+check_totals(80);
#endif
=== modified file 'testsuite/actionscript.all/SharedObject.as'
--- a/testsuite/actionscript.all/SharedObject.as 2008-09-13 07:08:00
+0000
+++ b/testsuite/actionscript.all/SharedObject.as 2008-12-09 14:29:19
+0000
@@ -26,19 +26,6 @@
var sharedobjectObj = new SharedObject;
-#if OUTPUT_VERSION < 6
-
-// test the SharedObject constuctor
-xcheck_equals (typeof(sharedobjectObj), 'object');
-
-// test the SharedObject::getlocal method
-check_equals (typeof(sharedobjectObj.getLocal), 'undefined');
-xcheck_equals (typeof(SharedObject.getLocal), 'function');
-
-check_totals(3);
-
-#else // OUTPUT_VERSION >= 6
-
// test the SharedObject constuctor
check_equals (typeof(sharedobjectObj), 'object');
@@ -47,36 +34,59 @@
check_equals (typeof(sharedobjectObj.getLocal), 'undefined');
check_equals (typeof(SharedObject.getLocal), 'function');
-// test the SharedObject.connect method (asnative 2106,0)
+#if OUTPUT_VERSION > 5
+
+check(SharedObject.prototype.hasOwnProperty("connect"));
+check(SharedObject.prototype.hasOwnProperty("send"));
+check(SharedObject.prototype.hasOwnProperty("flush"));
+check(SharedObject.prototype.hasOwnProperty("getSize"));
+check(SharedObject.prototype.hasOwnProperty("setFps"));
+check(SharedObject.prototype.hasOwnProperty("clear"));
+check(SharedObject.prototype.hasOwnProperty("close"));
+check(!SharedObject.prototype.hasOwnProperty("data"));
+
+check(!SharedObject.prototype.hasOwnProperty("getLocal"));
+check(!SharedObject.prototype.hasOwnProperty("getRemote"));
+check(!SharedObject.prototype.hasOwnProperty("getDiskUsage"));
+check(!SharedObject.prototype.hasOwnProperty("deleteAll"));
+check(SharedObject.hasOwnProperty("getLocal"));
+check(SharedObject.hasOwnProperty("getRemote"));
+check(SharedObject.hasOwnProperty("getDiskUsage"));
+check(SharedObject.hasOwnProperty("deleteAll"));
+
check_equals (typeof(sharedobjectObj.connect), 'function');
-
-// test the SharedObject.send method (asnative 2106,1)
check_equals (typeof(sharedobjectObj.send), 'function');
-
-// test the SharedObject.flush method (asnative 2106,2)
check_equals (typeof(sharedobjectObj.flush), 'function');
-
-// test the SharedObject.close method (asnative 2106,3)
check_equals (typeof(sharedobjectObj.close), 'function');
-
-// test the SharedObject.getsize method (asnative 2106,4)
check_equals (typeof(sharedobjectObj.getSize), 'function');
-
-// test the SharedObject.setFps method (asnative 2106,5)
check_equals (typeof(sharedobjectObj.setFps), 'function');
-
-// test the SharedObject.clear method (asnative 2106,6)
check_equals (typeof(sharedobjectObj.clear), 'function');
+check_equals (typeof(sharedobjectObj.data), 'undefined');
+#else
+check_equals (typeof(sharedobjectObj.connect), 'undefined');
+check_equals (typeof(sharedobjectObj.send), 'undefined');
+check_equals (typeof(sharedobjectObj.flush), 'undefined');
+check_equals (typeof(sharedobjectObj.close), 'undefined');
+check_equals (typeof(sharedobjectObj.getSize), 'undefined');
+check_equals (typeof(sharedobjectObj.setFps), 'undefined');
+check_equals (typeof(sharedobjectObj.clear), 'undefined');
+#endif
// FIXME: Test code that will soon be a formal test case.
so = SharedObject.getLocal("level1/level2/settings", "/");
+check(so instanceof SharedObject);
+
// Private data
so.name = "Joe";
so.age = 20;
so.pet = "Dog";
// public data that gets written
+#if OUTPUT_VERSION > 5
+check(so.hasOwnProperty("data"));
+#endif
+
so.data.gain = 50.0;
so.data.echosuppression = false;
so.data.defaultmicrophone = "/dev/input/mic";
@@ -110,13 +120,14 @@
so3 = SharedObject.getLocal("level1/level2/settings3", "/");
check(so3 != so);
+// Doesn't make much sense to test the rest for SWF5
+#if OUTPUT_VERSION > 5
// trace(so.getSize());
ret = so.flush();
check_equals(typeof(ret), 'boolean');
check_equals(ret, true);
-
newso = SharedObject.getLocal("level1/level2/settings", "/");
check_equals (typeof(newso), 'object');
trace(newso.getSize());
@@ -138,8 +149,6 @@
check_equals (typeof(newso.data.defaultalways), 'boolean');
check_equals (newso.data.defaultalways, so.data.defaultalways);
- // FIXME: why did all these start failing ? Accoring to dump() they
- // all still exist.
check_equals (typeof(newso.data.crossdomainAllow), 'boolean');
check_equals (newso.data.crossdomainAllow, true);
check_equals (typeof(newso.data.crossdomainAlways), 'boolean');
@@ -156,9 +165,9 @@
so4 = SharedObject.getLocal("Another-one", "/subdir");
check(so4 != so3);
-xcheck_equals(typeof(so4.data), 'undefined');
+check_equals(typeof(so4.data), 'undefined');
ret = so4.flush();
-xcheck_equals(typeof(ret), 'undefined');
+check_equals(typeof(ret), 'undefined');
//------------------------------------------
// Test that if 'data' is a getter-setter,
@@ -183,6 +192,10 @@
//------------------------------------------
so6 = SharedObject.getLocal("so6");
+check(so6.hasOwnProperty("data"));
+ret = so6.flush();
+check_equals(ret, true);
+
a = new Array;
for (var i in so6) a.push(i);
check_equals(a.toString(), 'data');
@@ -204,7 +217,12 @@
check_equals(typeof(so7), 'null');
#endif
so7.data.a = 1;
-so7.flush();
+ret = so7.flush();
+#if OUTPUT_VERSION < 7
+check_equals(ret, undefined);
+#else
+check_equals(ret, true);
+#endif
so8 = SharedObject.getLocal('');
check_equals(typeof(so8), 'null');
@@ -216,6 +234,12 @@
// END OF TESTS
//------------------------------------------
-check_totals(55);
-
-#endif // OUTPUT_VERSION >= 6
+check_totals(77);
+
+#else
+
+// SWF5 totals
+check_totals(17);
+
+#endif
+
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r10401: Various fixes to SharedObject AS compatibility.,
Benjamin Wolsey <=