archive_r_ruby 0.1.8 → 0.1.9

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -0
  3. data/ext/archive_r/archive_r_ext.cc +6 -8
  4. data/ext/archive_r/vendor/archive_r/include/archive_r/data_stream.h +2 -2
  5. data/ext/archive_r/vendor/archive_r/include/archive_r/entry.h +8 -8
  6. data/ext/archive_r/vendor/archive_r/include/archive_r/multi_volume_stream_base.h +2 -2
  7. data/ext/archive_r/vendor/archive_r/include/archive_r/path_hierarchy_utils.h +0 -1
  8. data/ext/archive_r/vendor/archive_r/include/archive_r/platform_compat.h +8 -8
  9. data/ext/archive_r/vendor/archive_r/include/archive_r/traverser.h +2 -2
  10. data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.cc +10 -34
  11. data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.h +1 -3
  12. data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.cc +4 -5
  13. data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.h +1 -1
  14. data/ext/archive_r/vendor/archive_r/src/archive_type.cc +4 -13
  15. data/ext/archive_r/vendor/archive_r/src/archive_type.h +2 -2
  16. data/ext/archive_r/vendor/archive_r/src/entry.cc +2 -17
  17. data/ext/archive_r/vendor/archive_r/src/entry_fault_error.cc +23 -23
  18. data/ext/archive_r/vendor/archive_r/src/entry_impl.h +1 -2
  19. data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.cc +3 -8
  20. data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.h +2 -4
  21. data/ext/archive_r/vendor/archive_r/src/multi_volume_stream_base.cc +23 -14
  22. data/ext/archive_r/vendor/archive_r/src/path_hierarchy.cc +1 -4
  23. data/ext/archive_r/vendor/archive_r/src/path_hierarchy_utils.cc +14 -36
  24. data/ext/archive_r/vendor/archive_r/src/simple_profiler.h +64 -75
  25. data/ext/archive_r/vendor/archive_r/src/system_file_stream.cc +13 -26
  26. data/ext/archive_r/vendor/archive_r/src/system_file_stream.h +2 -2
  27. data/ext/archive_r/vendor/archive_r/src/traverser.cc +17 -41
  28. data/lib/archive_r.rb +5 -1
  29. metadata +7 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dcd3f5a0a9f170a6ee4a822bdd790801d91e4e2dfca60066af52d476c53cf33c
4
- data.tar.gz: 653bd71f6ef6a36c977b7881f7954d9838745ac316e87534d6199ddde8f434c4
3
+ metadata.gz: a67077047d1881a2760f1e04788746c09f7476ac86543d0edf506446f3c95d27
4
+ data.tar.gz: 7c9c88796f1382285ff08cbcc2e61e59cbe517ef81d72eb7d41ef2c20ddb438a
5
5
  SHA512:
6
- metadata.gz: af0d8b32e8823256e7b2f92ca7f1fe653890c77ada2c8a08829cb89d1ef285e93b6f85a30f43a52373c66b3417ae708654676816be3d1df627eaabfadc848b31
7
- data.tar.gz: cca473ded868f07468f5b3dd59d6d7f737594af4f3470940ebed7287fbaaf33f173fbc167d2febfcc73eb4c836dd51b352c08558519f329e4cee8cd8604d77cf
6
+ metadata.gz: a5129e0027a2f4bd1d9bf99f98589f9713408deb0a3ebf207101af4ea25b371ee81396579396590e6b659187967a84fb967d9cbc5dae6cf167eeb3f4345b43ed
7
+ data.tar.gz: 118cb09083a9ca57fa4a90ad719a16178bcdd4d5f7926892f31c5849a9af0e40487dfe1d4f6bdaee61c684d942db3b3c43195fcee7d510ddcf0ed5b8f34a1f00
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.9
@@ -15,13 +15,13 @@
15
15
  #ifdef memcpy
16
16
  #undef memcpy
17
17
  #endif
18
+ #include <limits>
19
+ #include <optional>
18
20
  #include <stdexcept>
19
21
  #include <string>
20
22
  #include <utility>
21
23
  #include <variant>
22
24
  #include <vector>
23
- #include <limits>
24
- #include <optional>
25
25
 
26
26
  using namespace archive_r;
27
27
 
@@ -295,16 +295,14 @@ static void stream_wrapper_free(void *ptr) {
295
295
  delete wrapper;
296
296
  }
297
297
 
298
- static size_t stream_wrapper_memsize(const void *ptr) {
299
- return sizeof(RubyStreamWrapper);
300
- }
298
+ static size_t stream_wrapper_memsize(const void *ptr) { return sizeof(RubyStreamWrapper); }
301
299
 
302
300
  static const rb_data_type_t stream_wrapper_type = {
303
301
  "ArchiveR::Stream",
304
302
  {
305
- nullptr,
306
- stream_wrapper_free,
307
- stream_wrapper_memsize,
303
+ nullptr,
304
+ stream_wrapper_free,
305
+ stream_wrapper_memsize,
308
306
  },
309
307
  nullptr,
310
308
  nullptr,
@@ -3,12 +3,12 @@
3
3
 
4
4
  #pragma once
5
5
 
6
- #include "archive_r/platform_compat.h"
7
6
  #include "archive_r/path_hierarchy.h"
7
+ #include "archive_r/platform_compat.h"
8
8
 
9
+ #include <cstdint>
9
10
  #include <functional>
10
11
  #include <memory>
11
- #include <cstdint>
12
12
 
13
13
  namespace archive_r {
14
14
 
@@ -97,8 +97,8 @@ public:
97
97
  /**
98
98
  * @brief Read data from the entry
99
99
  *
100
- * Each call uses an internal ArchiveStackOrchestrator so reads remain valid even
101
- * if the owning iterator advances.
100
+ * Each call uses an internal ArchiveStackOrchestrator so reads remain valid even
101
+ * if the owning iterator advances.
102
102
  *
103
103
  * @param buffer Buffer to read data into
104
104
  * @param length Maximum number of bytes to read
@@ -109,9 +109,9 @@ public:
109
109
  /**
110
110
  * @brief Enable or disable automatic descent into this entry
111
111
  * @param enabled true to descend (default), false to keep traversal at current level
112
- *
113
- * This control is only available for entries that are managed by a Traverser.
114
- * Calling this on an Entry that is not traverser-managed reports a fault.
112
+ *
113
+ * This control is only available for entries that are managed by a Traverser.
114
+ * Calling this on an Entry that is not traverser-managed reports a fault.
115
115
  */
116
116
  void set_descent(bool enabled);
117
117
 
@@ -139,9 +139,9 @@ public:
139
139
  * }
140
140
  * }
