Browse Source

Merge remote-tracking branch 'origin/master' into cmake

Sam Edwards 7 years ago
parent
commit
56a6e6a80a
39 changed files with 310 additions and 223 deletions
  1. 12 10
      README.md
  2. 4 2
      direct/src/distributed/cConnectionRepository.cxx
  3. 15 0
      dtool/src/dtoolbase/pvector.h
  4. 56 8
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  5. 5 0
      dtool/src/parser-inc/stdtypedefs.h
  6. 4 3
      dtool/src/prc/encryptStreamBuf.cxx
  7. 7 5
      dtool/src/prc/streamReader.cxx
  8. 2 1
      dtool/src/prc/streamReader.h
  9. 3 2
      makepanda/makepanda.py
  10. 18 37
      panda/src/downloader/downloadDb.cxx
  11. 4 4
      panda/src/downloader/downloadDb.h
  12. 9 10
      panda/src/downloader/socketStream.cxx
  13. 2 1
      panda/src/downloader/socketStream.h
  14. 2 1
      panda/src/event/asyncTaskChain.cxx
  15. 22 52
      panda/src/express/datagram.I
  16. 4 10
      panda/src/express/datagram.h
  17. 5 6
      panda/src/express/datagramIterator.I
  18. 7 7
      panda/src/express/datagramIterator.cxx
  19. 2 2
      panda/src/express/datagramIterator.h
  20. 3 3
      panda/src/express/hashVal.cxx
  21. 2 2
      panda/src/express/hashVal.h
  22. 2 4
      panda/src/express/multifile.cxx
  23. 26 0
      panda/src/express/pointerToArray.I
  24. 2 0
      panda/src/express/pointerToArray.h
  25. 10 0
      panda/src/express/pointerToArrayBase.I
  26. 1 0
      panda/src/express/pointerToArrayBase.h
  27. 9 6
      panda/src/ffmpeg/config_ffmpeg.cxx
  28. 1 0
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  29. 3 1
      panda/src/gobj/texture.cxx
  30. 4 4
      panda/src/gobj/texture.h
  31. 6 5
      panda/src/movies/wavAudioCursor.cxx
  32. 6 7
      panda/src/net/datagramTCPHeader.cxx
  33. 8 7
      panda/src/net/datagramUDPHeader.cxx
  34. 19 9
      panda/src/putil/datagramInputFile.cxx
  35. 4 2
      panda/src/recorder/socketStreamRecorder.cxx
  36. 4 8
      pandatool/src/flt/fltBeadID.cxx
  37. 3 2
      pandatool/src/flt/fltRecord.cxx
  38. 2 2
      tests/bullet/test_bullet_bam.py
  39. 12 0
      tests/putil/test_datagram.py

+ 12 - 10
README.md

@@ -43,24 +43,26 @@ Building Panda3D
 Windows
 Windows
 -------
 -------
 
 
-We currently build using the Microsoft Visual C++ 2010 compiler.  You do not
-need Microsoft Visual Studio to build Panda3D, though - the relevant compilers
-are included as part of the Windows 7.1 SDK.
+We currently build using the Microsoft Visual C++ 2015 compiler.  You will
+also need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk),
+and if you intend to target Windows XP, you will also need the
+[Windows 7.1 SDK](https://www.microsoft.com/en-us/download/details.aspx?id=8279).
 
 
 You will also need to have the third-party dependency libraries available for
 You will also need to have the third-party dependency libraries available for
 the build scripts to use.  These are available from one of these two URLs,
 the build scripts to use.  These are available from one of these two URLs,
-depending on whether you are on a 32-bit or 64-bit system:
-https://www.panda3d.org/download/panda3d-1.9.4/panda3d-1.9.4-tools-win32.zip
-https://www.panda3d.org/download/panda3d-1.9.4/panda3d-1.9.4-tools-win64.zip
+depending on whether you are on a 32-bit or 64-bit system, or you can
+[click here](https://github.com/rdb/panda3d-thirdparty) for instructions on
+building them from source.
 
 
-(It is also possible to build using MSVC 2015 and 2017, which requires a
-different set of thirdparty libraries, but that is not described here.)
+http://rdb.name/thirdparty-vc14-x64.7z
+http://rdb.name/thirdparty-vc14.7z
 
 
 After acquiring these dependencies, you may simply build Panda3D from the
 After acquiring these dependencies, you may simply build Panda3D from the
-command prompt using the following command:
+command prompt using the following command.  (Add the `--windows-sdk=10`
+option if you don't need to support Windows XP.)
 
 
 ```bash
 ```bash
-makepanda\makepanda.bat --everything --installer --no-eigen
+makepanda\makepanda.bat --everything --installer --no-eigen --threads=2
 ```
 ```
 
 
 When the build succeeds, it will produce an .exe file that you can use to
 When the build succeeds, it will produce an .exe file that you can use to

+ 4 - 2
direct/src/distributed/cConnectionRepository.cxx

@@ -803,8 +803,9 @@ handle_update_field_owner() {
       Py_DECREF(dclass_this);
       Py_DECREF(dclass_this);
 
 
       // check if we should forward this update to the owner view
       // check if we should forward this update to the owner view
+      vector_uchar data = _di.get_remaining_bytes();
       DCPacker packer;
       DCPacker packer;
-      packer.set_unpack_data(_di.get_remaining_bytes());
+      packer.set_unpack_data((const char *)data.data(), data.size(), false);
       int field_id = packer.raw_unpack_uint16();
       int field_id = packer.raw_unpack_uint16();
       DCField *field = dclass->get_field_by_index(field_id);
       DCField *field = dclass->get_field_by_index(field_id);
       if (field->is_ownrecv()) {
       if (field->is_ownrecv()) {
@@ -845,8 +846,9 @@ handle_update_field_owner() {
       Py_DECREF(dclass_this);
       Py_DECREF(dclass_this);
 
 
       // check if we should forward this update to the owner view
       // check if we should forward this update to the owner view
+      vector_uchar data = _di.get_remaining_bytes();
       DCPacker packer;
       DCPacker packer;
-      packer.set_unpack_data(_di.get_remaining_bytes());
+      packer.set_unpack_data((const char *)data.data(), data.size(), false);
       int field_id = packer.raw_unpack_uint16();
       int field_id = packer.raw_unpack_uint16();
       DCField *field = dclass->get_field_by_index(field_id);
       DCField *field = dclass->get_field_by_index(field_id);
       if (true) {//field->is_broadcast()) {
       if (true) {//field->is_broadcast()) {

+ 15 - 0
dtool/src/dtoolbase/pvector.h

@@ -46,9 +46,24 @@ public:
   typedef TYPENAME base_class::size_type size_type;
   typedef TYPENAME base_class::size_type size_type;
 
 
   explicit pvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator(type_handle)) { }
   explicit pvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator(type_handle)) { }
+  pvector(const pvector<Type> &copy) : base_class(copy) { }
   explicit pvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator(type_handle)) { }
   explicit pvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator(type_handle)) { }
   explicit pvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator(type_handle)) { }
   explicit pvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator(type_handle)) { }
   pvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator(type_handle)) { }
   pvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator(type_handle)) { }
+
+#ifdef USE_MOVE_SEMANTICS
+  pvector(pvector<Type> &&from) NOEXCEPT : base_class(move(from)) {};
+
+  pvector<Type> &operator =(pvector<Type> &&from) NOEXCEPT {
+    base_class::operator =(move(from));
+    return *this;
+  }
+#endif
+
+  pvector<Type> &operator =(const pvector<Type> &copy) {
+    base_class::operator =(copy);
+    return *this;
+  }
 };
 };
 
 
 #endif  // USE_STL_ALLOCATOR
 #endif  // USE_STL_ALLOCATOR

+ 56 - 8
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -5414,6 +5414,18 @@ write_function_instance(ostream &out, FunctionRemap *remap,
         parameter_list += ", &" + param_name;
         parameter_list += ", &" + param_name;
       }
       }
 
 
+      // If the default value is NULL, we also accept a None value.
+      bool maybe_none = false;
+      if (default_value != nullptr && (return_flags & RF_coerced) == 0) {
+        CPPExpression::Result res = param->get_default_value()->evaluate();
+        if (res._type == CPPExpression::RT_integer ||
+            res._type == CPPExpression::RT_pointer) {
+          if (res.as_integer() == 0) {
+            maybe_none = true;
+          }
+        }
+      }
+
       string class_name = obj_type->get_local_name(&parser);
       string class_name = obj_type->get_local_name(&parser);
 
 
       // need to a forward scope for this class..
       // need to a forward scope for this class..
