text: // Copyright Daniel Wallin 2006. Use, modification and distribution is
  // subject to the Boost Software License, Version 1.0. (See accompanying
  // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  
  #include "boost_python.hpp"
  #include <libtorrent/identify_client.hpp>
  #include <libtorrent/bencode.hpp>
  #include <libtorrent/bdecode.hpp>
  #include "bytes.hpp"
  #include "gil.hpp"
  
  using namespace boost::python;
  using namespace lt;
  
  #ifdef _MSC_VER
  #pragma warning(push)
  // warning C4996: X: was declared deprecated
  #pragma warning( disable : 4996 )
  #endif
  
  struct bytes_to_python
  {
      static PyObject* convert(bytes const& p)
      {
  #if PY_MAJOR_VERSION >= 3
          PyObject *ret = PyBytes_FromStringAndSize(p.arr.c_str(), p.arr.size());
  #else
          PyObject *ret = PyString_FromStringAndSize(p.arr.c_str(), p.arr.size());
  #endif
          return ret;
      }
  };
  
  template <size_t N>
  struct array_to_python
  {
      static PyObject* convert(std::array<char, N> const& p)
      {
  #if PY_MAJOR_VERSION >= 3
          PyObject *ret = PyBytes_FromStringAndSize(p.data(), p.size());
  #else
          PyObject *ret = PyString_FromStringAndSize(p.data(), p.size());
  #endif
          return ret;
      }
  };
  
  struct bytes_from_python
  {
      bytes_from_python()
      {
          converter::registry::push_back(
              &convertible, &construct, type_id<bytes>());
      }
  
      static void* convertible(PyObject* x)
      {
  #if PY_MAJOR_VERSION >= 3
          return (PyBytes_Check(x) || PyByteArray_Check(x)) ? x : nullptr;
  #else
          return PyString_Check(x) ? x : nullptr;
  #endif
      }
  
      static void construct(PyObject* x, converter::rvalue_from_python_stage1_data* data)
      {
  #if PY_MAJOR_VERSION >= 3
          void* storage = ((converter::rvalue_from_python_storage<bytes>*)data)->storage.bytes;
          bytes* ret = new (storage) bytes();
          if (PyByteArray_Check(x))
          {
              ret->arr.resize(PyByteArray_Size(x));
              memcpy(&ret->arr[0], PyByteArray_AsString(x), ret->arr.size());
          }
          else
          {
              ret->arr.resize(PyBytes_Size(x));
              memcpy(&ret->arr[0], PyBytes_AsString(x), ret->arr.size());
          }
          data->convertible = storage;
  #else
          void* storage = ((converter::rvalue_from_python_storage<bytes>*)data)->storage.bytes;
          bytes* ret = new (storage) bytes();
          ret->arr.resize(PyString_Size(x));
          memcpy(&ret->arr[0], PyString_AsString(x), ret->arr.size());
          data->convertible = storage;
  #endif
      }
  };
  
  #if TORRENT_ABI_VERSION == 1
  std::string identify_client_(const peer_id& p)
  {
      python_deprecated("identify_client is deprecated");
      return lt::identify_client(p);
  }
  
  object client_fingerprint_(peer_id const& id)
  {
      python_deprecated("client_fingerprint is deprecated");
      std::optional<fingerprint> result = client_fingerprint(id);
      return result ? object(*result) : object();
  }
  #endif
  
  entry bdecode_(bytes const& data)
  {
      return bdecode(data.arr);
  }
  
  bytes bencode_(entry const& e)
  {
      bytes result;
      bencode(std::back_inserter(result.arr), e);
      return result;
  }
  
  void bind_utility()
  {
      // TODO: it would be nice to install converters for sha1_hash as well
      to_python_converter<bytes, bytes_to_python>();
      to_python_converter<std::array<char, 32>, array_to_python<32>>();
      to_python_converter<std::array<char, 64>, array_to_python<64>>();
      bytes_from_python();
  
  #if TORRENT_ABI_VERSION == 1
      def("identify_client", &identify_client_);
      def("client_fingerprint", &client_fingerprint_);
  #endif
      def("bdecode", &bdecode_);
      def("bencode", &bencode_);
  }
  
  #ifdef _MSC_VER
  #pragma warning(pop)
  #endif
  
  