(
input: &str,
res_root: &Path,
allowed_prefix: &str,
)
| 122 | } |
| 123 | |
| 124 | fn resolve_res_subdir( |
| 125 | input: &str, |
| 126 | res_root: &Path, |
| 127 | allowed_prefix: &str, |
| 128 | ) -> Result<PathBuf, String> { |
| 129 | let trimmed = input.trim(); |
| 130 | if trimmed.is_empty() { |
| 131 | return Ok(res_root.to_path_buf()); |
| 132 | } |
| 133 | |
| 134 | let rel = if let Some(stripped) = trimmed.strip_prefix(allowed_prefix) { |
| 135 | stripped.trim_start_matches('/').trim_start_matches('\\') |
| 136 | } else if trimmed.contains("://") { |
| 137 | return Err(format!( |
| 138 | "path must use `{allowed_prefix}*` or `/...` style segments" |
| 139 | )); |
| 140 | } else if trimmed.starts_with('/') || trimmed.starts_with('\\') { |
| 141 | trimmed.trim_start_matches('/').trim_start_matches('\\') |
| 142 | } else { |
| 143 | trimmed |
| 144 | }; |
| 145 | |
| 146 | let rel_path = PathBuf::from(rel); |
| 147 | if rel_path |
| 148 | .components() |
| 149 | .any(|c| matches!(c, std::path::Component::ParentDir)) |
| 150 | { |
| 151 | return Err("res subdir cannot contain `..` segments".to_string()); |
| 152 | } |
| 153 | Ok(res_root.join(rel_path)) |
| 154 | } |
| 155 | |
| 156 | pub(crate) fn validate_dlc_name(raw: &str) -> Result<String, String> { |
| 157 | let dlc = raw.trim(); |
no test coverage detected