|
1 | 1 | use anyhow::{anyhow, Result}; |
2 | 2 | use log::debug; |
3 | 3 | use regex::Regex; |
4 | | -use std::path::{Path, PathBuf}; |
| 4 | +use std::{ |
| 5 | + path::{Path, PathBuf}, |
| 6 | + sync::LazyLock, |
| 7 | +}; |
5 | 8 |
|
6 | 9 | use crate::utils::fs::TempDir; |
7 | 10 | use apple_catalog_parsing; |
@@ -83,7 +86,7 @@ pub fn ipa_to_xcarchive(ipa_path: &Path, ipa_bytes: &[u8], temp_dir: &TempDir) - |
83 | 86 | let cursor = Cursor::new(ipa_bytes); |
84 | 87 | let mut ipa_archive = ZipArchive::new(cursor)?; |
85 | 88 |
|
86 | | - let app_name = extract_app_name_from_ipa(&ipa_archive)?; |
| 89 | + let app_name = extract_app_name_from_ipa(&ipa_archive)?.to_owned(); |
87 | 90 |
|
88 | 91 | // Extract all files from the archive |
89 | 92 | for i in 0..ipa_archive.len() { |
@@ -136,13 +139,16 @@ pub fn ipa_to_xcarchive(ipa_path: &Path, ipa_bytes: &[u8], temp_dir: &TempDir) - |
136 | 139 | Ok(xcarchive_dir) |
137 | 140 | } |
138 | 141 |
|
| 142 | +static PATTERN: LazyLock<Regex> = LazyLock::new(|| { |
| 143 | + Regex::new(r"^Payload/([^/]+)\.app/Info\.plist$").expect("regex is valid") |
| 144 | +}); |
| 145 | + |
139 | 146 | fn extract_app_name_from_ipa<'a>(archive: &'a ZipArchive<Cursor<&[u8]>>) -> Result<&'a str> { |
140 | | - let pattern = Regex::new(r"^Payload/([^/]+)\.app/Info\.plist$")?; |
141 | 147 | let matches = archive |
142 | 148 | .file_names() |
143 | | - .filter_map(|name| pattern.captures(name)) |
| 149 | + .filter_map(|name| PATTERN.captures(name)) |
144 | 150 | .map(|c| c.get(1).expect("group 1 must be present").as_str()) |
145 | | - .take(2) // If there are ≥2 matches, we already know the IPA is invalid |
| 151 | + .take(2) // If there are ≥2 matches, we already know the IPA is invalid |
146 | 152 | .collect::<Vec<_>>(); |
147 | 153 |
|
148 | 154 | if let &[app_name] = matches.as_slice() { |
|
0 commit comments