patch.rs (2980B)
1 // Copyright 2022 Adobe. All rights reserved. 2 // This file is licensed to you under the Apache License, 3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 4 // or the MIT license (http://opensource.org/licenses/MIT), 5 // at your option. 6 7 // Unless required by applicable law or agreed to in writing, 8 // this software is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or 10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the 11 // specific language governing permissions and limitations under 12 // each license. 13 14 use memchr::memmem; 15 16 use crate::error::{Error, Result}; 17 18 /** 19 Patch a sequence bytes with a new set of bytes - the search_bytes are erased and replaced with replace_bytes 20 This function only patches the first occurrence 21 returns the location where splice occurred 22 */ 23 pub fn patch_bytes(data: &mut Vec<u8>, search_bytes: &[u8], replace_bytes: &[u8]) -> Result<usize> { 24 // patch data bytes in memory 25 26 if let Some(splice_start) = memmem::find(data, search_bytes) { 27 data.splice( 28 splice_start..splice_start + search_bytes.len(), 29 replace_bytes.iter().cloned(), 30 ); 31 Ok(splice_start) 32 } else { 33 Err(Error::NotFound) 34 } 35 } 36 37 /** 38 Patch new content into a file 39 path - path to file to be patched 40 search_bytes - bytes to be replaced 41 replace_bytes - replacement bytes 42 returns the location where splice occurred 43 */ 44 #[cfg(all(test, feature = "file_io"))] 45 pub fn patch_file( 46 path: &std::path::Path, 47 search_bytes: &[u8], 48 replace_bytes: &[u8], 49 ) -> Result<usize> { 50 let mut buf = std::fs::read(path).map_err(Error::IoError)?; 51 52 let splice_point = patch_bytes(&mut buf, search_bytes, replace_bytes)?; 53 54 std::fs::write(path, &buf).map_err(Error::IoError)?; 55 56 Ok(splice_point) 57 } 58 59 #[cfg(test)] 60 pub mod tests { 61 #![allow(clippy::unwrap_used)] 62 63 use super::*; 64 65 #[test] 66 fn test_patch() { 67 let source = "Hello everyone this is a test".as_bytes(); 68 let mut source_vec = source.to_vec(); 69 let search_bytes = "everyone".as_bytes(); 70 let replace_bytes = "world".as_bytes(); 71 let replace_bytes2 = "universe".as_bytes(); 72 let test_bytes = "test".as_bytes(); 73 let unit_test_bytes = "unit test".as_bytes(); 74 75 println!("Original string: {}", String::from_utf8_lossy(&source_vec)); 76 77 patch_bytes(&mut source_vec, search_bytes, replace_bytes).unwrap(); 78 79 println!( 80 "Replaced string: {}\n", 81 String::from_utf8_lossy(&source_vec) 82 ); 83 84 patch_bytes(&mut source_vec, replace_bytes, replace_bytes2).unwrap(); 85 86 println!( 87 "Re-Replaced string: {}\n", 88 String::from_utf8_lossy(&source_vec) 89 ); 90 91 patch_bytes(&mut source_vec, test_bytes, unit_test_bytes).unwrap(); 92 93 println!( 94 "Pad end of data string: {}\n", 95 String::from_utf8_lossy(&source_vec) 96 ); 97 } 98 }