From: Nutchanon Wetchasit <Nutchanon.Wetchasit@gmail.com>
Subject: Test returning real JavaScript Object when libgnashplugin encountered "<object>" tag.
Bug: https://savannah.gnu.org/bugs/?32411

diff --git a/plugin/npapi/callbacks.cpp b/plugin/npapi/callbacks.cpp
index 081c72d..31aaf04 100644
--- a/plugin/npapi/callbacks.cpp
+++ b/plugin/npapi/callbacks.cpp
@@ -230,7 +230,7 @@ IsPlaying (NPObject *npobj, NPIdentifier /* name */, const NPVariant */*args */,
             return false;
         }
 
-        GnashNPVariant value = plugin::ExternalInterface::parseXML(data);
+        GnashNPVariant value = plugin::ExternalInterface::parseXML((GnashPluginScriptObject*)npobj, data);
         if (NPVARIANT_TO_BOOLEAN(value.get()) == true) {
             BOOLEAN_TO_NPVARIANT(true, *result);
         } else {
@@ -374,7 +374,7 @@ PercentLoaded (NPObject *npobj, NPIdentifier /* name */, const NPVariant */*args
             return false;
         }
         
-        GnashNPVariant value = plugin::ExternalInterface::parseXML(data);
+        GnashNPVariant value = plugin::ExternalInterface::parseXML((GnashPluginScriptObject*)npobj, data);
         if (NPVARIANT_IS_INT32(value.get())) {
             INT32_TO_NPVARIANT(NPVARIANT_TO_INT32(value.get()), *result);
         } else {
@@ -628,7 +628,7 @@ TotalFrames (NPObject *npobj, NPIdentifier /* name */, const NPVariant */*args *
             return false;
         }
 
-        GnashNPVariant value = plugin::ExternalInterface::parseXML(data);
+        GnashNPVariant value = plugin::ExternalInterface::parseXML((GnashPluginScriptObject*)npobj, data);
         if (NPVARIANT_IS_INT32(value.get())) {
             value.copy(*result);
         } else {
@@ -699,19 +699,9 @@ remoteCallback (NPObject *npobj, NPIdentifier name, const NPVariant *args,
         return false;
     }
 
-    std::string answer;
-    GnashNPVariant parsed = plugin::ExternalInterface::parseXML(data);
-    if (!NPVARIANT_IS_NULL(parsed.get())) {
-        answer = NPStringToString(NPVARIANT_TO_STRING(parsed.get()));
-    }
-    if (answer == "Error") {
-        NULL_TO_NPVARIANT(*result);
-    } else if (answer == "SecurityError") {
-        NULL_TO_NPVARIANT(*result);
-    } else {
-        parsed.copy(*result);
-    }
-    
+    GnashNPVariant parsed = plugin::ExternalInterface::parseXML((GnashPluginScriptObject*)npobj, data);
+    parsed.copy(*result);
+
     // printNPVariant(&parsed.get());
 
     // Returning false makes Javascript stop executing the script.
diff --git a/plugin/npapi/external.cpp b/plugin/npapi/external.cpp
index a1c199e..ed19b9a 100644
--- a/plugin/npapi/external.cpp
+++ b/plugin/npapi/external.cpp
@@ -200,7 +200,7 @@ ExternalInterface::makeObject (std::map<std::string, std::string> &args)
 //      </arguments>
 // </invoke>
 std::shared_ptr<ExternalInterface::invoke_t>
-ExternalInterface::parseInvoke(const std::string &xml)
+ExternalInterface::parseInvoke(GnashPluginScriptObject *scriptobj, const std::string &xml)
 {
     std::shared_ptr<ExternalInterface::invoke_t> invoke;
     if (xml.empty()) {
@@ -254,7 +254,7 @@ ExternalInterface::parseInvoke(const std::string &xml)
             end   = xml.find("</invoke");
             if (start != std::string::npos && end != std::string::npos) {
                     tag   = xml.substr(start, end-start);
-                    invoke->args = parseArguments(tag);
+                    invoke->args = parseArguments(scriptobj, tag);
                 }
         }
     }
@@ -263,7 +263,7 @@ ExternalInterface::parseInvoke(const std::string &xml)
 }
 
 GnashNPVariant 
-ExternalInterface::parseXML(const std::string &xml)
+ExternalInterface::parseXML(GnashPluginScriptObject *scriptobj, const std::string &xml)
 {
     NPVariant value;
     NULL_TO_NPVARIANT(value);
@@ -318,7 +318,7 @@ ExternalInterface::parseXML(const std::string &xml)
             end = xml.find("</array");
             if ( end != std::string::npos )  {
               std::string str = xml.substr(start, end-start);
-              std::map<std::string, GnashNPVariant> props = parseProperties(str);
+              std::map<std::string, GnashNPVariant> props = parseProperties(scriptobj, str);
               std::map<std::string, GnashNPVariant>::iterator it;
               for (it=props.begin(); it != props.end(); ++it) {
                   NPIdentifier id = NPN_GetStringIdentifier(it->first.c_str());
@@ -328,20 +328,39 @@ ExternalInterface::parseXML(const std::string &xml)
               OBJECT_TO_NPVARIANT(obj, value);
             }
         } else if (tag == "<object>") {
+            NPObject *jswindow;
+            NPObject *obj;
+            NPVariant objvar;
+
             start = end;
             end = xml.find("</object");
-            if ( end != std::string::npos )  {
-              NPObject *obj =  (NPObject *)NPN_MemAlloc(sizeof(NPObject));
-              obj->referenceCount = 1;
+            while ( end != std::string::npos )  {
+              // To create a new JavaScript Object, we call JavaScript's
+              // window.Object() method and use the returned NPObject.
+              // Then we assign members according to the received XML data.
+              if (NPN_GetValue(scriptobj->nppinstance, NPNVWindowNPObject,
+                               &jswindow) != NPERR_NO_ERROR) {
+                  break;
+              }
+              if (NPN_Invoke(scriptobj->nppinstance, jswindow,
+                             NPN_GetStringIdentifier("Object"),
+                             NULL, 0, &objvar) != NPERR_NO_ERROR) {
+                  NPN_ReleaseObject(jswindow);
+                  break;
+              }
+              obj = NPVARIANT_TO_OBJECT(objvar);
+
               std::string str = xml.substr(start, end-start);
-              std::map<std::string, GnashNPVariant> props = parseProperties(str);
+              std::map<std::string, GnashNPVariant> props = parseProperties(scriptobj, str);
               std::map<std::string, GnashNPVariant>::iterator it;
               for (it=props.begin(); it != props.end(); ++it) {
                   NPIdentifier id = NPN_GetStringIdentifier(it->first.c_str());
                   GnashNPVariant& value = it->second;
-                  NPN_SetProperty(nullptr, obj, id, &value.get());
+                  NPN_SetProperty(scriptobj->nppinstance, obj, id, &value.get());
               }
+              NPN_ReleaseObject(jswindow);
               OBJECT_TO_NPVARIANT(obj, value);
+              break;
             }
         }
     }
@@ -384,7 +403,7 @@ ExternalInterface::convertNPVariant (const NPVariant *value)
 }
 
 std::map<std::string, GnashNPVariant>
-ExternalInterface::parseProperties(const std::string &xml)
+ExternalInterface::parseProperties(GnashPluginScriptObject *scriptobj, const std::string &xml)
 {
     std::map<std::string, GnashNPVariant> props;
 
@@ -404,7 +423,7 @@ ExternalInterface::parseProperties(const std::string &xml)
         start = end + 2;
         end = xml.find("</property>", start) ;
         std::string data = xml.substr(start, end-start);
-        props[id] = parseXML(data);
+        props[id] = parseXML(scriptobj, data);
         start = xml.find(" id=", end);
     }
 
@@ -412,7 +431,7 @@ ExternalInterface::parseProperties(const std::string &xml)
 }
 
 std::vector<GnashNPVariant>
-ExternalInterface::parseArguments(const std::string &xml)
+ExternalInterface::parseArguments(GnashPluginScriptObject *scriptobj, const std::string &xml)
 {
     std::vector<GnashNPVariant> args;
 
@@ -437,7 +456,7 @@ ExternalInterface::parseArguments(const std::string &xml)
         if (data == "</arguments>") {
             break;
         }
-        args.push_back(parseXML(sub));
+        args.push_back(parseXML(scriptobj, sub));
         data.erase(0, end);
     }
 
diff --git a/plugin/npapi/external.h b/plugin/npapi/external.h
index 7a0aa67..60590cb 100644
--- a/plugin/npapi/external.h
+++ b/plugin/npapi/external.h
@@ -31,7 +31,7 @@
 #include "npapi.h"
 #include "npruntime.h"
 
-#include "GnashNPVariant.h"
+#include "pluginScriptObject.h"
 
 namespace gnash {
 
@@ -61,11 +61,11 @@ struct ExternalInterface
     static std::string makeArray (std::vector<std::string> &args);
     static std::string makeObject (std::map<std::string, std::string> &args);
     
-    static GnashNPVariant parseXML(const std::string &xml);
-    static std::shared_ptr<invoke_t> parseInvoke(const std::string &xml);
+    static GnashNPVariant parseXML(GnashPluginScriptObject *scriptobj, const std::string &xml);
+    static std::shared_ptr<invoke_t> parseInvoke(GnashPluginScriptObject *scriptobj, const std::string &xml);
     
-    static std::map<std::string, GnashNPVariant> parseProperties(const std::string &xml);
-    static std::vector<GnashNPVariant> parseArguments(const std::string &xml);
+    static std::map<std::string, GnashNPVariant> parseProperties(GnashPluginScriptObject *scriptobj, const std::string &xml);
+    static std::vector<GnashNPVariant> parseArguments(GnashPluginScriptObject *scriptobj, const std::string &xml);
     static std::string convertNPVariant (const NPVariant *npv);
 };
 
diff --git a/plugin/npapi/plugin.cpp b/plugin/npapi/plugin.cpp
index 3c6f423..7d81489 100644
--- a/plugin/npapi/plugin.cpp
+++ b/plugin/npapi/plugin.cpp
@@ -821,7 +821,7 @@ nsPluginInstance::processPlayerRequest()
         // Extract a message from the packet
         std::string msg = packet.substr(0, pos + term.size());
         std::shared_ptr<plugin::ExternalInterface::invoke_t> invoke =
-            plugin::ExternalInterface::parseInvoke(msg);
+            plugin::ExternalInterface::parseInvoke(_scriptObject, msg);
 
         // drop the parsed message from the packet
         packet.erase(0, msg.size());
diff --git a/plugin/npapi/pluginScriptObject.cpp b/plugin/npapi/pluginScriptObject.cpp
index 3b599c8..2320cc3 100644
--- a/plugin/npapi/pluginScriptObject.cpp
+++ b/plugin/npapi/pluginScriptObject.cpp
@@ -125,7 +125,7 @@ GnashPluginScriptObject::initializeIdentifiers()
 {
     // log_debug("initializeIdentifiers");
 
-//    NPN_Status(_nppinstance, __FUNCTION__);
+//    NPN_Status(nppinstance, __FUNCTION__);
     
 //    http://www.adobe.com/support/flash/publishexport/scriptingwithflash/scriptingwithflash_04.html
     
@@ -247,7 +247,7 @@ GnashPluginScriptObject::initializeIdentifiers()
 
 // Constructor
 GnashPluginScriptObject::GnashPluginScriptObject()
-    : _nppinstance (nullptr),
+    : nppinstance (nullptr),
       _controlfd(-1),
       _hostfd(-1)
 {
@@ -259,7 +259,7 @@ GnashPluginScriptObject::GnashPluginScriptObject()
 
 // Constructor
 GnashPluginScriptObject::GnashPluginScriptObject(NPP npp)
-    : _nppinstance (npp),
+    : nppinstance (npp),
       _controlfd(-1),
       _hostfd(-1)
 {
@@ -519,7 +519,7 @@ GnashPluginScriptObject::Invoke(NPObject */* npobj */, NPIdentifier name,
 
     return false;
     
-//    return NPN_Invoke(_nppinstance, this, name, args, argCount, result);
+//    return NPN_Invoke(nppinstance, this, name, args, argCount, result);
 }
 
 bool
@@ -621,7 +621,7 @@ GnashPluginScriptObject::GetVariable(const std::string &name)
         return GnashNPVariant();
     }
 