141
141
  * @endcode
142
- *
143
- * This control is only available for entries that are managed by a Traverser.
144
- * Calling this on an Entry that is not traverser-managed reports a fault.
142
+ *
143
+ * This control is only available for entries that are managed by a Traverser.
144
+ * Calling this on an Entry that is not traverser-managed reports a fault.
145
145
  */
146
146
  void set_multi_volume_group(const std::string &base_name, const MultiVolumeGroupOptions &options = {});
147
147
 
@@ -30,8 +30,8 @@ protected:
30
30
  virtual void open_single_part(const PathHierarchy &single_part) = 0;
31
31
  virtual void close_single_part() = 0;
32
32
  virtual ssize_t read_from_single_part(void *buffer, size_t size) = 0;
33
- virtual int64_t seek_within_single_part(int64_t offset, int whence) = 0;
34
- virtual int64_t size_of_single_part(const PathHierarchy &single_part) = 0;
33
+ virtual int64_t seek_within_single_part(int64_t offset, int whence);
34
+ virtual int64_t size_of_single_part(const PathHierarchy &single_part);
35
35
 
36
36
  PathHierarchy _logical_path;
37
37
  void deactivate_active_part();
@@ -33,5 +33,4 @@ bool entry_name_from_component(const PathEntry &entry, std::string &output);
33
33
  std::string path_entry_display(const PathEntry &entry);
34
34
  std::string hierarchy_display(const PathHierarchy &hierarchy);
35
35
 
36
-
37
36
  } // namespace archive_r
@@ -6,16 +6,16 @@
6
6
  #include <sys/types.h>
7
7
 
8
8
  #if defined(_WIN32)
9
- # include <sys/stat.h>
10
- # include <BaseTsd.h>
11
- # if !defined(_SSIZE_T_DEFINED)
9
+ #include <BaseTsd.h>
10
+ #include <sys/stat.h>
11
+ #if !defined(_SSIZE_T_DEFINED)
12
12
  using ssize_t = SSIZE_T;
13
- # define _SSIZE_T_DEFINED
14
- # endif
15
- # if !defined(_MODE_T_DEFINED)
13
+ #define _SSIZE_T_DEFINED
14
+ #endif
15
+ #if !defined(_MODE_T_DEFINED)
16
16
  using mode_t = unsigned short; // MSVC does not expose POSIX mode_t by default
17
- # define _MODE_T_DEFINED
18
- # endif
17
+ #define _MODE_T_DEFINED
18
+ #endif
19
19
  #endif
20
20
 
21
21
  namespace archive_r {
@@ -75,8 +75,8 @@ public:
75
75
  * Provide one or more paths to traverse. Single-path traversal can be
76
76
  * achieved by passing a container with one element:
77
77
  * Traverser traverser({make_single_path("archive.tar.gz")});
78
- *
79
- * @throws std::invalid_argument if paths is empty or contains an empty hierarchy
78
+ *
79
+ * @throws std::invalid_argument if paths is empty or contains an empty hierarchy
80
80
  */
81
81
  explicit Traverser(std::vector<PathHierarchy> paths, TraverserOptions options = {});
82
82
 
@@ -125,9 +125,7 @@ EntryPayloadStream::EntryPayloadStream(std::shared_ptr<StreamArchive> parent_arc
125
125
  }
126
126
  }
127
127
 
128
- EntryPayloadStream::~EntryPayloadStream() {
129
- deactivate_active_part();
130
- }
128
+ EntryPayloadStream::~EntryPayloadStream() { deactivate_active_part(); }
131
129
 
132
130
  std::shared_ptr<StreamArchive> EntryPayloadStream::parent_archive() const { return _parent_archive; }
133
131
 
@@ -154,19 +152,7 @@ void EntryPayloadStream::close_single_part() {
154
152
  // so explicit skipping here is unnecessary and avoids potential exceptions in destructor.
155
153
  }
156
154
 
157
- ssize_t EntryPayloadStream::read_from_single_part(void *buffer, size_t size) {
158
- if (size == 0) {
159
- return 0;
160
- }
161
- return _parent_archive->read_current(buffer, size);
162
- }
163
-
164
- int64_t EntryPayloadStream::seek_within_single_part(int64_t offset, int whence) { return -1; }
165
-
166
- int64_t EntryPayloadStream::size_of_single_part(const PathHierarchy &single_part) {
167
- (void)single_part;
168
- return -1;
169
- }
155
+ ssize_t EntryPayloadStream::read_from_single_part(void *buffer, size_t size) { return _parent_archive->read_current(buffer, size); }
170
156
 
171
157
  // ============================================================================
172
158
  // ArchiveStackCursor Implementation
@@ -177,9 +163,7 @@ ArchiveStackCursor::ArchiveStackCursor()
177
163
  , _current_stream(nullptr)
178
164
  , _current_archive(nullptr) {}
179
165
 
180
- void ArchiveStackCursor::configure(const ArchiveOption &options) {
181
- options_snapshot = options;
182
- }
166
+ void ArchiveStackCursor::configure(const ArchiveOption &options) { options_snapshot = options; }
183
167
 
184
168
  void ArchiveStackCursor::reset() {
185
169
  options_snapshot = ArchiveOption{};
@@ -207,17 +191,12 @@ bool ArchiveStackCursor::descend() {
207
191
  }
208
192
 
209
193
  bool ArchiveStackCursor::ascend() {
210
- if (depth() <= 0) {
194
+ if (!_current_archive) {
211
195
  return false;
212
196
  }
213
197
 
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
- }
220
-
198
+ _current_stream = _current_archive->get_stream();
199
+ _current_archive = _current_archive->parent_archive();
221
200
  return true;
222
201
  }
223
202
 
@@ -250,8 +229,7 @@ bool ArchiveStackCursor::synchronize_to_hierarchy(const PathHierarchy &target_hi
250
229
  // 1. Ascend until we find a common ancestor
251
230
  while (depth() > 0) {
252
231
  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))) {
232
+ if (current_h.size() <= target_hierarchy.size() && hierarchies_equal(current_h, pathhierarchy_prefix_until(target_hierarchy, current_h.size() - 1))) {
255
233
  break;
256
234
  }
257
235
  ascend();
@@ -289,12 +267,10 @@ ssize_t ArchiveStackCursor::read(void *buff, size_t len) {
289
267
  return 0;
290
268
  }
291
269
 
292
- StreamArchive *ArchiveStackCursor::current_archive() {
293
- return _current_archive.get();
294
- }
270
+ StreamArchive *ArchiveStackCursor::current_archive() { return _current_archive.get(); }
295
271
 
296
272
  PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
297
- if (depth() == 0 || (!_current_stream && !_current_archive)) {
273
+ if (!_current_stream && !_current_archive) {
298
274
  return {};
299
275
  }
300
276
 
@@ -306,7 +282,7 @@ PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
306
282
  return path;
307
283
  }
308
284
 
309
- return _current_stream->source_hierarchy();
285
+ return _current_stream ? _current_stream->source_hierarchy() : PathHierarchy{};
310
286
  }
