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
5use crate::{Error, Header, create::placement, write::fresh_guid};
6
7type 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.
11pub 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.
27pub 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)]
35mod 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}