1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use crate::error::Result;
use crate::iff::chunk::Chunks;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};

use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};

pub(in crate::id3::v2) fn write_to_chunk_file<B>(data: &mut File, tag: &[u8]) -> Result<()>
where
	B: ByteOrder,
{
	data.seek(SeekFrom::Current(4))?;
	let file_size = data.read_u32::<B>()?;
	data.seek(SeekFrom::Current(4))?;

	let mut id3v2_chunk = (None, None);

	let mut chunks = Chunks::<B>::new(file_size);

	while chunks.next(data).is_ok() {
		if &chunks.fourcc == b"ID3 " || &chunks.fourcc == b"id3 " {
			id3v2_chunk = (
				Some(data.seek(SeekFrom::Current(0))? - 8),
				Some(chunks.size),
			);
			break;
		}

		data.seek(SeekFrom::Current(i64::from(chunks.size)))?;

		chunks.correct_position(data)?;
	}

	if let (Some(chunk_start), Some(mut chunk_size)) = id3v2_chunk {
		data.seek(SeekFrom::Start(0))?;

		// We need to remove the padding byte if it exists
		if chunk_size % 2 != 0 {
			chunk_size += 1;
		}

		let mut file_bytes = Vec::new();
		data.read_to_end(&mut file_bytes)?;

		file_bytes.splice(
			chunk_start as usize..(chunk_start + u64::from(chunk_size) + 8) as usize,
			[],
		);

		data.seek(SeekFrom::Start(0))?;
		data.set_len(0)?;
		data.write_all(&*file_bytes)?;
	}

	if !tag.is_empty() {
		data.seek(SeekFrom::End(0))?;
		data.write_all(&[b'I', b'D', b'3', b' '])?;
		data.write_u32::<B>(tag.len() as u32)?;
		data.write_all(tag)?;

		// It is required an odd length chunk be padded with a 0
		// The 0 isn't included in the chunk size, however
		if tag.len() % 2 != 0 {
			data.write_u8(0)?;
		}

		let total_size = data.seek(SeekFrom::Current(0))? - 8;

		data.seek(SeekFrom::Start(4))?;

		data.write_u32::<B>(total_size as u32)?;
	}

	Ok(())
}