-    GnashNPVariant parsed = plugin::ExternalInterface::parseXML(data);
+    GnashNPVariant parsed = plugin::ExternalInterface::parseXML(this, data);
 
     printNPVariant(&parsed.get());
     
diff --git a/plugin/npapi/pluginScriptObject.h b/plugin/npapi/pluginScriptObject.h
index 2a8b7aa..5847829 100644
--- a/plugin/npapi/pluginScriptObject.h
+++ b/plugin/npapi/pluginScriptObject.h
@@ -138,6 +138,10 @@ public:
     void AddProperty(const std::string &name, double num);
     void AddProperty(const std::string &name, int num);
 
+    /// Plugin instance object
+    // nppinstance->pdata should be the nsPluginInstance once NPP_New() is finished.
+    NPP nppinstance;
+
 protected:
     // Internal functions for the API
     void Deallocate();
@@ -155,10 +159,7 @@ protected:
 
 private:
     void initializeIdentifiers();
-    void setInstance(NPP inst) { _nppinstance = inst; };
-    
-    // _nppinstance->pdata should be the nsPluginInstance once NPP_New() is finished.
-    NPP _nppinstance;
+    void setInstance(NPP inst) { nppinstance = inst; };
     
     std::map<NPIdentifier, GnashNPVariant> _properties;
     std::map<NPIdentifier, NPInvokeFunctionPtr> _methods;
