1use crate::error::Error;
2use crate::resources::Resource;
3use crate::result::Result;
4use crate::utils::*;
5use manual_serializer::*;
6use std::collections::HashMap;
7use std::fmt;
8use std::sync::Arc;
9
10#[derive(Debug)]
14pub struct Header {
15 pub length: usize,
16 pub value_length: usize,
17 pub data_type: DataType,
18 pub key: String,
19 pub last: usize,
20}
21
22impl Header {
23 pub fn new(length: usize, value_length: usize, data_type: DataType, key: &str) -> Header {
24 Header {
25 length,
26 value_length,
27 data_type,
28 key: key.to_string(),
29 last: 0,
30 }
31 }
32}
33
34impl TrySerialize for Header {
35 type Error = Error;
36 fn try_serialize(&self, dest: &mut Serializer) -> Result<()> {
37 dest.try_align_u32()?;
38 dest.try_store_u16le(self.length as u16)?;
39 dest.try_store_u16le(self.value_length as u16)?;
40 match self.data_type {
41 DataType::Binary => {
42 dest.try_store_u16le(0)?;
43 }
44 DataType::Text => {
45 dest.try_store_u16le(1)?;
46 }
47 };
48 dest.try_store_utf16le_sz(&self.key)?;
49 dest.try_align_u32()?;
50 Ok(())
51 }
52}
53
54impl TryDeserialize for Header {
55 type Error = Error;
56
57 fn try_deserialize(src: &mut Deserializer) -> Result<Header> {
58 src.try_align_u32()?;
59
60 let cursor = src.cursor();
61 let length = src.try_load_u16le()? as usize;
62 let value_length = src.try_load_u16le()? as usize;
63 let data_type = src.try_load_u16le()?;
64 let data_type = match data_type {
66 0 => DataType::Binary,
67 1 => DataType::Text,
68 _ => return Err("Header::try_deserealize(): invalid resource data type (must be 1 or 0) - possible misalignment/corruption".into())
69 };
70 let key = src.try_load_utf16le_sz()?;
71
72 let padding = src.cursor() % 4;
73 src.try_offset(padding)?;
74 let last = cursor + length;
75
76 let header = Header {
77 length,
78 value_length,
79 data_type,
80 key,
81 last,
82 };
83 Ok(header)
85 }
86}
87
88fn try_build_struct(
89 key: &str,
90 data_type: DataType,
91 value_len: usize,
92 value: &[u8],
93) -> Result<Vec<u8>> {
94 let mut dest = Serializer::new(4096);
95 let header = Header::new(0, 0, data_type, key);
96 dest.try_store(&header)?;
97 dest.try_store_u8_slice(value)?;
98 let mut vec = dest.to_vec();
99 store_u16le(&mut vec[0..2], dest.len() as u16);
100 store_u16le(&mut vec[2..4], value_len as u16);
101 Ok(vec)
102}
103
104#[derive(Debug, Clone, Default)]
109pub struct Version([u16; 4]);
110
111impl TryDeserialize for Version {
112 type Error = Error;
113 fn try_deserialize(src: &mut Deserializer) -> Result<Self> {
114 let ms = src.try_load_u32le()?;
115 let ls = src.try_load_u32le()?;
116 Ok(Version([
117 (ms >> 16) as u16,
118 (ms & 0xffff) as u16,
119 (ls >> 16) as u16,
120 (ls & 0xffff) as u16,
121 ]))
122 }
123}
124
125impl TrySerialize for Version {
126 type Error = Error;
127 fn try_serialize(&self, dest: &mut Serializer) -> Result<()> {
128 dest.try_store_u32le((self.0[0] as u32) << 16 | (self.0[1] as u32))?;
129 dest.try_store_u32le((self.0[2] as u32) << 16 | (self.0[3] as u32))?;
130 Ok(())
131 }
132}
133
134impl fmt::Display for Version {
135 fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
136 if self.0[3] == 0 {
137 write!(f, "{}.{}.{}", self.0[0], self.0[1], self.0[2])?;
138 } else {
139 write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3])?;
140 }
141 Ok(())
142 }
143}
144
145#[derive(Debug, Clone, Default)]
148pub struct Date(u64);
149
150impl TryDeserialize for Date {
151 type Error = Error;
152 fn try_deserialize(src: &mut Deserializer) -> Result<Self> {
153 let ms = src.try_load_u32le()? as u64;
154 let ls = src.try_load_u32le()? as u64;
155 Ok(Date(ms << 32 | ls))
156 }
157}
158
159impl TrySerialize for Date {
160 type Error = Error;
161 fn try_serialize(&self, dest: &mut Serializer) -> Result<()> {
162 dest.try_store_u32le((self.0 >> 32) as u32)?;
163 dest.try_store_u32le((self.0 & 0xffffffff) as u32)?;
164 Ok(())
165 }
166}
167
168impl fmt::Display for Date {
169 fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
170 write!(f, "{}", self.0)?;
171 Ok(())
172 }
173}
174
175#[derive(Debug, Clone)]
178pub struct FileInfo {
179 pub signature: u32,
180 pub struc_version: u32,
181 pub file_version: Version,
182 pub product_version: Version,
183 pub file_flags_mask: u32,
184 pub file_flags: u32,
185 pub file_os: u32,
186 pub file_type: u32,
187 pub file_subtype: u32,
188 pub file_date: Date,
189}
190
191impl Default for FileInfo {
192 fn default() -> Self {
193 FileInfo {
194 signature: 0xfeef04bd,
195 struc_version: 0,
196 file_version: Version::default(),
197 product_version: Version::default(),
198 file_flags_mask: 0,
199 file_flags: 0,
200 file_os: 0,
201 file_type: 0,
202 file_subtype: 0,
203 file_date: Date::default(),
204 }
205 }
206}
207
208impl FileInfo {
209 pub fn print(&self) {
210 println!("signature: 0x{:x}", self.signature);
211 println!("struc_version: 0x{:x}", self.struc_version);
212 println!("file_version: {}", self.file_version);
213 println!("product_version: {}", self.product_version);
214 println!("file_flags_mask: 0x{:x}", self.file_flags_mask);
215 println!("file_flags: 0x{:x}", self.file_flags);
216 println!("file_os: 0x{:x}", self.file_os);
217 println!("file_type: 0x{:x}", self.file_type);
218 println!("file_subtype: 0x{:x}", self.file_subtype);
219 println!("file_date: {}", self.file_date);
220 }
221}
222impl TryDeserialize for FileInfo {
224 type Error = Error;
225 fn try_deserialize(src: &mut Deserializer) -> Result<FileInfo> {
226 let info = FileInfo {
229 signature: src.try_load_u32le()?,
230 struc_version: src.try_load_u32le()?,
231 file_version: src.try_load()?,
232 product_version: src.try_load()?,
233 file_flags_mask: src.try_load_u32le()?,
234 file_flags: src.try_load_u32le()?,
235 file_os: src.try_load_u32le()?,
236 file_type: src.try_load_u32le()?,
237 file_subtype: src.try_load_u32le()?,
238 file_date: src.try_load()?,
239 };
240
241 if info.signature != 0xfeef04bd {
242 return Err(format!("FileInfo: invalid signature 0x{:8x}", info.signature).into());
243 }
244
245 Ok(info)
246 }
247}
248
249impl TrySerialize for FileInfo {
250 type Error = Error;
251 fn try_serialize(&self, dest: &mut Serializer) -> Result<()> {
252 dest.try_store_u32le(self.signature)?
253 .try_store_u32le(self.struc_version)?
254 .try_store(&self.file_version)?
255 .try_store(&self.product_version)?
256 .try_store_u32le(self.file_flags_mask)?
257 .try_store_u32le(self.file_flags)?
258 .try_store_u32le(self.file_os)?
259 .try_store_u32le(self.file_type)?
260 .try_store_u32le(self.file_subtype)?
261 .try_store(&self.file_date)?;
262
263 Ok(())
264 }
265}
266
267#[derive(Debug, Clone)]
269pub enum VersionInfoChild {
270 StringFileInfo {
271 tables: HashMap<String, HashMap<String, Data>>,
272 },
273 VarFileInfo {
274 vars: HashMap<String, Vec<u32>>,
275 },
276}
277
278#[derive(Debug, Clone)]
280pub enum Data {
281 Binary(Vec<u8>),
282 Text(String),
283}
284
285impl TrySerialize for VersionInfoChild {
286 type Error = Error;
287 fn try_serialize(&self, dest: &mut Serializer) -> Result<()> {
288 match self {
289 VersionInfoChild::StringFileInfo { tables } => {
290 for (key_lang, map) in tables {
291 let mut lang_records = Serializer::default();
292 for (key_record, data) in map {
293 let (data_type, data) = match data {
294 Data::Binary(data) => (DataType::Binary, data.clone()),
295 Data::Text(text) => (DataType::Text, string_to_u8vec_sz(text)),
296 };
297
298 let string_record =
299 try_build_struct(key_record, data_type, data.len() / 2, &data)?;
300 lang_records.try_align_u32()?;
301 lang_records.try_store_u8_slice(&string_record)?;
302 }
303
304 let string_table =
305 try_build_struct(key_lang, DataType::Binary, 0, &lang_records.to_vec())?;
306 let string_file_info =
307 try_build_struct("StringFileInfo", DataType::Binary, 0, &string_table)?;
308 dest.try_align_u32()?;
309 dest.try_store_u8_slice(&string_file_info)?;
310 }
311 }
312 VersionInfoChild::VarFileInfo { vars } => {
313 let mut var_records = Serializer::default();
314 for (k, data) in vars {
315 let var_record = try_build_struct(
316 k,
317 DataType::Binary,
318 data.len() / 2,
319 &u32slice_to_u8vec(data),
320 )?;
321 var_records.try_align_u32()?;
322 var_records.try_store_u8_slice(&var_record)?;
323 }
324 let var_file_info =
325 try_build_struct("VarFileInfo", DataType::Binary, 0, &var_records.to_vec())?;
326 dest.try_align_u32()?;
327 dest.try_store_u8_slice(&var_file_info)?;
328 }
329 }
330
331 Ok(())
332 }
333}
334
335impl TryDeserialize for VersionInfoChild {
336 type Error = Error;
337 fn try_deserialize(src: &mut Deserializer) -> Result<VersionInfoChild> {
338 let header: Header = src.try_load()?;
339
340 let data = match header.key.as_str() {
341 "StringFileInfo" => {
342 let mut tables = HashMap::new();
343 while src.cursor() < header.last {
344 let string_table_header: Header = src.try_load()?;
345 let lang = string_table_header.key;
346 let mut data = HashMap::new();
347
348 while src.cursor() < string_table_header.last {
349 let string_header: Header = src.try_load()?;
350 match string_header.data_type {
351 DataType::Binary => {
352 let len = string_header.value_length * 2;
353 let vec = src.try_load_u8_vec(len)?;
354 data.insert(string_header.key, Data::Binary(vec));
355 }
356 DataType::Text => {
357 let text = src.try_load_utf16le_sz()?;
358 data.insert(string_header.key, Data::Text(text));
359 }
360 };
361 }
362
363 tables.insert(lang, data);
364 }
365
366 VersionInfoChild::StringFileInfo { tables }
367 }
368 "VarFileInfo" => {
369 let mut vars = HashMap::new();
370 while src.cursor() < header.last {
371 let var_header: Header = src.try_load()?;
373
374 let mut values = Vec::new();
375 while src.cursor() < var_header.last {
376 values.push(src.try_load_u32le()?);
377 }
378
379 vars.insert(var_header.key, values);
380 }
381
382 VersionInfoChild::VarFileInfo { vars }
383 }
384 _ => return Err(format!("Unknown child type: {}", header.key).into()),
385 };
386
387 Ok(data)
388 }
389}
390
391#[derive(Debug, Clone)]
393pub enum DataType {
394 Binary,
395 Text,
396}
397
398#[derive(Debug, Clone)]
401pub struct VersionInfo {
402 pub resource: Arc<Resource>,
404 pub data_type: DataType,
406 pub key: String,
408 pub info: FileInfo,
411 pub children: Vec<VersionInfoChild>,
415}
416
417impl TryFrom<Arc<Resource>> for VersionInfo {
418 type Error = Error;
419 fn try_from(resource: Arc<Resource>) -> Result<VersionInfo> {
420 let data = resource.encoded.lock().unwrap();
422 let mut src = Deserializer::new(&data);
423
424 let header: Header = src.try_load()?;
425 let info: FileInfo = src.try_load()?;
426 let skip = src.cursor() % 4;
427 src.try_offset(skip)?;
428
429 let mut children = Vec::new();
430 let mut remaining = src.remaining();
431 while remaining > 0 {
432 let child: VersionInfoChild = src.try_load()?;
433 children.push(child);
434 remaining = src.remaining();
435 }
436
437 let info = VersionInfo {
438 resource: resource.clone(),
439 data_type: header.data_type,
440 key: header.key,
441 info,
442 children,
443 };
444
445 Ok(info)
446 }
447}
448
449impl VersionInfo {
450 pub fn try_to_vec(&self) -> Result<Vec<u8>> {
451 let mut dest = Serializer::default();
452
453 let mut child_data = Serializer::default();
454 for child in &self.children {
455 child_data.try_store(child)?;
456 child_data.try_align_u32()?;
457 }
458 let child_data = child_data.to_vec();
459
460 let file_info_data = Serializer::default().try_store(&self.info)?.to_vec();
461
462 let data = Serializer::default()
463 .try_store_u8_slice(&file_info_data)?
464 .try_align_u32()?
465 .try_store_u8_slice(&child_data)?
466 .to_vec();
467
468 let version_info = try_build_struct(
469 "VS_VERSION_INFO",
470 DataType::Binary,
471 file_info_data.len(),
472 &data,
473 )?;
474 dest.try_store_u8_slice(&version_info)?;
475
476 Ok(dest.to_vec())
477 }
478
479 pub fn set_file_version(&mut self, v: &[u16; 4]) -> &mut Self {
480 self.info.file_version = Version(*v);
481 self.insert_string("FileVersion", &Version(*v).to_string());
482 self
483 }
484
485 pub fn set_product_version(&mut self, v: &[u16; 4]) -> &mut Self {
486 self.info.product_version = Version(*v);
487 self.insert_string("ProductVersion", &Version(*v).to_string());
488 self
489 }
490
491 pub fn set_version(&mut self, v: &[u16; 4]) -> &mut Self {
492 self.set_file_version(v);
493 self.set_product_version(v);
494 self
495 }
496
497 pub fn replace_string(&mut self, key: &str, text: &str) -> &mut Self {
498 for child in self.children.iter_mut() {
499 if let VersionInfoChild::StringFileInfo { tables } = child {
500 for table in tables.values_mut() {
501 if table.get(key).is_some() {
502 table.insert(key.to_string(), Data::Text(text.to_string()));
503 }
504 }
505 }
506 }
507 self
508 }
509
510 pub fn insert_string(&mut self, key: &str, text: &str) -> &mut Self {
511 for child in self.children.iter_mut() {
512 if let VersionInfoChild::StringFileInfo { tables } = child {
513 for table in tables.values_mut() {
514 table.insert(key.to_string(), Data::Text(text.to_string()));
515 }
516 }
517 }
518 self
519 }
520
521 pub fn insert_strings(&mut self, tuples: &[(&str, &str)]) -> &mut Self {
522 for child in self.children.iter_mut() {
523 if let VersionInfoChild::StringFileInfo { tables } = child {
524 for table in tables.values_mut() {
525 for (key, text) in tuples {
526 table.insert(key.to_string(), Data::Text(text.to_string()));
527 }
528 }
529 }
530 }
531 self
532 }
533
534 pub fn remove_string(&mut self, key: &str) -> &mut Self {
535 for child in self.children.iter_mut() {
536 if let VersionInfoChild::StringFileInfo { tables } = child {
537 for table in tables.values_mut() {
538 table.remove(key);
539 }
540 }
541 }
542 self
543 }
544
545 pub fn ensure_language(&mut self, lang: &str) -> &mut Self {
546 for child in self.children.iter_mut() {
547 if let VersionInfoChild::StringFileInfo { tables } = child {
548 if tables.get(lang).is_none() {
549 tables.insert(lang.to_string(), HashMap::new());
550 }
551 }
552 }
553 self
554 }
555
556 pub fn update(&mut self) -> Result<()> {
557 self.resource.replace(&self.try_to_vec()?)?.update()?;
558 Ok(())
559 }
560}