David Rose 16 years ago
parent
commit
8c28147996

+ 1 - 0
direct/src/plugin/Sources.pp

@@ -13,6 +13,7 @@
   #define SOURCES \
     fileSpec.cxx fileSpec.h fileSpec.I \
     find_root_dir.cxx find_root_dir.h \
+    get_tinyxml.h \
     handleStream.cxx handleStream.h handleStream.I \
     handleStreamBuf.cxx handleStreamBuf.h \
     mkdir_complete.cxx mkdir_complete.h \

+ 1 - 1
direct/src/plugin/fileSpec.h

@@ -15,7 +15,7 @@
 #ifndef FILESPEC_H
 #define FILESPEC_H
 
-#include <tinyxml.h>
+#include "get_tinyxml.h"
 #include <string>
 using namespace std;
 

+ 28 - 0
direct/src/plugin/get_tinyxml.h

@@ -0,0 +1,28 @@
+// Filename: get_tinyxml.h
+// Created by:  drose (01Jul09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GET_TINYXML_H
+#define GET_TINYXML_H
+
+// This header file exists just to include tinyxml.h safely.  We need
+// this since tinyxml.h requires having the symbol TIXML_USE_STL
+// already defined before you include it.
+
+#ifndef TIXML_USE_STL
+#define TIXML_USE_STL
+#endif
+
+#include <tinyxml.h>
+
+#endif

+ 1 - 2
direct/src/plugin/p3dCInstance.h

@@ -19,10 +19,9 @@
 
 #include "p3d_plugin.h"
 #include "pvector.h"
+#include "get_tinyxml.h"
 
 #include <Python.h>
-#define TIXML_USE_STL
-#include <tinyxml.h>
 
 class P3DSession;
 

+ 1 - 2
direct/src/plugin/p3dFileParams.h

@@ -16,8 +16,7 @@
 #define P3DFILEPARAMS_H
 
 #include "p3d_plugin_common.h"
-
-#include <tinyxml.h>
+#include "get_tinyxml.h"
 #include <vector>
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
direct/src/plugin/p3dInstance.h

@@ -19,10 +19,10 @@
 #include "p3dFileDownload.h"
 #include "p3dFileParams.h"
 #include "p3dWindowParams.h"
+#include "get_tinyxml.h"
 
 #include <deque>
 #include <map>
-#include <tinyxml.h>
 
 class P3DSession;
 class P3DSplashWindow;

+ 1 - 1
direct/src/plugin/p3dPackage.h

@@ -18,7 +18,7 @@
 #include "p3d_plugin_common.h"
 #include "p3dFileDownload.h"
 #include "fileSpec.h"
-#include <tinyxml.h>
+#include "get_tinyxml.h"
 
 class P3DInstance;
 

+ 82 - 16
direct/src/plugin/p3dPythonRun.cxx

