]> git.proxmox.com Git - rustc.git/blob - vendor/measureme/src/file_header.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / vendor / measureme / src / file_header.rs
1 //! All binary files generated by measureme have a simple file header that
2 //! consists of a 4 byte file magic string and a 4 byte little-endian version
3 //! number.
4
5 use crate::serialization::SerializationSink;
6 use byteorder::{ByteOrder, LittleEndian};
7 use std::error::Error;
8
9 pub const CURRENT_FILE_FORMAT_VERSION: u32 = 0;
10 pub const FILE_MAGIC_EVENT_STREAM: &[u8; 4] = b"MMES";
11 pub const FILE_MAGIC_STRINGTABLE_DATA: &[u8; 4] = b"MMSD";
12 pub const FILE_MAGIC_STRINGTABLE_INDEX: &[u8; 4] = b"MMSI";
13
14 /// The size of the file header in bytes. Note that functions in this module
15 /// rely on this size to be `8`.
16 pub const FILE_HEADER_SIZE: usize = 8;
17
18 pub fn write_file_header<S: SerializationSink>(s: &S, file_magic: &[u8; 4]) {
19 // The implementation here relies on FILE_HEADER_SIZE to have the value 8.
20 // Let's make sure this assumption cannot be violated without being noticed.
21 assert_eq!(FILE_HEADER_SIZE, 8);
22
23 s.write_atomic(FILE_HEADER_SIZE, |bytes| {
24 bytes[0..4].copy_from_slice(file_magic);
25 LittleEndian::write_u32(&mut bytes[4..8], CURRENT_FILE_FORMAT_VERSION);
26 });
27 }
28
29 pub fn read_file_header(bytes: &[u8], expected_magic: &[u8; 4]) -> Result<u32, Box<dyn Error>> {
30 // The implementation here relies on FILE_HEADER_SIZE to have the value 8.
31 // Let's make sure this assumption cannot be violated without being noticed.
32 assert_eq!(FILE_HEADER_SIZE, 8);
33
34 let actual_magic = &bytes[0..4];
35
36 if actual_magic != expected_magic {
37 // FIXME: The error message should mention the file path in order to be
38 // more useful.
39 let msg = format!(
40 "Unexpected file magic `{:?}`. Expected `{:?}`",
41 actual_magic, expected_magic,
42 );
43
44 return Err(From::from(msg));
45 }
46
47 Ok(LittleEndian::read_u32(&bytes[4..8]))
48 }
49
50 pub fn strip_file_header(data: &[u8]) -> &[u8] {
51 &data[FILE_HEADER_SIZE..]
52 }
53
54 #[cfg(test)]
55 mod tests {
56 use super::*;
57 use crate::serialization::test::TestSink;
58
59 #[test]
60 fn roundtrip() {
61 let data_sink = TestSink::new();
62
63 write_file_header(&data_sink, FILE_MAGIC_EVENT_STREAM);
64
65 let data = data_sink.into_bytes();
66
67 assert_eq!(
68 read_file_header(&data, FILE_MAGIC_EVENT_STREAM).unwrap(),
69 CURRENT_FILE_FORMAT_VERSION
70 );
71 }
72
73 #[test]
74 fn invalid_magic() {
75 let data_sink = TestSink::new();
76 write_file_header(&data_sink, FILE_MAGIC_STRINGTABLE_DATA);
77 let mut data = data_sink.into_bytes();
78
79 // Invalidate the filemagic
80 data[2] = 0;
81 assert!(read_file_header(&data, FILE_MAGIC_STRINGTABLE_DATA).is_err());
82 }
83
84 #[test]
85 fn other_version() {
86 let data_sink = TestSink::new();
87
88 write_file_header(&data_sink, FILE_MAGIC_STRINGTABLE_INDEX);
89
90 let mut data = data_sink.into_bytes();
91
92 // Change version
93 data[4] = 0xFF;
94 data[5] = 0xFF;
95 data[6] = 0xFF;
96 data[7] = 0xFF;
97 assert_eq!(
98 read_file_header(&data, FILE_MAGIC_STRINGTABLE_INDEX).unwrap(),
99 0xFFFF_FFFF
100 );
101 }
102 }