| 1 | //! A file's identity and place, rewritten in an image held whole: OneNote 2010 saves a |
| 2 | //! section as a copy, and writes a package's files, outside any notebook, and gives each |
| 3 | //! file it unpacks an identity of its own (`corpus/notebook-package`). |
| 4 | |
| 5 | use crate::{Error, Header, create::placement, write::fresh_guid}; |
| 6 | |
| 7 | type Result<T> = std::result::Result<T, Error>; |
| 8 | |
| 9 | /// Gives the file `image` holds a new `guidFile` and version (`guidFileVersion`, |
| 10 | /// `nFileVersionGeneration`, `guidDenyReadFileVersion`), returning the identity. |
| 11 | pub fn reidentify(image: &mut [u8]) -> Result<[u8; 16]> { |
| 12 | let header = Header::parse(image)?; |
| 13 | let identity = fresh_guid()?; |
| 14 | let generation = header.generation.checked_add(1).ok_or(Error { |
| 15 | offset: 228, |
| 16 | message: "File generation counter is exhausted", |
| 17 | })?; |
| 18 | image[16..32].copy_from_slice(&identity); |
| 19 | image[212..228].copy_from_slice(&fresh_guid()?); |
| 20 | image[228..236].copy_from_slice(&generation.to_le_bytes()); |
| 21 | image[236..252].copy_from_slice(&fresh_guid()?); |
| 22 | Ok(identity) |
| 23 | } |
| 24 | |
| 25 | /// Places the file `image` holds as `place` does a file on disk; without `at`, outside any |
| 26 | /// notebook, its `guidAncestor` and `crcName` zero. |
| 27 | pub fn place_image(image: &mut [u8], at: Option<([u8; 16], &str)>) -> Result<()> { |
| 28 | Header::parse(image)?; |
| 29 | image[128..148] |
| 30 | .copy_from_slice(&at.map_or([0; 20], |(ancestor, name)| placement(ancestor, name))); |
| 31 | Ok(()) |
| 32 | } |
| 33 | |
| 34 | #[cfg(test)] |
| 35 | mod tests { |
| 36 | use super::*; |
| 37 | |
| 38 | #[test] |
| 39 | fn a_file_takes_a_new_identity_and_leaves_its_notebook() { |
| 40 | let mut image = crate::create_empty_section("A.one", None).unwrap(); |
| 41 | let before = Header::parse(&image).unwrap(); |
| 42 | place_image(&mut image, Some(([7; 16], "A.one"))).unwrap(); |
| 43 | assert_eq!(Header::parse(&image).unwrap().ancestor, [7; 16]); |
| 44 | let identity = reidentify(&mut image).unwrap(); |
| 45 | place_image(&mut image, None).unwrap(); |
| 46 | let after = Header::parse(&image).unwrap(); |
| 47 | assert_eq!(after.file_id, identity); |
| 48 | assert_ne!(after.file_id, before.file_id); |
| 49 | assert_ne!(after.version_id, before.version_id); |
| 50 | assert_eq!(after.generation, before.generation + 1); |
| 51 | assert_eq!((after.ancestor, after.name_crc), ([0; 16], 0)); |
| 52 | crate::Store::parse(&image).unwrap(); |
| 53 | } |
| 54 | } |