@@ -202,24 +202,35 @@ handle_command(TiXmlDocument *doc) {
         }
 
       } else if (strcmp(cmd, "terminate_instance") == 0) {
-        int id;
-        if (xcommand->Attribute("instance_id", &id)) {
-          terminate_instance(id);
+        int instance_id;
+        if (xcommand->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) {
+          terminate_instance(instance_id);
         }
 
       } else if (strcmp(cmd, "setup_window") == 0) {
-        int id;
+        int instance_id;
         TiXmlElement *xwparams = xcommand->FirstChildElement("wparams");
         if (xwparams != (TiXmlElement *)NULL && 
-            xcommand->Attribute("instance_id", &id)) {
-          setup_window(id, xwparams);
+            xcommand->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) {
+          setup_window(instance_id, xwparams);
         }
 
       } else if (strcmp(cmd, "exit") == 0) {
         terminate_session();
 
       } else if (strcmp(cmd, "feed_value") == 0) {
-        
+        int instance_id, unique_id;
+        TiXmlElement *xvalue = xcommand->FirstChildElement("value");
+        if (xvalue != (TiXmlElement *)NULL &&
+            xcommand->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS &&
+            xcommand->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) {
+          // TODO: deal with instance_id.
+          PyObject *value = from_xml_value(xvalue);
+          PyObject *result = PyObject_CallMethod
+            (_runner, (char*)"feedValue", (char*)"iO", unique_id, value);
+          Py_DECREF(value);
+          Py_XDECREF(result);
+        }
         
       } else {
         nout << "Unhandled command " << cmd << "\n";
@@ -330,7 +341,7 @@ py_request_func(PyObject *args) {
     }
 
     xrequest->SetAttribute("property_name", property_name);
-    append_xml_value(xrequest, value);
+    xrequest->LinkEndChild(make_xml_value(value));
     nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
 
@@ -345,7 +356,7 @@ py_request_func(PyObject *args) {
 
     xrequest->SetAttribute("property_name", property_name);
     xrequest->SetAttribute("unique_id", unique_id);
-    append_xml_value(xrequest, params);
+    xrequest->LinkEndChild(make_xml_value(params));
     nout << "sending " << doc << "\n" << flush;
     _pipe_write << doc << flush;
 
@@ -597,14 +608,14 @@ terminate_session() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DPythonRun::append_xml_value
+//     Function: P3DPythonRun::make_xml_value
 //       Access: Private
 //  Description: Converts the indicated PyObject to the appropriate
-//               XML representation of a P3D_value type, and appends
-//               it to the child list of the indicated element.
+//               XML representation of a P3D_value type, and returns a
+//               freshly-allocated TiXmlElement.
 ////////////////////////////////////////////////////////////////////
-void P3DPythonRun::
-append_xml_value(TiXmlElement *xelement, PyObject *value) {
+TiXmlElement *P3DPythonRun::
+make_xml_value(PyObject *value) {
   TiXmlElement *xvalue = new TiXmlElement("value");
   if (value == Py_None) {
     // None.
@@ -671,7 +682,7 @@ append_xml_value(TiXmlElement *xelement, PyObject *value) {
     Py_ssize_t length = PySequence_Length(value);
     for (Py_ssize_t i = 0; i < length; ++i) {
       PyObject *obj = PySequence_GetItem(value, i);
-      append_xml_value(xvalue, obj);
+      xvalue->LinkEndChild(make_xml_value(obj));
     }
 
   } else {
@@ -690,7 +701,62 @@ append_xml_value(TiXmlElement *xelement, PyObject *value) {
     }
   }
 
-  xelement->LinkEndChild(xvalue);
+  return xvalue;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::from_xml_value
+//       Access: Private
+//  Description: Converts the XML representation of a P3D_value type
+//               into the equivalent Python object and returns it.
+////////////////////////////////////////////////////////////////////
+PyObject *P3DPythonRun::
+from_xml_value(TiXmlElement *xvalue) {
+  const char *type = xvalue->Attribute("type");
+  if (strcmp(type, "none") == 0) {
+    return Py_BuildValue("");
+
+  } else if (strcmp(type, "bool") == 0) {
+    int value;
+    if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
+      return PyBool_FromLong(value);
+    }
+
+  } else if (strcmp(type, "int") == 0) {
+    int value;
+    if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
+      return PyInt_FromLong(value);
+    }
+
+  } else if (strcmp(type, "float") == 0) {
+    double value;
+    if (xvalue->QueryDoubleAttribute("value", &value) == TIXML_SUCCESS) {
+      return PyFloat_FromDouble(value);
+    }
+
+  } else if (strcmp(type, "string") == 0) {
+    // Using the string form here instead of the char * form, so we
+    // don't get tripped up on embedded null characters.
+    const string *value = xvalue->Attribute(string("value"));
+    if (value != NULL) {
+      return PyString_FromStringAndSize(value->data(), value->length());
+    }
+
+  } else if (strcmp(type, "list") == 0) {
+    PyObject *list = PyList_New(0);
+
+    TiXmlElement *xchild = xvalue->FirstChildElement("value");
+    while (xchild != NULL) {
+      PyObject *child = from_xml_value(xchild);
+      PyList_Append(list, child);
+      Py_DECREF(child);
+      xchild = xchild->NextSiblingElement("value");
+    }
+    return list;
+  }
+
+  // Something went wrong in decoding.
+  return Py_BuildValue("");
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
direct/src/plugin/p3dPythonRun.h

@@ -28,9 +28,9 @@
 #include "genericAsyncTask.h"
 #include "pmap.h"
 #include "pdeque.h"
+#include "get_tinyxml.h"
 
 #include <Python.h>
-#include <tinyxml.h>
 
 // Python 2.5 adds Py_ssize_t; earlier versions don't have it.
 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
@@ -88,7 +88,8 @@ private:
   void terminate_session();
 
 private:
-  void append_xml_value(TiXmlElement *xelement, PyObject *value);
+  TiXmlElement *make_xml_value(PyObject *value);
+  PyObject *from_xml_value(TiXmlElement *xvalue);
 
 private:
   // This method runs only within the read thread.

+ 1 - 1
direct/src/plugin/p3dSession.h

@@ -18,10 +18,10 @@
 #include "p3d_plugin_common.h"
 #include "handleStream.h"
 #include "p3dPackage.h"
+#include "get_tinyxml.h"
 
 #include <map>
 #include <vector>
-#include <tinyxml.h>
 
 class P3DInstance;
 class P3DProgressWindow;

+ 1 - 2
direct/src/plugin/p3dWindowParams.h

@@ -16,8 +16,7 @@
 #define P3DWINDOWPARAMS_H
 
 #include "p3d_plugin_common.h"
-
-#include <tinyxml.h>
+#include "get_tinyxml.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DWindowParams

+ 1 - 1
direct/src/plugin_npapi/ppInstance.h

@@ -17,9 +17,9 @@
 
 #include "nppanda3d_common.h"
 #include "fileSpec.h"
+#include "get_tinyxml.h"
 
 #include <vector>
-#include <tinyxml.h>
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PPInstance

+ 81 - 7
direct/src/plugin_standalone/panda3d.cxx

@@ -255,6 +255,68 @@ run(int argc, char *argv[]) {
   return 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Panda3D::feed_file
+//       Access: Private
+//  Description: Opens the named file (extracted from a file:// URL)
+//               and feeds its contents to the plugin.
+////////////////////////////////////////////////////////////////////
+void Panda3D::
+feed_file(P3D_instance *inst, int unique_id, string filename) {
+#ifdef _WIN32 
+  // On Windows, we have to munge the filename specially, because it's
+  // been URL-munged.  It might begin with a leading slash as well as
+  // a drive letter.  Clean up that nonsense.
+  if (!filename.empty()) {
+    if (filename[0] == '/' || filename[0] == '\\') {
+      Filename fname = Filename::from_os_specific(filename.substr(1));
+      if (fname.is_local()) {
+        // Put the slash back on.
+        fname = string("/") + fname.get_fullpath();
+      }
+      filename = fname.to_os_specific();
+    }
+  }
+#endif  // _WIN32
+
+  ifstream file(filename.c_str(), ios::in || ios::binary);
+
+  // First, seek to the end to get the file size.
+  file.seekg(0, ios::end);
+  size_t file_size = file.tellg();
+
+  // Then return to the beginning to read the data.
+  file.seekg(0, ios::beg);
+
+  static const size_t buffer_size = 4096;
+  char buffer[buffer_size];
+
+  file.read(buffer, buffer_size);
+  size_t count = file.gcount();
+  size_t total_count = 0;
+  while (count != 0) {
+    bool download_ok = P3D_instance_feed_url_stream
+      (inst, unique_id, P3D_RC_in_progress,
+       0, file_size, (const unsigned char *)buffer, count);
+
+    if (!download_ok) {
+      // Never mind.
+      return;
+    }
+    file.read(buffer, buffer_size);
+    count = file.gcount();
+    total_count += count;
+  }
+  
+  P3D_result_code result = P3D_RC_done;
+  if (file.fail() && !file.eof()) {
+    // Got an error while reading.
+    result = P3D_RC_generic_error;
+  }
+
+  P3D_instance_feed_url_stream
+    (inst, unique_id, result, 0, total_count, NULL, 0);
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3D::run_getters
@@ -305,10 +367,20 @@ handle_request(P3D_request *request) {
     cerr << "Got P3D_RT_get_url: " << request->_request._get_url._url
          << "\n";
     {
-      URLGetter *getter = new URLGetter
-        (request->_instance, request->_request._get_url._unique_id,
-         URLSpec(request->_request._get_url._url), "");
-      _url_getters.insert(getter);
+      int unique_id = request->_request._get_url._unique_id;
+      const string &url = request->_request._get_url._url;
+      if (url.substr(0, 7) == "file://") {
+        // A special case: if the url begins with "file://", just open
+        // the named file and feed it directly to the plugin.
+        feed_file(request->_instance, unique_id, url.substr(7));
+
+      } else {
+        // Otherwise, assume it's a legitimate URL and pass it down to
+        // Panda's HTTPClient to read it.
+        URLGetter *getter = new URLGetter
+          (request->_instance, unique_id, URLSpec(url), "");
+        _url_getters.insert(getter);
+      }
       handled = true;
     }
     break;
@@ -317,10 +389,12 @@ handle_request(P3D_request *request) {
     cerr << "Got P3D_RT_post_url: " << request->_request._post_url._url 
          << "\n";
     {
+      int unique_id = request->_request._post_url._unique_id;
+      const string &url = request->_request._post_url._url;
+      string post_data(request->_request._post_url._post_data, 
+                       request->_request._post_url._post_data_size);
       URLGetter *getter = new URLGetter
-        (request->_instance, request->_request._post_url._unique_id,
-         URLSpec(request->_request._post_url._url), 
-         string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
+        (request->_instance, unique_id, URLSpec(url), post_data);
       _url_getters.insert(getter);
       handled = true;
     }

+ 1 - 0
direct/src/plugin_standalone/panda3d.h

@@ -41,6 +41,7 @@ public:
   int run(int argc, char *argv[]);
 
 private:
+  void feed_file(P3D_instance *inst, int unique_id, string filename);
   void run_getters();
   void handle_request(P3D_request *request);
   void make_parent_window(P3D_window_handle &parent_window, 

+ 6 - 0
direct/src/showutil/runp3d.py

@@ -234,6 +234,12 @@ class AppRunner(DirectObject):
     def sendRequest(self, request, *args):
         self.requestFunc(self.instanceId, request, args)
 
+    def feedValue(self, uniqueId, value):
+        """ Called by the host in response to a 'get_property' or
+        'call' request. """
+
+        print "feedValue(%s, %s)" % (uniqueId, value)
+
     def windowEvent(self, win):
         print "Got window event in runp3d"