311
287
 
312
288
  std::shared_ptr<IDataStream> ArchiveStackCursor::create_stream(const PathHierarchy &hierarchy) {
@@ -4,10 +4,10 @@
4
4
  #pragma once
5
5
 
6
6
  #include "archive_r/data_stream.h"
7
+ #include "archive_r/multi_volume_stream_base.h"
7
8
  #include "archive_r/path_hierarchy.h"
8
9
  #include "archive_type.h"
9
10
  #include "entry_fault_error.h"
10
- #include "archive_r/multi_volume_stream_base.h"
11
11
  #include <array>
12
12
  #include <cstddef>
13
13
  #include <exception>
@@ -64,8 +64,6 @@ private:
64
64
  void open_single_part(const PathHierarchy &single_part) override;
65
65
  void close_single_part() override;
66
66
  ssize_t read_from_single_part(void *buffer, size_t size) override;
67
- int64_t seek_within_single_part(int64_t offset, int whence) override;
68
- int64_t size_of_single_part(const PathHierarchy &single_part) override;
69
67
  };
70
68
 
71
69
  // ============================================================================
@@ -2,8 +2,8 @@
2
2
  // Copyright (c) 2025 archive_r Team
3
3
 
4
4
  #include "archive_stack_orchestrator.h"
5
- #include "archive_r/path_hierarchy_utils.h"
6
5
  #include "archive_r/entry_fault.h"
6
+ #include "archive_r/path_hierarchy_utils.h"
7
7
  #include "system_file_stream.h"
8
8
 
9
9
  #include <algorithm>
@@ -19,8 +19,7 @@
19
19
  namespace archive_r {
20
20
 
21
21
  ArchiveStackOrchestrator::ArchiveStackOrchestrator(const ArchiveOption &options)
22
- : _archive_options(options)
23
- {
22
+ : _archive_options(options) {
24
23
  _head.configure(_archive_options);
25
24
  }
26
25
 
@@ -135,12 +134,12 @@ void ArchiveStackOrchestrator::mark_entry_as_multi_volume(const PathHierarchy &e
135
134
  }
136
135
 
137
136
  bool ArchiveStackOrchestrator::descend_pending_multi_volumes() {
138
- const PathHierarchy current_hierarchy = _head.current_entry_hierarchy();
137
+ const PathHierarchy current_hierarchy = (depth() == 0) ? PathHierarchy{} : _head.current_entry_hierarchy();
139
138
  PathHierarchy multi_volume_target;
140
139
  if (!_multi_volume_manager.pop_multi_volume_group(current_hierarchy, multi_volume_target)) {
141
140
  return false;
142
141
  }
143
-
142
+
144
143
  _head.synchronize_to_hierarchy(multi_volume_target);
145
144
  _head.descend();
146
145
  return true;
@@ -5,8 +5,8 @@
5
5
 
6
6
  #include "archive_r/path_hierarchy.h"
7
7
  #include "archive_r/platform_compat.h"
8
- #include "archive_type.h"
9
8
  #include "archive_stack_cursor.h"
9
+ #include "archive_type.h"
10
10
  #include "entry_fault_error.h"
11
11
  #include "multi_volume_manager.h"
12
12
  #include <limits>
@@ -232,9 +232,7 @@ bool Archive::search_forward_until_eof(const std::string &entryname) {
232
232
  if (current_entryname == entryname) {
233
233
  return true;
234
234
  }
235
- if (!skip_data()) {
236
- return false;
237
- }
235
+ skip_data();
238
236
  }
239
237
  return false;
240
238
  }
@@ -247,9 +245,7 @@ bool Archive::search_until_position(const std::string &entryname, const std::str
247
245
  if (current_entryname == stop_position) {
248
246
  break;
249
247
  }
250
- if (!skip_data()) {
251
- return false;
252
- }
248
+ skip_data();
253
249
  }
254
250
  return false;
255
251
  }
@@ -453,14 +449,9 @@ EntryMetadataMap Archive::current_entry_metadata(const std::unordered_set<std::s
453
449
  }
454
450
  }
455
451
 
456
- ssize_t acl_length = 0;
457
- char *acl_text = wants("acl_text") ? archive_entry_acl_to_text(current_entry, &acl_length, ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) : nullptr;
452
+ char *acl_text = wants("acl_text") ? archive_entry_acl_to_text(current_entry, nullptr, ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) : nullptr;
458
453
  if (acl_text) {
459
- if (acl_length >= 0) {
460
- metadata["acl_text"] = std::string(acl_text, static_cast<size_t>(acl_length));
461
- } else {
462
- metadata["acl_text"] = std::string(acl_text);
463
- }
454
+ metadata["acl_text"] = std::string(acl_text);
464
455
  std::free(acl_text);
465
456
  }
466
457
 
@@ -26,8 +26,8 @@ using archive_ptr = std::unique_ptr<struct archive, archive_deleter>;
26
26
  using open_delegate = std::function<int(struct archive *ar)>;
27
27
 
28
28
  struct ArchiveOption {
29
- std::vector<std::string> passphrases; ///< Passphrases for encrypted archives
30
- std::vector<std::string> formats; ///< Specific format names to enable (empty = all)
29
+ std::vector<std::string> passphrases; ///< Passphrases for encrypted archives
30
+ std::vector<std::string> formats; ///< Specific format names to enable (empty = all)
31
31
  std::unordered_set<std::string> metadata_keys; ///< Metadata keys to capture (empty = none)
32
32
  };
33
33
 
@@ -32,24 +32,9 @@ Entry::Impl::Impl(const Impl &other)
32
32
  , _descend_enabled(other._descend_enabled)
33
33
  , _orchestrator(nullptr)
34
34
  , _shares_traverser_orchestrator(false)
35
- , _archive_options(other._archive_options) {
36
- }
35
+ , _archive_options(other._archive_options) {}
37
36
 
38
37
  // Copy assignment operator
39
- Entry::Impl &Entry::Impl::operator=(const Impl &other) {
40
- if (this != &other) {
41
- _path_hierarchy = other._path_hierarchy;
42
- _size = other._size;
43
- _filetype = other._filetype;
44
- _metadata = other._metadata;
45
- _descend_enabled = other._descend_enabled;
46
- _orchestrator.reset();
47
- _shares_traverser_orchestrator = false;
48
- _archive_options = other._archive_options;
49
- }
50
- return *this;
51
- }
52
-
53
38
  Entry::Impl::Impl(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent)
