mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
More thoroughly fix issues with pickling Panda objects in Python 3
This also adds DatagramBuffer, a class for writing datagrams to memory and reading them from there again.
This commit is contained in:
parent
08629ef1a0
commit
1b1d80cd27
@ -4808,18 +4808,9 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||||||
|
|
||||||
if (args_type == AT_single_arg) {
|
if (args_type == AT_single_arg) {
|
||||||
out << "#if PY_MAJOR_VERSION >= 3\n";
|
out << "#if PY_MAJOR_VERSION >= 3\n";
|
||||||
// As a special hack to fix pickling in Python 3, if the method name
|
|
||||||
// starts with py_decode_, we take a bytes object instead of a str.
|
|
||||||
if (remap->_cppfunc->get_local_name().substr(0, 10) == "py_decode_") {
|
|
||||||
indent(out, indent_level) << "if (PyBytes_AsStringAndSize(arg, (char **)&"
|
|
||||||
<< param_name << "_str, &" << param_name << "_len) == -1) {\n";
|
|
||||||
indent(out, indent_level + 2) << param_name << "_str = NULL;\n";
|
|
||||||
indent(out, indent_level) << "}\n";
|
|
||||||
} else {
|
|
||||||
indent(out, indent_level)
|
indent(out, indent_level)
|
||||||
<< param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &"
|
<< param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &"
|
||||||
<< param_name << "_len);\n";
|
<< param_name << "_len);\n";
|
||||||
}
|
|
||||||
out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode.
|
out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode.
|
||||||
indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, (char **)&"
|
indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, (char **)&"
|
||||||
<< param_name << "_str, &" << param_name << "_len) == -1) {\n";
|
<< param_name << "_str, &" << param_name << "_len) == -1) {\n";
|
||||||
|
@ -222,7 +222,7 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char> &value) {
|
ALWAYS_INLINE PyObject *Dtool_WrapValue(const vector_uchar &value) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||||
#else
|
#else
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "pnotify.h"
|
#include "pnotify.h"
|
||||||
|
#include "vector_uchar.h"
|
||||||
|
|
||||||
#if defined(HAVE_PYTHON) && !defined(CPPPARSER)
|
#if defined(HAVE_PYTHON) && !defined(CPPPARSER)
|
||||||
|
|
||||||
@ -549,7 +550,7 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
|
|||||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
|
ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
|
||||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(nullptr_t);
|
ALWAYS_INLINE PyObject *Dtool_WrapValue(nullptr_t);
|
||||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
|
ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
|
||||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char> &value);
|
ALWAYS_INLINE PyObject *Dtool_WrapValue(const vector_uchar &value);
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 0x02060000
|
#if PY_MAJOR_VERSION >= 0x02060000
|
||||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(Py_buffer *value);
|
ALWAYS_INLINE PyObject *Dtool_WrapValue(Py_buffer *value);
|
||||||
|
@ -78,9 +78,7 @@ __reduce__(PyObject *self) const {
|
|||||||
|
|
||||||
// Since a TextureCollection is itself an iterator, we can simply pass it as
|
// Since a TextureCollection is itself an iterator, we can simply pass it as
|
||||||
// the fourth tuple component.
|
// the fourth tuple component.
|
||||||
PyObject *result = Py_BuildValue("(O()OO)", this_class, Py_None, self);
|
return Py_BuildValue("(N()OO)", this_class, Py_None, self);
|
||||||
Py_DECREF(this_class);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
@ -2103,11 +2103,11 @@ get_name() const {
|
|||||||
* This method is used by __reduce__ to handle streaming of NodePaths to a
|
* This method is used by __reduce__ to handle streaming of NodePaths to a
|
||||||
* pickle file.
|
* pickle file.
|
||||||
*/
|
*/
|
||||||
INLINE string NodePath::
|
INLINE vector_uchar NodePath::
|
||||||
encode_to_bam_stream() const {
|
encode_to_bam_stream() const {
|
||||||
string data;
|
vector_uchar data;
|
||||||
if (!encode_to_bam_stream(data)) {
|
if (!encode_to_bam_stream(data)) {
|
||||||
return string();
|
data.clear();
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@
|
|||||||
#include "modelNode.h"
|
#include "modelNode.h"
|
||||||
#include "bam.h"
|
#include "bam.h"
|
||||||
#include "bamWriter.h"
|
#include "bamWriter.h"
|
||||||
|
#include "datagramBuffer.h"
|
||||||
|
|
||||||
// stack seems to overflow on Intel C++ at 7000. If we need more than 7000,
|
// stack seems to overflow on Intel C++ at 7000. If we need more than 7000,
|
||||||
// need to increase stack size.
|
// need to increase stack size.
|
||||||
@ -5576,28 +5577,24 @@ write_bam_stream(ostream &out) const {
|
|||||||
* calls this function.
|
* calls this function.
|
||||||
*/
|
*/
|
||||||
bool NodePath::
|
bool NodePath::
|
||||||
encode_to_bam_stream(string &data, BamWriter *writer) const {
|
encode_to_bam_stream(vector_uchar &data, BamWriter *writer) const {
|
||||||
data.clear();
|
data.clear();
|
||||||
ostringstream stream;
|
ostringstream stream;
|
||||||
|
|
||||||
DatagramOutputFile dout;
|
DatagramBuffer buffer;
|
||||||
if (!dout.open(stream)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BamWriter local_writer;
|
BamWriter local_writer;
|
||||||
bool used_local_writer = false;
|
bool used_local_writer = false;
|
||||||
if (writer == NULL) {
|
if (writer == NULL) {
|
||||||
// Create our own writer.
|
// Create our own writer.
|
||||||
|
|
||||||
if (!dout.write_header(_bam_header)) {
|
if (!buffer.write_header(_bam_header)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
writer = &local_writer;
|
writer = &local_writer;
|
||||||
used_local_writer = true;
|
used_local_writer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer->set_target(&dout);
|
writer->set_target(&buffer);
|
||||||
|
|
||||||
int num_nodes = get_num_nodes();
|
int num_nodes = get_num_nodes();
|
||||||
if (used_local_writer && num_nodes > 1) {
|
if (used_local_writer && num_nodes > 1) {
|
||||||
@ -5615,7 +5612,7 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
|
|||||||
dg.add_uint8(_error_type);
|
dg.add_uint8(_error_type);
|
||||||
dg.add_int32(num_nodes);
|
dg.add_int32(num_nodes);
|
||||||
|
|
||||||
if (!dout.put_datagram(dg)) {
|
if (!buffer.put_datagram(dg)) {
|
||||||
writer->set_target(NULL);
|
writer->set_target(NULL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5631,7 +5628,7 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
|
|||||||
}
|
}
|
||||||
writer->set_target(NULL);
|
writer->set_target(NULL);
|
||||||
|
|
||||||
data = stream.str();
|
buffer.swap_data(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5640,22 +5637,17 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
|
|||||||
* extracts and returns the NodePath on that string. Returns NULL on error.
|
* extracts and returns the NodePath on that string. Returns NULL on error.
|
||||||
*/
|
*/
|
||||||
NodePath NodePath::
|
NodePath NodePath::
|
||||||
decode_from_bam_stream(const string &data, BamReader *reader) {
|
decode_from_bam_stream(vector_uchar data, BamReader *reader) {
|
||||||
NodePath result;
|
NodePath result;
|
||||||
|
|
||||||
istringstream stream(data);
|
DatagramBuffer buffer(move(data));
|
||||||
|
|
||||||
DatagramInputFile din;
|
|
||||||
if (!din.open(stream)) {
|
|
||||||
return NodePath::fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
BamReader local_reader;
|
BamReader local_reader;
|
||||||
if (reader == NULL) {
|
if (reader == NULL) {
|
||||||
// Create a local reader.
|
// Create a local reader.
|
||||||
|
|
||||||
string head;
|
string head;
|
||||||
if (!din.read_header(head, _bam_header.size())) {
|
if (!buffer.read_header(head, _bam_header.size())) {
|
||||||
return NodePath::fail();
|
return NodePath::fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5666,11 +5658,11 @@ decode_from_bam_stream(const string &data, BamReader *reader) {
|
|||||||
reader = &local_reader;
|
reader = &local_reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
reader->set_source(&din);
|
reader->set_source(&buffer);
|
||||||
|
|
||||||
// One initial datagram to encode the error type, and the number of nodes.
|
// One initial datagram to encode the error type, and the number of nodes.
|
||||||
Datagram dg;
|
Datagram dg;
|
||||||
if (!din.get_datagram(dg)) {
|
if (!buffer.get_datagram(dg)) {
|
||||||
return NodePath::fail();
|
return NodePath::fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,9 +940,9 @@ PUBLISHED:
|
|||||||
BLOCKING bool write_bam_file(const Filename &filename) const;
|
BLOCKING bool write_bam_file(const Filename &filename) const;
|
||||||
BLOCKING bool write_bam_stream(ostream &out) const;
|
BLOCKING bool write_bam_stream(ostream &out) const;
|
||||||
|
|
||||||
INLINE string encode_to_bam_stream() const;
|
INLINE vector_uchar encode_to_bam_stream() const;
|
||||||
bool encode_to_bam_stream(string &data, BamWriter *writer = NULL) const;
|
bool encode_to_bam_stream(vector_uchar &data, BamWriter *writer = nullptr) const;
|
||||||
static NodePath decode_from_bam_stream(const string &data, BamReader *reader = NULL);
|
static NodePath decode_from_bam_stream(vector_uchar data, BamReader *reader = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static NodePathComponent *
|
static NodePathComponent *
|
||||||
|
@ -120,7 +120,7 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
|
|
||||||
// We have a non-empty NodePath.
|
// We have a non-empty NodePath.
|
||||||
|
|
||||||
string bam_stream;
|
vector_uchar bam_stream;
|
||||||
if (!_this->encode_to_bam_stream(bam_stream, writer)) {
|
if (!_this->encode_to_bam_stream(bam_stream, writer)) {
|
||||||
ostringstream stream;
|
ostringstream stream;
|
||||||
stream << "Could not bamify " << _this;
|
stream << "Could not bamify " << _this;
|
||||||
@ -150,7 +150,6 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
} else {
|
} else {
|
||||||
// The traditional pickle support: call the non-persistent version of this
|
// The traditional pickle support: call the non-persistent version of this
|
||||||
// function.
|
// function.
|
||||||
|
|
||||||
func = Extension<TypedWritable>::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream");
|
func = Extension<TypedWritable>::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream");
|
||||||
if (func == NULL) {
|
if (func == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream()");
|
PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream()");
|
||||||
@ -159,14 +158,15 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
// PyTuple_SET_ITEM conveniently borrows the reference it is passed.
|
||||||
PyObject *result = Py_BuildValue("(O(y#))", func, bam_stream.data(), (Py_ssize_t) bam_stream.size());
|
PyObject *args = PyTuple_New(2);
|
||||||
#else
|
PyTuple_SET_ITEM(args, 0, this_class);
|
||||||
PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), (Py_ssize_t) bam_stream.size());
|
PyTuple_SET_ITEM(args, 1, Dtool_WrapValue(bam_stream));
|
||||||
#endif
|
|
||||||
Py_DECREF(func);
|
PyObject *tuple = PyTuple_New(2);
|
||||||
Py_DECREF(this_class);
|
PyTuple_SET_ITEM(tuple, 0, func);
|
||||||
return result;
|
PyTuple_SET_ITEM(tuple, 1, args);
|
||||||
|
return tuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,15 +190,15 @@ find_net_python_tag(PyObject *key) const {
|
|||||||
* This wrapper is defined as a global function to suit pickle's needs.
|
* This wrapper is defined as a global function to suit pickle's needs.
|
||||||
*/
|
*/
|
||||||
NodePath
|
NodePath
|
||||||
py_decode_NodePath_from_bam_stream(const string &data) {
|
py_decode_NodePath_from_bam_stream(vector_uchar data) {
|
||||||
return py_decode_NodePath_from_bam_stream_persist(NULL, data);
|
return py_decode_NodePath_from_bam_stream_persist(nullptr, move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This wrapper is defined as a global function to suit pickle's needs.
|
* This wrapper is defined as a global function to suit pickle's needs.
|
||||||
*/
|
*/
|
||||||
NodePath
|
NodePath
|
||||||
py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &data) {
|
py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, vector_uchar data) {
|
||||||
BamReader *reader = NULL;
|
BamReader *reader = NULL;
|
||||||
if (unpickler != NULL) {
|
if (unpickler != NULL) {
|
||||||
PyObject *py_reader = PyObject_GetAttrString(unpickler, "bamReader");
|
PyObject *py_reader = PyObject_GetAttrString(unpickler, "bamReader");
|
||||||
@ -211,7 +211,7 @@ py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &da
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NodePath::decode_from_bam_stream(data, reader);
|
return NodePath::decode_from_bam_stream(move(data), reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,8 +56,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
BEGIN_PUBLISH
|
BEGIN_PUBLISH
|
||||||
NodePath py_decode_NodePath_from_bam_stream(const string &data);
|
NodePath py_decode_NodePath_from_bam_stream(vector_uchar data);
|
||||||
NodePath py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &data);
|
NodePath py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, vector_uchar data);
|
||||||
END_PUBLISH
|
END_PUBLISH
|
||||||
|
|
||||||
#include "nodePath_ext.I"
|
#include "nodePath_ext.I"
|
||||||
|
@ -2124,8 +2124,8 @@ is_ambient_light() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the string created by a previous call to encode_to_bam_stream(), and
|
* Reads the bytes created by a previous call to encode_to_bam_stream(), and
|
||||||
* extracts and returns the single object on that string. Returns NULL on
|
* extracts and returns the single object on those bytes. Returns NULL on
|
||||||
* error.
|
* error.
|
||||||
*
|
*
|
||||||
* This method is intended to replace decode_raw_from_bam_stream() when you
|
* This method is intended to replace decode_raw_from_bam_stream() when you
|
||||||
@ -2134,15 +2134,15 @@ is_ambient_light() const {
|
|||||||
* responsible for maintaining the reference count on the return value.
|
* responsible for maintaining the reference count on the return value.
|
||||||
*/
|
*/
|
||||||
PT(PandaNode) PandaNode::
|
PT(PandaNode) PandaNode::
|
||||||
decode_from_bam_stream(const string &data, BamReader *reader) {
|
decode_from_bam_stream(vector_uchar data, BamReader *reader) {
|
||||||
TypedWritable *object;
|
TypedWritable *object;
|
||||||
ReferenceCount *ref_ptr;
|
ReferenceCount *ref_ptr;
|
||||||
|
|
||||||
if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data, reader)) {
|
if (TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, move(data), reader)) {
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DCAST(PandaNode, object);
|
return DCAST(PandaNode, object);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,7 +321,7 @@ PUBLISHED:
|
|||||||
INLINE int get_fancy_bits(Thread *current_thread = Thread::get_current_thread()) const;
|
INLINE int get_fancy_bits(Thread *current_thread = Thread::get_current_thread()) const;
|
||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
static PT(PandaNode) decode_from_bam_stream(const string &data, BamReader *reader = NULL);
|
static PT(PandaNode) decode_from_bam_stream(vector_uchar data, BamReader *reader = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class BoundsData;
|
class BoundsData;
|
||||||
|
68
panda/src/putil/datagramBuffer.I
Normal file
68
panda/src/putil/datagramBuffer.I
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* 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."
|
||||||
|
*
|
||||||
|
* @file datagramBuffer.I
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-11-07
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an empty datagram buffer.
|
||||||
|
*/
|
||||||
|
INLINE DatagramBuffer::
|
||||||
|
DatagramBuffer() :
|
||||||
|
_read_offset(0),
|
||||||
|
_wrote_first_datagram(false),
|
||||||
|
_read_first_datagram(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the buffer with the given data.
|
||||||
|
*/
|
||||||
|
INLINE DatagramBuffer::
|
||||||
|
DatagramBuffer(vector_uchar data) :
|
||||||
|
_data(move(data)),
|
||||||
|
_read_offset(0),
|
||||||
|
_wrote_first_datagram(false),
|
||||||
|
_read_first_datagram(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the internal buffer.
|
||||||
|
*/
|
||||||
|
INLINE void DatagramBuffer::
|
||||||
|
clear() {
|
||||||
|
_data.clear();
|
||||||
|
_read_offset = 0;
|
||||||
|
_wrote_first_datagram = false;
|
||||||
|
_read_first_datagram = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the internal buffer.
|
||||||
|
*/
|
||||||
|
INLINE const vector_uchar &DatagramBuffer::
|
||||||
|
get_data() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the data in the internal buffer.
|
||||||
|
*/
|
||||||
|
INLINE void DatagramBuffer::
|
||||||
|
set_data(vector_uchar data) {
|
||||||
|
_data = move(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the data in the internal buffer with that of the other buffer.
|
||||||
|
*/
|
||||||
|
INLINE void DatagramBuffer::
|
||||||
|
swap_data(vector_uchar &other) {
|
||||||
|
_data.swap(other);
|
||||||
|
}
|
152
panda/src/putil/datagramBuffer.cxx
Normal file
152
panda/src/putil/datagramBuffer.cxx
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/**
|
||||||
|
* 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."
|
||||||
|
*
|
||||||
|
* @file datagramBuffer.cxx
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-11-07
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "datagramBuffer.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a sequence of bytes to the beginning of the datagram file. This may
|
||||||
|
* be called any number of times after the file has been opened and before the
|
||||||
|
* first datagram is written. It may not be called once the first datagram is
|
||||||
|
* written.
|
||||||
|
*/
|
||||||
|
bool DatagramBuffer::
|
||||||
|
write_header(const string &header) {
|
||||||
|
nassertr(!_wrote_first_datagram, false);
|
||||||
|
|
||||||
|
_data.insert(_data.end(), header.begin(), header.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given datagram to the file. Returns true on success, false if
|
||||||
|
* there is an error.
|
||||||
|
*/
|
||||||
|
bool DatagramBuffer::
|
||||||
|
put_datagram(const Datagram &data) {
|
||||||
|
_wrote_first_datagram = true;
|
||||||
|
|
||||||
|
// First, write the size of the upcoming datagram.
|
||||||
|
size_t num_bytes = data.get_length();
|
||||||
|
size_t offset = _data.size();
|
||||||
|
|
||||||
|
if (num_bytes == (uint32_t)-1 || num_bytes != (uint32_t)num_bytes) {
|
||||||
|
// Write a large value as a 64-bit size.
|
||||||
|
_data.resize(offset + num_bytes + 4 + sizeof(uint64_t));
|
||||||
|
_data[offset++] = 0xff;
|
||||||
|
_data[offset++] = 0xff;
|
||||||
|
_data[offset++] = 0xff;
|
||||||
|
_data[offset++] = 0xff;
|
||||||
|
|
||||||
|
LittleEndian s(&num_bytes, sizeof(uint64_t));
|
||||||
|
memcpy(&_data[offset], s.get_data(), sizeof(uint64_t));
|
||||||
|
offset += sizeof(uint64_t);
|
||||||
|
} else {
|
||||||
|
// Write a value that fits in 32 bits.
|
||||||
|
_data.resize(offset + num_bytes + sizeof(uint32_t));
|
||||||
|
|
||||||
|
LittleEndian s(&num_bytes, sizeof(uint32_t));
|
||||||
|
memcpy(&_data[offset], s.get_data(), sizeof(uint32_t));
|
||||||
|
offset += sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, write the datagram itself.
|
||||||
|
memcpy(&_data[offset], data.get_data(), data.get_length());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This does absolutely nothing.
|
||||||
|
*/
|
||||||
|
void DatagramBuffer::
|
||||||
|
flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a sequence of bytes from the beginning of the datagram file. This
|
||||||
|
* may be called any number of times after the file has been opened and before
|
||||||
|
* the first datagram is read. It may not be called once the first datagram
|
||||||
|
* has been read.
|
||||||
|
*/
|
||||||
|
bool DatagramBuffer::
|
||||||
|
read_header(string &header, size_t num_bytes) {
|
||||||
|
nassertr(!_read_first_datagram, false);
|
||||||
|
if (_read_offset + num_bytes > _data.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = string((char *)&_data[_read_offset], num_bytes);
|
||||||
|
_read_offset += num_bytes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the next datagram from the file. Returns true on success, false if
|
||||||
|
* there is an error or end of file.
|
||||||
|
*/
|
||||||
|
bool DatagramBuffer::
|
||||||
|
get_datagram(Datagram &data) {
|
||||||
|
_read_first_datagram = true;
|
||||||
|
if (_read_offset + sizeof(uint32_t) > _data.size()) {
|
||||||
|
// Reached the end of the buffer.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, get the size of the upcoming datagram.
|
||||||
|
uint32_t num_bytes_32;
|
||||||
|
LittleEndian s(&_data[_read_offset], 0, sizeof(uint32_t));
|
||||||
|
s.store_value(&num_bytes_32, sizeof(uint32_t));
|
||||||
|
_read_offset += 4;
|
||||||
|
|
||||||
|
if (num_bytes_32 == 0) {
|
||||||
|
// A special case for a zero-length datagram: no need to try to read any
|
||||||
|
// data.
|
||||||
|
data.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t num_bytes = (size_t)num_bytes_32;
|
||||||
|
if (num_bytes_32 == (uint32_t)-1) {
|
||||||
|
// Another special case for a value larger than 32 bits.
|
||||||
|
uint64_t num_bytes_64;
|
||||||
|
LittleEndian s(&_data[_read_offset], 0, sizeof(uint64_t));
|
||||||
|
s.store_value(&num_bytes_64, sizeof(uint64_t));
|
||||||
|
_read_offset += 8;
|
||||||
|
|
||||||
|
num_bytes = (size_t)num_bytes_64;
|
||||||
|
nassertr((uint64_t)num_bytes == num_bytes_64, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have this much data to read.
|
||||||
|
nassertr_always(_read_offset + num_bytes <= _data.size(), false);
|
||||||
|
|
||||||
|
data = Datagram(&_data[_read_offset], num_bytes);
|
||||||
|
_read_offset += num_bytes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the buffer has reached the end-of-buffer. This test may
|
||||||
|
* only be made after a call to read_header() or get_datagram() has failed.
|
||||||
|
*/
|
||||||
|
bool DatagramBuffer::
|
||||||
|
is_eof() {
|
||||||
|
return (_read_offset + sizeof(uint32_t)) > _data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the buffer has reached an error condition.
|
||||||
|
*/
|
||||||
|
bool DatagramBuffer::
|
||||||
|
is_error() {
|
||||||
|
return false;
|
||||||
|
}
|
63
panda/src/putil/datagramBuffer.h
Normal file
63
panda/src/putil/datagramBuffer.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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."
|
||||||
|
*
|
||||||
|
* @file datagramBuffer.h
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-11-07
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATAGRAMBUFFER_H
|
||||||
|
#define DATAGRAMBUFFER_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
#include "datagramSink.h"
|
||||||
|
#include "vector_uchar.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used to write a series of datagrams into a memory buffer.
|
||||||
|
* It acts as both a datagram sink and generator; you can fill it up with
|
||||||
|
* datagrams and then read as many datagrams from it.
|
||||||
|
*
|
||||||
|
* This uses the same format as DatagramInputFile and DatagramOutputFile,
|
||||||
|
* meaning that Datagram sizes are always stored little-endian.
|
||||||
|
*/
|
||||||
|
class EXPCL_PANDA_PUTIL DatagramBuffer : public DatagramSink, public DatagramGenerator {
|
||||||
|
PUBLISHED:
|
||||||
|
INLINE DatagramBuffer();
|
||||||
|
INLINE explicit DatagramBuffer(vector_uchar data);
|
||||||
|
|
||||||
|
INLINE void clear();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool write_header(const string &header);
|
||||||
|
virtual bool put_datagram(const Datagram &data) override;
|
||||||
|
virtual void flush() override;
|
||||||
|
|
||||||
|
bool read_header(string &header, size_t num_bytes);
|
||||||
|
virtual bool get_datagram(Datagram &data) override;
|
||||||
|
virtual bool is_eof() override;
|
||||||
|
|
||||||
|
virtual bool is_error() override;
|
||||||
|
|
||||||
|
INLINE const vector_uchar &get_data() const;
|
||||||
|
INLINE void set_data(vector_uchar data);
|
||||||
|
INLINE void swap_data(vector_uchar &other);
|
||||||
|
|
||||||
|
PUBLISHED:
|
||||||
|
MAKE_PROPERTY(data, get_data, set_data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector_uchar _data;
|
||||||
|
size_t _read_offset;
|
||||||
|
bool _wrote_first_datagram;
|
||||||
|
bool _read_first_datagram;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "datagramBuffer.I"
|
||||||
|
|
||||||
|
#endif
|
@ -22,6 +22,7 @@
|
|||||||
#include "copyOnWriteObject.cxx"
|
#include "copyOnWriteObject.cxx"
|
||||||
#include "copyOnWritePointer.cxx"
|
#include "copyOnWritePointer.cxx"
|
||||||
#include "cPointerCallbackObject.cxx"
|
#include "cPointerCallbackObject.cxx"
|
||||||
|
#include "datagramBuffer.cxx"
|
||||||
#include "datagramInputFile.cxx"
|
#include "datagramInputFile.cxx"
|
||||||
#include "datagramOutputFile.cxx"
|
#include "datagramOutputFile.cxx"
|
||||||
#include "doubleBitMask.cxx"
|
#include "doubleBitMask.cxx"
|
||||||
|
@ -53,22 +53,21 @@ get_bam_modified() const {
|
|||||||
return _bam_modified;
|
return _bam_modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the TypedWritable object into a single stream of data using a
|
* Converts the TypedWritable object into a single stream of data using a
|
||||||
* BamWriter, and returns that data as a string string. Returns empty string
|
* BamWriter, and returns that data as a bytes object. Returns an empty bytes
|
||||||
* on failure.
|
* object on failure.
|
||||||
*
|
*
|
||||||
* This is a convenience method particularly useful for cases when you are
|
* This is a convenience method particularly useful for cases when you are
|
||||||
* only serializing a single object. If you have many objects to process, it
|
* only serializing a single object. If you have many objects to process, it
|
||||||
* is more efficient to use the same BamWriter to serialize all of them
|
* is more efficient to use the same BamWriter to serialize all of them
|
||||||
* together.
|
* together.
|
||||||
*/
|
*/
|
||||||
INLINE string TypedWritable::
|
INLINE vector_uchar TypedWritable::
|
||||||
encode_to_bam_stream() const {
|
encode_to_bam_stream() const {
|
||||||
string data;
|
vector_uchar data;
|
||||||
if (!encode_to_bam_stream(data)) {
|
if (!encode_to_bam_stream(data)) {
|
||||||
return string();
|
data.clear();
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
#include "typedWritable.h"
|
#include "typedWritable.h"
|
||||||
#include "bamWriter.h"
|
#include "bamWriter.h"
|
||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "datagramOutputFile.h"
|
#include "datagramBuffer.h"
|
||||||
#include "datagramInputFile.h"
|
|
||||||
#include "lightMutexHolder.h"
|
#include "lightMutexHolder.h"
|
||||||
#include "bam.h"
|
#include "bam.h"
|
||||||
|
|
||||||
@ -134,26 +133,18 @@ as_reference_count() {
|
|||||||
* together.
|
* together.
|
||||||
*/
|
*/
|
||||||
bool TypedWritable::
|
bool TypedWritable::
|
||||||
encode_to_bam_stream(string &data, BamWriter *writer) const {
|
encode_to_bam_stream(vector_uchar &data, BamWriter *writer) const {
|
||||||
data.clear();
|
data.clear();
|
||||||
ostringstream stream;
|
|
||||||
|
|
||||||
// We use nested scoping to ensure the destructors get called in the right
|
DatagramBuffer buffer;
|
||||||
// order.
|
if (writer == nullptr) {
|
||||||
{
|
|
||||||
DatagramOutputFile dout;
|
|
||||||
if (!dout.open(stream)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writer == NULL) {
|
|
||||||
// Create our own writer.
|
// Create our own writer.
|
||||||
|
|
||||||
if (!dout.write_header(_bam_header)) {
|
if (!buffer.write_header(_bam_header)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BamWriter writer(&dout);
|
BamWriter writer(&buffer);
|
||||||
if (!writer.init()) {
|
if (!writer.init()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -163,23 +154,22 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use the existing writer.
|
// Use the existing writer.
|
||||||
writer->set_target(&dout);
|
writer->set_target(&buffer);
|
||||||
bool result = writer->write_object(this);
|
bool result = writer->write_object(this);
|
||||||
writer->set_target(NULL);
|
writer->set_target(nullptr);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
data = stream.str();
|
buffer.swap_data(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the string created by a previous call to encode_to_bam_stream(), and
|
* Reads the bytes created by a previous call to encode_to_bam_stream(), and
|
||||||
* extracts the single object on that string. Returns true on success, false
|
* extracts the single object on those bytes. Returns true on success, false
|
||||||
* on on error.
|
* on error.
|
||||||
*
|
*
|
||||||
* This variant sets the TypedWritable and ReferenceCount pointers separately;
|
* This variant sets the TypedWritable and ReferenceCount pointers separately;
|
||||||
* both are pointers to the same object. The reference count is not
|
* both are pointers to the same object. The reference count is not
|
||||||
@ -198,18 +188,14 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
|
|||||||
*/
|
*/
|
||||||
bool TypedWritable::
|
bool TypedWritable::
|
||||||
decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
|
decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
|
||||||
const string &data, BamReader *reader) {
|
vector_uchar data, BamReader *reader) {
|
||||||
istringstream stream(data);
|
|
||||||
|
|
||||||
DatagramInputFile din;
|
DatagramBuffer buffer(move(data));
|
||||||
if (!din.open(stream)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reader == NULL) {
|
if (reader == NULL) {
|
||||||
// Create a local reader.
|
// Create a local reader.
|
||||||
string head;
|
string head;
|
||||||
if (!din.read_header(head, _bam_header.size())) {
|
if (!buffer.read_header(head, _bam_header.size())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +203,7 @@ decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BamReader reader(&din);
|
BamReader reader(&buffer);
|
||||||
if (!reader.init()) {
|
if (!reader.init()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -241,7 +227,7 @@ decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Use the existing reader.
|
// Use the existing reader.
|
||||||
reader->set_source(&din);
|
reader->set_source(&buffer);
|
||||||
if (!reader->read_object(ptr, ref_ptr)) {
|
if (!reader->read_object(ptr, ref_ptr)) {
|
||||||
reader->set_source(NULL);
|
reader->set_source(NULL);
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "pvector.h"
|
#include "pvector.h"
|
||||||
#include "lightMutex.h"
|
#include "lightMutex.h"
|
||||||
#include "updateSeq.h"
|
#include "updateSeq.h"
|
||||||
|
#include "vector_uchar.h"
|
||||||
|
|
||||||
class BamReader;
|
class BamReader;
|
||||||
class BamWriter;
|
class BamWriter;
|
||||||
@ -62,11 +63,11 @@ PUBLISHED:
|
|||||||
EXTENSION(PyObject *__reduce__(PyObject *self) const);
|
EXTENSION(PyObject *__reduce__(PyObject *self) const);
|
||||||
EXTENSION(PyObject *__reduce_persist__(PyObject *self, PyObject *pickler) const);
|
EXTENSION(PyObject *__reduce_persist__(PyObject *self, PyObject *pickler) const);
|
||||||
|
|
||||||
INLINE string encode_to_bam_stream() const;
|
INLINE vector_uchar encode_to_bam_stream() const;
|
||||||
bool encode_to_bam_stream(string &data, BamWriter *writer = NULL) const;
|
bool encode_to_bam_stream(vector_uchar &data, BamWriter *writer = NULL) const;
|
||||||
static bool decode_raw_from_bam_stream(TypedWritable *&ptr,
|
static bool decode_raw_from_bam_stream(TypedWritable *&ptr,
|
||||||
ReferenceCount *&ref_ptr,
|
ReferenceCount *&ref_ptr,
|
||||||
const string &data,
|
vector_uchar data,
|
||||||
BamReader *reader = NULL);
|
BamReader *reader = NULL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -26,8 +26,8 @@ as_reference_count() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the string created by a previous call to encode_to_bam_stream(), and
|
* Reads the bytes created by a previous call to encode_to_bam_stream(), and
|
||||||
* extracts and returns the single object on that string. Returns NULL on
|
* extracts and returns the single object on those bytes. Returns NULL on
|
||||||
* error.
|
* error.
|
||||||
*
|
*
|
||||||
* This method is intended to replace decode_raw_from_bam_stream() when you
|
* This method is intended to replace decode_raw_from_bam_stream() when you
|
||||||
@ -37,13 +37,13 @@ as_reference_count() {
|
|||||||
* reference count on the return value.
|
* reference count on the return value.
|
||||||
*/
|
*/
|
||||||
PT(TypedWritableReferenceCount) TypedWritableReferenceCount::
|
PT(TypedWritableReferenceCount) TypedWritableReferenceCount::
|
||||||
decode_from_bam_stream(const string &data, BamReader *reader) {
|
decode_from_bam_stream(vector_uchar data, BamReader *reader) {
|
||||||
TypedWritable *object;
|
TypedWritable *object;
|
||||||
ReferenceCount *ref_ptr;
|
ReferenceCount *ref_ptr;
|
||||||
|
|
||||||
if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data, reader)) {
|
if (TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, move(data), reader)) {
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DCAST(TypedWritableReferenceCount, object);
|
return DCAST(TypedWritableReferenceCount, object);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
virtual ReferenceCount *as_reference_count();
|
virtual ReferenceCount *as_reference_count();
|
||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
static PT(TypedWritableReferenceCount) decode_from_bam_stream(const string &data, BamReader *reader = NULL);
|
static PT(TypedWritableReferenceCount) decode_from_bam_stream(vector_uchar data, BamReader *reader = nullptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual TypeHandle get_type() const {
|
virtual TypeHandle get_type() const {
|
||||||
|
@ -71,7 +71,7 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First, streamify the object, if possible.
|
// First, streamify the object, if possible.
|
||||||
string bam_stream;
|
vector_uchar bam_stream;
|
||||||
if (!_this->encode_to_bam_stream(bam_stream, writer)) {
|
if (!_this->encode_to_bam_stream(bam_stream, writer)) {
|
||||||
ostringstream stream;
|
ostringstream stream;
|
||||||
stream << "Could not bamify object of type " << _this->get_type() << "\n";
|
stream << "Could not bamify object of type " << _this->get_type() << "\n";
|
||||||
@ -101,7 +101,6 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
} else {
|
} else {
|
||||||
// The traditional pickle support: call the non-persistent version of this
|
// The traditional pickle support: call the non-persistent version of this
|
||||||
// function.
|
// function.
|
||||||
|
|
||||||
func = find_global_decode(this_class, "py_decode_TypedWritable_from_bam_stream");
|
func = find_global_decode(this_class, "py_decode_TypedWritable_from_bam_stream");
|
||||||
if (func == NULL) {
|
if (func == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_TypedWritable_from_bam_stream()");
|
PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_TypedWritable_from_bam_stream()");
|
||||||
@ -110,14 +109,15 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
// PyTuple_SET_ITEM conveniently borrows the reference it is passed.
|
||||||
PyObject *result = Py_BuildValue("(O(Oy#))", func, this_class, bam_stream.data(), (Py_ssize_t) bam_stream.size());
|
PyObject *args = PyTuple_New(2);
|
||||||
#else
|
PyTuple_SET_ITEM(args, 0, this_class);
|
||||||
PyObject *result = Py_BuildValue("(O(Os#))", func, this_class, bam_stream.data(), (Py_ssize_t) bam_stream.size());
|
PyTuple_SET_ITEM(args, 1, Dtool_WrapValue(bam_stream));
|
||||||
#endif
|
|
||||||
Py_DECREF(func);
|
PyObject *tuple = PyTuple_New(2);
|
||||||
Py_DECREF(this_class);
|
PyTuple_SET_ITEM(tuple, 0, func);
|
||||||
return result;
|
PyTuple_SET_ITEM(tuple, 1, args);
|
||||||
|
return tuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,7 +131,8 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
|
|||||||
*/
|
*/
|
||||||
PyObject *Extension<TypedWritable>::
|
PyObject *Extension<TypedWritable>::
|
||||||
find_global_decode(PyObject *this_class, const char *func_name) {
|
find_global_decode(PyObject *this_class, const char *func_name) {
|
||||||
PyObject *module_name = PyObject_GetAttrString(this_class, "__module__");
|
// Get the module in which BamWriter is defined.
|
||||||
|
PyObject *module_name = PyObject_GetAttrString((PyObject *)&Dtool_BamWriter, "__module__");
|
||||||
if (module_name != NULL) {
|
if (module_name != NULL) {
|
||||||
// borrowed reference
|
// borrowed reference
|
||||||
PyObject *sys_modules = PyImport_GetModuleDict();
|
PyObject *sys_modules = PyImport_GetModuleDict();
|
||||||
@ -146,8 +147,8 @@ find_global_decode(PyObject *this_class, const char *func_name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Py_DECREF(module_name);
|
Py_DECREF(module_name);
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *bases = PyObject_GetAttrString(this_class, "__bases__");
|
PyObject *bases = PyObject_GetAttrString(this_class, "__bases__");
|
||||||
if (bases != NULL) {
|
if (bases != NULL) {
|
||||||
@ -178,8 +179,8 @@ find_global_decode(PyObject *this_class, const char *func_name) {
|
|||||||
* properly handle self-referential BAM objects.
|
* properly handle self-referential BAM objects.
|
||||||
*/
|
*/
|
||||||
PyObject *
|
PyObject *
|
||||||
py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data) {
|
py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const vector_uchar &data) {
|
||||||
return py_decode_TypedWritable_from_bam_stream_persist(NULL, this_class, data);
|
return py_decode_TypedWritable_from_bam_stream_persist(nullptr, this_class, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,7 +193,7 @@ py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data
|
|||||||
* direct/src/stdpy.
|
* direct/src/stdpy.
|
||||||
*/
|
*/
|
||||||
PyObject *
|
PyObject *
|
||||||
py_decode_TypedWritable_from_bam_stream_persist(PyObject *pickler, PyObject *this_class, const string &data) {
|
py_decode_TypedWritable_from_bam_stream_persist(PyObject *pickler, PyObject *this_class, const vector_uchar &data) {
|
||||||
|
|
||||||
PyObject *py_reader = NULL;
|
PyObject *py_reader = NULL;
|
||||||
if (pickler != NULL) {
|
if (pickler != NULL) {
|
||||||
@ -210,28 +211,30 @@ py_decode_TypedWritable_from_bam_stream_persist(PyObject *pickler, PyObject *thi
|
|||||||
// decode_from_bam_stream appropriate to this class.
|
// decode_from_bam_stream appropriate to this class.
|
||||||
|
|
||||||
PyObject *func = PyObject_GetAttrString(this_class, "decode_from_bam_stream");
|
PyObject *func = PyObject_GetAttrString(this_class, "decode_from_bam_stream");
|
||||||
if (func == NULL) {
|
if (func == nullptr) {
|
||||||
return NULL;
|
Py_XDECREF(py_reader);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *bytes = Dtool_WrapValue(data);
|
||||||
|
if (bytes == nullptr) {
|
||||||
|
Py_DECREF(func);
|
||||||
|
Py_XDECREF(py_reader);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
if (py_reader != NULL){
|
if (py_reader != nullptr) {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
result = PyObject_CallFunctionObjArgs(func, bytes, py_reader, nullptr);
|
||||||
result = PyObject_CallFunction(func, (char *)"(y#O)", data.data(), (Py_ssize_t) data.size(), py_reader);
|
|
||||||
#else
|
|
||||||
result = PyObject_CallFunction(func, (char *)"(s#O)", data.data(), (Py_ssize_t) data.size(), py_reader);
|
|
||||||
#endif
|
|
||||||
Py_DECREF(py_reader);
|
Py_DECREF(py_reader);
|
||||||
} else {
|
} else {
|
||||||
#if PY_MAJOR_VERSION >= 3
|
result = PyObject_CallFunctionObjArgs(func, bytes, nullptr);
|
||||||
result = PyObject_CallFunction(func, (char *)"(y#)", data.data(), (Py_ssize_t) data.size());
|
|
||||||
#else
|
|
||||||
result = PyObject_CallFunction(func, (char *)"(s#)", data.data(), (Py_ssize_t) data.size());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
Py_DECREF(bytes);
|
||||||
|
Py_DECREF(func);
|
||||||
|
|
||||||
if (result == NULL) {
|
if (result == nullptr) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == Py_None) {
|
if (result == Py_None) {
|
||||||
|
@ -33,12 +33,11 @@ public:
|
|||||||
PyObject *__reduce_persist__(PyObject *self, PyObject *pickler) const;
|
PyObject *__reduce_persist__(PyObject *self, PyObject *pickler) const;
|
||||||
|
|
||||||
static PyObject *find_global_decode(PyObject *this_class, const char *func_name);
|
static PyObject *find_global_decode(PyObject *this_class, const char *func_name);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BEGIN_PUBLISH
|
BEGIN_PUBLISH
|
||||||
PyObject *py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data);
|
PyObject *py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const vector_uchar &data);
|
||||||
PyObject *py_decode_TypedWritable_from_bam_stream_persist(PyObject *unpickler, PyObject *this_class, const string &data);
|
PyObject *py_decode_TypedWritable_from_bam_stream_persist(PyObject *unpickler, PyObject *this_class, const vector_uchar &data);
|
||||||
END_PUBLISH
|
END_PUBLISH
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
Loading…
x
Reference in New Issue
Block a user