archive_r_ruby 0.1.21 → 0.1.22
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.
- checksums.yaml +4 -4
- data/LICENSE +21 -21
- data/NOTICE +116 -116
- data/README.md +106 -106
- data/VERSION +1 -1
- data/ext/archive_r/archive_r_ext.cc +1098 -1098
- data/ext/archive_r/extconf.rb +125 -125
- data/ext/archive_r/vendor/archive_r/LICENSE +21 -21
- data/ext/archive_r/vendor/archive_r/NOTICE +116 -116
- data/ext/archive_r/vendor/archive_r/include/archive_r/data_stream.h +42 -42
- data/ext/archive_r/vendor/archive_r/include/archive_r/entry.h +180 -180
- data/ext/archive_r/vendor/archive_r/include/archive_r/entry_fault.h +34 -34
- data/ext/archive_r/vendor/archive_r/include/archive_r/entry_metadata.h +56 -56
- data/ext/archive_r/vendor/archive_r/include/archive_r/multi_volume_stream_base.h +46 -46
- data/ext/archive_r/vendor/archive_r/include/archive_r/path_hierarchy.h +92 -92
- data/ext/archive_r/vendor/archive_r/include/archive_r/path_hierarchy_utils.h +36 -36
- data/ext/archive_r/vendor/archive_r/include/archive_r/platform_compat.h +34 -34
- data/ext/archive_r/vendor/archive_r/include/archive_r/traverser.h +156 -156
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.cc +300 -300
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.h +110 -110
- data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.cc +161 -161
- data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.h +53 -53
- data/ext/archive_r/vendor/archive_r/src/archive_type.cc +545 -545
- data/ext/archive_r/vendor/archive_r/src/archive_type.h +77 -77
- data/ext/archive_r/vendor/archive_r/src/data_stream.cc +35 -35
- data/ext/archive_r/vendor/archive_r/src/entry.cc +238 -238
- data/ext/archive_r/vendor/archive_r/src/entry_fault.cc +26 -26
- data/ext/archive_r/vendor/archive_r/src/entry_fault_error.cc +54 -54
- data/ext/archive_r/vendor/archive_r/src/entry_fault_error.h +32 -32
- data/ext/archive_r/vendor/archive_r/src/entry_impl.h +56 -56
- data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.cc +76 -76
- data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.h +39 -39
- data/ext/archive_r/vendor/archive_r/src/multi_volume_stream_base.cc +208 -208
- data/ext/archive_r/vendor/archive_r/src/path_hierarchy.cc +127 -127
- data/ext/archive_r/vendor/archive_r/src/path_hierarchy_utils.cc +251 -251
- data/ext/archive_r/vendor/archive_r/src/simple_profiler.h +109 -109
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.cc +294 -294
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.h +46 -46
- data/ext/archive_r/vendor/archive_r/src/traverser.cc +295 -295
- data/lib/archive_r.rb +120 -120
- metadata +3 -6
|
@@ -1,251 +1,251 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Copyright (c) 2025 archive_r Team
|
|
3
|
-
|
|
4
|
-
#include "archive_r/path_hierarchy_utils.h"
|
|
5
|
-
|
|
6
|
-
#include <algorithm>
|
|
7
|
-
#include <filesystem>
|
|
8
|
-
|
|
9
|
-
namespace archive_r {
|
|
10
|
-
|
|
11
|
-
namespace {
|
|
12
|
-
|
|
13
|
-
struct CollapseSegments {
|
|
14
|
-
PathHierarchy prefix;
|
|
15
|
-
PathHierarchy suffix;
|
|
16
|
-
std::size_t multi_volume_depth = 0;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
PathHierarchy hierarchy_suffix_from(const PathHierarchy &hierarchy, std::size_t start_index) {
|
|
20
|
-
if (hierarchy.empty() || start_index >= hierarchy.size()) {
|
|
21
|
-
return {};
|
|
22
|
-
}
|
|
23
|
-
const auto begin = hierarchy.begin() + static_cast<PathHierarchy::difference_type>(start_index);
|
|
24
|
-
return PathHierarchy(begin, hierarchy.end());
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
bool determine_multi_volume_segments(const std::vector<PathHierarchy> &sources, CollapseSegments &segments) {
|
|
28
|
-
if (sources.empty()) {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const PathHierarchy &reference = sources.front();
|
|
33
|
-
if (reference.empty()) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
std::size_t multi_volume_depth = reference.size() - 1;
|
|
38
|
-
bool difference_found = false;
|
|
39
|
-
|
|
40
|
-
for (std::size_t depth = 0; depth < reference.size(); ++depth) {
|
|
41
|
-
const PathEntry &reference_entry = reference[depth];
|
|
42
|
-
for (std::size_t i = 1; i < sources.size(); ++i) {
|
|
43
|
-
const PathHierarchy &candidate = sources[i];
|
|
44
|
-
if (candidate.size() <= depth) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
if (!archive_r::entries_equal(reference_entry, candidate[depth])) {
|
|
48
|
-
multi_volume_depth = depth;
|
|
49
|
-
difference_found = true;
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (difference_found) {
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (!difference_found) {
|
|
59
|
-
for (std::size_t i = 1; i < sources.size(); ++i) {
|
|
60
|
-
if (sources[i].size() != reference.size()) {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
segments.multi_volume_depth = multi_volume_depth;
|
|
67
|
-
segments.prefix.clear();
|
|
68
|
-
if (multi_volume_depth > 0) {
|
|
69
|
-
segments.prefix = pathhierarchy_prefix_until(reference, multi_volume_depth - 1);
|
|
70
|
-
}
|
|
71
|
-
segments.suffix = hierarchy_suffix_from(reference, multi_volume_depth + 1);
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const CollapseSegments &segments, std::vector<std::string> &parts) {
|
|
76
|
-
const std::size_t suffix_size = segments.suffix.size();
|
|
77
|
-
const std::size_t required_size = segments.multi_volume_depth + 1 + suffix_size;
|
|
78
|
-
|
|
79
|
-
parts.clear();
|
|
80
|
-
parts.reserve(sources.size());
|
|
81
|
-
|
|
82
|
-
for (const auto &hierarchy : sources) {
|
|
83
|
-
if (hierarchy.empty() || hierarchy.size() <= segments.multi_volume_depth) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (hierarchy.size() != required_size) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const PathEntry &component = hierarchy[segments.multi_volume_depth];
|
|
92
|
-
if (!component.is_single()) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
for (std::size_t offset = 0; offset < suffix_size; ++offset) {
|
|
97
|
-
const PathEntry &reference_entry = segments.suffix[offset];
|
|
98
|
-
const PathEntry &candidate_entry = hierarchy[segments.multi_volume_depth + 1 + offset];
|
|
99
|
-
if (!archive_r::entries_equal(reference_entry, candidate_entry)) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
parts.push_back(component.single_value());
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
} // namespace
|
|
111
|
-
|
|
112
|
-
const std::string *path_entry_component_at(const PathEntry &entry, std::size_t index) {
|
|
113
|
-
if (entry.is_single()) {
|
|
114
|
-
if (index == 0) {
|
|
115
|
-
return &entry.single_value();
|
|
116
|
-
}
|
|
117
|
-
return nullptr;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const auto &parts = entry.multi_volume_parts().values;
|
|
121
|
-
if (index < parts.size()) {
|
|
122
|
-
return &parts[index];
|
|
123
|
-
}
|
|
124
|
-
return nullptr;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
std::size_t pathhierarchy_volume_size(const PathHierarchy &logical) {
|
|
128
|
-
if (logical.empty()) {
|
|
129
|
-
return 0;
|
|
130
|
-
}
|
|
131
|
-
const PathEntry &tail = logical.back();
|
|
132
|
-
if (!tail.is_multi_volume()) {
|
|
133
|
-
return 1;
|
|
134
|
-
}
|
|
135
|
-
const auto &parts = tail.multi_volume_parts().values;
|
|
136
|
-
return parts.size();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
std::string pathhierarchy_volume_entry_name(const PathHierarchy &logical, std::size_t index) {
|
|
140
|
-
if (logical.empty()) {
|
|
141
|
-
return {};
|
|
142
|
-
}
|
|
143
|
-
const PathEntry &tail = logical.back();
|
|
144
|
-
if (!tail.is_multi_volume()) {
|
|
145
|
-
if (index != 0) {
|
|
146
|
-
return {};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return tail.single_value();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const auto &parts = tail.multi_volume_parts().values;
|
|
153
|
-
if (index >= parts.size()) {
|
|
154
|
-
return {};
|
|
155
|
-
}
|
|
156
|
-
return parts[index];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
bool pathhierarchy_is_multivolume(const PathHierarchy &hierarchy) {
|
|
160
|
-
if (hierarchy.empty()) {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
return hierarchy.back().is_multi_volume();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
PathHierarchy pathhierarchy_select_single_part(const PathHierarchy &logical, std::size_t index) {
|
|
167
|
-
if (logical.empty()) {
|
|
168
|
-
return {};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
PathHierarchy result = parent_hierarchy(logical);
|
|
172
|
-
append_single(result, pathhierarchy_volume_entry_name(logical, index));
|
|
173
|
-
return result;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
void sort_hierarchies(std::vector<PathHierarchy> &hierarchies) {
|
|
177
|
-
std::sort(hierarchies.begin(), hierarchies.end(), [](const PathHierarchy &lhs, const PathHierarchy &rhs) { return archive_r::compare_hierarchies(lhs, rhs) < 0; });
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
bool flatten_entry_to_string(const PathEntry &entry, std::string &output) {
|
|
181
|
-
if (entry.is_single()) {
|
|
182
|
-
output = entry.single_value();
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
bool entry_name_from_component(const PathEntry &entry, std::string &output) {
|
|
190
|
-
if (entry.is_multi_volume()) {
|
|
191
|
-
const auto &parts = entry.multi_volume_parts().values;
|
|
192
|
-
if (parts.empty()) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
output = parts.front();
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return flatten_entry_to_string(entry, output);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
PathHierarchy merge_multi_volume_sources(const std::vector<PathHierarchy> &sources) {
|
|
203
|
-
CollapseSegments segments;
|
|
204
|
-
if (!determine_multi_volume_segments(sources, segments)) {
|
|
205
|
-
return {};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
std::vector<std::string> parts;
|
|
209
|
-
if (!collect_multi_volume_parts(sources, segments, parts)) {
|
|
210
|
-
return {};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
PathHierarchy result = segments.prefix;
|
|
214
|
-
result.reserve(result.size() + 1 + segments.suffix.size());
|
|
215
|
-
result.emplace_back(PathEntry::multi_volume(std::move(parts)));
|
|
216
|
-
result.insert(result.end(), segments.suffix.begin(), segments.suffix.end());
|
|
217
|
-
return result;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
std::string path_entry_display(const PathEntry &entry) {
|
|
221
|
-
if (entry.is_single()) {
|
|
222
|
-
return entry.single_value();
|
|
223
|
-
}
|
|
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('|');
|
|
230
|
-
}
|
|
231
|
-
value += part;
|
|
232
|
-
first = false;
|
|
233
|
-
}
|
|
234
|
-
value.push_back(']');
|
|
235
|
-
return value;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
std::string hierarchy_display(const PathHierarchy &hierarchy) {
|
|
239
|
-
std::string result;
|
|
240
|
-
bool first = true;
|
|
241
|
-
for (const auto &component : hierarchy) {
|
|
242
|
-
if (!first) {
|
|
243
|
-
result.push_back('/');
|
|
244
|
-
}
|
|
245
|
-
result += path_entry_display(component);
|
|
246
|
-
first = false;
|
|
247
|
-
}
|
|
248
|
-
return result;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
} // namespace archive_r
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2025 archive_r Team
|
|
3
|
+
|
|
4
|
+
#include "archive_r/path_hierarchy_utils.h"
|
|
5
|
+
|
|
6
|
+
#include <algorithm>
|
|
7
|
+
#include <filesystem>
|
|
8
|
+
|
|
9
|
+
namespace archive_r {
|
|
10
|
+
|
|
11
|
+
namespace {
|
|
12
|
+
|
|
13
|
+
struct CollapseSegments {
|
|
14
|
+
PathHierarchy prefix;
|
|
15
|
+
PathHierarchy suffix;
|
|
16
|
+
std::size_t multi_volume_depth = 0;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
PathHierarchy hierarchy_suffix_from(const PathHierarchy &hierarchy, std::size_t start_index) {
|
|
20
|
+
if (hierarchy.empty() || start_index >= hierarchy.size()) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
const auto begin = hierarchy.begin() + static_cast<PathHierarchy::difference_type>(start_index);
|
|
24
|
+
return PathHierarchy(begin, hierarchy.end());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
bool determine_multi_volume_segments(const std::vector<PathHierarchy> &sources, CollapseSegments &segments) {
|
|
28
|
+
if (sources.empty()) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const PathHierarchy &reference = sources.front();
|
|
33
|
+
if (reference.empty()) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
std::size_t multi_volume_depth = reference.size() - 1;
|
|
38
|
+
bool difference_found = false;
|
|
39
|
+
|
|
40
|
+
for (std::size_t depth = 0; depth < reference.size(); ++depth) {
|
|
41
|
+
const PathEntry &reference_entry = reference[depth];
|
|
42
|
+
for (std::size_t i = 1; i < sources.size(); ++i) {
|
|
43
|
+
const PathHierarchy &candidate = sources[i];
|
|
44
|
+
if (candidate.size() <= depth) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (!archive_r::entries_equal(reference_entry, candidate[depth])) {
|
|
48
|
+
multi_volume_depth = depth;
|
|
49
|
+
difference_found = true;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (difference_found) {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!difference_found) {
|
|
59
|
+
for (std::size_t i = 1; i < sources.size(); ++i) {
|
|
60
|
+
if (sources[i].size() != reference.size()) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
segments.multi_volume_depth = multi_volume_depth;
|
|
67
|
+
segments.prefix.clear();
|
|
68
|
+
if (multi_volume_depth > 0) {
|
|
69
|
+
segments.prefix = pathhierarchy_prefix_until(reference, multi_volume_depth - 1);
|
|
70
|
+
}
|
|
71
|
+
segments.suffix = hierarchy_suffix_from(reference, multi_volume_depth + 1);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const CollapseSegments &segments, std::vector<std::string> &parts) {
|
|
76
|
+
const std::size_t suffix_size = segments.suffix.size();
|
|
77
|
+
const std::size_t required_size = segments.multi_volume_depth + 1 + suffix_size;
|
|
78
|
+
|
|
79
|
+
parts.clear();
|
|
80
|
+
parts.reserve(sources.size());
|
|
81
|
+
|
|
82
|
+
for (const auto &hierarchy : sources) {
|
|
83
|
+
if (hierarchy.empty() || hierarchy.size() <= segments.multi_volume_depth) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (hierarchy.size() != required_size) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const PathEntry &component = hierarchy[segments.multi_volume_depth];
|
|
92
|
+
if (!component.is_single()) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (std::size_t offset = 0; offset < suffix_size; ++offset) {
|
|
97
|
+
const PathEntry &reference_entry = segments.suffix[offset];
|
|
98
|
+
const PathEntry &candidate_entry = hierarchy[segments.multi_volume_depth + 1 + offset];
|
|
99
|
+
if (!archive_r::entries_equal(reference_entry, candidate_entry)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
parts.push_back(component.single_value());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
} // namespace
|
|
111
|
+
|
|
112
|
+
const std::string *path_entry_component_at(const PathEntry &entry, std::size_t index) {
|
|
113
|
+
if (entry.is_single()) {
|
|
114
|
+
if (index == 0) {
|
|
115
|
+
return &entry.single_value();
|
|
116
|
+
}
|
|
117
|
+
return nullptr;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const auto &parts = entry.multi_volume_parts().values;
|
|
121
|
+
if (index < parts.size()) {
|
|
122
|
+
return &parts[index];
|
|
123
|
+
}
|
|
124
|
+
return nullptr;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
std::size_t pathhierarchy_volume_size(const PathHierarchy &logical) {
|
|
128
|
+
if (logical.empty()) {
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
const PathEntry &tail = logical.back();
|
|
132
|
+
if (!tail.is_multi_volume()) {
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
const auto &parts = tail.multi_volume_parts().values;
|
|
136
|
+
return parts.size();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
std::string pathhierarchy_volume_entry_name(const PathHierarchy &logical, std::size_t index) {
|
|
140
|
+
if (logical.empty()) {
|
|
141
|
+
return {};
|
|
142
|
+
}
|
|
143
|
+
const PathEntry &tail = logical.back();
|
|
144
|
+
if (!tail.is_multi_volume()) {
|
|
145
|
+
if (index != 0) {
|
|
146
|
+
return {};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return tail.single_value();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const auto &parts = tail.multi_volume_parts().values;
|
|
153
|
+
if (index >= parts.size()) {
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
return parts[index];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
bool pathhierarchy_is_multivolume(const PathHierarchy &hierarchy) {
|
|
160
|
+
if (hierarchy.empty()) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return hierarchy.back().is_multi_volume();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
PathHierarchy pathhierarchy_select_single_part(const PathHierarchy &logical, std::size_t index) {
|
|
167
|
+
if (logical.empty()) {
|
|
168
|
+
return {};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
PathHierarchy result = parent_hierarchy(logical);
|
|
172
|
+
append_single(result, pathhierarchy_volume_entry_name(logical, index));
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
void sort_hierarchies(std::vector<PathHierarchy> &hierarchies) {
|
|
177
|
+
std::sort(hierarchies.begin(), hierarchies.end(), [](const PathHierarchy &lhs, const PathHierarchy &rhs) { return archive_r::compare_hierarchies(lhs, rhs) < 0; });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
bool flatten_entry_to_string(const PathEntry &entry, std::string &output) {
|
|
181
|
+
if (entry.is_single()) {
|
|
182
|
+
output = entry.single_value();
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
bool entry_name_from_component(const PathEntry &entry, std::string &output) {
|
|
190
|
+
if (entry.is_multi_volume()) {
|
|
191
|
+
const auto &parts = entry.multi_volume_parts().values;
|
|
192
|
+
if (parts.empty()) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
output = parts.front();
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return flatten_entry_to_string(entry, output);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
PathHierarchy merge_multi_volume_sources(const std::vector<PathHierarchy> &sources) {
|
|
203
|
+
CollapseSegments segments;
|
|
204
|
+
if (!determine_multi_volume_segments(sources, segments)) {
|
|
205
|
+
return {};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
std::vector<std::string> parts;
|
|
209
|
+
if (!collect_multi_volume_parts(sources, segments, parts)) {
|
|
210
|
+
return {};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
PathHierarchy result = segments.prefix;
|
|
214
|
+
result.reserve(result.size() + 1 + segments.suffix.size());
|
|
215
|
+
result.emplace_back(PathEntry::multi_volume(std::move(parts)));
|
|
216
|
+
result.insert(result.end(), segments.suffix.begin(), segments.suffix.end());
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
std::string path_entry_display(const PathEntry &entry) {
|
|
221
|
+
if (entry.is_single()) {
|
|
222
|
+
return entry.single_value();
|
|
223
|
+
}
|
|
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('|');
|
|
230
|
+
}
|
|
231
|
+
value += part;
|
|
232
|
+
first = false;
|
|
233
|
+
}
|
|
234
|
+
value.push_back(']');
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
std::string hierarchy_display(const PathHierarchy &hierarchy) {
|
|
239
|
+
std::string result;
|
|
240
|
+
bool first = true;
|
|
241
|
+
for (const auto &component : hierarchy) {
|
|
242
|
+
if (!first) {
|
|
243
|
+
result.push_back('/');
|
|
244
|
+
}
|
|
245
|
+
result += path_entry_display(component);
|
|
246
|
+
first = false;
|
|
247
|
+
}
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
} // namespace archive_r
|