Library of Assembled Shared Sources
export_traits_filesystem.cpp
Go to the documentation of this file.
1/** @file
2* @author Bram de Greve (bram@cocamware.com)
3* @author Tom De Muer (tom@cocamware.com)
4*
5* *** BEGIN LICENSE INFORMATION ***
6*
7* The contents of this file are subject to the Common Public Attribution License
8* Version 1.0 (the "License"); you may not use this file except in compliance with
9* the License. You may obtain a copy of the License at
10* http://lass.sourceforge.net/cpal-license. The License is based on the
11* Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12* use of software over a computer network and provide for limited attribution for
13* the Original Developer. In addition, Exhibit A has been modified to be consistent
14* with Exhibit B.
15*
16* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18* language governing rights and limitations under the License.
19*
20* The Original Code is LASS - Library of Assembled Shared Sources.
21*
22* The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23* The Original Developer is the Initial Developer.
24*
25* All portions of the code written by the Initial Developer are:
26* Copyright (C) 2022-2024 the Initial Developer.
27* All Rights Reserved.
28*
29* Contributor(s):
30*
31* Alternatively, the contents of this file may be used under the terms of the
32* GNU General Public License Version 2 or later (the GPL), in which case the
33* provisions of GPL are applicable instead of those above. If you wish to allow use
34* of your version of this file only under the terms of the GPL and not to allow
35* others to use your version of this file under the CPAL, indicate your decision by
36* deleting the provisions above and replace them with the notice and other
37* provisions required by the GPL License. If you do not delete the provisions above,
38* a recipient may use your version of this file under either the CPAL or the GPL.
39*
40* *** END LICENSE INFORMATION ***
41*/
42
43#include "python_common.h"
45
46#if LASS_HAVE_STD_FILESYSTEM
47
48#if LASS_PLATFORM_TYPE != LASS_PLATFORM_TYPE_WIN32
49
50namespace
51{
52
53int getBytes(PyObject* obj, std::string& v)
54{
55 const char* data = PyBytes_AsString(obj);
56 if (!data)
57 {
58 return 1;
59 }
60 const Py_ssize_t size = PyBytes_GET_SIZE(obj);
61 v = std::string{ data, static_cast<size_t>(size) };
62 return 0;
63}
64
65}
66
67#endif
68
69
70namespace lass
71{
72namespace python
73{
74
75PyObject* PyExportTraits<std::filesystem::path>::build(const std::filesystem::path& v)
76{
77#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
78 // On Windows, paths use wchar_t: we can directly return it as unicode
79 static_assert(std::is_same_v<std::filesystem::path::value_type, wchar_t>);
80 TPyObjPtr path{ PyExportTraits<std::wstring>::build(v.native()) };
81#else
82 // On Linux, paths use char: we decode them to unicode
83 static_assert(std::is_same_v<std::filesystem::path::value_type, char>);
84 const std::string& s = v.native();
85 if (s.size() > PY_SSIZE_T_MAX)
86 {
87 PyErr_SetString(PyExc_OverflowError, "input too long");
88 return 0;
89 }
90 TPyObjPtr path{ PyUnicode_DecodeFSDefaultAndSize(s.data(), static_cast<Py_ssize_t>(s.size())) };
91#endif
92
93 static TPyObjPtr pathType;
94 if (!pathType)
95 {
96 TPyObjPtr pathlib(PyImport_ImportModule("pathlib"));
97 pathType.reset(PyObject_GetAttrString(pathlib.get(), "Path"));
98 }
99
100 return PyObject_CallFunctionObjArgs(pathType.get(), path.get(), nullptr);
101}
102
103
104int PyExportTraits<std::filesystem::path>::get(PyObject* obj, std::filesystem::path& v)
105{
106 TPyObjPtr path(PyOS_FSPath(obj));
107 if (!path)
108 {
109 return 1;
110 }
111#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
112 // On Windows, paths use wchar_t: decode bytes to unicode and get as wstring.
113 static_assert(std::is_same_v<std::filesystem::path::value_type, wchar_t>);
114 PyObject* strObj = nullptr;
115 if (!PyUnicode_FSDecoder(obj, &strObj))
116 {
117 return 1;
118 }
119 std::wstring str;
120 const int ret = PyExportTraits<std::wstring>::get(strObj, str);
121 Py_DECREF(strObj);
122 if (ret == 0)
123 {
124 v = std::move(str);
125 }
126 return ret;
127#else
128 // On POSIX, paths use char: encode unicode to bytes and get as string
129 static_assert(std::is_same_v<std::filesystem::path::value_type, char>);
130 PyObject* bytesObj = nullptr;
131 if (!PyUnicode_FSConverter(obj, &bytesObj))
132 {
133 return 1;
134 }
135 std::string bytes;
136 const int ret = getBytes(bytesObj, bytes);
137 Py_DECREF(bytesObj);
138 if (ret == 0)
139 {
140 v = std::move(bytes);
141 }
142 return ret;
143#endif
144}
145
146}
147}
148
149#endif
150
151// EOF
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.
Comprehensive C++ to Python binding library.
Library for Assembled Shared Sources.
Definition config.h:53