54
39
  : _path_hierarchy(hierarchy)
55
40
  , _size(0)
@@ -199,7 +184,7 @@ ssize_t Entry::Impl::read(void *buffer, size_t length) {
199
184
  // ============================================================================
200
185
 
201
186
  Entry::Entry(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent)
202
- : _impl(std::make_unique<Impl>(hierarchy, std::move(data_source_orchestrator), default_descent)) {}
187
+ : _impl(std::make_unique<Impl>(hierarchy, std::move(data_source_orchestrator), default_descent)) {}
203
188
 
204
189
  Entry::Entry(Impl *impl)
205
190
  : _impl(impl) {}
@@ -18,35 +18,35 @@ EntryFaultError::EntryFaultError(EntryFault fault, const std::string &internal_m
18
18
  , _fault(std::move(fault)) {}
19
19
 
20
20
  EntryFaultError make_entry_fault_error(const std::string &message, PathHierarchy hierarchy, int errno_value) {
21
- EntryFault fault;
22
- fault.hierarchy = std::move(hierarchy);
23
- fault.message = message;
24
- fault.errno_value = errno_value;
25
- return EntryFaultError(std::move(fault));
21
+ EntryFault fault;
22
+ fault.hierarchy = std::move(hierarchy);
23
+ fault.message = message;
24
+ fault.errno_value = errno_value;
25
+ return EntryFaultError(std::move(fault));
26
26
  }
27
27
 
28
28
  std::string format_errno_error(const std::string &prefix, int err) {
29
- if (err == 0) {
30
- return prefix;
31
- }
32
-
33
- std::string message = prefix;
34
- message.append(": ");
35
- message.append(std::strerror(err));
36
- message.append(" (posix errno=");
37
- message.append(std::to_string(err));
38
- message.push_back(')');
39
- return message;
29
+ if (err == 0) {
30
+ return prefix;
31
+ }
32
+
33
+ std::string message = prefix;
34
+ message.append(": ");
35
+ message.append(std::strerror(err));
36
+ message.append(" (posix errno=");
37
+ message.append(std::to_string(err));
38
+ message.push_back(')');
39
+ return message;
40
40
  }
41
41
 
42
42
  std::string format_path_errno_error(const std::string &action, const std::string &path, int err) {
43
- std::string prefix = action;
44
- if (!path.empty()) {
45
- prefix.append(" '");
46
- prefix.append(path);
47
- prefix.push_back('\'');
48
- }
49
- return format_errno_error(prefix, err);
43
+ std::string prefix = action;
44
+ if (!path.empty()) {
45
+ prefix.append(" '");
46
+ prefix.append(path);
47
+ prefix.push_back('\'');
48
+ }
49
+ return format_errno_error(prefix, err);
50
50
  }
51
51
 
52
52
  std::string prefer_error_detail(const std::string &detail, const std::string &fallback) { return detail.empty() ? fallback : detail; }
@@ -19,7 +19,6 @@ public:
19
19
  // No libarchive dependency
20
20
  // Copy constructor and assignment (orchestrator is not copied)
21
21
  Impl(const Impl &other);
22
- Impl &operator=(const Impl &other);
23
22
 
24
23
  Impl(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent);
25
24
 
@@ -45,7 +44,7 @@ private:
45
44
  EntryMetadataMap _metadata;
46
45
  bool _descend_enabled = true; // Flag to control automatic descent
47
46
 
48
- std::shared_ptr<ArchiveStackOrchestrator> _orchestrator; ///< Active orchestrator (shared with traverser or detached copy)
47
+ std::shared_ptr<ArchiveStackOrchestrator> _orchestrator; ///< Active orchestrator (shared with traverser or detached copy)
49
48
  bool _shares_traverser_orchestrator = false;
50
49
 
51
50
  mutable std::optional<ArchiveOption> _archive_options;
@@ -10,9 +10,7 @@
10
10
 
11
11
  namespace archive_r {
12
12
 
13
- MultiVolumeManager::MultiVolumeGroup &MultiVolumeManager::get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy,
14
- const std::string &base_name,
15
- PathEntry::Parts::Ordering ordering) {
13
+ MultiVolumeManager::MultiVolumeGroup &MultiVolumeManager::get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name, PathEntry::Parts::Ordering ordering) {
16
14
  GroupList &groups = _multi_volume_groups[parent_hierarchy];
17
15
  auto it = std::find_if(groups.begin(), groups.end(), [&](const MultiVolumeGroup &group) { return group.base_name == base_name; });
18
16
 
@@ -47,17 +45,14 @@ bool MultiVolumeManager::pop_group_for_parent(const PathHierarchy &parent_hierar
47
45
  return true;
48
46
  }
49
47
 
50
- void MultiVolumeManager::mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name,
51
- PathEntry::Parts::Ordering ordering) {
48
+ void MultiVolumeManager::mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name, PathEntry::Parts::Ordering ordering) {
52
49
  if (entry_path.empty() || pathhierarchy_is_multivolume(entry_path)) {
53
50
  return;
54
51
  }
55
52
 
56
53
  MultiVolumeGroup &target = get_or_create_multi_volume_group(parent_hierarchy(entry_path), base_name, ordering);
57
54
  auto &parts = target.parts;
58
- const bool exists = std::any_of(parts.begin(), parts.end(), [&](const PathHierarchy &existing) {
59
- return hierarchies_equal(existing, entry_path);
60
- });
55
+ const bool exists = std::any_of(parts.begin(), parts.end(), [&](const PathHierarchy &existing) { return hierarchies_equal(existing, entry_path); });
61
56
  if (!exists) {
62
57
  parts.push_back(entry_path);
63
58
  }
@@ -24,14 +24,12 @@ public:
24
24
  using GroupList = std::vector<MultiVolumeGroup>;
25
25
  using ParentGroupMap = std::map<PathHierarchy, GroupList, PathHierarchyLess>;
26
26
 
27
- void mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name,
28
- PathEntry::Parts::Ordering ordering = PathEntry::Parts::Ordering::Natural);
27
+ void mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name, PathEntry::Parts::Ordering ordering = PathEntry::Parts::Ordering::Natural);
29
28
 
30
29
  bool pop_multi_volume_group(const PathHierarchy &current_hierarchy, PathHierarchy &multi_volume_hierarchy);
31
30
 
32
31
  private:
33
- MultiVolumeGroup &get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name,
34
- PathEntry::Parts::Ordering ordering);
32
+ MultiVolumeGroup &get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name, PathEntry::Parts::Ordering ordering);
35
33
 
