physfs.py 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ Copyright (c) 2016 The Pybind Development Team, All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this
7
+ list of conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ 3. Neither the name of the copyright holder nor the names of its contributors
14
+ may be used to endorse or promote products derived from this software
15
+ without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ You are under no obligation whatsoever to provide any bug fixes, patches, or
29
+ upgrades to the features, functionality or performance of the source code
30
+ ("Enhancements") to anyone; however, if you choose to make your Enhancements
31
+ available either publicly, or directly to the author of this software, without
32
+ imposing a separate written license agreement for such Enhancements, then you
33
+ hereby grant the following license: a non-exclusive, royalty-free perpetual
34
+ license to install, use, modify, prepare derivative works, incorporate into
35
+ other computer software, distribute, and sublicense such enhancements or
36
+ derivative works thereof, in binary and source code form.
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.1
2
+ Name: physfs.py
3
+ Version: 0.0.2
4
+ Summary: PhysFS.py is a python wrapper for the PhysicsFS library.
5
+ Home-page: https://github.com/shabbywu/physfs.py
6
+ Author: shabbywu
7
+ Author-email: shabbywu@qq.com
8
+ Requires-Python: >=3.7
9
+ Provides-Extra: test
10
+ License-File: LICENSE
@@ -0,0 +1,61 @@
1
+ PhysFS.py
2
+ ==============
3
+
4
+ ![github-stars][stars-badge]
5
+
6
+ | CI | status |
7
+ |----------------------|--------|
8
+ | Linux/macOS Travis | [![Travis-CI][travis-badge]][travis-link] |
9
+ | MSVC 2019 | [![AppVeyor][appveyor-badge]][appveyor-link] |
10
+ | pip builds | [![Pip Actions Status][actions-pip-badge]][actions-pip-link] |
11
+ | [`cibuildwheel`][] | [![Wheels Actions Status][actions-wheels-badge]][actions-wheels-link] |
12
+
13
+ [gitter-badge]: https://badges.gitter.im/pybind/Lobby.svg
14
+ [stars-badge]: https://img.shields.io/github/stars/shabbywu/physfs.py?style=social
15
+ [actions-badge]: https://github.com/shabbywu/physfs.py/workflows/Tests/badge.svg
16
+ [actions-pip-link]: https://github.com/shabbywu/physfs.py/actions?query=workflow%3A%22Pip
17
+ [actions-pip-badge]: https://github.com/shabbywu/physfs.py/workflows/Pip/badge.svg
18
+ [actions-wheels-link]: https://github.com/shabbywu/physfs.py/actions?query=workflow%3AWheels
19
+ [actions-wheels-badge]: https://github.com/shabbywu/physfs.py/workflows/Wheels/badge.svg
20
+ [travis-link]: https://travis-ci.org/shabbywu/physfs.py
21
+ [travis-badge]: https://travis-ci.org/shabbywu/physfs.py.svg?branch=master&status=passed
22
+ [appveyor-link]: https://ci.appveyor.com/project/shabbywu/physfs.py
23
+ <!-- TODO: get a real badge link for appveyor -->
24
+ [appveyor-badge]: https://travis-ci.org/shabbywu/physfs.py.svg?branch=master&status=passed
25
+ [`cibuildwheel`]: https://cibuildwheel.readthedocs.io
26
+
27
+ PhysFS.py is a python wrapper for the PhysicsFS library.
28
+
29
+ Installation
30
+ ------------
31
+
32
+ - clone this repository
33
+ - `pip install ./physfs.py`
34
+
35
+ Requirements
36
+ ------------
37
+ CMake for building, and, of course, the PhysicsFS library.
38
+
39
+ Features
40
+ ------------
41
+ physfs.py provides an encapsulation of the basic interface of PhysFS, including `init`, `deinit`, `mount`, `unmount`, `ls`, `read(cat)`, `stat`.
42
+
43
+ Enables python to use PhysFS at a minimum.
44
+
45
+ License
46
+ -------
47
+
48
+ pybind11 is provided under a BSD-style license that can be found in the LICENSE
49
+ file. By using, distributing, or contributing to this project, you agree to the
50
+ terms and conditions of this license.
51
+
52
+ Test call
53
+ ---------
54
+
55
+ ```python
56
+ import physfs
57
+ physfs.init()
58
+
59
+ physfs.mount("./example.zip")
60
+ physfs.ls()
61
+ ```
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.1
2
+ Name: physfs.py
3
+ Version: 0.0.2
4
+ Summary: PhysFS.py is a python wrapper for the PhysicsFS library.
5
+ Home-page: https://github.com/shabbywu/physfs.py
6
+ Author: shabbywu
7
+ Author-email: shabbywu@qq.com
8
+ Requires-Python: >=3.7
9
+ Provides-Extra: test
10
+ License-File: LICENSE
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ libs/physfs
6
+ physfs.py.egg-info/PKG-INFO
7
+ physfs.py.egg-info/SOURCES.txt
8
+ physfs.py.egg-info/dependency_links.txt
9
+ physfs.py.egg-info/not-zip-safe
10
+ physfs.py.egg-info/requires.txt
11
+ physfs.py.egg-info/top_level.txt
12
+ src/main.cpp
13
+ src/shim.cpp
14
+ tests/test.py
@@ -0,0 +1,3 @@
1
+
2
+ [test]
3
+ pytest
@@ -0,0 +1 @@
1
+ physfs
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=42",
4
+ "pybind11>=2.10.0",
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [tool.cibuildwheel]
9
+ test-command = "python {project}/tests/test.py"
10
+ test-skip = "*universal2:arm64"
11
+
12
+ [tool.ruff]
13
+ extend-select = [
14
+ "B", # flake8-bugbear
15
+ "I", # isort
16
+ "PGH", # pygrep-hooks
17
+ "RUF", # Ruff-specific
18
+ "UP", # pyupgrade
19
+ ]
20
+ extend-ignore = [
21
+ "E501", # Line too long
22
+ ]
23
+ target-version = "py37"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,120 @@
1
+ # Available at setup time due to pyproject.toml
2
+ import platform
3
+ import os
4
+ from pathlib import Path
5
+ from glob import glob
6
+ from distutils import log
7
+
8
+ # Available at setup time due to pyproject.toml
9
+ from pybind11.setup_helpers import Pybind11Extension, build_ext
10
+ from setuptools.command.build_clib import build_clib as _build_clib
11
+ from setuptools import setup, Extension
12
+ from setuptools.extension import Library
13
+
14
+ __version__ = "0.0.2"
15
+ IS_WINDOWS = platform.system() == "Windows"
16
+ IS_MACOS = platform.system() == "Darwin"
17
+
18
+
19
+ ext_libraries = [
20
+ [
21
+ "physfs",
22
+ {
23
+ "sources": ["libs/physfs"],
24
+ "type": "cmake",
25
+ "cmake_args": [
26
+ # disable build shared library for macos and linux
27
+ "-DPHYSFS_BUILD_SHARED=false"
28
+ if not IS_WINDOWS else
29
+ # disable build static library for windows(before something wrong in windows)
30
+ "-DPHYSFS_BUILD_STATIC=false",
31
+ # disable build test
32
+ "-DPHYSFS_BUILD_TEST=false",
33
+ # disable build docs
34
+ "-DPHYSFS_BUILD_DOCS=false",
35
+ # set -fPIC
36
+ "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
37
+ ],
38
+ "copy_objects": [] if not IS_WINDOWS else ["physfs.dll"]
39
+ }
40
+ ]
41
+ ]
42
+
43
+
44
+ extra_link_args = []
45
+ if IS_MACOS:
46
+ extra_link_args = ["-framework", "IOKit", "-framework", "Foundation"]
47
+
48
+
49
+ ext_modules = [
50
+ Pybind11Extension("physfs",
51
+ ["src/main.cpp", "src/shim.cpp"],
52
+ # Example: passing in the version to the compiled code
53
+ define_macros = [('VERSION_INFO', __version__)],
54
+ include_dirs=["libs/physfs/src"],
55
+ extra_link_args=extra_link_args,
56
+ ),
57
+ ]
58
+
59
+
60
+ class build_clib(_build_clib):
61
+ def build_libraries(self, libraries):
62
+ cwd = Path().absolute()
63
+ other_libraries = []
64
+ for (lib_name, build_info) in libraries:
65
+ if build_info.get("type") != "cmake":
66
+ libraries.append((lib_name, build_info))
67
+ continue
68
+
69
+ log.info("building '%s' library", lib_name)
70
+ src = Path(build_info["sources"][0]).absolute()
71
+ build_temp = (Path(self.build_temp) / lib_name).absolute()
72
+ build_temp.mkdir(parents=True, exist_ok=True)
73
+ config = 'Debug' if self.debug else 'Release'
74
+ build_dest = build_temp / config if IS_WINDOWS else build_temp
75
+
76
+ build_ext = self.get_finalized_command('build_ext')
77
+ build_lib = Path(build_ext.build_lib).absolute()
78
+ cmake_args = [
79
+ '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + str(build_temp),
80
+ '-DCMAKE_BUILD_TYPE=' + config,
81
+ *build_info.get("cmake_args", [])
82
+ ]
83
+ build_args = [
84
+ '--config', config,
85
+ "-v"
86
+ ]
87
+ os.chdir(str(build_temp))
88
+ self.spawn(['cmake', str(src)] + cmake_args)
89
+ if not self.dry_run:
90
+ self.spawn(['cmake', '--build', '.'] + build_args)
91
+ # extend library_dirs
92
+ for ext in build_ext.extensions:
93
+ ext.library_dirs.append(str(build_dest))
94
+ # copy objects to dest
95
+ build_lib.mkdir(parents=True, exist_ok=True)
96
+ copy_objects = build_info.get("copy_objects")
97
+ if copy_objects:
98
+ for obj in copy_objects:
99
+ self.copy_file(str(build_dest / obj), str(build_lib / obj))
100
+ os.chdir(str(cwd))
101
+ return super().build_libraries(other_libraries)
102
+
103
+
104
+ setup(
105
+ name="physfs.py",
106
+ version=__version__,
107
+ author="shabbywu",
108
+ author_email="shabbywu@qq.com",
109
+ url="https://github.com/shabbywu/physfs.py",
110
+ description="PhysFS.py is a python wrapper for the PhysicsFS library.",
111
+ long_description="",
112
+ ext_modules=ext_modules,
113
+ libraries=ext_libraries,
114
+ extras_require={"test": "pytest"},
115
+ # Currently, build_ext only provides an optional "highest supported C++
116
+ # level" feature, but in the future it may provide more features.
117
+ cmdclass={"build_ext": build_ext, "build_clib": build_clib},
118
+ zip_safe=False,
119
+ python_requires=">=3.7",
120
+ )
@@ -0,0 +1,20 @@
1
+ #include <pybind11/pybind11.h>
2
+ #include "shim.h"
3
+
4
+ #define STRINGIFY(x) #x
5
+ #define MACRO_STRINGIFY(x) STRINGIFY(x)
6
+
7
+
8
+ namespace py = pybind11;
9
+
10
+
11
+ PYBIND11_MODULE(physfs, m) {
12
+ register_physfs(m);
13
+ #ifdef VERSION_INFO
14
+ m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
15
+ #else
16
+ m.attr("__version__") = "dev";
17
+ #endif
18
+
19
+ m.attr("__author__") = "shabbywu<shabbywu@qq.com>";
20
+ }
@@ -0,0 +1,222 @@
1
+ #include "shim.h"
2
+
3
+
4
+ namespace py = pybind11;
5
+
6
+
7
+ template<typename ... Args>
8
+ std::string string_format( const std::string& format, Args ... args )
9
+ {
10
+ int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
11
+ if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
12
+ auto size = static_cast<size_t>( size_s );
13
+ std::unique_ptr<char[]> buf( new char[ size ] );
14
+ std::snprintf( buf.get(), size, format.c_str(), args ... );
15
+ return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
16
+ }
17
+
18
+
19
+ void physfs_init() {
20
+ if (!PHYSFS_init(NULL)) {
21
+ throw std::runtime_error(string_format("Failure. Reason: [%s]", PHYSFS_getLastError()));
22
+ }
23
+ }
24
+
25
+
26
+ void physfs_deinit() {
27
+ if (!PHYSFS_isInit()) {
28
+ throw std::runtime_error("PHYSFS is not initialized, please call init() first");
29
+ }
30
+
31
+ if (!PHYSFS_deinit()) {
32
+ throw std::runtime_error(string_format("Failure. Reason: [%s]", PHYSFS_getLastError()));
33
+ }
34
+ }
35
+
36
+
37
+ void physfs_mount(std::string source, std::string mountPoint = "/", py::bool_ appendToPath = py::bool_(0)) {
38
+ if (!PHYSFS_isInit()) {
39
+ throw std::runtime_error("PHYSFS is not initialized, please call init() first");
40
+ }
41
+
42
+ if (!PHYSFS_mount(source.c_str(), mountPoint.c_str(), appendToPath)) {
43
+ throw std::runtime_error(string_format("Failure. Reason: [%s]", PHYSFS_getLastError()));
44
+ }
45
+ }
46
+
47
+
48
+ void physfs_unmount(std::string oldSource) {
49
+ if (!PHYSFS_isInit()) {
50
+ throw std::runtime_error("PHYSFS is not initialized, please call init() first");
51
+ }
52
+
53
+ if (!PHYSFS_unmount(oldSource.c_str())) {
54
+ throw std::runtime_error(string_format("Failure. Reason: [%s]", PHYSFS_getLastError()));
55
+ }
56
+ }
57
+
58
+
59
+ py::list enumerate_fs(std::string dir) {
60
+ if (!PHYSFS_isInit()) {
61
+ throw std::runtime_error("PHYSFS is not initialized, please call init() first");
62
+ }
63
+
64
+ char **rc;
65
+ rc = PHYSFS_enumerateFiles(dir.c_str());
66
+
67
+ py::list result;
68
+ char **i;
69
+ for (i = rc; *i != NULL; i++) {
70
+ result.append(std::string(*i));
71
+ }
72
+ return result;
73
+ }
74
+
75
+ PHYSFS_Stat physfs_stat(std::string file) {
76
+ if (!PHYSFS_isInit()) {
77
+ throw std::runtime_error("PHYSFS is not initialized, please call init() first");
78
+ }
79
+
80
+ PHYSFS_Stat stat;
81
+
82
+ if(!PHYSFS_stat(file.c_str(), &stat))
83
+ {
84
+ throw std::runtime_error(string_format("failed to stat. Reason [%s]", PHYSFS_getLastError()));
85
+ }
86
+ return stat;
87
+ }
88
+
89
+ py::bytes physfs_cat(std::string file) {
90
+ if (!PHYSFS_isInit()) {
91
+ throw std::runtime_error("PHYSFS is not initialized, please call init() first");
92
+ }
93
+
94
+ PHYSFS_File *f;
95
+ f = PHYSFS_openRead(file.c_str());
96
+ if (f == NULL) {
97
+ throw std::runtime_error(string_format("failed to open. Reason: [%s]", PHYSFS_getLastError()));
98
+ }
99
+
100
+ std::stringstream output;
101
+ while (1)
102
+ {
103
+ char buffer[1024];
104
+ PHYSFS_sint64 rc;
105
+ PHYSFS_sint64 i;
106
+ rc = PHYSFS_readBytes(f, buffer, sizeof (buffer));
107
+ if (rc == -1 ) {
108
+ PHYSFS_close(f);
109
+ throw std::runtime_error(string_format("Error condition in reading. Reason: [%s]", PHYSFS_getLastError()));
110
+ }
111
+
112
+ output.write(buffer, rc);
113
+ if (rc < sizeof (buffer))
114
+ {
115
+ if (!PHYSFS_eof(f))
116
+ {
117
+ PHYSFS_close(f);
118
+ throw std::runtime_error(string_format("Error condition in reading. Reason: [%s]", PHYSFS_getLastError()));
119
+ }
120
+ PHYSFS_close(f);
121
+ break;
122
+ }
123
+ }
124
+ return py::bytes(output.str());
125
+ }
126
+
127
+
128
+ void register_physfs(py::module_ &m) {
129
+ m.doc() = R"pbdoc(
130
+ physfs - PhysicsFS is a library to provide abstract access to various archives.
131
+ -----------------------
132
+
133
+ .. currentmodule:: physfs
134
+
135
+ .. autosummary::
136
+ :toctree: _generate
137
+
138
+ init
139
+ )pbdoc";
140
+
141
+ m.def("init", &physfs_init, R"pbdoc(
142
+ Initialize the PhysicsFS library.
143
+
144
+ * This must be called before any other PhysicsFS function.
145
+ *
146
+ * This should be called prior to any attempts to change your process's
147
+ * current working directory.
148
+
149
+ )pbdoc");
150
+
151
+ m.def("deinit", &physfs_deinit, R"pbdoc(
152
+ Deinitialize the PhysicsFS library.
153
+
154
+ * This closes any files opened via PhysicsFS, blanks the search/write paths,
155
+ * frees memory, and invalidates all of your file handles.
156
+ *
157
+ * Note that this call can FAIL if there's a file open for writing that
158
+ * refuses to close (for example, the underlying operating system was
159
+ * buffering writes to network filesystem, and the fileserver has crashed,
160
+ * or a hard drive has failed, etc). It is usually best to close all write
161
+ * handles yourself before calling this function, so that you can gracefully
162
+ * handle a specific failure.
163
+ *
164
+ * Once successfully deinitialized, PHYSFS_init() can be called again to
165
+ * restart the subsystem. All default API states are restored at this
166
+ * point, with the exception of any custom allocator you might have
167
+ * specified, which survives between initializations.
168
+
169
+ )pbdoc");
170
+
171
+ m.def("mount", &physfs_mount, R"pbdoc(
172
+ Add an archive or directory to the search path.
173
+
174
+ * \param source directory or archive to add to the path, in
175
+ * platform-dependent notation.
176
+ * \param mountPoint Location in the interpolated tree that this archive
177
+ * will be "mounted", in platform-independent notation.
178
+ * NULL or "" is equivalent to "/".
179
+ * \param appendToPath nonzero to append to search path, zero to prepend.
180
+ )pbdoc", py::arg("source").none(false), py::arg("mountPoint") = "/", py::arg("appendToPath") = py::bool_(0));
181
+
182
+ m.def("unmount", &physfs_unmount, R"pbdoc(
183
+ Remove a directory or archive from the search path.
184
+
185
+ * This must be a (case-sensitive) match to a dir or archive already in the
186
+ * search path, specified in platform-dependent notation.
187
+ *
188
+ * This call will fail (and fail to remove from the path) if the element still
189
+ * has files open in it.
190
+ *
191
+ * \param oldSource dir/archive to remove.
192
+
193
+ )pbdoc", py::arg("oldSource").none(false));
194
+
195
+ m.def("ls", &enumerate_fs, R"pbdoc(
196
+ Get a file listing of a search path's directory.
197
+ )pbdoc", py::arg("dir") = "/");
198
+
199
+ m.def("stat", &physfs_stat, R"pbdoc(
200
+ Get various information about a directory or a file.
201
+ )pbdoc", py::arg("file").none(false));
202
+
203
+ m.def("cat", &physfs_cat, R"pbdoc(
204
+ Read bytes from a PhysicsFS filehandle
205
+ )pbdoc", py::arg("file").none(false));
206
+
207
+ m.def("read", &physfs_cat, R"pbdoc(
208
+ Read bytes from a PhysicsFS filehandle, read is alias of cat.
209
+ )pbdoc", py::arg("file").none(false));
210
+
211
+ py::class_<PHYSFS_Stat>(m, "PHYSFS_Stat")
212
+ .def_readwrite("filetype", &PHYSFS_Stat::filetype)
213
+ .def_readwrite("filesize", &PHYSFS_Stat::filesize)
214
+ ;
215
+
216
+ py::enum_<PHYSFS_FileType>(m, "PHYSFS_FileType")
217
+ .value("PHYSFS_FILETYPE_REGULAR", PHYSFS_FileType::PHYSFS_FILETYPE_REGULAR)
218
+ .value("PHYSFS_FILETYPE_DIRECTORY", PHYSFS_FileType::PHYSFS_FILETYPE_DIRECTORY)
219
+ .value("PHYSFS_FILETYPE_SYMLINK", PHYSFS_FileType::PHYSFS_FILETYPE_SYMLINK)
220
+ .value("PHYSFS_FILETYPE_OTHER", PHYSFS_FileType::PHYSFS_FILETYPE_OTHER);
221
+
222
+ }
@@ -0,0 +1,24 @@
1
+ from pathlib import Path
2
+ import physfs
3
+
4
+ rootdir = Path(__file__).parent
5
+ assert physfs.__version__ == '0.0.2'
6
+
7
+ physfs.init()
8
+ assert physfs.ls("/") == []
9
+
10
+ physfs.mount(str(rootdir / "./example.zip"))
11
+ assert physfs.ls("/") == ["example"]
12
+ assert physfs.cat("example/flag") == b"OqP$IwK7eiZyTWk4Xi3jYECi^IXLdZw1u@H5wOo4\n"
13
+
14
+ physfs.unmount(str(rootdir / "./example.zip"))
15
+ assert physfs.ls("/") == []
16
+
17
+ physfs.deinit()
18
+
19
+ E = None
20
+ try:
21
+ physfs.ls()
22
+ except RuntimeError as e:
23
+ E = e
24
+ assert E is not None