iceoryx2
C++ Language Bindings
Loading...
Searching...
No Matches
path_and_file_verifier.hpp
Go to the documentation of this file.
1// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
2// Copyright (c) 2023 by ekxide IO GmbH. All rights reserved.
3// Copyright (c) 2025 Contributors to the Eclipse Foundation
4//
5// See the NOTICE file(s) distributed with this work for additional
6// information regarding copyright ownership.
7//
8// This program and the accompanying materials are made available under the
9// terms of the Apache Software License 2.0 which is available at
10// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
11// which is available at https://opensource.org/licenses/MIT.
12//
13// SPDX-License-Identifier: Apache-2.0 OR MIT
14
15#ifndef IOX2_BB_DETAIL_PATH_AND_FILE_VERIFIER_HPP
16#define IOX2_BB_DETAIL_PATH_AND_FILE_VERIFIER_HPP
17
19
20#include <cstdint>
21
22namespace iox2 {
23namespace bb {
24namespace platform {
25#ifdef _WIN32
26constexpr uint64_t IOX2_NUMBER_OF_PATH_SEPARATORS = 2U;
27// NOLINTNEXTLINE(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays, hicpp-explicit-conversions, modernize-avoid-c-arrays)
28constexpr const char IOX2_PATH_SEPARATORS[IOX2_NUMBER_OF_PATH_SEPARATORS] = { '/', '\\' };
29#else
30constexpr uint64_t IOX2_NUMBER_OF_PATH_SEPARATORS = 1U;
31// NOLINTNEXTLINE(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays, hicpp-explicit-conversions, modernize-avoid-c-arrays)
33#endif
34} // namespace platform
35
36namespace detail {
37// AXIVION DISABLE STYLE AutosarC++19_03-A3.9.1: Not used as an integer but as actual character.
38constexpr char ASCII_A { 'a' };
39constexpr char ASCII_Z { 'z' };
40constexpr char ASCII_CAPITAL_A { 'A' };
41constexpr char ASCII_CAPITAL_Z { 'Z' };
42constexpr char ASCII_0 { '0' };
43constexpr char ASCII_9 { '9' };
44constexpr char ASCII_DASH { '-' };
45constexpr char ASCII_DOT { '.' };
46constexpr char ASCII_COLON { ':' };
47constexpr char ASCII_UNDERSCORE { '_' };
48// AXIVION ENABLE STYLE AutosarC++19_03-A3.9.1
49
50enum class RelativePathComponents : uint8_t {
51 Reject,
52 Accept
53};
54
72template <uint64_t StringCapacity>
74 RelativePathComponents relative_path_components) noexcept -> bool;
75
81template <uint64_t StringCapacity>
82auto is_valid_file_name(const bb::StaticString<StringCapacity>& name) noexcept -> bool;
83
86template <uint64_t StringCapacity>
87auto does_end_with_path_separator(const bb::StaticString<StringCapacity>& name) noexcept -> bool;
88
89template <uint64_t StringCapacity>
91 RelativePathComponents relative_path_components) noexcept -> bool {
92 const auto current_directory = bb::StaticString<StringCapacity>::from_utf8_unchecked(".");
93 const auto parent_directory = bb::StaticString<StringCapacity>::from_utf8_unchecked("..");
94
95 if ((name == current_directory) || (name == parent_directory)) {
96 return relative_path_components == RelativePathComponents::Accept;
97 }
98
99 const auto name_size = name.size();
100
101 for (uint64_t i { 0 }; i < name_size; ++i) {
102 // AXIVION Next Construct AutosarC++19_03-A3.9.1: Not used as an integer but as actual character
103 // NOLINTNEXTLINE(readability-identifier-length)
104 const char c { name.unchecked_access()[i] };
105
106 // AXIVION DISABLE STYLE FaultDetection-UnusedAssignments : False positive, variable IS used
107 // AXIVION DISABLE STYLE AutosarC++19_03-A0.1.1 : False positive, variable IS used
108 // AXIVION DISABLE STYLE AutosarC++19_03-M4.5.3 : We are explicitly checking for ASCII characters which have defined consecutive values
109 const bool is_small_letter { (ASCII_A <= c) && (c <= ASCII_Z) };
110 const bool is_capital_letter { (ASCII_CAPITAL_A <= c) && (c <= ASCII_CAPITAL_Z) };
111 const bool is_number { (ASCII_0 <= c) && (c <= ASCII_9) };
112 const bool is_special_character { ((c == ASCII_DASH) || (c == ASCII_DOT))
113 || ((c == ASCII_COLON) || (c == ASCII_UNDERSCORE)) };
114 // AXIVION ENABLE STYLE AutosarC++19_03-M4.5.3
115 // AXIVION ENABLE STYLE AutosarC++19_03-A0.1.1
116 // AXIVION ENABLE STYLE FaultDetection-UnusedAssignments
117
118 if ((!is_small_letter && !is_capital_letter) && (!is_number && !is_special_character)) {
119 return false;
120 }
121 }
122
123 if (name_size == 0) {
124 return true;
125 }
126
127 // dot at the end is invalid to be compatible with windows api
128 return !(name.unchecked_access()[name_size - 1] == '.');
129}
130
131template <uint64_t StringCapacity>
132inline auto is_valid_file_name(const bb::StaticString<StringCapacity>& name) noexcept -> bool {
133 if (name.empty()) {
134 return false;
135 }
136
137 // check if the file contains only valid characters
139}
140
141template <uint64_t StringCapacity>
142inline auto is_valid_path_to_file(const bb::StaticString<StringCapacity>& name) noexcept -> bool {
144 return false;
145 }
146
147 auto maybe_separator = name.code_units().find_last_of(platform::IOX2_PATH_SEPARATORS);
148 if (!maybe_separator.has_value()) {
149 return is_valid_file_name(name);
150 }
151
152 const auto& position = maybe_separator.value();
153
154 bool is_file_name_valid { false };
155 auto sub_str = name.code_units().substr(position + 1, name.size());
156 if (sub_str.has_value()) {
157 is_file_name_valid = is_valid_file_name(*sub_str);
158 }
159
160 bool is_path_valid { false };
161 sub_str = name.code_units().substr(0, position);
162 if (sub_str.has_value()) {
163 const bool is_empty_path { sub_str->empty() };
164 const bool is_path_to_directory_valid { is_valid_path_to_directory(*sub_str) };
165 is_path_valid = is_empty_path || is_path_to_directory_valid;
166 }
167
168 // AXIVION Next Construct AutosarC++19_03-M0.1.2, AutosarC++19_03-M0.1.9, FaultDetection-DeadBranches : False positive! Branching depends on input parameter
169 return is_path_valid && is_file_name_valid;
170}
171
172template <uint64_t StringCapacity>
173inline auto is_valid_path_to_directory(const bb::StaticString<StringCapacity>& name) noexcept -> bool {
174 if (name.empty()) {
175 return false;
176 }
177
178 auto const current_directory = bb::StaticString<StringCapacity>::from_utf8_unchecked(".");
179 auto const parent_directory = bb::StaticString<StringCapacity>::from_utf8_unchecked("..");
180
181 auto remaining = name;
182 while (!remaining.empty()) {
183 const auto separator_position = remaining.code_units().find_first_of(platform::IOX2_PATH_SEPARATORS);
184
185 if (separator_position.has_value()) {
186 const uint64_t position { separator_position.value() };
187
188 // multiple slashes are explicitly allowed. the following paths
189 // are equivalent:
190 // /some/fuu/bar
191 // //some///fuu////bar
192
193 // verify if the entry between two path separators is a valid directory
194 // name, e.g. either it has the relative component . or .. or conforms
195 // with a valid file name
196 if (position != 0) {
197 const auto guaranteed_substr = remaining.code_units().substr(0, position);
198 const auto& filename_to_verify = guaranteed_substr.value();
199 const bool is_valid_directory { (is_valid_file_name(filename_to_verify))
200 || ((filename_to_verify == current_directory)
201 || (filename_to_verify == parent_directory)) };
202 if (!is_valid_directory) {
203 return false;
204 }
205 }
206
207 auto sub_str = remaining.code_units().substr(position + 1, remaining.size());
208 if (sub_str.has_value()) {
209 remaining = *sub_str;
210 }
211 } else // we reached the last entry, if its a valid file name the path is valid
212 {
214 }
215 }
216
217 return true;
218}
219
220// AXIVION Next Construct AutosarC++19_03-A5.2.5, AutosarC++19_03-M5.0.16, FaultDetection-OutOfBounds : IOX2_PATH_SEPARATORS is not a string but an array of chars without a null termination and all elements are valid characters
221template <uint64_t StringCapacity>
222inline auto does_end_with_path_separator(const bb::StaticString<StringCapacity>& name) noexcept -> bool {
223 if (name.empty()) {
224 return false;
225 }
226 // AXIVION Next Construct AutosarC++19_03-A3.9.1: Not used as an integer but as actual character
227 const char last_character { *name.code_units().back_element() };
228
229 // NOLINTNEXTLINE(readability-use-anyofallof)
230 for (const auto separator : platform::IOX2_PATH_SEPARATORS) {
231 if (last_character == separator) {
232 return true;
233 }
234 }
235 return false;
236}
237
238} // namespace detail
239} // namespace bb
240} // namespace iox2
241
242#endif // IOX2_BB_DETAIL_PATH_AND_FILE_VERIFIER_HPP
static auto from_utf8_unchecked(char const (&utf8_str)[M]) noexcept -> StaticString
auto is_valid_path_to_directory(const bb::StaticString< StringCapacity > &name) noexcept -> bool
returns true if the provided name is a valid path, otherwise false
constexpr char ASCII_UNDERSCORE
auto is_valid_path_entry(const bb::StaticString< StringCapacity > &name, RelativePathComponents relative_path_components) noexcept -> bool
checks if the given string is a valid path entry. A path entry is the string between two path separat...
auto is_valid_path_to_file(const bb::StaticString< StringCapacity > &name) noexcept -> bool
verifies if the given string is a valid path to a file
auto is_valid_file_name(const bb::StaticString< StringCapacity > &name) noexcept -> bool
checks if the given string is a valid filename. It must fulfill the requirements of a valid path entr...
auto does_end_with_path_separator(const bb::StaticString< StringCapacity > &name) noexcept -> bool
returns true if the provided name ends with a path separator, otherwise false
constexpr uint64_t IOX2_NUMBER_OF_PATH_SEPARATORS
constexpr const char IOX2_PATH_SEPARATORS[IOX2_NUMBER_OF_PATH_SEPARATORS]