36
34
  bool pop_group_for_parent(const PathHierarchy &parent_hierarchy, MultiVolumeGroup &out_group);
37
35
 
@@ -33,9 +33,9 @@ struct MultiVolumeStreamBase::Impl {
33
33
  };
34
34
 
35
35
  MultiVolumeStreamBase::MultiVolumeStreamBase(PathHierarchy logical_path, bool supports_seek)
36
- : _logical_path(std::move(logical_path))
37
- , _supports_seek(supports_seek)
38
- , _impl(std::make_unique<Impl>(*this)) {
36
+ : _logical_path(std::move(logical_path))
37
+ , _supports_seek(supports_seek)
38
+ , _impl(std::make_unique<Impl>(*this)) {
39
39
  _impl->total_parts = pathhierarchy_volume_size(_logical_path);
40
40
  if (_impl->total_parts == 0) {
41
41
  throw std::invalid_argument("MultiVolumeStreamBase requires at least one volume component");
@@ -84,9 +84,7 @@ void MultiVolumeStreamBase::rewind() {
84
84
  _impl->logical_offset = 0;
85
85
  }
86
86
 
87
- bool MultiVolumeStreamBase::at_end() const {
88
- return _impl->active_part_index >= _impl->total_parts;
89
- }
87
+ bool MultiVolumeStreamBase::at_end() const { return _impl->active_part_index >= _impl->total_parts; }
90
88
 
91
89
  int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
92
90
  if (!_supports_seek) {
@@ -122,6 +120,17 @@ int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
122
120
 
123
121
  int64_t MultiVolumeStreamBase::tell() const { return _impl->logical_offset; }
124
122
 
123
+ int64_t MultiVolumeStreamBase::seek_within_single_part(int64_t offset, int whence) {
124
+ (void)offset;
125
+ (void)whence;
126
+ return -1;
127
+ }
128
+
129
+ int64_t MultiVolumeStreamBase::size_of_single_part(const PathHierarchy &single_part) {
130
+ (void)single_part;
131
+ return -1;
132
+ }
133
+
125
134
  void MultiVolumeStreamBase::Impl::ensure_part_active(std::size_t part_index) {
126
135
  if (part_open && open_part_index == part_index) {
127
136
  return;
@@ -173,14 +182,14 @@ bool MultiVolumeStreamBase::Impl::ensure_size_metadata() {
173
182
 
174
183
  int64_t MultiVolumeStreamBase::Impl::compute_target_offset(int64_t offset, int whence) const {
175
184
  switch (whence) {
176
- case SEEK_SET:
177
- return offset;
178
- case SEEK_CUR:
179
- return logical_offset + offset;
180
- case SEEK_END:
181
- return total_size + offset;
182
- default:
183
- return -1;
185
+ case SEEK_SET:
186
+ return offset;
187
+ case SEEK_CUR:
188
+ return logical_offset + offset;
189
+ case SEEK_END:
190
+ return total_size + offset;
191
+ default:
192
+ return -1;
184
193
  }
185
194
  }
186
195
 
@@ -107,9 +107,7 @@ PathHierarchy make_single_path(const std::string &root) {
107
107
 
108
108
  void append_single(PathHierarchy &hierarchy, std::string value) { hierarchy.emplace_back(PathEntry::single(std::move(value))); }
109
109
 
110
- void append_multi_volume(PathHierarchy &hierarchy, std::vector<std::string> parts, PathEntry::Parts::Ordering ordering) {
111
- hierarchy.emplace_back(PathEntry::multi_volume(std::move(parts), ordering));
112
- }
110
+ void append_multi_volume(PathHierarchy &hierarchy, std::vector<std::string> parts, PathEntry::Parts::Ordering ordering) { hierarchy.emplace_back(PathEntry::multi_volume(std::move(parts), ordering)); }
113
111
 
114
112
  PathHierarchy pathhierarchy_prefix_until(const PathHierarchy &hierarchy, size_t inclusive_index) {
115
113
  if (hierarchy.empty() || inclusive_index >= hierarchy.size()) {
@@ -126,5 +124,4 @@ PathHierarchy parent_hierarchy(const PathHierarchy &hierarchy) {
126
124
  return pathhierarchy_prefix_until(hierarchy, hierarchy.size() - 2);
127
125
  }
128
126
 
129
-
130
127
  } // namespace archive_r
@@ -73,10 +73,6 @@ bool determine_multi_volume_segments(const std::vector<PathHierarchy> &sources,
73
73
  }
74
74
 
75
75
  bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const CollapseSegments &segments, std::vector<std::string> &parts) {
76
- if (sources.empty()) {
77
- return false;
78
- }
79
-
80
76
  const std::size_t suffix_size = segments.suffix.size();
81
77
  const std::size_t required_size = segments.multi_volume_depth + 1 + suffix_size;
82
78
 
@@ -111,14 +107,6 @@ bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const
111
107
  return true;
112
108
  }
113
109
 
114
- bool flatten_single_entry(const PathEntry &entry, std::string &output) {
115
- if (entry.is_single()) {
116
- output = entry.single_value();
117
- return true;
118
- }
119
- return flatten_entry_to_string(entry, output);
120
- }
121
-
122
110
  } // namespace
123
111
 
124
112
  const std::string *path_entry_component_at(const PathEntry &entry, std::size_t index) {
@@ -129,14 +117,10 @@ const std::string *path_entry_component_at(const PathEntry &entry, std::size_t i
129
117
  return nullptr;
130
118
  }
131
119
 
132
- if (entry.is_multi_volume()) {
133
- const auto &parts = entry.multi_volume_parts().values;
134
- if (index < parts.size()) {
135
- return &parts[index];
136
- }
137
- return nullptr;
120
+ const auto &parts = entry.multi_volume_parts().values;
121
+ if (index < parts.size()) {
122
+ return &parts[index];
138
123
  }
139
-
140
124
  return nullptr;
141
125
  }
142
126
 
@@ -162,11 +146,7 @@ std::string pathhierarchy_volume_entry_name(const PathHierarchy &logical, std::s
162
146
  return {};
163
147
  }
164
148
 
165
- std::string entry_name;
166
- if (!flatten_single_entry(tail, entry_name)) {
167
- return {};
168
- }
169
- return entry_name;
149
+ return tail.single_value();
170
150
  }
171
151
 
172
152
  const auto &parts = tail.multi_volume_parts().values;
@@ -241,20 +221,18 @@ std::string path_entry_display(const PathEntry &entry) {
241
221
  if (entry.is_single()) {
242
222
  return entry.single_value();
243
223
  }
244
- if (entry.is_multi_volume()) {
245
- std::string value = "[";
246
- bool first = true;
247
- for (const auto &part : entry.multi_volume_parts().values) {
248
- if (!first) {
249
- value.push_back('|');
250
- }
251
- value += part;
252
- first = false;
224
+
225
+ std::string value = "[";
226
+ bool first = true;
227
+ for (const auto &part : entry.multi_volume_parts().values) {
228
+ if (!first) {
229
+ value.push_back('|');
253
230
  }
254
- value.push_back(']');
255
- return value;
231
+ value += part;
232
+ first = false;
256
233
  }
257
- return {};
234
+ value.push_back(']');
235
+ return value;
258
236
  }
259
237
 
260
238
  std::string hierarchy_display(const PathHierarchy &hierarchy) {
@@ -4,106 +4,95 @@
4
4
  #pragma once
5
5
  #include <string>
6
6
 
7
+ #include <algorithm>
7
8
  #include <chrono>
9
+ #include <iomanip>
8
10
  #include <iostream>
9
11
  #include <map>
10
- #include <vector>
11
- #include <algorithm>
12
- #include <iomanip>
13
12
  #include <mutex>
14
-
13
+ #include <vector>
15
14
 
16
15
  namespace archive_r {
17
16
  namespace internal {
18
17
 
19
-
20
-
21
18
  class SimpleProfiler {
22
19
  public:
23
- static SimpleProfiler& instance() {
24
- static SimpleProfiler inst;
25
- return inst;
20
+ static SimpleProfiler &instance() {
21
+ static SimpleProfiler inst;
22
+ return inst;
23
+ }
24
+
25
+ ~SimpleProfiler() { report(); }
26
+
27
+ void start(const std::string &name) {
28
+ std::lock_guard<std::mutex> lock(mutex_);
29
+ auto now = std::chrono::high_resolution_clock::now();
30
+ start_times_[name] = now;
31
+ }
32
+
33
+ void stop(const std::string &name) {
34
+ std::lock_guard<std::mutex> lock(mutex_);
35
+ auto now = std::chrono::high_resolution_clock::now();
36
+ auto it = start_times_.find(name);
37
+ if (it != start_times_.end()) {
38
+ auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(now - it->second).count();
39
+ durations_[name] += duration;
40
+ counts_[name]++;
26
41
  }
42
+ }
27
43
 
28
- ~SimpleProfiler() {
29
- report();
30
- }
44
+ void report() {
45
+ std::lock_guard<std::mutex> lock(mutex_);
46
+ if (durations_.empty())
47
+ return;
31
48
 
32
- void start(const std::string& name) {
33
- std::lock_guard<std::mutex> lock(mutex_);
34
- auto now = std::chrono::high_resolution_clock::now();
35
- start_times_[name] = now;
49
+ std::cout << "\n=== Profiling Report (archive_r::internal) ===" << std::endl;
50
+ std::vector<std::pair<std::string, long long>> sorted_durations;
51
+ for (const auto &pair : durations_) {
52
+ sorted_durations.push_back(pair);
36
53
  }
37
54
 
38
- void stop(const std::string& name) {
39
- std::lock_guard<std::mutex> lock(mutex_);
40
- auto now = std::chrono::high_resolution_clock::now();
41
- auto it = start_times_.find(name);
42
- if (it != start_times_.end()) {
43
- auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(now - it->second).count();
44
- durations_[name] += duration;
45
- counts_[name]++;
46
- }
47
- }
55
+ std::sort(sorted_durations.begin(), sorted_durations.end(), [](const auto &a, const auto &b) { return a.second > b.second; });
48
56
 
49
- void report() {
50
- std::lock_guard<std::mutex> lock(mutex_);
51
- if (durations_.empty()) return;
52
-
53
- std::cout << "\n=== Profiling Report (archive_r::internal) ===" << std::endl;
54
- std::vector<std::pair<std::string, long long>> sorted_durations;
55
- for (const auto& pair : durations_) {
56
- sorted_durations.push_back(pair);
57
- }
58
-
59
- std::sort(sorted_durations.begin(), sorted_durations.end(),
60
- [](const auto& a, const auto& b) { return a.second > b.second; });
61
-
62
- std::cout << std::left << std::setw(40) << "Name"
63
- << std::right << std::setw(15) << "Total (ms)"
64
- << std::setw(10) << "Count"
65
- << std::setw(15) << "Avg (us)" << std::endl;
66
- std::cout << std::string(80, '-') << std::endl;
67
-
68
- for (const auto& pair : sorted_durations) {
69
- const auto& name = pair.first;
70
- long long total_ns = pair.second;
71
- long long count = counts_[name];
72
- double avg_ns = count > 0 ? (double)total_ns / count : 0;
73
-
74
- std::cout << std::left << std::setw(40) << name
75
- << std::right << std::setw(15) << std::fixed << std::setprecision(3) << total_ns / 1000000.0
76
- << std::setw(10) << count
77
- << std::setw(15) << std::fixed << std::setprecision(3) << avg_ns / 1000.0
78
- << std::endl;
79
- }
80
- std::cout << "==============================================\n" << std::endl;
81
- }
57
+ std::cout << std::left << std::setw(40) << "Name" << std::right << std::setw(15) << "Total (ms)" << std::setw(10) << "Count" << std::setw(15) << "Avg (us)" << std::endl;
58
+ std::cout << std::string(80, '-') << std::endl;
59
+
60
+ for (const auto &pair : sorted_durations) {
61
+ const auto &name = pair.first;
62
+ long long total_ns = pair.second;
63
+ long long count = counts_[name];
64
+ double avg_ns = count > 0 ? (double)total_ns / count : 0;
82
65
 
83
- void reset() {
84
- std::lock_guard<std::mutex> lock(mutex_);
85
- start_times_.clear();
86
- durations_.clear();
87
- counts_.clear();
66
+ std::cout << std::left << std::setw(40) << name << std::right << std::setw(15) << std::fixed << std::setprecision(3) << total_ns / 1000000.0 << std::setw(10) << count << std::setw(15)
67
+ << std::fixed << std::setprecision(3) << avg_ns / 1000.0 << std::endl;
88
68
  }
69
+ std::cout << "==============================================\n" << std::endl;
70
+ }
71
+
72
+ void reset() {
73
+ std::lock_guard<std::mutex> lock(mutex_);
74
+ start_times_.clear();
75
+ durations_.clear();
76
+ counts_.clear();
77
+ }
89
78
 
90
79
  private:
91
- std::map<std::string, std::chrono::high_resolution_clock::time_point> start_times_;
92
- std::map<std::string, long long> durations_;
93
- std::map<std::string, long long> counts_;
94
- std::mutex mutex_;
80
+ std::map<std::string, std::chrono::high_resolution_clock::time_point> start_times_;
81
+ std::map<std::string, long long> durations_;
82
+ std::map<std::string, long long> counts_;
83
+ std::mutex mutex_;
95
84
  };
96
85
 
97
86
  class ScopedTimer {
98
87
  public:
99
- ScopedTimer(const std::string& name) : name_(name) {
100
- SimpleProfiler::instance().start(name_);
101
- }
102
- ~ScopedTimer() {
103
- SimpleProfiler::instance().stop(name_);
104
- }
88
+ ScopedTimer(const std::string &name)
89
+ : name_(name) {
90
+ SimpleProfiler::instance().start(name_);
91
+ }
92
+ ~ScopedTimer() { SimpleProfiler::instance().stop(name_); }
93
+
105
94
  private:
106
- std::string name_;
95
+ std::string name_;
107
96
  };
108
97
 
109
98
  } // namespace internal
@@ -11,16 +11,16 @@
11
11
  #include <cstdio>
12
12
  #include <filesystem>
13
13
  #include <stdexcept>
14
+ #include <string_view>
14
15
  #include <sys/stat.h>
15
16
  #include <system_error>
16
- #include <string_view>
17
17
  #include <utility>
18
18
  #include <vector>
19
19
 
20
20
  #if !defined(_WIN32)
21
- # include <grp.h>
22
- # include <pwd.h>
23
- # include <unistd.h>
21
+ #include <grp.h>
22
+ #include <pwd.h>
23
+ #include <unistd.h>
24
24
  #endif
25
25
 
26
26
  namespace archive_r {
@@ -66,21 +66,10 @@ static bool lookup_groupname(gid_t gid, std::string &name_out) {
66
66
  } // namespace
67
67
 
68
68
  SystemFileStream::SystemFileStream(PathHierarchy logical_path)
69
- : MultiVolumeStreamBase(std::move(logical_path), true)
70
- , _handle(nullptr) {
71
- if (_logical_path.empty()) {
72
- throw std::invalid_argument("Root file hierarchy cannot be empty");
73
- }
69
+ : MultiVolumeStreamBase(std::move(logical_path), true)
70
+ , _handle(nullptr) {}
74
71
 
75
- const PathEntry &root_entry = _logical_path.front();
76
- if (!root_entry.is_single() && !root_entry.is_multi_volume()) {
77
- throw std::invalid_argument("Root file hierarchy must be a single file or multi-volume source");
78
- }
79
- }
80
-
81
- SystemFileStream::~SystemFileStream() {
82
- deactivate_active_part();
83
- }
72
+ SystemFileStream::~SystemFileStream() { deactivate_active_part(); }
84
73
 
85
74
  void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
86
75
  const PathEntry &entry = single_part.back();
@@ -100,7 +89,7 @@ void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
100
89
  // Enable larger buffering on Windows to improve performance
101
90
  // Use 64KB buffer to match StreamArchive's buffer size
102
91
  if (_handle) {
103
- std::setvbuf(_handle, nullptr, _IOFBF, 65536);
92
+ std::setvbuf(_handle, nullptr, _IOFBF, 65536);
104
93
  }
105
94
  #endif
106
95
  }
@@ -227,9 +216,7 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
227
216
  info.filetype = filetype;
228
217
  EntryMetadataMap metadata;
229
218
  if (!allowed_keys.empty()) {
230
- const auto wants = [&allowed_keys](std::string_view key) {
231
- return allowed_keys.find(std::string(key)) != allowed_keys.end();
232
- };
219
+ const auto wants = [&allowed_keys](std::string_view key) { return allowed_keys.find(std::string(key)) != allowed_keys.end(); };
233
220
 
234
221
  // Path hierarchy / directory entry derived metadata
235
222
  if (wants("pathname")) {
@@ -254,10 +241,10 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
254
241
  }
255
242
 
256
243
  const bool needs_stat = (wants("size") && size == 0)
257
- #if !defined(_WIN32)
258
- || wants("uid") || wants("gid") || wants("uname") || wants("gname")
259
- #endif
260
- ;
244
+ #if !defined(_WIN32)
245
+ || wants("uid") || wants("gid") || wants("uname") || wants("gname")
246
+ #endif
247
+ ;
261
248
 
262
249
  struct stat stat_buffer;
263
250
  bool have_stat = false;
@@ -10,10 +10,10 @@
10
10
  #include <unordered_set>
11
11
  #include <vector>
12
12
 
13
- #include "archive_r/multi_volume_stream_base.h"
14
- #include "archive_r/platform_compat.h"
15
13
  #include "archive_r/entry_metadata.h"
14
+ #include "archive_r/multi_volume_stream_base.h"
16
15
  #include "archive_r/path_hierarchy.h"
16
+ #include "archive_r/platform_compat.h"
17
17
 
18
18
  namespace archive_r {
19
19
 
@@ -3,9 +3,9 @@
3
3
 
4
4
  #include "archive_r/traverser.h"
5
5
  #include "archive_r/entry.h"
6
+ #include "archive_r/entry_fault.h"
6
7
  #include "archive_r/path_hierarchy.h"
7
8
  #include "archive_r/path_hierarchy_utils.h"
8
- #include "archive_r/entry_fault.h"
9
9
  #include "archive_stack_orchestrator.h"
10
10
  #include "archive_type.h"
11
11
  #include "entry_fault_error.h"
@@ -48,14 +48,13 @@ Traverser::Traverser(std::vector<PathHierarchy> paths, TraverserOptions options)
48
48
  throw std::invalid_argument("path hierarchy cannot be empty");
49
49
  }
50
50
  }
51
-
52
51
  }
53
52
 
54
53
  Traverser::Traverser(PathHierarchy path, TraverserOptions options)
55
- : Traverser(std::vector<PathHierarchy>{std::move(path)}, std::move(options)) {}
54
+ : Traverser(std::vector<PathHierarchy>{ std::move(path) }, std::move(options)) {}
56
55
 
57
56
  Traverser::Traverser(const std::string &path, TraverserOptions options)
58
- : Traverser(std::vector<PathHierarchy>{make_single_path(path)}, std::move(options)) {}
57
+ : Traverser(std::vector<PathHierarchy>{ make_single_path(path) }, std::move(options)) {}
59
58
 
60
59
  Traverser::~Traverser() = default;
61
60
 
@@ -65,7 +64,7 @@ Traverser::~Traverser() = default;
65
64
 
66
65
  class Traverser::Iterator::Impl {
67
66
  public:
68
- Impl(std::vector<PathHierarchy> paths, bool at_end, const TraverserOptions &traverser_options)
67
+ Impl(std::vector<PathHierarchy> paths, bool at_end, const TraverserOptions &traverser_options)
69
68
  : _paths(std::move(paths))
70
69
  , _at_end(at_end)
71
70
  , _archive_options(to_archive_option(traverser_options))
@@ -73,14 +72,9 @@ public:
73
72
  if (_at_end) {
74
73
  return;
75
74
  }
76
- if (_paths.empty()) {
77
- throw std::invalid_argument("paths cannot be empty");
78
- }
79
75
  ensure_shared_orchestrator();
80
-
81
- if (!advance_to_next_root()) {
82
- _at_end = true;
83
- }
76
+
77
+ _at_end = !advance_to_next_root();
84
78
  }
85
79
 
86
80
  Entry &get_entry() {
@@ -100,7 +94,7 @@ public:
100
94
  if (_current_entry->depth() == 0 && request_descend_into_archive && !_current_entry->is_directory()) {
101
95
  request_descend_into_archive = false;
102
96
  attempt_descend_into_root(_current_entry->path_hierarchy());
103
- }
97
+ }
104
98
  _current_entry.reset();
105
99
 
106
100
  if (fetch_from_archive(request_descend_into_archive)) {
@@ -114,13 +108,13 @@ public:
114
108
  if (advance_to_next_root()) {
115
109
  return;
116
110
  }
117
-
111
+
118
112
  descend_pending_multi_volumes();
119
-
113
+
120
114
  if (fetch_from_archive(false)) {
121
115
  return;
122
116
  }
123
-
117
+
124
118
  _at_end = true;
125
119
  }
126
120
 
@@ -128,10 +122,7 @@ public:
128
122
  if (this == other) {
129
123
  return true;
130
124
  }
131
- if (!other) {
132
- return false;
133
- }
134
- return _at_end && other->_at_end;
125
+ return other && _at_end && other->_at_end;
135
126
  }
136
127
 
137
128
  private:
@@ -143,9 +134,6 @@ private:
143
134
  }
144
135
 
145
136
  std::string normalize_path_string(const std::string &value) {
146
- if (value.empty()) {
147
- return value;
148
- }
149
137
  std::filesystem::path path_value(value);
150
138
  return path_value.lexically_normal().string();
151
139
  }
@@ -169,14 +157,9 @@ private:
169
157
  }
170
158
  ArchiveStackOrchestrator &orchestrator = *ensure_shared_orchestrator();
171
159
 
172
- try {
173
- if (orchestrator.advance(request_descend_into_archive)) {
174
- set_current_entry(orchestrator.current_entry_hierarchy());
175
- return true;
176
- }
177
- } catch (const EntryFaultError &error) {
178
- EntryFault fault = enrich_orchestrator_error(error, orchestrator);
179
- handle_orchestrator_error(fault);
160
+ if (orchestrator.advance(request_descend_into_archive)) {
161
+ set_current_entry(orchestrator.current_entry_hierarchy());
162
+ return true;
180
163
  }
181
164
  return false;
182
165
  }
@@ -224,13 +207,9 @@ private:
224
207
  }
225
208
  }
226
209
 
227
- void set_current_entry(PathHierarchy hierarchy) {
228
- _current_entry = Entry::create(std::move(hierarchy), ensure_shared_orchestrator(), _default_descent);
229
- }
210
+ void set_current_entry(PathHierarchy hierarchy) { _current_entry = Entry::create(std::move(hierarchy), ensure_shared_orchestrator(), _default_descent); }
230
211
 
231
- void handle_orchestrator_error(const EntryFault &fault) {
232
- dispatch_registered_fault(fault);
233
- }
212
+ void handle_orchestrator_error(const EntryFault &fault) { dispatch_registered_fault(fault); }
234
213
 
235
214
  void reset_source_state() {
236
215
  reset_directory_traversal();
@@ -251,9 +230,6 @@ private:
251
230
  if (fault.hierarchy.empty()) {
252
231
  fault.hierarchy = orchestrator.current_entry_hierarchy();
253
232
  }
254
- if (fault.message.empty() && error.what()) {
255
- fault.message = error.what();
256
- }
257
233
  return fault;
258
234
  }
259
235
 
@@ -273,7 +249,7 @@ private:
273
249
  // ============================================================================
274
250
 
275
251
  Traverser::Iterator::Iterator(std::unique_ptr<Impl> impl)
276
- : _impl(std::move(impl)) {}
252
+ : _impl(std::move(impl)) {}
277
253
 
278
254
  Traverser::Iterator::~Iterator() = default;
279
255
 
data/lib/archive_r.rb CHANGED
@@ -35,7 +35,11 @@ rescue LoadError
35
35
  end
36
36
 
37
37
  module Archive_r
38
- VERSION = "0.1.8"
38
+ version_path = File.expand_path('../VERSION', __dir__)
39
+ unless File.exist?(version_path)
40
+ version_path = File.expand_path('../../../VERSION', __dir__)
41
+ end
42
+ VERSION = File.read(version_path).strip
39
43
  # Common archive formats excluding libarchive's mtree/raw pseudo formats
40
44
  STANDARD_FORMATS = %w[
41
45
  7zip ar cab cpio empty iso9660 lha rar tar warc xar zip
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: archive_r_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - raizo.tcs
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-12-25 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: rake
@@ -51,6 +52,7 @@ files:
51
52
  - LICENSE
52
53
  - NOTICE
53
54
  - README.md
55
+ - VERSION
54
56
  - ext/archive_r/archive_r_ext.cc
55
57
  - ext/archive_r/extconf.rb
56
58
  - ext/archive_r/vendor/archive_r/LICENSE
@@ -94,6 +96,7 @@ metadata:
94
96
  source_code_uri: https://github.com/raizo-tcs/archive_r
95
97
  bug_tracker_uri: https://github.com/raizo-tcs/archive_r/issues
96
98
  changelog_uri: https://github.com/raizo-tcs/archive_r/releases
99
+ post_install_message:
97
100
  rdoc_options: []
98
101
  require_paths:
99
102
  - lib
@@ -108,7 +111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
111
  - !ruby/object:Gem::Version
109
112
  version: '0'
110
113
  requirements: []
111
- rubygems_version: 4.0.1
114
+ rubygems_version: 3.4.20
115
+ signing_key:
112
116
  specification_version: 4
113
117
  summary: 'Ruby bindings for archive_r: libarchive-based streaming traversal for recursive
114
118
  nested archives (no temp files, no large in-memory buffers)'