archive-r-python 0.1.2__tar.gz → 0.1.6__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.
Files changed (50) hide show
  1. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/LICENSE.txt +27 -7
  2. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/MANIFEST.in +2 -0
  3. {archive_r_python-0.1.2/archive_r_python.egg-info → archive_r_python-0.1.6}/PKG-INFO +6 -3
  4. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/README.md +3 -2
  5. archive_r_python-0.1.6/VERSION +1 -0
  6. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/data_stream.h +11 -0
  7. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/entry.h +5 -0
  8. archive_r_python-0.1.6/_vendor/archive_r/include/archive_r/platform_compat.h +19 -0
  9. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/archive_stack_cursor.cc +60 -66
  10. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/archive_stack_cursor.h +18 -4
  11. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/archive_stack_orchestrator.h +1 -1
  12. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/archive_type.h +2 -1
  13. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/entry_impl.h +0 -1
  14. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/multi_volume_stream_base.cc +4 -4
  15. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/system_file_stream.cc +56 -20
  16. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/system_file_stream.h +1 -1
  17. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/traverser.cc +0 -1
  18. {archive_r_python-0.1.2 → archive_r_python-0.1.6/archive_r_python.egg-info}/PKG-INFO +6 -3
  19. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/archive_r_python.egg-info/SOURCES.txt +7 -1
  20. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/setup.cfg +3 -1
  21. archive_r_python-0.1.6/setup.py +426 -0
  22. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/test/test_traverser.py +57 -4
  23. archive_r_python-0.1.6/tools/build-deps-macos.sh +220 -0
  24. archive_r_python-0.1.6/tools/build-deps-manylinux.sh +297 -0
  25. archive_r_python-0.1.2/VERSION +0 -1
  26. archive_r_python-0.1.2/setup.py +0 -173
  27. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/entry_fault.h +0 -0
  28. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/entry_metadata.h +0 -0
  29. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/multi_volume_stream_base.h +0 -0
  30. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/path_hierarchy.h +0 -0
  31. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/path_hierarchy_utils.h +0 -0
  32. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/include/archive_r/traverser.h +0 -0
  33. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/archive_stack_orchestrator.cc +0 -0
  34. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/archive_type.cc +0 -0
  35. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/data_stream.cc +0 -0
  36. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/entry.cc +0 -0
  37. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/entry_fault.cc +0 -0
  38. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/entry_fault_error.cc +0 -0
  39. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/entry_fault_error.h +0 -0
  40. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/multi_volume_manager.cc +0 -0
  41. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/multi_volume_manager.h +0 -0
  42. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/path_hierarchy.cc +0 -0
  43. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/path_hierarchy_utils.cc +0 -0
  44. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/_vendor/archive_r/src/simple_profiler.h +0 -0
  45. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/archive_r_python.egg-info/dependency_links.txt +0 -0
  46. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/archive_r_python.egg-info/not-zip-safe +0 -0
  47. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/archive_r_python.egg-info/top_level.txt +0 -0
  48. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/examples/traverse_archive.py +0 -0
  49. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/pyproject.toml +0 -0
  50. {archive_r_python-0.1.2 → archive_r_python-0.1.6}/src/archive_r_py.cc +0 -0
@@ -1,5 +1,5 @@
1
1
  archive_r License
2
- Version: 0.1.2 (2025-12-02)
2
+ Version: 0.1.6 (2025-12-10)
3
3
 
4
4
  ----------------------------------------
5
5
  Primary License