@@ -5464,17 +5476,27 @@ write_function_instance(ostream &out, FunctionRemap *remap,
 
 
           type->output_instance(extra_convert, param_name + "_this", &parser);
           type->output_instance(extra_convert, param_name + "_this", &parser);
 
 
-          if (is_optional) {
+          if (is_optional && maybe_none) {
+            extra_convert
+              << default_expr << ";\n"
+              << "if (" << param_name << " != NULL && " << param_name << " != Py_None) {\n"
+              << "  " << param_name << "_this";
+          } else if (is_optional) {
             extra_convert
             extra_convert
               << default_expr << ";\n"
               << default_expr << ";\n"
               << "if (" << param_name << " != NULL) {\n"
               << "if (" << param_name << " != NULL) {\n"
               << "  " << param_name << "_this";
               << "  " << param_name << "_this";
+          } else if (maybe_none) {
+            extra_convert
+              << " = NULL;\n"
+              << "if (" << param_name << " != Py_None) {\n"
+              << "  " << param_name << "_this";
           }
           }
 
 
           extra_convert << " = Dtool_Coerce_" + make_safe_name(class_name) +
           extra_convert << " = Dtool_Coerce_" + make_safe_name(class_name) +
             "(" + param_name + ", " + param_name + "_local);\n";
             "(" + param_name + ", " + param_name + "_local);\n";
 
 
-          if (is_optional) {
+          if (is_optional || maybe_none) {
             extra_convert << "}\n";
             extra_convert << "}\n";
           }
           }
 
 
@@ -5485,8 +5507,12 @@ write_function_instance(ostream &out, FunctionRemap *remap,
 
 
         if (report_errors) {
         if (report_errors) {
           // We were asked to report any errors.  Let's do it.
           // We were asked to report any errors.  Let's do it.
-          if (is_optional) {
+          if (is_optional && maybe_none) {
+            extra_convert << "if (" << param_name << " != NULL && " << param_name << " != Py_None && !" << coerce_call << ") {\n";
+          } else if (is_optional) {
             extra_convert << "if (" << param_name << " != NULL && !" << coerce_call << ") {\n";
             extra_convert << "if (" << param_name << " != NULL && !" << coerce_call << ") {\n";
+          } else if (maybe_none) {
+            extra_convert << "if (" << param_name << " != Py_None && !" << coerce_call << ") {\n";
           } else {
           } else {
             extra_convert << "if (!" << coerce_call << ") {\n";
             extra_convert << "if (!" << coerce_call << ") {\n";
           }
           }
@@ -5509,19 +5535,35 @@ write_function_instance(ostream &out, FunctionRemap *remap,
           }
           }
           extra_convert << "}\n";
           extra_convert << "}\n";
 
 
+        } else if (is_optional && maybe_none) {
+          extra_param_check << " && (" << param_name << " == NULL || " << param_name << " == Py_None || " << coerce_call << ")";
+
         } else if (is_optional) {
         } else if (is_optional) {
           extra_param_check << " && (" << param_name << " == NULL || " << coerce_call << ")";
           extra_param_check << " && (" << param_name << " == NULL || " << coerce_call << ")";
 
 
+        } else if (maybe_none) {
+          extra_param_check << " && (" << param_name << " == Py_None || " << coerce_call << ")";
+
         } else {
         } else {
           extra_param_check << " && " << coerce_call;
           extra_param_check << " && " << coerce_call;
         }
         }
 
 
-      } else {
+      } else { // The regular, non-coercion case.
         type->output_instance(extra_convert, param_name + "_this", &parser);
         type->output_instance(extra_convert, param_name + "_this", &parser);
-        if (is_optional) {
+        if (is_optional && maybe_none) {
+          extra_convert
+            << default_expr << ";\n"
+            << "if (" << param_name << " != NULL && " << param_name << " != Py_None) {\n"
+            << "  " << param_name << "_this";
+        } else if (is_optional) {
           extra_convert
           extra_convert
             << default_expr << ";\n"
             << default_expr << ";\n"
-            << "if (" << param_name << " != (PyObject *)NULL) {\n"
+            << "if (" << param_name << " != NULL) {\n"
+            << "  " << param_name << "_this";
+        } else if (maybe_none) {
+          extra_convert
+            << " = NULL;\n"
+            << "if (" << param_name << " != Py_None) {\n"
             << "  " << param_name << "_this";
             << "  " << param_name << "_this";
         }
         }
         if (const_ok && !report_errors) {
         if (const_ok && !report_errors) {
@@ -5529,7 +5571,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
           // simpler.  But maybe we should just reorganize these functions
           // simpler.  But maybe we should just reorganize these functions
           // entirely?
           // entirely?
           extra_convert << " = NULL;\n";
           extra_convert << " = NULL;\n";
-          int indent_level = is_optional ? 2 : 0;
+          int indent_level = (is_optional || maybe_none) ? 2 : 0;
           indent(extra_convert, indent_level)
           indent(extra_convert, indent_level)
             << "DtoolInstance_GetPointer(" << param_name
             << "DtoolInstance_GetPointer(" << param_name
             << ", " << param_name << "_this"
             << ", " << param_name << "_this"
@@ -5545,9 +5587,15 @@ write_function_instance(ostream &out, FunctionRemap *remap,
             << "\", " << const_ok << ", " << report_errors << ");\n";
             << "\", " << const_ok << ", " << report_errors << ");\n";
         }
         }
 
 
-        if (is_optional) {
+        if (is_optional && maybe_none) {
+          extra_convert << "}\n";
+          extra_param_check << " && (" << param_name << " == NULL || " << param_name << " == Py_None || " << param_name << "_this != NULL)";
+        } else if (is_optional) {
           extra_convert << "}\n";
           extra_convert << "}\n";
           extra_param_check << " && (" << param_name << " == NULL || " << param_name << "_this != NULL)";
           extra_param_check << " && (" << param_name << " == NULL || " << param_name << "_this != NULL)";
+        } else if (maybe_none) {
+          extra_convert << "}\n";
+          extra_param_check << " && (" << param_name << " == Py_None || " << param_name << "_this != NULL)";
         } else {
         } else {
           extra_param_check << " && " << param_name << "_this != NULL";
           extra_param_check << " && " << param_name << "_this != NULL";
         }
         }

+ 5 - 0
dtool/src/parser-inc/stdtypedefs.h

@@ -41,6 +41,11 @@ inline namespace std {
 
 
 struct timeval;
 struct timeval;
 
 
+#ifdef __cplusplus
+#define NULL 0L
+#else
+#define NULL ((void *)0)
+#endif
 typedef decltype(nullptr) nullptr_t;
 typedef decltype(nullptr) nullptr_t;
 
 
 // One day, we might extend interrogate to be able to parse this,
 // One day, we might extend interrogate to be able to parse this,

+ 4 - 3
dtool/src/prc/encryptStreamBuf.cxx

@@ -146,14 +146,15 @@ open_read(istream *source, bool owns_source, const string &password) {
   int iv_length = EVP_CIPHER_iv_length(cipher);
   int iv_length = EVP_CIPHER_iv_length(cipher);
   _read_block_size = EVP_CIPHER_block_size(cipher);
   _read_block_size = EVP_CIPHER_block_size(cipher);
 
 
-  string iv = sr.extract_bytes(iv_length);
+  unsigned char *iv = (unsigned char *)alloca(iv_length);
+  iv_length = (int)sr.extract_bytes(iv, iv_length);
 
 
   _read_ctx = EVP_CIPHER_CTX_new();
   _read_ctx = EVP_CIPHER_CTX_new();
   nassertv(_read_ctx != NULL);
   nassertv(_read_ctx != NULL);
 
 
   // Initialize the context
   // Initialize the context
   int result;
   int result;
-  result = EVP_DecryptInit(_read_ctx, cipher, NULL, (unsigned char *)iv.data());
+  result = EVP_DecryptInit(_read_ctx, cipher, NULL, (unsigned char *)iv);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   result = EVP_CIPHER_CTX_set_key_length(_read_ctx, key_length);
   result = EVP_CIPHER_CTX_set_key_length(_read_ctx, key_length);
@@ -170,7 +171,7 @@ open_read(istream *source, bool owns_source, const string &password) {
   unsigned char *key = (unsigned char *)alloca(key_length);
   unsigned char *key = (unsigned char *)alloca(key_length);
   result =
   result =
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
-                           (unsigned char *)iv.data(), iv.length(),
+                           iv, iv_length,
                            count * iteration_count_factor + 1,
                            count * iteration_count_factor + 1,
                            key_length, key);
                            key_length, key);
   nassertv(result > 0);
   nassertv(result > 0);

+ 7 - 5
dtool/src/prc/streamReader.cxx

@@ -117,16 +117,18 @@ extract_bytes(unsigned char *into, size_t size) {
  * Extracts the indicated number of bytes in the stream and returns them as a
  * Extracts the indicated number of bytes in the stream and returns them as a
  * string.  Returns empty string at end-of-file.
  * string.  Returns empty string at end-of-file.
  */
  */
-string StreamReader::
+vector_uchar StreamReader::
 extract_bytes(size_t size) {
 extract_bytes(size_t size) {
+  vector_uchar buffer;
   if (_in->eof() || _in->fail()) {
   if (_in->eof() || _in->fail()) {
-    return string();
+    return buffer;
   }
   }
 
 
-  char *buffer = (char *)alloca(size);
-  _in->read(buffer, size);
+  buffer.resize(size);
+  _in->read((char *)&buffer[0], size);
   size_t read_bytes = _in->gcount();
   size_t read_bytes = _in->gcount();
-  return string(buffer, read_bytes);
+  buffer.resize(read_bytes);
+  return buffer;
 }
 }
 
 
 /**
 /**

+ 2 - 1
dtool/src/prc/streamReader.h

@@ -19,6 +19,7 @@
 #include "numeric_types.h"
 #include "numeric_types.h"
 #include "littleEndian.h"
 #include "littleEndian.h"
 #include "bigEndian.h"
 #include "bigEndian.h"
+#include "vector_uchar.h"
 
 
 /**
 /**
  * A class to read sequential binary data directly from an istream.  Its
  * A class to read sequential binary data directly from an istream.  Its
@@ -71,7 +72,7 @@ PUBLISHED:
   EXTENSION(BLOCKING PyObject *readlines());
   EXTENSION(BLOCKING PyObject *readlines());
 
 
 public:
 public:
-  BLOCKING string extract_bytes(size_t size);
+  BLOCKING vector_uchar extract_bytes(size_t size);
   BLOCKING string readline();
   BLOCKING string readline();
 
 
 private:
 private:

+ 3 - 2
makepanda/makepanda.py

@@ -552,6 +552,7 @@ if (COMPILER == "MSVC"):
     PkgDisable("EGL")
     PkgDisable("EGL")
     PkgDisable("CARBON")
     PkgDisable("CARBON")
     PkgDisable("COCOA")
     PkgDisable("COCOA")
+    DefSymbol("FLEX", "YY_NO_UNISTD_H")
     if (PkgSkip("PYTHON")==0):
     if (PkgSkip("PYTHON")==0):
         IncDirectory("ALWAYS", SDK["PYTHON"] + "/include")
         IncDirectory("ALWAYS", SDK["PYTHON"] + "/include")
         LibDirectory("ALWAYS", SDK["PYTHON"] + "/libs")
         LibDirectory("ALWAYS", SDK["PYTHON"] + "/libs")
@@ -827,7 +828,7 @@ if (COMPILER=="GCC"):
         SmartPkgEnable("EIGEN",     "eigen3",    (), ("Eigen/Dense",), target_pkg = 'ALWAYS')
         SmartPkgEnable("EIGEN",     "eigen3",    (), ("Eigen/Dense",), target_pkg = 'ALWAYS')
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
-        SmartPkgEnable("ASSIMP",    "assimp", ("assimp"), "assimp")
+        SmartPkgEnable("ASSIMP",    "",          ("assimp"), "assimp")
         SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h"))
         SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h"))
         SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
@@ -1396,7 +1397,7 @@ def CompileBison(wobj, wsrc, opts):
         CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile+".h")
         CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile+".h")
 
 
     # Finally, compile the generated source file.
     # Finally, compile the generated source file.
-    CompileCxx(wobj,wdstc,opts)
+    CompileCxx(wobj, wdstc, opts + ["FLEX"])
 
 
 ########################################################################
 ########################################################################
 ##
 ##

+ 18 - 37
panda/src/downloader/downloadDb.cxx

@@ -583,9 +583,7 @@ add_multifile_record(PT(MultifileRecord) mfr) {
  * Verifies magic number, returns the number of multifiles or -1 if invalid
  * Verifies magic number, returns the number of multifiles or -1 if invalid
  */
  */
 int DownloadDb::Db::
 int DownloadDb::Db::
-parse_header(const string &data) {
-  Datagram dg(data);
-
+parse_header(Datagram dg) {
   // Make sure we have a good header
   // Make sure we have a good header
   DatagramIterator di(dg);
   DatagramIterator di(dg);
   uint32_t magic_number = di.get_uint32();
   uint32_t magic_number = di.get_uint32();
@@ -623,8 +621,7 @@ parse_header(const string &data) {
  * record
  * record
  */
  */
 int DownloadDb::Db::
 int DownloadDb::Db::
-parse_record_header(const string &data) {
-  Datagram dg(data);
+parse_record_header(Datagram dg) {
   DatagramIterator di(dg);
   DatagramIterator di(dg);
   int32_t record_length = di.get_int32();
   int32_t record_length = di.get_int32();
   downloader_cat.spam()
   downloader_cat.spam()
@@ -639,14 +636,12 @@ parse_record_header(const string &data) {
  * Parses a multifile record (mfr) and returns one
  * Parses a multifile record (mfr) and returns one
  */
  */
 PT(DownloadDb::MultifileRecord) DownloadDb::Db::
 PT(DownloadDb::MultifileRecord) DownloadDb::Db::
-parse_mfr(const string &data) {
+parse_mfr(Datagram dg) {
 
 
   PT(DownloadDb::MultifileRecord) mfr = new DownloadDb::MultifileRecord;
   PT(DownloadDb::MultifileRecord) mfr = new DownloadDb::MultifileRecord;
 
 
-  Datagram dg(data);
   DatagramIterator di(dg);
   DatagramIterator di(dg);
-  int32_t mfr_name_length = di.get_int32();
-  mfr->_name = di.extract_bytes(mfr_name_length);
+  mfr->_name = di.get_string32();
   mfr->_phase = di.get_float64();
   mfr->_phase = di.get_float64();
   mfr->_size = di.get_int32();
   mfr->_size = di.get_int32();
   mfr->_status = di.get_int32();
   mfr->_status = di.get_int32();
@@ -676,14 +671,12 @@ parse_mfr(const string &data) {
  * Parses a file record (fr) and returns one
  * Parses a file record (fr) and returns one
  */
  */
 PT(DownloadDb::FileRecord) DownloadDb::Db::
 PT(DownloadDb::FileRecord) DownloadDb::Db::
-parse_fr(const string &data) {
+parse_fr(Datagram dg) {
 
 
   PT(DownloadDb::FileRecord) fr = new DownloadDb::FileRecord;
   PT(DownloadDb::FileRecord) fr = new DownloadDb::FileRecord;
 
 
-  Datagram dg(data);
   DatagramIterator di(dg);
   DatagramIterator di(dg);
-  int32_t fr_name_length = di.get_int32();
-  fr->_name = di.extract_bytes(fr_name_length);
+  fr->_name = di.get_string32();
 
 
   // At one time, we stored files in the database with a backslash separator.
   // At one time, we stored files in the database with a backslash separator.
   // Nowadays we use a forward slash, but we should make sure we properly
   // Nowadays we use a forward slash, but we should make sure we properly
@@ -706,15 +699,14 @@ parse_fr(const string &data) {
 bool DownloadDb::Db::
 bool DownloadDb::Db::
 read(StreamReader &sr, bool want_server_info) {
 read(StreamReader &sr, bool want_server_info) {
   // Read the header
   // Read the header
-  string header;
-  header = sr.extract_bytes(_header_length);
+  vector_uchar header = sr.extract_bytes(_header_length);
   if (header.size() != (size_t)_header_length) {
   if (header.size() != (size_t)_header_length) {
     downloader_cat.error() << "truncated db file" << endl;
     downloader_cat.error() << "truncated db file" << endl;
     return false;
     return false;
   }
   }
 
 
   // Parse the header
   // Parse the header
-  int num_multifiles = parse_header(header);
+  int num_multifiles = parse_header(Datagram(move(header)));
   if (num_multifiles < 0) {
   if (num_multifiles < 0) {
     downloader_cat.error() << "invalid db header" << endl;
     downloader_cat.error() << "invalid db header" << endl;
     return false;
     return false;
@@ -727,26 +719,26 @@ read(StreamReader &sr, bool want_server_info) {
     // of the record
     // of the record
     int mfr_header_length = sizeof(int32_t);
     int mfr_header_length = sizeof(int32_t);
 
 
-    string mfr_header = sr.extract_bytes(mfr_header_length);
+    vector_uchar mfr_header = sr.extract_bytes(mfr_header_length);
     if (mfr_header.size() != (size_t)mfr_header_length) {
     if (mfr_header.size() != (size_t)mfr_header_length) {
       downloader_cat.error() << "invalid mfr header" << endl;
       downloader_cat.error() << "invalid mfr header" << endl;
       return false;
       return false;
     }
     }
 
 
     // Parse the header
     // Parse the header
-    int mfr_length = parse_record_header(mfr_header);
+    int mfr_length = parse_record_header(Datagram(move(mfr_header)));
 
 
     // Ok, now that we know the size of the mfr, read it in Make a buffer to
     // Ok, now that we know the size of the mfr, read it in Make a buffer to
     // read the multifile record into do not count the header length twice
     // read the multifile record into do not count the header length twice
     int read_length = (mfr_length - mfr_header_length);
     int read_length = (mfr_length - mfr_header_length);
-    string mfr_record = sr.extract_bytes(read_length);
+    vector_uchar mfr_record = sr.extract_bytes(read_length);
     if (mfr_record.size() != (size_t)read_length) {
     if (mfr_record.size() != (size_t)read_length) {
       downloader_cat.error() << "invalid mfr record" << endl;
       downloader_cat.error() << "invalid mfr record" << endl;
       return false;
       return false;
     }
     }
 
 
     // Parse the mfr
     // Parse the mfr
-    PT(DownloadDb::MultifileRecord) mfr = parse_mfr(mfr_record);
+    PT(DownloadDb::MultifileRecord) mfr = parse_mfr(Datagram(move(mfr_record)));
 
 
     // Only read in the individual file info if you are the server
     // Only read in the individual file info if you are the server
     if (want_server_info) {
     if (want_server_info) {
@@ -758,27 +750,27 @@ read(StreamReader &sr, bool want_server_info) {
         int fr_header_length = sizeof(int32_t);
         int fr_header_length = sizeof(int32_t);
 
 
         // Read the header
         // Read the header
-        string fr_header = sr.extract_bytes(fr_header_length);
+        vector_uchar fr_header = sr.extract_bytes(fr_header_length);
         if (fr_header.size() != (size_t)fr_header_length) {
         if (fr_header.size() != (size_t)fr_header_length) {
           downloader_cat.error() << "invalid fr header" << endl;
           downloader_cat.error() << "invalid fr header" << endl;
           return false;
           return false;
         }
         }
 
 
         // Parse the header
         // Parse the header
-        int fr_length = parse_record_header(fr_header);
+        int fr_length = parse_record_header(Datagram(move(fr_header)));
 
 
         // Ok, now that we know the size of the mfr, read it in do not count
         // Ok, now that we know the size of the mfr, read it in do not count
         // the header length twice
         // the header length twice
         int read_length = (fr_length - fr_header_length);
         int read_length = (fr_length - fr_header_length);
 
 
-        string fr_record = sr.extract_bytes(read_length);
+        vector_uchar fr_record = sr.extract_bytes(read_length);
         if (fr_record.size() != (size_t)read_length) {
         if (fr_record.size() != (size_t)read_length) {
           downloader_cat.error() << "invalid fr record" << endl;
           downloader_cat.error() << "invalid fr record" << endl;
           return false;
           return false;
         }
         }
 
 
         // Parse the file record
         // Parse the file record
-        PT(DownloadDb::FileRecord) fr = parse_fr(fr_record);
+        PT(DownloadDb::FileRecord) fr = parse_fr(Datagram(move(fr_record)));
 
 
         // Add this file record to the current multifilerecord
         // Add this file record to the current multifilerecord
         mfr->add_file_record(fr);
         mfr->add_file_record(fr);
@@ -900,12 +892,10 @@ write_header(ostream &write_stream) {
   // Write the number of multifiles
   // Write the number of multifiles
   dg.add_int32(get_num_multifiles());
   dg.add_int32(get_num_multifiles());
 
 
-  string msg = dg.get_message();
-
   // Seek back to the beginning of the write stream
   // Seek back to the beginning of the write stream
   write_stream.seekp(0);
   write_stream.seekp(0);
   // Overwrite the old bogus header with the real header
   // Overwrite the old bogus header with the real header
-  write_stream.write(msg.data(), msg.length());
+  write_stream.write((const char *)dg.get_data(), dg.get_length());
   return true;
   return true;
 }
 }
 
 
@@ -1100,17 +1090,8 @@ read_version_map(StreamReader &sr) {
 
 
   for (int i = 0; i < num_entries; i++) {
   for (int i = 0; i < num_entries; i++) {
 
 
-    // Get the length of the file name
-    int name_length = sr.get_int32();
-    if (sr.get_istream()->fail()) {
-      return false;
-    }
-    downloader_cat.spam()
-      << "DownloadDb::read_version_map() - name length: " << name_length
-      << endl;
-
     // Get the file name
     // Get the file name
-    string name = sr.extract_bytes(name_length);
+    string name = sr.get_string32();
     downloader_cat.spam()
     downloader_cat.spam()
       << "DownloadDb::read_version_map() - name: " << name << endl;
       << "DownloadDb::read_version_map() - name: " << name << endl;
 
 

+ 4 - 4
panda/src/downloader/downloadDb.h

@@ -171,10 +171,10 @@ public:
     bool multifile_exists(string mfname) const;
     bool multifile_exists(string mfname) const;
     PT(MultifileRecord) get_multifile_record_named(string mfname) const;
     PT(MultifileRecord) get_multifile_record_named(string mfname) const;
     void add_multifile_record(PT(MultifileRecord) mfr);
     void add_multifile_record(PT(MultifileRecord) mfr);
-    int parse_header(const string &data);
-    int parse_record_header(const string &data);
-    PT(MultifileRecord) parse_mfr(const string &data);
-    PT(FileRecord) parse_fr(const string &data);
+    int parse_header(Datagram dg);
+    int parse_record_header(Datagram dg);
+    PT(MultifileRecord) parse_mfr(Datagram dg);
+    PT(FileRecord) parse_fr(Datagram dg);
     bool read(StreamReader &sr, bool want_server_info);
     bool read(StreamReader &sr, bool want_server_info);
     bool write(StreamWriter &sw, bool want_server_info);
     bool write(StreamWriter &sw, bool want_server_info);
     Filename _filename;
     Filename _filename;

+ 9 - 10
panda/src/downloader/socketStream.cxx

@@ -50,17 +50,17 @@ SSReader::
 bool SSReader::
 bool SSReader::
 do_receive_datagram(Datagram &dg) {
 do_receive_datagram(Datagram &dg) {
   if (_tcp_header_size == 0) {
   if (_tcp_header_size == 0) {
-    _data_expected = _data_so_far.length();
+    _data_expected = _data_so_far.size();
   }
   }
   if (_data_expected == 0) {
   if (_data_expected == 0) {
     // Read the first two bytes: the datagram length.
     // Read the first two bytes: the datagram length.
-    while ((int)_data_so_far.length() < _tcp_header_size) {
+    while ((int)_data_so_far.size() < _tcp_header_size) {
       int ch = _istream->get();
       int ch = _istream->get();
       if (_istream->eof() || _istream->fail()) {
       if (_istream->eof() || _istream->fail()) {
         _istream->clear();
         _istream->clear();
         return false;
         return false;
       }
       }
-      _data_so_far += (char)ch;
+      _data_so_far.push_back((unsigned char)ch);
     }
     }
 
 
     Datagram header(_data_so_far);
     Datagram header(_data_so_far);
@@ -70,7 +70,7 @@ do_receive_datagram(Datagram &dg) {
     } else if (_tcp_header_size == 4) {
     } else if (_tcp_header_size == 4) {
       _data_expected = di.get_uint32();
       _data_expected = di.get_uint32();
     }
     }
-    _data_so_far = _data_so_far.substr(_tcp_header_size);
+    _data_so_far.erase(_data_so_far.begin(), _data_so_far.begin() + _tcp_header_size);
 
 
     if (_data_expected == 0) {
     if (_data_expected == 0) {
       // Empty datagram.
       // Empty datagram.
@@ -84,20 +84,19 @@ do_receive_datagram(Datagram &dg) {
   static const size_t buffer_size = 1024;
   static const size_t buffer_size = 1024;
   char buffer[buffer_size];
   char buffer[buffer_size];
 
 
-  size_t read_count = min(_data_expected - _data_so_far.length(),
-                          buffer_size);
+  size_t read_count = min(_data_expected - _data_so_far.size(), buffer_size);
   _istream->read(buffer, read_count);
   _istream->read(buffer, read_count);
   size_t count = _istream->gcount();
   size_t count = _istream->gcount();
   while (count != 0) {
   while (count != 0) {
-    _data_so_far.append(buffer, count);
+    _data_so_far.insert(_data_so_far.end(), buffer, buffer + count);
 
 
-    read_count = min(_data_expected - _data_so_far.length(),
+    read_count = min(_data_expected - _data_so_far.size(),
                      buffer_size);
                      buffer_size);
     _istream->read(buffer, read_count);
     _istream->read(buffer, read_count);
     count = _istream->gcount();
     count = _istream->gcount();
   }
   }
 
 
-  if (_data_so_far.length() < _data_expected) {
+  if (_data_so_far.size() < _data_expected) {
     // Not yet here.  Clear the istream error flag and return false to
     // Not yet here.  Clear the istream error flag and return false to
     // indicate more coming.
     // indicate more coming.
     _istream->clear();
     _istream->clear();
@@ -108,7 +107,7 @@ do_receive_datagram(Datagram &dg) {
   dg.append_data(_data_so_far);
   dg.append_data(_data_so_far);
 
 
   _data_expected = 0;
   _data_expected = 0;
-  _data_so_far = string();
+  _data_so_far.clear();
 
 
   return true;
   return true;
 }
 }

+ 2 - 1
panda/src/downloader/socketStream.h

@@ -21,6 +21,7 @@
 #include "pdeque.h"
 #include "pdeque.h"
 #include "typedReferenceCount.h"
 #include "typedReferenceCount.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
+#include "vector_uchar.h"
 
 
 // At the present, this module is not compiled if OpenSSL is not available,
 // At the present, this module is not compiled if OpenSSL is not available,
 // since the only current use for it is to implement OpenSSL-defined
 // since the only current use for it is to implement OpenSSL-defined
@@ -54,7 +55,7 @@ private:
 
 
   istream *_istream;
   istream *_istream;
   size_t _data_expected;
   size_t _data_expected;
-  string _data_so_far;
+  vector_uchar _data_so_far;
   int _tcp_header_size;
   int _tcp_header_size;
 
 
 #ifdef SIMULATE_NETWORK_DELAY
 #ifdef SIMULATE_NETWORK_DELAY

+ 2 - 1
panda/src/event/asyncTaskChain.cxx

@@ -477,6 +477,7 @@ do_remove(AsyncTask *task, bool upon_death) {
     {
     {
       int index = find_task_on_heap(_sleeping, task);
       int index = find_task_on_heap(_sleeping, task);
       nassertr(index != -1, false);
       nassertr(index != -1, false);
+      PT(AsyncTask) hold_task = task;
       _sleeping.erase(_sleeping.begin() + index);
       _sleeping.erase(_sleeping.begin() + index);
       make_heap(_sleeping.begin(), _sleeping.end(), AsyncTaskSortWakeTime());
       make_heap(_sleeping.begin(), _sleeping.end(), AsyncTaskSortWakeTime());
       cleanup_task(task, upon_death, false);
       cleanup_task(task, upon_death, false);
@@ -486,6 +487,7 @@ do_remove(AsyncTask *task, bool upon_death) {
   case AsyncTask::S_active:
   case AsyncTask::S_active:
     {
     {
       // Active, but not being serviced, easy.
       // Active, but not being serviced, easy.
+      PT(AsyncTask) hold_task = task;
       int index = find_task_on_heap(_active, task);
       int index = find_task_on_heap(_active, task);
       if (index != -1) {
       if (index != -1) {
         _active.erase(_active.begin() + index);
         _active.erase(_active.begin() + index);
@@ -769,7 +771,6 @@ cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit) {
   }
   }
 
 
   nassertv(task->_chain == this);
   nassertv(task->_chain == this);
-  PT(AsyncTask) hold_task = task;
 
 
   task->_state = AsyncTask::S_inactive;
   task->_state = AsyncTask::S_inactive;
   task->_chain = nullptr;
   task->_chain = nullptr;

+ 22 - 52
panda/src/express/datagram.I

@@ -42,58 +42,16 @@ Datagram(const void *data, size_t size) :
  * Constructs a datagram from an existing block of data.
  * Constructs a datagram from an existing block of data.
  */
  */
 INLINE Datagram::
 INLINE Datagram::
-Datagram(const string &data) :
+Datagram(vector_uchar data) :
+  _data(move(data)),
 #ifdef STDFLOAT_DOUBLE
 #ifdef STDFLOAT_DOUBLE
   _stdfloat_double(true)
   _stdfloat_double(true)
 #else
 #else
   _stdfloat_double(false)
   _stdfloat_double(false)
 #endif
 #endif
 {
 {
-  append_data(data);
 }
 }
 
 
-/**
- *
- */
-INLINE Datagram::
-Datagram(const Datagram &copy) :
-  _data(copy._data),
-  _stdfloat_double(copy._stdfloat_double)
-{
-}
-
-/**
- *
- */
-INLINE void Datagram::
-operator = (const Datagram &copy) {
-  _data = copy._data;
-  _stdfloat_double = copy._stdfloat_double;
-}
-
-#ifdef USE_MOVE_SEMANTICS
-/**
- *
- */
-INLINE Datagram::
-Datagram(Datagram &&from) NOEXCEPT :
-  _data(move(from._data)),
-  _stdfloat_double(from._stdfloat_double)
-{
-}
-#endif  // USE_MOVE_SEMANTICS
-
-#ifdef USE_MOVE_SEMANTICS
-/**
- *
- */
-INLINE void Datagram::
-operator = (Datagram &&from) NOEXCEPT {
-  _data = move(from._data);
-  _stdfloat_double = from._stdfloat_double;
-}
-#endif  // USE_MOVE_SEMANTICS
-
 /**
 /**
  * Adds a boolean value to the datagram.
  * Adds a boolean value to the datagram.
  */
  */
@@ -291,7 +249,7 @@ add_string(const string &str) {
   add_uint16((uint16_t)str.length());
   add_uint16((uint16_t)str.length());
 
 
   // Add the string
   // Add the string
-  append_data(str);
+  append_data(str.data(), str.length());
 }
 }
 
 
 /**
 /**
@@ -304,18 +262,18 @@ add_string32(const string &str) {
   add_uint32((uint32_t)str.length());
   add_uint32((uint32_t)str.length());
 
 
   // Add the string
   // Add the string
-  append_data(str);
+  append_data(str.data(), str.length());
 }
 }
 
 
 /**
 /**
  * Adds a variable-length string to the datagram, as a NULL-terminated string.
  * Adds a variable-length string to the datagram, as a NULL-terminated string.
  */
  */
 INLINE void Datagram::
 INLINE void Datagram::
-add_z_string(string str) {
+add_z_string(const string &str) {
   // We must not have any nested null characters in the string.
   // We must not have any nested null characters in the string.
   size_t null_pos = str.find('\0');
   size_t null_pos = str.find('\0');
   // Add the string (sans the null character).
   // Add the string (sans the null character).
-  append_data(str.substr(0, null_pos));
+  append_data(str.data(), std::min<size_t>(null_pos, str.length()));
 
 
   // And the null character.
   // And the null character.
   add_uint8('\0');
   add_uint8('\0');
@@ -329,11 +287,11 @@ add_z_string(string str) {
 INLINE void Datagram::
 INLINE void Datagram::
 add_fixed_string(const string &str, size_t size) {
 add_fixed_string(const string &str, size_t size) {
   if (str.length() < size) {
   if (str.length() < size) {
-    append_data(str);
+    append_data(str.data(), str.length());
     pad_bytes(size - str.length());
     pad_bytes(size - str.length());
 
 
   } else { // str.length() >= size
   } else { // str.length() >= size
-    append_data(str.substr(0, size));
+    append_data(str.data(), size);
   }
   }
 }
 }
 
 
@@ -341,8 +299,8 @@ add_fixed_string(const string &str, size_t size) {
  * Appends some more raw data to the end of the datagram.
  * Appends some more raw data to the end of the datagram.
  */
  */
 INLINE void Datagram::
 INLINE void Datagram::
-append_data(const string &data) {
-  append_data(data.data(), data.length());
+append_data(const vector_uchar &data) {
+  append_data(data.data(), data.size());
 }
 }
 
 
 /**
 /**
@@ -358,6 +316,18 @@ get_message() const {
   }
   }
 }
 }
 
 
+/**
+ * Returns the datagram's data as a bytes object.
+ */
+INLINE vector_uchar Datagram::
+__bytes__() const {
+  if (!_data.empty()) {
+    return vector_uchar(_data.v());
+  } else {
+    return vector_uchar();
+  }
+}
+
 /**
 /**
  * Returns a pointer to the beginning of the datagram's data.
  * Returns a pointer to the beginning of the datagram's data.
  */
  */

+ 4 - 10
panda/src/express/datagram.h

@@ -39,14 +39,7 @@ class EXPCL_PANDAEXPRESS Datagram : public TypedObject {
 PUBLISHED:
 PUBLISHED:
   INLINE Datagram();
   INLINE Datagram();
   INLINE Datagram(const void *data, size_t size);
   INLINE Datagram(const void *data, size_t size);
-  INLINE Datagram(const string &data);
-  INLINE Datagram(const Datagram &copy);
-  INLINE void operator = (const Datagram &copy);
-
-#ifdef USE_MOVE_SEMANTICS
-  INLINE Datagram(Datagram &&from) NOEXCEPT;
-  INLINE void operator = (Datagram &&from) NOEXCEPT;
-#endif
+  INLINE explicit Datagram(vector_uchar data);
 
 
   virtual ~Datagram();
   virtual ~Datagram();
 
 
@@ -80,17 +73,18 @@ PUBLISHED:
 
 
   INLINE void add_string(const string &str);
   INLINE void add_string(const string &str);
   INLINE void add_string32(const string &str);
   INLINE void add_string32(const string &str);
-  INLINE void add_z_string(string str);
+  INLINE void add_z_string(const string &str);
   INLINE void add_fixed_string(const string &str, size_t size);
   INLINE void add_fixed_string(const string &str, size_t size);
   void add_wstring(const wstring &str);
   void add_wstring(const wstring &str);
 
 
   void pad_bytes(size_t size);
   void pad_bytes(size_t size);
   void append_data(const void *data, size_t size);
   void append_data(const void *data, size_t size);
-  INLINE void append_data(const string &data);
+  INLINE void append_data(const vector_uchar &data);
 
 
   void assign(const void *data, size_t size);
   void assign(const void *data, size_t size);
 
 
   INLINE string get_message() const;
   INLINE string get_message() const;
+  INLINE vector_uchar __bytes__() const;
   INLINE const void *get_data() const;
   INLINE const void *get_data() const;
   INLINE size_t get_length() const;
   INLINE size_t get_length() const;
 
 

+ 5 - 6
panda/src/express/datagramIterator.I

@@ -422,14 +422,13 @@ skip_bytes(size_t size) {
  * Returns the remaining bytes in the datagram as a string, but does not
  * Returns the remaining bytes in the datagram as a string, but does not
  * extract them from the iterator.
  * extract them from the iterator.
  */
  */
-INLINE string DatagramIterator::
+INLINE vector_uchar DatagramIterator::
 get_remaining_bytes() const {
 get_remaining_bytes() const {
-  nassertr(_datagram != (const Datagram *)NULL, "");
-  nassertr(_current_index <= _datagram->get_length(), "");
+  nassertr(_datagram != (const Datagram *)NULL, vector_uchar());
+  nassertr(_current_index <= _datagram->get_length(), vector_uchar());
 
 
-  const char *ptr = (const char *)_datagram->get_data();
-  size_t remaining_size = _datagram->get_length() - _current_index;
-  return string(ptr + _current_index, remaining_size);
+  const unsigned char *ptr = (const unsigned char *)_datagram->get_data();
+  return vector_uchar(ptr + _current_index, ptr + _datagram->get_length());
 }
 }
 
 
 /**
 /**

+ 7 - 7
panda/src/express/datagramIterator.cxx

@@ -119,18 +119,18 @@ get_wstring() {
  * Extracts the indicated number of bytes in the datagram and returns them as
  * Extracts the indicated number of bytes in the datagram and returns them as
  * a string.
  * a string.
  */
  */
-string DatagramIterator::
+vector_uchar DatagramIterator::
 extract_bytes(size_t size) {
 extract_bytes(size_t size) {
-  nassertr((int)size >= 0, "");
-  nassertr(_datagram != (const Datagram *)NULL, "");
-  nassertr(_current_index + size <= _datagram->get_length(), "");
+  nassertr((int)size >= 0, vector_uchar());
+  nassertr(_datagram != (const Datagram *)NULL, vector_uchar());
+  nassertr(_current_index + size <= _datagram->get_length(), vector_uchar());
 
 
-  const char *ptr = (const char *)_datagram->get_data();
-  size_t last_index = _current_index;
+  const unsigned char *ptr = (const unsigned char *)_datagram->get_data();
+  ptr += _current_index;
 
 
   _current_index += size;
   _current_index += size;
 
 
-  return string(ptr + last_index, size);
+  return vector_uchar(ptr, ptr + size);
 }
 }
 
 
 /**
 /**

+ 2 - 2
panda/src/express/datagramIterator.h

@@ -62,10 +62,10 @@ PUBLISHED:
   wstring get_wstring();
   wstring get_wstring();
 
 
   INLINE void skip_bytes(size_t size);
   INLINE void skip_bytes(size_t size);
-  string extract_bytes(size_t size);
+  vector_uchar extract_bytes(size_t size);
   size_t extract_bytes(unsigned char *into, size_t size);
   size_t extract_bytes(unsigned char *into, size_t size);
 
 
-  INLINE string get_remaining_bytes() const;
+  INLINE vector_uchar get_remaining_bytes() const;
   INLINE size_t get_remaining_size() const;
   INLINE size_t get_remaining_size() const;
 
 
   INLINE const Datagram &get_datagram() const;
   INLINE const Datagram &get_datagram() const;

+ 3 - 3
panda/src/express/hashVal.cxx

@@ -143,11 +143,11 @@ set_from_hex(const string &text) {
 /**
 /**
  * Returns the HashVal as a 16-byte binary string.
  * Returns the HashVal as a 16-byte binary string.
  */
  */
-string HashVal::
+vector_uchar HashVal::
 as_bin() const {
 as_bin() const {
   Datagram dg;
   Datagram dg;
   write_datagram(dg);
   write_datagram(dg);
-  return dg.get_message();
+  return vector_uchar((unsigned char *)dg.get_data(), (unsigned char *)dg.get_data() + dg.get_length());
 }
 }
 
 
 /**
 /**
@@ -155,7 +155,7 @@ as_bin() const {
  * false otherwise.
  * false otherwise.
  */
  */
 bool HashVal::
 bool HashVal::
-set_from_bin(const string &text) {
+set_from_bin(const vector_uchar &text) {
   nassertr(text.size() == 16, false);
   nassertr(text.size() == 16, false);
   Datagram dg(text);
   Datagram dg(text);
   DatagramIterator dgi(dg);
   DatagramIterator dgi(dg);

+ 2 - 2
panda/src/express/hashVal.h

@@ -55,8 +55,8 @@ PUBLISHED:
   string as_hex() const;
   string as_hex() const;
   bool set_from_hex(const string &text);
   bool set_from_hex(const string &text);
 
 
-  string as_bin() const;
-  bool set_from_bin(const string &text);
+  vector_uchar as_bin() const;
+  bool set_from_bin(const vector_uchar &text);
 
 
   INLINE void write_datagram(Datagram &destination) const;
   INLINE void write_datagram(Datagram &destination) const;
   INLINE void read_datagram(DatagramIterator &source);
   INLINE void read_datagram(DatagramIterator &source);

+ 2 - 4
panda/src/express/multifile.cxx

@@ -2402,7 +2402,7 @@ check_signatures() {
     nassertv(stream != NULL);
     nassertv(stream != NULL);
     StreamReader reader(*stream);
     StreamReader reader(*stream);
     size_t sig_size = reader.get_uint32();
     size_t sig_size = reader.get_uint32();
-    string sig_string = reader.extract_bytes(sig_size);
+    vector_uchar sig_data = reader.extract_bytes(sig_size);
 
 
     size_t num_certs = reader.get_uint32();
     size_t num_certs = reader.get_uint32();
 
 
@@ -2470,9 +2470,7 @@ check_signatures() {
 
 
       // Now check that the signature matches the hash.
       // Now check that the signature matches the hash.
       int verify_result =
       int verify_result =
-        EVP_VerifyFinal(md_ctx,
-                        (unsigned char *)sig_string.data(),
-                        sig_string.size(), pkey);
+        EVP_VerifyFinal(md_ctx, sig_data.data(), sig_data.size(), pkey);
       if (verify_result == 1) {
       if (verify_result == 1) {
         // The signature matches; save the certificate and its chain.
         // The signature matches; save the certificate and its chain.
         _signatures.push_back(chain);
         _signatures.push_back(chain);

+ 26 - 0
panda/src/express/pointerToArray.I

@@ -92,6 +92,19 @@ PointerToArray(PointerToArray<Element> &&from) NOEXCEPT :
 }
 }
 #endif  // USE_MOVE_SEMANTICS
 #endif  // USE_MOVE_SEMANTICS
 
 
+#ifdef USE_MOVE_SEMANTICS
+/**
+ * Initializes the PTA from a vector.
+ */
+template<class Element>
+INLINE PointerToArray<Element>::
+PointerToArray(pvector<Element> &&from, TypeHandle type_handle) :
+  PointerToArrayBase<Element>(new ReferenceCountedVector<Element>(move(from))),
+  _type_handle(type_handle)
+{
+}
+#endif  // USE_MOVE_SEMANTICS
+
 /**
 /**
  *
  *
  */
  */
@@ -710,6 +723,19 @@ ConstPointerToArray(ConstPointerToArray<Element> &&from) NOEXCEPT :
 }
 }
 #endif  // USE_MOVE_SEMANTICS
 #endif  // USE_MOVE_SEMANTICS
 
 
+#ifdef USE_MOVE_SEMANTICS
+/**
+ * Initializes the PTA from a vector.
+ */
+template<class Element>
+INLINE ConstPointerToArray<Element>::
+ConstPointerToArray(pvector<Element> &&from, TypeHandle type_handle) :
+  PointerToArrayBase<Element>(new ReferenceCountedVector<Element>(move(from))),
+  _type_handle(type_handle)
+{
+}
+#endif  // USE_MOVE_SEMANTICS
+
 /**
 /**
  *
  *
  */
  */

+ 2 - 0
panda/src/express/pointerToArray.h

@@ -141,6 +141,7 @@ public:
 
 
 #ifdef USE_MOVE_SEMANTICS
 #ifdef USE_MOVE_SEMANTICS
   INLINE PointerToArray(PointerToArray<Element> &&from) NOEXCEPT;
   INLINE PointerToArray(PointerToArray<Element> &&from) NOEXCEPT;
+  INLINE explicit PointerToArray(pvector<Element> &&from, TypeHandle type_handle = get_type_handle(Element));
 #endif
 #endif
 
 
 public:
 public:
@@ -302,6 +303,7 @@ PUBLISHED:
 #ifdef USE_MOVE_SEMANTICS
 #ifdef USE_MOVE_SEMANTICS
   INLINE ConstPointerToArray(PointerToArray<Element> &&from) NOEXCEPT;
   INLINE ConstPointerToArray(PointerToArray<Element> &&from) NOEXCEPT;
   INLINE ConstPointerToArray(ConstPointerToArray<Element> &&from) NOEXCEPT;
   INLINE ConstPointerToArray(ConstPointerToArray<Element> &&from) NOEXCEPT;
+  INLINE explicit ConstPointerToArray(pvector<Element> &&from, TypeHandle type_handle = get_type_handle(Element));
 #endif
 #endif
 
 
   // Duplicating the interface of vector.
   // Duplicating the interface of vector.

+ 10 - 0
panda/src/express/pointerToArrayBase.I

@@ -39,6 +39,16 @@ ReferenceCountedVector(const Element *begin, const Element *end, TypeHandle type
 {
 {
 }
 }
 
 
+/**
+ * Creates an array that takes its elements from the given vector.
+ */
+template<class Element>
+INLINE ReferenceCountedVector<Element>::
+ReferenceCountedVector(pvector<Element> &&from) :
+  pvector<Element>(move(from))
+{
+}
+
 /**
 /**
  *
  *
  */
  */

+ 1 - 0
panda/src/express/pointerToArrayBase.h

@@ -43,6 +43,7 @@ public:
   INLINE ReferenceCountedVector(TypeHandle type_handle);
   INLINE ReferenceCountedVector(TypeHandle type_handle);
   INLINE ReferenceCountedVector(size_type initial_size, TypeHandle type_handle);
   INLINE ReferenceCountedVector(size_type initial_size, TypeHandle type_handle);
   INLINE ReferenceCountedVector(const Element *begin, const Element *end, TypeHandle type_handle);
   INLINE ReferenceCountedVector(const Element *begin, const Element *end, TypeHandle type_handle);
+  INLINE ReferenceCountedVector(pvector<Element> &&from);
   ALLOC_DELETED_CHAIN(ReferenceCountedVector<Element>);
   ALLOC_DELETED_CHAIN(ReferenceCountedVector<Element>);
 
 
   INLINE size_type size() const;
   INLINE size_type size() const;

+ 9 - 6
panda/src/ffmpeg/config_ffmpeg.cxx

@@ -30,16 +30,19 @@ extern "C" {
   #error Buildsystem error: BUILDING_FFMPEG not defined
   #error Buildsystem error: BUILDING_FFMPEG not defined
 #endif
 #endif
 
 
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 86, 100)
-  #error Minimum supported version of libavcodec is 54.86.100.
+// Minimum supported versions:
+// FFmpeg: 1.1
+// libav: 9.20 (for Ubuntu 14.04)
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 35, 1)
+  #error Minimum supported version of libavcodec is 54.35.1.
 #endif
 #endif
 
 
-#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(54, 59, 106)
-  #error Minimum supported version of libavformat is 54.59.106.
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(54, 20, 4)
+  #error Minimum supported version of libavformat is 54.20.4.
 #endif
 #endif
 
 
-#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 13, 100)
-  #error Minimum supported version of libavutil is 52.13.100.
+#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 3, 0)
+  #error Minimum supported version of libavutil is 52.3.0.
 #endif
 #endif
 
 
 ConfigureDef(config_ffmpeg);
 ConfigureDef(config_ffmpeg);

+ 1 - 0
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -1767,6 +1767,7 @@ resolve_multisamples() {
   }
   }
   glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo);
   glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo);
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);
+  glgsg->_current_fbo = fbo;
 
 
   // If the depth buffer is shared, resolve it only on the last to render FBO.
   // If the depth buffer is shared, resolve it only on the last to render FBO.
   bool do_depth_blit = false;
   bool do_depth_blit = false;

+ 3 - 1
panda/src/gobj/texture.cxx

@@ -4207,7 +4207,9 @@ bool Texture::
 do_read_ktx(CData *cdata, istream &in, const string &filename, bool header_only) {
 do_read_ktx(CData *cdata, istream &in, const string &filename, bool header_only) {
   StreamReader ktx(in);
   StreamReader ktx(in);
 
 
-  if (ktx.extract_bytes(12) != "\xABKTX 11\xBB\r\n\x1A\n") {
+  unsigned char magic[12];
+  if (ktx.extract_bytes(magic, 12) != 12 ||
+      memcmp(magic, "\xABKTX 11\xBB\r\n\x1A\n", 12) != 0) {
     gobj_cat.error()
     gobj_cat.error()
       << filename << " is not a KTX file.\n";
       << filename << " is not a KTX file.\n";
     return false;
     return false;

+ 4 - 4
panda/src/gobj/texture.h

@@ -464,10 +464,10 @@ PUBLISHED:
   MAKE_PROPERTY(keep_ram_image, get_keep_ram_image, set_keep_ram_image);
   MAKE_PROPERTY(keep_ram_image, get_keep_ram_image, set_keep_ram_image);
   MAKE_PROPERTY(cacheable, is_cacheable);
   MAKE_PROPERTY(cacheable, is_cacheable);
 
 
-  INLINE bool compress_ram_image(CompressionMode compression = CM_on,
-                                 QualityLevel quality_level = QL_default,
-                                 GraphicsStateGuardianBase *gsg = NULL);
-  INLINE bool uncompress_ram_image();
+  BLOCKING INLINE bool compress_ram_image(CompressionMode compression = CM_on,
+                                          QualityLevel quality_level = QL_default,
+                                          GraphicsStateGuardianBase *gsg = NULL);
+  BLOCKING INLINE bool uncompress_ram_image();
 
 
   INLINE int get_num_ram_mipmap_images() const;
   INLINE int get_num_ram_mipmap_images() const;
   INLINE bool has_ram_mipmap_image(int n) const;
   INLINE bool has_ram_mipmap_image(int n) const;

+ 6 - 5
panda/src/movies/wavAudioCursor.cxx

@@ -106,7 +106,8 @@ WavAudioCursor(WavAudio *src, istream *stream) :
   nassertv(stream != NULL);
   nassertv(stream != NULL);
 
 
   // Beginning of "RIFF" chunk.
   // Beginning of "RIFF" chunk.
-  if (_reader.extract_bytes(4) != "RIFF") {
+  unsigned char magic[4];
+  if (_reader.extract_bytes(magic, 4) != 4 || memcmp(magic, "RIFF", 4) != 0) {
     movies_cat.error()
     movies_cat.error()
       << ".wav file is not a valid RIFF file.\n";
       << ".wav file is not a valid RIFF file.\n";
     return;
     return;
@@ -114,7 +115,7 @@ WavAudioCursor(WavAudio *src, istream *stream) :
 
 
   unsigned int chunk_size = _reader.get_uint32();
   unsigned int chunk_size = _reader.get_uint32();
 
 
-  if (_reader.extract_bytes(4) != "WAVE") {
+  if (_reader.extract_bytes(magic, 4) != 4 || memcmp(magic, "WAVE", 4) != 0) {
     movies_cat.error()
     movies_cat.error()
       << ".wav file is a RIFF file but does not start with a WAVE chunk.\n";
       << ".wav file is a RIFF file but does not start with a WAVE chunk.\n";
     return;
     return;
@@ -126,10 +127,10 @@ WavAudioCursor(WavAudio *src, istream *stream) :
 
 
   while ((!have_fmt || !have_data) && _stream->good() && (bytes_read + 8) < chunk_size) {
   while ((!have_fmt || !have_data) && _stream->good() && (bytes_read + 8) < chunk_size) {
 
 
-    string subchunk_id = _reader.extract_bytes(4);
+    _reader.extract_bytes(magic, 4);
     unsigned int subchunk_size = _reader.get_uint32();
     unsigned int subchunk_size = _reader.get_uint32();
 
 
-    if (subchunk_id == "fmt ") {
+    if (memcmp(magic, "fmt ", 4) == 0) {
       // The format chunk specifies information about the storage.
       // The format chunk specifies information about the storage.
       nassertv(subchunk_size >= 16);
       nassertv(subchunk_size >= 16);
       have_fmt = true;
       have_fmt = true;
@@ -202,7 +203,7 @@ WavAudioCursor(WavAudio *src, istream *stream) :
         _reader.skip_bytes(subchunk_size - read_bytes);
         _reader.skip_bytes(subchunk_size - read_bytes);
       }
       }
 
 
-    } else if (subchunk_id == "data") {
+    } else if (memcmp(magic, "data", 4) == 0) {
       // The data chunk contains the actual sammples.
       // The data chunk contains the actual sammples.
       if (!have_fmt) {
       if (!have_fmt) {
         movies_cat.error()
         movies_cat.error()

+ 6 - 7
panda/src/net/datagramTCPHeader.cxx

@@ -24,23 +24,23 @@
  */
  */
 DatagramTCPHeader::
 DatagramTCPHeader::
 DatagramTCPHeader(const NetDatagram &datagram, int header_size) {
 DatagramTCPHeader(const NetDatagram &datagram, int header_size) {
-  const string &str = datagram.get_message();
+  size_t length = datagram.get_length();
   switch (header_size) {
   switch (header_size) {
   case 0:
   case 0:
     break;
     break;
 
 
   case datagram_tcp16_header_size:
   case datagram_tcp16_header_size:
     {
     {
-      uint16_t size = str.length();
-      nassertv(size == str.length());
+      uint16_t size = (uint16_t)length;
+      nassertv((size_t)size == length);
       _header.add_uint16(size);
       _header.add_uint16(size);
     }
     }
     break;
     break;
 
 
   case datagram_tcp32_header_size:
   case datagram_tcp32_header_size:
     {
     {
-      uint32_t size = str.length();
-      nassertv(size == str.length());
+      uint32_t size = (uint32_t)length;
+      nassertv((size_t)size == length);
       _header.add_uint32(size);
       _header.add_uint32(size);
     }
     }
     break;
     break;
@@ -93,8 +93,7 @@ verify_datagram(const NetDatagram &datagram, int header_size) const {
     return true;
     return true;
   }
   }
 
 
-  const string &str = datagram.get_message();
-  int actual_size = str.length();
+  int actual_size = (int)datagram.get_length();
   int expected_size = get_datagram_size(header_size);
   int expected_size = get_datagram_size(header_size);
   if (actual_size == expected_size) {
   if (actual_size == expected_size) {
     return true;
     return true;

+ 8 - 7
panda/src/net/datagramUDPHeader.cxx

@@ -24,10 +24,11 @@
  */
  */
 DatagramUDPHeader::
 DatagramUDPHeader::
 DatagramUDPHeader(const NetDatagram &datagram) {
 DatagramUDPHeader(const NetDatagram &datagram) {
-  const string &str = datagram.get_message();
+  const unsigned char *begin = (const unsigned char *)datagram.get_data();
+  const unsigned char *end = begin + datagram.get_length();
   uint16_t checksum = 0;
   uint16_t checksum = 0;
-  for (size_t p = 0; p < str.size(); p++) {
-    checksum += (uint16_t)(uint8_t)str[p];
+  for (const unsigned char *p = begin; p != end; ++p) {
+    checksum += (uint16_t)(uint8_t)*p;
   }
   }
 
 
   // Now pack the header.
   // Now pack the header.
@@ -49,11 +50,11 @@ DatagramUDPHeader(const void *data) : _header(data, datagram_udp_header_size) {
  */
  */
 bool DatagramUDPHeader::
 bool DatagramUDPHeader::
 verify_datagram(const NetDatagram &datagram) const {
 verify_datagram(const NetDatagram &datagram) const {
-  const string &str = datagram.get_message();
-
+  const unsigned char *begin = (const unsigned char *)datagram.get_data();
+  const unsigned char *end = begin + datagram.get_length();
   uint16_t checksum = 0;
   uint16_t checksum = 0;
-  for (size_t p = 0; p < str.size(); p++) {
-    checksum += (uint16_t)(uint8_t)str[p];
+  for (const unsigned char *p = begin; p != end; ++p) {
+    checksum += (uint16_t)(uint8_t)*p;
   }
   }
 
 
   if (checksum == get_datagram_checksum()) {
   if (checksum == get_datagram_checksum()) {

+ 19 - 9
panda/src/putil/datagramInputFile.cxx

@@ -138,35 +138,45 @@ get_datagram(Datagram &data) {
     return true;
     return true;
   }
   }
 
 
-  streamsize num_bytes = (streamsize)num_bytes_32;
+  size_t num_bytes = (size_t)num_bytes_32;
   if (num_bytes_32 == (uint32_t)-1) {
   if (num_bytes_32 == (uint32_t)-1) {
     // Another special case for a value larger than 32 bits.
     // Another special case for a value larger than 32 bits.
-    num_bytes = reader.get_uint64();
-  }
+    uint64_t num_bytes_64 = reader.get_uint64();
 
 
-  // Make sure we have a reasonable datagram size for putting into memory.
-  nassertr(num_bytes == (size_t)num_bytes, false);
+    if (_in->fail() || _in->eof()) {
+      _error = true;
+      return false;
+    }
+
+    num_bytes = (size_t)num_bytes_64;
+
+    // Make sure we have a reasonable datagram size for putting into memory.
+    if (num_bytes_64 != (uint64_t)num_bytes) {
+      _error = true;
+      return false;
+    }
+  }
 
 
   // Now, read the datagram itself. We construct an empty datagram, use
   // Now, read the datagram itself. We construct an empty datagram, use
   // pad_bytes to make it big enough, and read *directly* into the datagram's
   // pad_bytes to make it big enough, and read *directly* into the datagram's
   // internal buffer. Doing this saves us a copy operation.
   // internal buffer. Doing this saves us a copy operation.
   data = Datagram();
   data = Datagram();
 
 
-  streamsize bytes_read = 0;
+  size_t bytes_read = 0;
   while (bytes_read < num_bytes) {
   while (bytes_read < num_bytes) {
-    streamsize bytes_left = num_bytes - bytes_read;
+    size_t bytes_left = num_bytes - bytes_read;
 
 
     // Hold up a second - datagrams >4MB are pretty large by bam/network
     // Hold up a second - datagrams >4MB are pretty large by bam/network
     // standards. Let's take it 4MB at a time just in case the length is
     // standards. Let's take it 4MB at a time just in case the length is
     // corrupt, so we don't allocate potentially a few GBs of RAM only to
     // corrupt, so we don't allocate potentially a few GBs of RAM only to
     // find a truncated file.
     // find a truncated file.
-    bytes_left = min(bytes_left, (streamsize)4*1024*1024);
+    bytes_left = min(bytes_left, (size_t)4*1024*1024);
 
 
     PTA_uchar buffer = data.modify_array();
     PTA_uchar buffer = data.modify_array();
     buffer.resize(buffer.size() + bytes_left);
     buffer.resize(buffer.size() + bytes_left);
     unsigned char *ptr = &buffer.p()[bytes_read];
     unsigned char *ptr = &buffer.p()[bytes_read];
 
 
-    _in->read((char *)ptr, bytes_left);
+    _in->read((char *)ptr, (streamsize)bytes_left);
     if (_in->fail() || _in->eof()) {
     if (_in->fail() || _in->eof()) {
       _error = true;
       _error = true;
       return false;
       return false;

+ 4 - 2
panda/src/recorder/socketStreamRecorder.cxx

@@ -82,8 +82,10 @@ play_frame(DatagramIterator &scan, BamReader *manager) {
 
 
   int num_packets = scan.get_uint16();
   int num_packets = scan.get_uint16();
   for (int i = 0; i < num_packets; i++) {
   for (int i = 0; i < num_packets; i++) {
-    string packet = scan.get_string();
-    _data.push_back(Datagram(packet));
+    size_t size = scan.get_uint16();
+    vector_uchar packet(size);
+    scan.extract_bytes(&packet[0], size);
+    _data.push_back(Datagram(move(packet)));
   }
   }
 }
 }
 
 

+ 4 - 8
pandatool/src/flt/fltBeadID.cxx

@@ -78,9 +78,8 @@ extract_record(FltRecordReader &reader) {
 bool FltBeadID::
 bool FltBeadID::
 extract_ancillary(FltRecordReader &reader) {
 extract_ancillary(FltRecordReader &reader) {
   if (reader.get_opcode() == FO_long_id) {
   if (reader.get_opcode() == FO_long_id) {
-    string s = reader.get_iterator().get_remaining_bytes();
-    size_t zero_byte = s.find('\0');
-    _id = s.substr(0, zero_byte);
+    DatagramIterator &di = reader.get_iterator();
+    _id = di.get_fixed_string(di.get_remaining_size());
     return true;
     return true;
   }
   }
 
 
@@ -109,14 +108,11 @@ build_record(FltRecordWriter &writer) const {
 FltError FltBeadID::
 FltError FltBeadID::
 write_ancillary(FltRecordWriter &writer) const {
 write_ancillary(FltRecordWriter &writer) const {
   if (_id.length() > 7) {
   if (_id.length() > 7) {
+    Datagram dc;
 
 
     // Although the manual mentions nothing of this, it is essential that the
     // Although the manual mentions nothing of this, it is essential that the
     // length of the record be a multiple of 4 bytes.
     // length of the record be a multiple of 4 bytes.
-    string id = _id;
-    while ((id.length() % 4) != 0) {
-      id += '\0';
-    }
-    Datagram dc(id);
+    dc.add_fixed_string(_id, (_id.length() + 3) & ~3);
 
 
     FltError result = writer.write_record(FO_long_id, dc);
     FltError result = writer.write_record(FO_long_id, dc);
     if (result != FE_ok) {
     if (result != FE_ok) {

+ 3 - 2
pandatool/src/flt/fltRecord.cxx

@@ -621,7 +621,8 @@ extract_record(FltRecordReader &) {
 bool FltRecord::
 bool FltRecord::
 extract_ancillary(FltRecordReader &reader) {
 extract_ancillary(FltRecordReader &reader) {
   if (reader.get_opcode() == FO_comment) {
   if (reader.get_opcode() == FO_comment) {
-    _comment = reader.get_iterator().get_remaining_bytes();
+    DatagramIterator &di = reader.get_iterator();
+    _comment = di.get_fixed_string(di.get_remaining_size());
     return true;
     return true;
   }
   }
 
 
@@ -735,7 +736,7 @@ build_record(FltRecordWriter &) const {
 FltError FltRecord::
 FltError FltRecord::
 write_ancillary(FltRecordWriter &writer) const {
 write_ancillary(FltRecordWriter &writer) const {
   if (!_comment.empty()) {
   if (!_comment.empty()) {
-    Datagram dc(_comment);
+    Datagram dc(_comment.data(), _comment.size());
     FltError result = writer.write_record(FO_comment, dc);
     FltError result = writer.write_record(FO_comment, dc);
     if (result != FE_ok) {
     if (result != FE_ok) {
       return result;
       return result;

+ 2 - 2
tests/bullet/test_bullet_bam.py

@@ -88,8 +88,8 @@ def test_minkowski_sum_shape():
     assert type(shape) is type(shape2)
     assert type(shape) is type(shape2)
     assert shape.margin == shape2.margin
     assert shape.margin == shape2.margin
     assert shape.name == shape2.name
     assert shape.name == shape2.name
-    assert shape.transform_a.compare_to(shape2.transform_a, True) == 0
-    assert shape.transform_b.compare_to(shape2.transform_b, True) == 0
+    assert shape.transform_a.mat.compare_to(shape2.transform_a.mat) == 0
+    assert shape.transform_b.mat.compare_to(shape2.transform_b.mat) == 0
     assert type(shape.shape_a) == type(shape2.shape_a)
     assert type(shape.shape_a) == type(shape2.shape_a)
     assert type(shape.shape_b) == type(shape2.shape_b)
     assert type(shape.shape_b) == type(shape2.shape_b)
 
 

+ 12 - 0
tests/putil/test_datagram.py

@@ -1,5 +1,6 @@
 import pytest
 import pytest
 from panda3d import core
 from panda3d import core
+import sys
 
 
 # Fixtures for generating interesting datagrams (and verification functions) on
 # Fixtures for generating interesting datagrams (and verification functions) on
 # the fly...
 # the fly...
@@ -76,6 +77,17 @@ def datagram_large():
 
 
     return dg, readback_function
     return dg, readback_function
 
 
[email protected](sys.version_info < (3, 0), reason="Requires Python 3")
+def test_datagram_bytes():
+    """Tests that we can put and get a bytes object on Datagram."""
+    dg = core.Datagram(b'abc\x00')
+    dg.append_data(b'\xff123')
+    assert bytes(dg) == b'abc\x00\xff123'
+
+    dgi = core.DatagramIterator(dg)
+    dgi.get_remaining_bytes() == b'abc\x00\xff123'
+
+
 def test_iterator(datagram_small):
 def test_iterator(datagram_small):
     """This tests Datagram/DatagramIterator, and sort of serves as a self-check
     """This tests Datagram/DatagramIterator, and sort of serves as a self-check
     of the test fixtures too."""
     of the test fixtures too."""