@@ -66,12 +66,32 @@ The following components are redistributed only because libarchive (bundled with
66
66
  - Purpose: libarchive dependency providing Zstandard compression; shipped within archive_r binaries.
67
67
  - License: BSD License (https://github.com/facebook/zstd)
68
68
 
69
- 8. OpenSSL 3
70
- - Purpose: libarchive dependency providing cryptographic support for encrypted archives; included with archive_r packages.
71
- - License: Apache License 2.0 with OpenSSL exception (https://www.openssl.org/source/license.html)
69
+ 8. Nettle
70
+ - Purpose: libarchive dependency providing cryptographic support (macOS/Linux); bundled with archive_r binaries.
71
+ - License: GNU LGPLv3+ or GNU GPLv2+ (https://www.lysator.liu.se/~nisse/nettle/)
72
72
 
73
- 9. libiconv / libcharset
74
- - Purpose: libxml2/libarchive dependency for character set conversion; redistributed with archive_r artifacts.
75
- - License: GNU LGPLv2.1+ (https://www.gnu.org/software/libiconv/)
73
+ 9. mini-gmp
74
+ - Purpose: Nettle dependency for arithmetic operations (macOS/Linux); bundled with archive_r binaries.
75
+ - License: GNU LGPLv3+ or GNU GPLv2+ (https://gmplib.org/)
76
+
77
+ 10. OpenSSL 3
78
+ - Purpose: libarchive dependency providing cryptographic support (Windows); bundled with archive_r binaries.
79
+ - License: Apache License 2.0 with OpenSSL exception (https://www.openssl.org/source/license.html)
80
+
81
+ 11. lz4
82
+ - Purpose: libarchive dependency providing LZ4 compression; shipped with archive_r artifacts when required.
83
+ - License: BSD 2-Clause (https://github.com/lz4/lz4)
84
+
85
+ 12. libb2 (BLAKE2)
86
+ - Purpose: libarchive dependency providing BLAKE2 hashing; bundled when archive formats require it.
87
+ - License: CC0 1.0 Universal (https://github.com/BLAKE2/libb2)
88
+
89
+ 13. libattr
90
+ - Purpose: libarchive dependency providing extended attribute support on POSIX platforms; included in POSIX builds only.
91
+ - License: LGPL-2.1-or-later for the library (https://savannah.nongnu.org/projects/attr)
92
+
93
+ 14. libacl
94
+ - Purpose: libarchive dependency providing POSIX ACL support; included in POSIX builds only.
95
+ - License: LGPL-2.1-or-later for the library (https://savannah.nongnu.org/projects/acl)
76
96
  Users of archive_r should review the linked third-party licenses to ensure
77
97
  compliance with their terms when redistributing this software.
@@ -9,3 +9,5 @@ recursive-include examples *.py
9
9
  recursive-include test *.py
10
10
  recursive-include _vendor/archive_r/include *
11
11
  recursive-include _vendor/archive_r/src *
12
+ include tools/build-deps-manylinux.sh
13
+ include tools/build-deps-macos.sh
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: archive_r_python
3
- Version: 0.1.2
3
+ Version: 0.1.6
4
4
  Summary: Python bindings for archive_r that recursively traverse nested archives without creating temporary extraction files
5
5
  Home-page: https://github.com/Raizo-TCS/archive_r
6
6
  Author: archive_r Team
@@ -17,6 +17,8 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Operating System :: POSIX :: Linux
20
+ Classifier: Operating System :: MacOS
21
+ Classifier: Operating System :: Microsoft :: Windows
20
22
  Classifier: Development Status :: 4 - Beta
21
23
  Classifier: Topic :: System :: Archiving
22
24
  Classifier: Topic :: Software Development :: Libraries
@@ -484,7 +486,7 @@ Or use the project-wide test runner:
484
486
 
485
487
  ```bash
486
488
  cd archive_r
487
- ./run_tests.sh
489
+ ./bindings/python/run_binding_tests.sh
488
490
  ```
489
491
 
490
492
  ---
@@ -609,4 +611,5 @@ The Python bindings are distributed under the MIT License, consistent with the a
609
611
 
610
612
  ---
611
613
 
612
- **Note**: This document describes archive_r Python bindings version 0.1.2.
614
+ **Note**: This document describes archive_r Python bindings version 0.1.6.
615
+
@@ -455,7 +455,7 @@ Or use the project-wide test runner:
455
455
 
456
456
  ```bash
457
457
  cd archive_r
458
- ./run_tests.sh
458
+ ./bindings/python/run_binding_tests.sh
459
459
  ```
460
460
 
461
461
  ---
@@ -580,4 +580,5 @@ The Python bindings are distributed under the MIT License, consistent with the a
580
580
 
581
581
  ---
582
582
 
583
- **Note**: This document describes archive_r Python bindings version 0.1.2.
583
+ **Note**: This document describes archive_r Python bindings version 0.1.6.
584
+
@@ -0,0 +1 @@
1
+ 0.1.6
@@ -8,6 +8,17 @@
8
8
  #include <functional>
9
9
  #include <memory>
10
10
  #include <sys/types.h>
11
+ #include <cstdint>
12
+
13
+ #ifdef _WIN32
14
+ #include <basetsd.h>
15
+ using ssize_t = SSIZE_T;
16
+ #endif
17
+
18
+ // Avoid conflict with potential 'read' macro on Windows
19
+ #ifdef read
20
+ #undef read
21
+ #endif
11
22
 
12
23
  namespace archive_r {
13
24
 
@@ -10,6 +10,11 @@
10
10
  #include <sys/types.h>
11
11
  #include <vector>
12
12
 
13
+ #ifdef _MSC_VER
14
+ #include <BaseTsd.h>
15
+ typedef SSIZE_T ssize_t;
16
+ #endif
17
+
13
18
  #include "archive_r/entry_fault.h"
14
19
  #include "archive_r/entry_metadata.h"
15
20
  #include "archive_r/path_hierarchy.h"
@@ -0,0 +1,19 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2025 archive_r Team
3
+
4
+ #pragma once
5
+
6
+ #include <sys/types.h>
7
+
8
+ #if defined(_WIN32)
9
+ # include <sys/stat.h>
10
+ # if !defined(_SSIZE_T_DEFINED)
11
+ # include <BaseTsd.h>
12
+ using ssize_t = SSIZE_T;
13
+ # define _SSIZE_T_DEFINED
14
+ # endif
15
+ # if !defined(_MODE_T_DEFINED)
16
+ using mode_t = unsigned short; // MSVC does not expose POSIX mode_t by default
17
+ # define _MODE_T_DEFINED
18
+ # endif
19
+ #endif
@@ -60,6 +60,11 @@ void StreamArchive::rewind() {
60
60
 
61
61
  PathHierarchy StreamArchive::source_hierarchy() const { return _stream->source_hierarchy(); }
62
62
 
63
+ std::shared_ptr<StreamArchive> StreamArchive::parent_archive() const {
64
+ auto entry_stream = std::dynamic_pointer_cast<EntryPayloadStream>(_stream);
65
+ return entry_stream ? entry_stream->parent_archive() : nullptr;
66
+ }
67
+
63
68
  la_ssize_t StreamArchive::read_callback_bridge(struct archive *a, void *client_data, const void **buff) {
64
69
  auto *archive = static_cast<StreamArchive *>(client_data);
65
70
 
@@ -120,7 +125,9 @@ EntryPayloadStream::EntryPayloadStream(std::shared_ptr<StreamArchive> parent_arc
120
125
  }
121
126
  }
122
127
 
123
- EntryPayloadStream::~EntryPayloadStream() = default;
128
+ EntryPayloadStream::~EntryPayloadStream() {
129
+ deactivate_active_part();
130
+ }
124
131
 
125
132
  std::shared_ptr<StreamArchive> EntryPayloadStream::parent_archive() const { return _parent_archive; }
126
133
 
@@ -143,11 +150,8 @@ void EntryPayloadStream::open_single_part(const PathHierarchy &single_part) {
143
150
  }
144
151
 
145
152
  void EntryPayloadStream::close_single_part() {
146
- if (_parent_archive->current_entryname.empty()) {
147
- return;
148
- }
149
-
150
- _parent_archive->skip_data();
153
+ // libarchive automatically skips unread data when reading the next header,
154
+ // so explicit skipping here is unnecessary and avoids potential exceptions in destructor.
151
155
  }
152
156
 
153
157
  ssize_t EntryPayloadStream::read_from_single_part(void *buffer, size_t size) {
@@ -170,7 +174,8 @@ int64_t EntryPayloadStream::size_of_single_part(const PathHierarchy &single_part
170
174
 
171
175
  ArchiveStackCursor::ArchiveStackCursor()
172
176
  : options_snapshot()
173
- , stream_stack() {}
177
+ , _current_stream(nullptr)
178
+ , _current_archive(nullptr) {}
174
179
 
175
180
  void ArchiveStackCursor::configure(const ArchiveOption &options) {
176
181
  options_snapshot = options;
@@ -178,16 +183,16 @@ void ArchiveStackCursor::configure(const ArchiveOption &options) {
178
183
 
179
184
  void ArchiveStackCursor::reset() {
180
185
  options_snapshot = ArchiveOption{};
181
- stream_stack.clear();
186
+ _current_stream = nullptr;
187
+ _current_archive = nullptr;
182
188
  }
183
189
 
184
190
  bool ArchiveStackCursor::descend() {
185
- if (stream_stack.empty()) {
186
- throw std::logic_error("stream stack is empty");
191
+ if (!_current_stream) {
192
+ throw std::logic_error("current stream is empty");
187
193
  }
188
194
 
189
- auto stream = stream_stack.back();
190
-
195
+ auto stream = _current_stream;
191
196
  if (auto *archive = current_archive()) {
192
197
  if (stream && !archive->current_entry_content_ready()) {
193
198
  stream->rewind();
@@ -196,17 +201,22 @@ bool ArchiveStackCursor::descend() {
196
201
 
197
202
  PathHierarchy dummy_hierarchy = stream->source_hierarchy();
198
203
  auto archive_ptr = std::make_shared<StreamArchive>(std::move(stream), options_snapshot);
199
- append_single(dummy_hierarchy, std::string{});
200
- stream_stack.emplace_back(std::make_shared<EntryPayloadStream>(archive_ptr, std::move(dummy_hierarchy)));
204
+ _current_archive = archive_ptr;
205
+ _current_stream = nullptr;
201
206
  return true;
202
207
  }
203
208
 
204
209
  bool ArchiveStackCursor::ascend() {
205
- if (stream_stack.size() <= 0) {
210
+ if (depth() <= 0) {
206
211
  return false;
207
212
  }
208
213
 
209
- stream_stack.pop_back();
214
+ if (_current_archive) {
215
+ _current_stream = _current_archive->get_stream();
216
+ _current_archive = _current_archive->parent_archive();
217
+ } else {
218
+ _current_stream = nullptr;
219
+ }
210
220
 
211
221
  return true;
212
222
  }
@@ -217,6 +227,8 @@ bool ArchiveStackCursor::next() {
217
227
  return false;
218
228
  }
219
229
 
230
+ _current_stream = nullptr;
231
+
220
232
  while (true) {
221
233
  if (!archive->skip_to_next_header()) {
222
234
  return false;
@@ -225,7 +237,8 @@ bool ArchiveStackCursor::next() {
225
237
  break;
226
238
  }
227
239
  }
228
- stream_stack.back() = create_stream(current_entry_hierarchy());
240
+
241
+ _current_stream = create_stream(current_entry_hierarchy());
229
242
  return true;
230
243
  }
231
244
 
@@ -233,33 +246,32 @@ bool ArchiveStackCursor::synchronize_to_hierarchy(const PathHierarchy &target_hi
233
246
  if (target_hierarchy.empty()) {
234
247
  throw_entry_fault("target hierarchy cannot be empty", {});
235
248
  }
236
-
237
- const size_t last_depth = target_hierarchy.size() - 1;
238
- if (stream_stack.size() < target_hierarchy.size()) {
239
- stream_stack.resize(target_hierarchy.size());
249
+
250
+ // 1. Ascend until we find a common ancestor
251
+ while (depth() > 0) {
252
+ auto current_h = _current_archive->source_hierarchy();
253
+ if (current_h.size() <= target_hierarchy.size() &&
254
+ hierarchies_equal(current_h, pathhierarchy_prefix_until(target_hierarchy, current_h.size() - 1))) {
255
+ break;
256
+ }
257
+ ascend();
240
258
  }
241
- for (size_t depth = 0; depth < target_hierarchy.size(); ++depth) {
242
- auto prefix = pathhierarchy_prefix_until(target_hierarchy, depth);
243
- auto stream = stream_stack[depth];
244
259
 
245
- // Reuse the existing stream when it already matches this prefix.
246
- if (stream && hierarchies_equal(stream->source_hierarchy(), prefix)) {
247
- continue;
260
+ // 2. Descend to target
261
+ for (size_t d = depth(); d < target_hierarchy.size(); ++d) {
262
+ auto prefix = pathhierarchy_prefix_until(target_hierarchy, d);
263
+
264
+ if (!_current_stream || !hierarchies_equal(_current_stream->source_hierarchy(), prefix)) {
265
+ _current_stream = create_stream(prefix);
266
+ _current_stream->rewind();
248
267
  }
249
- // Shrink the stack to the current depth before creating a fresh stream.
250
- stream_stack.resize(depth+1);
251
- stream = create_stream(prefix);
252
- stream_stack.back() = stream;
253
- stream->rewind();
254
-
255
- if (depth == last_depth) {
256
- return true;
268
+
269
+ if (d < target_hierarchy.size() - 1) {
270
+ descend();
257
271
  }
258
- // Descend into the archive for the next level of the hierarchy.
259
- descend();
260
272
  }
261
-
262
- return true;
273
+
274
+ return true;
263
275
  }
264
276
 
265
277
  ssize_t ArchiveStackCursor::read(void *buff, size_t len) {
@@ -267,38 +279,22 @@ ssize_t ArchiveStackCursor::read(void *buff, size_t len) {
267
279
  return 0;
268
280
  }
269
281
 
270
- if (stream_stack.empty()) {
271
- throw_entry_fault("Stream stack is empty", {});
282
+ if (StreamArchive *archive = current_archive()) {
283
+ return archive->read_current(buff, len);
272
284
  }
273
285
 
274
- auto stream = stream_stack.back();
275
- ssize_t bytes = 0;
276
- bytes = stream->read(buff, len);
277
-
278
- if (bytes < 0) {
279
- const std::string message = "Failed to read from active stream";
280
- throw_entry_fault(message, current_entry_hierarchy());
286
+ if (_current_stream) {
287
+ return _current_stream->read(buff, len);
281
288
  }
282
-
283
- return bytes;
289
+ return 0;
284
290
  }
285
291
 
286
292
  StreamArchive *ArchiveStackCursor::current_archive() {
287
- if (stream_stack.size() <= 0) {
288
- return nullptr;
289
- }
290
-
291
- const auto stream = std::dynamic_pointer_cast<EntryPayloadStream>(stream_stack.back());
292
- if (!stream) {
293
- return nullptr;
294
- }
295
-
296
- auto parent_archive = stream->parent_archive();
297
- return parent_archive ? parent_archive.get() : nullptr;
293
+ return _current_archive.get();
298
294
  }
299
295
 
300
296
  PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
301
- if (stream_stack.empty() || !stream_stack.front()) {
297
+ if (depth() == 0 || (!_current_stream && !_current_archive)) {
302
298
  return {};
303
299
  }
304
300
 
@@ -310,7 +306,7 @@ PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
310
306
  return path;
311
307
  }
312
308
 
313
- return stream_stack.front()->source_hierarchy();
309
+ return _current_stream->source_hierarchy();
314
310
  }
315
311
 
316
312
  std::shared_ptr<IDataStream> ArchiveStackCursor::create_stream(const PathHierarchy &hierarchy) {
@@ -322,9 +318,7 @@ std::shared_ptr<IDataStream> ArchiveStackCursor::create_stream(const PathHierarc
322
318
  }
323
319
  return std::make_shared<SystemFileStream>(hierarchy);
324
320
  }
325
- auto stream = std::dynamic_pointer_cast<EntryPayloadStream>(stream_stack.back());
326
-
327
- return std::make_shared<EntryPayloadStream>(stream->parent_archive(), hierarchy);
321
+ return std::make_shared<EntryPayloadStream>(_current_archive, hierarchy);
328
322
  }
329
323
 
330
324
  } // namespace archive_r
@@ -13,7 +13,6 @@
13
13
  #include <exception>
14
14
  #include <memory>
15
15
  #include <string>
16
- #include <sys/types.h>
17
16
  #include <vector>
18
17
 
19
18
  namespace archive_r {
@@ -32,6 +31,9 @@ public:
32
31
  void rewind() override;
33
32
 
34
33
  PathHierarchy source_hierarchy() const;
34
+ std::shared_ptr<StreamArchive> parent_archive() const;
35
+
36
+ std::shared_ptr<IDataStream> get_stream() const { return _stream; }
35
37
 
36
38
  private:
37
39
  static la_ssize_t read_callback_bridge(struct archive *a, void *client_data, const void **buff);
@@ -76,7 +78,7 @@ struct ArchiveStackCursor {
76
78
 
77
79
  void configure(const ArchiveOption &options);
78
80
  void reset();
79
- bool has_stream() const { return !stream_stack.empty(); }
81
+ bool has_stream() const { return _current_stream != nullptr; }
80
82
 
81
83
  bool descend();
82
84
  bool ascend();
@@ -84,7 +86,16 @@ struct ArchiveStackCursor {
84
86
  bool synchronize_to_hierarchy(const PathHierarchy &hierarchy);
85
87
  ssize_t read(void *buffer, size_t len);
86
88
 
87
- size_t depth() const { return stream_stack.size(); }
89
+ size_t depth() const {
90
+ size_t d = 0;
91
+ auto a = _current_archive;
92
+ while (a) {
93
+ d++;
94
+ a = a->parent_archive();
95
+ }
96
+ return d;
97
+ }
98
+
88
99
  StreamArchive *current_archive();
89
100
 
90
101
  PathHierarchy current_entry_hierarchy();
@@ -92,7 +103,10 @@ struct ArchiveStackCursor {
92
103
  std::shared_ptr<IDataStream> create_stream(const PathHierarchy &hierarchy);
93
104
 
94
105
  ArchiveOption options_snapshot;
95
- std::vector<std::shared_ptr<IDataStream>> stream_stack;
106
+
107
+ private:
108
+ std::shared_ptr<IDataStream> _current_stream;
109
+ std::shared_ptr<StreamArchive> _current_archive;
96
110
  };
97
111
 
98
112
  } // namespace archive_r
@@ -4,6 +4,7 @@
4
4
  #pragma once
5
5
 
6
6
  #include "archive_r/path_hierarchy.h"
7
+ #include "archive_r/platform_compat.h"
7
8
  #include "archive_type.h"
8
9
  #include "archive_stack_cursor.h"
9
10
  #include "entry_fault_error.h"
@@ -11,7 +12,6 @@
11
12
  #include <limits>
12
13
  #include <memory>
13
14
  #include <string>
14
- #include <sys/types.h>
15
15
  #include <unordered_set>
16
16
 
17
17
  namespace archive_r {
@@ -11,10 +11,11 @@
11
11
  #include <memory>
12
12
  #include <stdexcept>
13
13
  #include <string>
14
- #include <sys/types.h>
15
14
  #include <unordered_set>
16
15
  #include <vector>
17
16
 
17
+ #include "archive_r/platform_compat.h"
18
+
18
19
  namespace archive_r {
19
20
 
20
21
  struct archive_deleter {
@@ -8,7 +8,6 @@
8
8
  #include <filesystem>
9
9
  #include <memory>
10
10
  #include <optional>
11
- #include <sys/types.h> // for mode_t
12
11
  #include <unordered_set>
13
12
 
14
13
  namespace archive_r {
@@ -20,6 +20,7 @@ struct MultiVolumeStreamBase::Impl {
20
20
  std::vector<int64_t> part_offsets;
21
21
  std::size_t total_parts = 0;
22
22
  std::size_t active_part_index = 0;
23
+ std::size_t open_part_index = 0;
23
24
  bool part_open = false;
24
25
  int64_t logical_offset = 0;
25
26
  int64_t total_size = -1;
@@ -84,7 +85,7 @@ void MultiVolumeStreamBase::rewind() {
84
85
  }
85
86
 
86
87
  bool MultiVolumeStreamBase::at_end() const {
87
- return (_impl->active_part_index >= _impl->total_parts) && !_impl->part_open;
88
+ return _impl->active_part_index >= _impl->total_parts;
88
89
  }
89
90
 
90
91
  int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
@@ -122,14 +123,14 @@ int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
122
123
  int64_t MultiVolumeStreamBase::tell() const { return _impl->logical_offset; }
123
124
 
124
125
  void MultiVolumeStreamBase::Impl::ensure_part_active(std::size_t part_index) {
125
- if (part_open && active_part_index == part_index) {
126
+ if (part_open && open_part_index == part_index) {
126
127
  return;
127
128
  }
128
129
 
129
130
  self.deactivate_active_part();
130
131
  PathHierarchy single_part = pathhierarchy_select_single_part(self._logical_path, part_index);
131
132
  self.open_single_part(single_part);
132
- active_part_index = part_index;
133
+ open_part_index = part_index;
133
134
  part_open = true;
134
135
  }
135
136
 
@@ -144,7 +145,6 @@ bool MultiVolumeStreamBase::Impl::advance_to_next_part() {
144
145
  if (active_part_index >= total_parts) {
145
146
  return false;
146
147
  }
147
- self.deactivate_active_part();
148
148
  ++active_part_index;
149
149
  return active_part_index < total_parts;
150
150
  }